Coverage Report

Created: 2025-10-10 15:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/builder/project/test/blockchaintest/blockchaintest.cpp
Line
Count
Source
1
// evmone: Fast Ethereum Virtual Machine implementation
2
// Copyright 2023 The evmone Authors.
3
// SPDX-License-Identifier: Apache-2.0
4
5
#include "blockchaintest.hpp"
6
#include <CLI/CLI.hpp>
7
#include <evmone/evmone.h>
8
#include <evmone/version.h>
9
#include <gtest/gtest.h>
10
#include <iostream>
11
12
namespace fs = std::filesystem;
13
14
namespace
15
{
16
/// Implementation of a gtest Test which runs all blockchain tests from a given file.
17
class BlockchainGTestFile : public testing::Test
18
{
19
    fs::path m_json_test_file;
20
    evmc::VM& m_vm;
21
22
public:
23
    explicit BlockchainGTestFile(fs::path json_test_file, evmc::VM& vm) noexcept
24
2.82k
      : m_json_test_file{std::move(json_test_file)}, m_vm{vm}
25
2.82k
    {}
26
27
    void TestBody() final
28
2.82k
    {
29
2.82k
        std::ifstream f{m_json_test_file};
30
31
2.82k
        try
32
2.82k
        {
33
2.82k
            evmone::test::run_blockchain_tests(evmone::test::load_blockchain_tests(f), m_vm);
34
2.82k
        }
35
2.82k
        catch (const evmone::test::UnsupportedTestFeature& ex)
36
2.82k
        {
37
2
            GTEST_SKIP() << ex.what();
38
2
        }
39
2.82k
    }
40
41
    static void register_one(const std::string& suite_name, const fs::path& file, evmc::VM& vm)
42
2.82k
    {
43
2.82k
        testing::RegisterTest(suite_name.c_str(), file.stem().string().c_str(), nullptr, nullptr,
44
2.82k
            file.string().c_str(), 0,
45
2.82k
            [file, &vm]() -> testing::Test* { return new BlockchainGTestFile(file, vm); });
46
2.82k
    }
47
};
48
49
/// Implementation of a gtest Test which runs a single blockchain test.
50
class BlockchainGTest : public testing::Test
51
{
52
    const evmone::test::BlockchainTest m_blockchain_test;
53
    evmc::VM& m_vm;
54
55
public:
56
    explicit BlockchainGTest(evmone::test::BlockchainTest blockchain_test, evmc::VM& vm) noexcept
57
0
      : m_blockchain_test{std::move(blockchain_test)}, m_vm{vm}
58
0
    {}
59
60
    void TestBody() final
61
0
    {
62
0
        evmone::test::run_blockchain_tests(std::array{m_blockchain_test}, m_vm);
63
0
    }
64
65
    static void register_one(const evmone::test::BlockchainTest& test,
66
        const std::string& suite_name, const std::string& test_name, const fs::path& file,
67
        evmc::VM& vm)
68
0
    {
69
0
        testing::RegisterTest(suite_name.c_str(), test_name.c_str(), nullptr, nullptr,
70
0
            file.string().c_str(), 0,
71
0
            [test, &vm]() -> testing::Test* { return new BlockchainGTest(test, vm); });
72
0
    }
73
};
74
75
void register_test_files(const fs::path& root, evmc::VM& vm)
76
1
{
77
1
    if (is_directory(root))
78
1
    {
79
1
        std::vector<fs::path> test_files;
80
1
        std::copy_if(fs::recursive_directory_iterator{root}, fs::recursive_directory_iterator{},
81
2.95k
            std::back_inserter(test_files), [](const fs::directory_entry& entry) {
82
                // "index.json" files are just lists of tests generated by other tools.
83
2.95k
                return entry.is_regular_file() && 
entry.path().extension() == ".json"2.82k
&&
84
2.95k
                       
entry.path().filename() != "index.json"2.82k
;
  MC/DC Decision Region (83:24) to (84:63)

  Number of Conditions: 3
     Condition C1 --> (83:24)
     Condition C2 --> (83:51)
     Condition C3 --> (84:24)

  Executed MC/DC Test Vectors:

     C1, C2, C3    Result
  1 { F,  -,  -  = F      }
  2 { T,  T,  T  = T      }

  C1-Pair: covered: (1,2)
  C2-Pair: not covered
  C3-Pair: not covered
  MC/DC Coverage for Expression: 33.33%
85
2.95k
            });
86
1
        std::ranges::sort(test_files);
87
88
1
        for (const auto& p : test_files)
89
2.82k
            BlockchainGTestFile::register_one(fs::relative(p, root).parent_path().string(), p, vm);
90
1
    }
91
0
    else  // Treat as a file.
92
0
    {
93
0
        std::ifstream f{root};
94
0
        try
95
0
        {
96
0
            const auto tests = evmone::test::load_blockchain_tests(f);
97
0
            for (const auto& test : tests)
98
0
                BlockchainGTest::register_one(test, root.string(), test.name, root, vm);
99
0
        }
100
0
        catch (const evmone::test::UnsupportedTestFeature& ex)
101
0
        {
102
0
            std::cerr << ex.what() << ": " << root.string() << '\n';
103
0
        }
104
0
    }
105
1
}
106
}  // namespace
107
108
109
int main(int argc, char* argv[])
110
1
{
111
1
    try
112
1
    {
113
1
        testing::InitGoogleTest(&argc, argv);  // Process GoogleTest flags.
114
115
1
        CLI::App app{"evmone blockchain test runner"};
116
117
1
        app.set_version_flag("--version", "evmone-blockchaintest " EVMONE_VERSION);
118
119
1
        std::vector<std::string> paths;
120
1
        app.add_option("path", paths,
121
1
               "Path to test file or directory. For a directory, all .json "
122
1
               "files (except index.json) are considered test files, and each file is treated as a "
123
1
               "separate test. For a file, all tests in the file are treated as separate tests.")
124
1
            ->required()
125
1
            ->check(CLI::ExistingPath);
126
127
1
        bool trace_flag = false;
128
1
        app.add_flag("--trace", trace_flag, "Enable EVM tracing");
129
130
1
        CLI11_PARSE(app, argc, argv);
131
132
1
        evmc::VM vm{evmc_create_evmone()};
133
134
1
        if (trace_flag)
135
0
            vm.set_option("trace", "1");
136
137
1
        for (const auto& p : paths)
138
1
            register_test_files(p, vm);
139
140
1
        return RUN_ALL_TESTS();
141
1
    }
142
1
    catch (const std::exception& ex)
143
1
    {
144
0
        std::cerr << ex.what() << "\n";
145
0
        return -1;
146
0
    }
147
1
}