1 | // Copyright 2011 Google Inc. All Rights Reserved. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | #ifndef NINJA_TEST_H_ |
16 | #define NINJA_TEST_H_ |
17 | |
18 | #include "disk_interface.h" |
19 | #include "manifest_parser.h" |
20 | #include "state.h" |
21 | #include "util.h" |
22 | |
23 | // A tiny testing framework inspired by googletest, but much simpler and |
24 | // faster to compile. It supports most things commonly used from googltest. The |
25 | // most noticeable things missing: EXPECT_* and ASSERT_* don't support |
26 | // streaming notes to them with operator<<, and for failing tests the lhs and |
27 | // rhs are not printed. That's so that this header does not have to include |
28 | // sstream, which slows down building ninja_test almost 20%. |
29 | namespace testing { |
30 | class Test { |
31 | bool failed_; |
32 | int assertion_failures_; |
33 | public: |
34 | Test() : failed_(false), assertion_failures_(0) {} |
35 | virtual ~Test() {} |
36 | virtual void SetUp() {} |
37 | virtual void TearDown() {} |
38 | virtual void Run() = 0; |
39 | |
40 | bool Failed() const { return failed_; } |
41 | int AssertionFailures() const { return assertion_failures_; } |
42 | void AddAssertionFailure() { assertion_failures_++; } |
43 | bool Check(bool condition, const char* file, int line, const char* error); |
44 | }; |
45 | } |
46 | |
47 | void RegisterTest(testing::Test* (*)(), const char*); |
48 | |
49 | extern testing::Test* g_current_test; |
50 | #define TEST_F_(x, y, name) \ |
51 | struct y : public x { \ |
52 | static testing::Test* Create() { return g_current_test = new y; } \ |
53 | virtual void Run(); \ |
54 | }; \ |
55 | struct Register##y { \ |
56 | Register##y() { RegisterTest(y::Create, name); } \ |
57 | }; \ |
58 | Register##y g_register_##y; \ |
59 | void y::Run() |
60 | |
61 | #define TEST_F(x, y) TEST_F_(x, x##y, #x "." #y) |
62 | #define TEST(x, y) TEST_F_(testing::Test, x##y, #x "." #y) |
63 | |
64 | #define EXPECT_EQ(a, b) \ |
65 | g_current_test->Check(a == b, __FILE__, __LINE__, #a " == " #b) |
66 | #define EXPECT_NE(a, b) \ |
67 | g_current_test->Check(a != b, __FILE__, __LINE__, #a " != " #b) |
68 | #define EXPECT_GT(a, b) \ |
69 | g_current_test->Check(a > b, __FILE__, __LINE__, #a " > " #b) |
70 | #define EXPECT_LT(a, b) \ |
71 | g_current_test->Check(a < b, __FILE__, __LINE__, #a " < " #b) |
72 | #define EXPECT_GE(a, b) \ |
73 | g_current_test->Check(a >= b, __FILE__, __LINE__, #a " >= " #b) |
74 | #define EXPECT_LE(a, b) \ |
75 | g_current_test->Check(a <= b, __FILE__, __LINE__, #a " <= " #b) |
76 | #define EXPECT_TRUE(a) \ |
77 | g_current_test->Check(static_cast<bool>(a), __FILE__, __LINE__, #a) |
78 | #define EXPECT_FALSE(a) \ |
79 | g_current_test->Check(!static_cast<bool>(a), __FILE__, __LINE__, #a) |
80 | |
81 | #define ASSERT_EQ(a, b) \ |
82 | if (!EXPECT_EQ(a, b)) { g_current_test->AddAssertionFailure(); return; } |
83 | #define ASSERT_NE(a, b) \ |
84 | if (!EXPECT_NE(a, b)) { g_current_test->AddAssertionFailure(); return; } |
85 | #define ASSERT_GT(a, b) \ |
86 | if (!EXPECT_GT(a, b)) { g_current_test->AddAssertionFailure(); return; } |
87 | #define ASSERT_LT(a, b) \ |
88 | if (!EXPECT_LT(a, b)) { g_current_test->AddAssertionFailure(); return; } |
89 | #define ASSERT_GE(a, b) \ |
90 | if (!EXPECT_GE(a, b)) { g_current_test->AddAssertionFailure(); return; } |
91 | #define ASSERT_LE(a, b) \ |
92 | if (!EXPECT_LE(a, b)) { g_current_test->AddAssertionFailure(); return; } |
93 | #define ASSERT_TRUE(a) \ |
94 | if (!EXPECT_TRUE(a)) { g_current_test->AddAssertionFailure(); return; } |
95 | #define ASSERT_FALSE(a) \ |
96 | if (!EXPECT_FALSE(a)) { g_current_test->AddAssertionFailure(); return; } |
97 | #define ASSERT_NO_FATAL_FAILURE(a) \ |
98 | { \ |
99 | int fail_count = g_current_test->AssertionFailures(); \ |
100 | a; \ |
101 | if (fail_count != g_current_test->AssertionFailures()) { \ |
102 | g_current_test->AddAssertionFailure(); \ |
103 | return; \ |
104 | } \ |
105 | } |
106 | |
107 | // Support utilities for tests. |
108 | |
109 | struct Node; |
110 | |
111 | /// A base test fixture that includes a State object with a |
112 | /// builtin "cat" rule. |
113 | struct StateTestWithBuiltinRules : public testing::Test { |
114 | StateTestWithBuiltinRules(); |
115 | |
116 | /// Add a "cat" rule to \a state. Used by some tests; it's |
117 | /// otherwise done by the ctor to state_. |
118 | void AddCatRule(State* state); |
119 | |
120 | /// Short way to get a Node by its path from state_. |
121 | Node* GetNode(const std::string& path); |
122 | |
123 | State state_; |
124 | }; |
125 | |
126 | void AssertParse(State* state, const char* input, |
127 | ManifestParserOptions = ManifestParserOptions()); |
128 | void AssertHash(const char* expected, uint64_t actual); |
129 | void VerifyGraph(const State& state); |
130 | |
131 | /// An implementation of DiskInterface that uses an in-memory representation |
132 | /// of disk state. It also logs file accesses and directory creations |
133 | /// so it can be used by tests to verify disk access patterns. |
134 | struct VirtualFileSystem : public DiskInterface { |
135 | VirtualFileSystem() : now_(1) {} |
136 | |
137 | /// "Create" a file with contents. |
138 | void Create(const std::string& path, const std::string& contents); |
139 | |
140 | /// Tick "time" forwards; subsequent file operations will be newer than |
141 | /// previous ones. |
142 | int Tick() { |
143 | return ++now_; |
144 | } |
145 | |
146 | // DiskInterface |
147 | virtual TimeStamp Stat(const std::string& path, std::string* err) const; |
148 | virtual bool WriteFile(const std::string& path, const std::string& contents); |
149 | virtual bool MakeDir(const std::string& path); |
150 | virtual Status ReadFile(const std::string& path, std::string* contents, |
151 | std::string* err); |
152 | virtual int RemoveFile(const std::string& path); |
153 | |
154 | /// An entry for a single in-memory file. |
155 | struct Entry { |
156 | int mtime; |
157 | std::string stat_error; // If mtime is -1. |
158 | std::string contents; |
159 | }; |
160 | |
161 | std::vector<std::string> directories_made_; |
162 | std::vector<std::string> files_read_; |
163 | typedef std::map<std::string, Entry> FileMap; |
164 | FileMap files_; |
165 | std::set<std::string> files_removed_; |
166 | std::set<std::string> files_created_; |
167 | |
168 | /// A simple fake timestamp for file operations. |
169 | int now_; |
170 | }; |
171 | |
172 | struct ScopedTempDir { |
173 | /// Create a temporary directory and chdir into it. |
174 | void CreateAndEnter(const std::string& name); |
175 | |
176 | /// Clean up the temporary directory. |
177 | void Cleanup(); |
178 | |
179 | /// The temp directory containing our dir. |
180 | std::string start_dir_; |
181 | /// The subdirectory name for our dir, or empty if it hasn't been set up. |
182 | std::string temp_dir_name_; |
183 | }; |
184 | |
185 | #endif // NINJA_TEST_H_ |
186 | |