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%.
29namespace testing {
30class 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
47void RegisterTest(testing::Test* (*)(), const char*);
48
49extern 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
109struct Node;
110
111/// A base test fixture that includes a State object with a
112/// builtin "cat" rule.
113struct 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
126void AssertParse(State* state, const char* input,
127 ManifestParserOptions = ManifestParserOptions());
128void AssertHash(const char* expected, uint64_t actual);
129void 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.
134struct 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
172struct 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