/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 | } |