summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorNico Weber <nicolasweber@gmx.de>2014-09-18 05:00:33 (GMT)
committerNico Weber <nicolasweber@gmx.de>2014-09-18 05:00:33 (GMT)
commit17dcd6570035d7f675c7ff0e246b51ba3a12a364 (patch)
tree503e3ef698ff7b1ea547bb0ddb354be47d6d0d56 /src
parent5758dc13dd9b943ed584bd0cbaa520b2207a09f5 (diff)
parent954669e9c53301989af3a05bbd69564a3eb41bec (diff)
downloadNinja-17dcd6570035d7f675c7ff0e246b51ba3a12a364.zip
Ninja-17dcd6570035d7f675c7ff0e246b51ba3a12a364.tar.gz
Ninja-17dcd6570035d7f675c7ff0e246b51ba3a12a364.tar.bz2
Merge pull request #812 from nico/ninjatest
Use a small, standalone testing framework for ninja instead of googletest.
Diffstat (limited to 'src')
-rw-r--r--src/build_test.cc4
-rw-r--r--src/depfile_parser_test.cc2
-rw-r--r--src/deps_log_test.cc5
-rw-r--r--src/disk_interface_test.cc4
-rw-r--r--src/includes_normalize_test.cc2
-rw-r--r--src/lexer_test.cc3
-rw-r--r--src/manifest_parser_test.cc5
-rw-r--r--src/msvc_helper_test.cc2
-rw-r--r--src/ninja_test.cc158
-rw-r--r--src/state_test.cc3
-rw-r--r--src/subprocess_test.cc10
-rw-r--r--src/test.cc4
-rw-r--r--src/test.h86
13 files changed, 221 insertions, 67 deletions
diff --git a/src/build_test.cc b/src/build_test.cc
index dad69dc..6336206 100644
--- a/src/build_test.cc
+++ b/src/build_test.cc
@@ -14,6 +14,8 @@
#include "build.h"
+#include <assert.h>
+
#include "build_log.h"
#include "deps_log.h"
#include "graph.h"
@@ -506,7 +508,7 @@ void BuildTest::RebuildTarget(const string& target, const char* manifest,
builder.command_runner_.reset(&command_runner_);
if (!builder.AlreadyUpToDate()) {
bool build_res = builder.Build(&err);
- EXPECT_TRUE(build_res) << "builder.Build(&err)";
+ EXPECT_TRUE(build_res);
}
builder.command_runner_.release();
}
diff --git a/src/depfile_parser_test.cc b/src/depfile_parser_test.cc
index a5f3321..e67ef79 100644
--- a/src/depfile_parser_test.cc
+++ b/src/depfile_parser_test.cc
@@ -14,7 +14,7 @@
#include "depfile_parser.h"
-#include <gtest/gtest.h>
+#include "test.h"
struct DepfileParserTest : public testing::Test {
bool Parse(const char* input, string* err);
diff --git a/src/deps_log_test.cc b/src/deps_log_test.cc
index e8e5138..4fa4008 100644
--- a/src/deps_log_test.cc
+++ b/src/deps_log_test.cc
@@ -14,6 +14,11 @@
#include "deps_log.h"
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+
#include "graph.h"
#include "util.h"
#include "test.h"
diff --git a/src/disk_interface_test.cc b/src/disk_interface_test.cc
index b2e8cb5..05d509c 100644
--- a/src/disk_interface_test.cc
+++ b/src/disk_interface_test.cc
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gtest/gtest.h>
-
+#include <assert.h>
+#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
diff --git a/src/includes_normalize_test.cc b/src/includes_normalize_test.cc
index 419996f..cf4a4a3 100644
--- a/src/includes_normalize_test.cc
+++ b/src/includes_normalize_test.cc
@@ -14,8 +14,6 @@
#include "includes_normalize.h"
-#include <gtest/gtest.h>
-
#include "test.h"
#include "util.h"
diff --git a/src/lexer_test.cc b/src/lexer_test.cc
index e8a1642..331d8e1 100644
--- a/src/lexer_test.cc
+++ b/src/lexer_test.cc
@@ -14,9 +14,8 @@
#include "lexer.h"
-#include <gtest/gtest.h>
-
#include "eval_env.h"
+#include "test.h"
TEST(Lexer, ReadVarValue) {
Lexer lexer("plain text $var $VaR ${x}\n");
diff --git a/src/manifest_parser_test.cc b/src/manifest_parser_test.cc
index 5f4b30a..20168df 100644
--- a/src/manifest_parser_test.cc
+++ b/src/manifest_parser_test.cc
@@ -17,17 +17,16 @@
#include <map>
#include <vector>
-#include <gtest/gtest.h>
-
#include "graph.h"
#include "state.h"
+#include "test.h"
struct ParserTest : public testing::Test,
public ManifestParser::FileReader {
void AssertParse(const char* input) {
ManifestParser parser(&state, this);
string err;
- ASSERT_TRUE(parser.ParseTest(input, &err)) << err;
+ EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
}
diff --git a/src/msvc_helper_test.cc b/src/msvc_helper_test.cc
index 391c045..29db650 100644
--- a/src/msvc_helper_test.cc
+++ b/src/msvc_helper_test.cc
@@ -14,8 +14,6 @@
#include "msvc_helper.h"
-#include <gtest/gtest.h>
-
#include "test.h"
#include "util.h"
diff --git a/src/ninja_test.cc b/src/ninja_test.cc
index 989ea5c..54d8784 100644
--- a/src/ninja_test.cc
+++ b/src/ninja_test.cc
@@ -15,9 +15,35 @@
#include <stdarg.h>
#include <stdio.h>
-#include "gtest/gtest.h"
+#ifdef _WIN32
+#include "getopt.h"
+#else
+#include <getopt.h>
+#endif
+
+#include "test.h"
#include "line_printer.h"
+struct RegisteredTest {
+ testing::Test* (*factory)();
+ const char *name;
+ bool should_run;
+};
+// This can't be a vector because tests call RegisterTest from static
+// initializers and the order static initializers run it isn't specified. So
+// the vector constructor isn't guaranteed to run before all of the
+// RegisterTest() calls.
+static RegisteredTest tests[10000];
+testing::Test* g_current_test;
+static int ntests;
+static LinePrinter printer;
+
+void RegisterTest(testing::Test* (*factory)(), const char* name) {
+ tests[ntests].factory = factory;
+ tests[ntests++].name = name;
+}
+
+namespace {
string StringPrintf(const char* format, ...) {
const int N = 1024;
char buf[N];
@@ -30,59 +56,101 @@ string StringPrintf(const char* format, ...) {
return buf;
}
-/// A test result printer that's less wordy than gtest's default.
-struct LaconicPrinter : public testing::EmptyTestEventListener {
- LaconicPrinter() : tests_started_(0), test_count_(0), iteration_(0) {}
- virtual void OnTestProgramStart(const testing::UnitTest& unit_test) {
- test_count_ = unit_test.test_to_run_count();
- }
+void Usage() {
+ fprintf(stderr,
+"usage: ninja_tests [options]\n"
+"\n"
+"options:\n"
+" --gtest_filter=POSTIVE_PATTERN[-NEGATIVE_PATTERN]\n"
+" Run tests whose names match the positive but not the negative pattern.\n"
+" '*' matches any substring. (gtest's ':', '?' are not implemented).\n");
+}
- virtual void OnTestIterationStart(const testing::UnitTest& test_info,
- int iteration) {
- tests_started_ = 0;
- iteration_ = iteration;
+bool PatternMatchesString(const char* pattern, const char* str) {
+ switch (*pattern) {
+ case '\0':
+ case '-': return *str == '\0';
+ case '*': return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
+ PatternMatchesString(pattern + 1, str);
+ default: return *pattern == *str &&
+ PatternMatchesString(pattern + 1, str + 1);
}
+}
- virtual void OnTestStart(const testing::TestInfo& test_info) {
- ++tests_started_;
- printer_.Print(
- StringPrintf("[%d/%d%s] %s.%s",
- tests_started_,
- test_count_,
- iteration_ ? StringPrintf(" iter %d", iteration_).c_str()
- : "",
- test_info.test_case_name(),
- test_info.name()),
- LinePrinter::ELIDE);
- }
+bool TestMatchesFilter(const char* test, const char* filter) {
+ // Split --gtest_filter at '-' into positive and negative filters.
+ const char* const dash = strchr(filter, '-');
+ const char* pos = dash == filter ? "*" : filter; //Treat '-test1' as '*-test1'
+ const char* neg = dash ? dash + 1 : "";
+ return PatternMatchesString(pos, test) && !PatternMatchesString(neg, test);
+}
- virtual void OnTestPartResult(
- const testing::TestPartResult& test_part_result) {
- if (!test_part_result.failed())
- return;
- printer_.PrintOnNewLine(StringPrintf(
- "*** Failure in %s:%d\n%s\n", test_part_result.file_name(),
- test_part_result.line_number(), test_part_result.summary()));
- }
+bool ReadFlags(int* argc, char*** argv, const char** test_filter) {
+ enum { OPT_GTEST_FILTER = 1 };
+ const option kLongOptions[] = {
+ { "gtest_filter", required_argument, NULL, OPT_GTEST_FILTER },
+ { NULL, 0, NULL, 0 }
+ };
- virtual void OnTestProgramEnd(const testing::UnitTest& unit_test) {
- printer_.PrintOnNewLine(unit_test.Passed() ? "passed\n" : "failed\n");
+ int opt;
+ while ((opt = getopt_long(*argc, *argv, "h", kLongOptions, NULL)) != -1) {
+ switch (opt) {
+ case OPT_GTEST_FILTER:
+ if (strchr(optarg, '?') == NULL && strchr(optarg, ':') == NULL) {
+ *test_filter = optarg;
+ break;
+ } // else fall through.
+ default:
+ Usage();
+ return false;
+ }
}
+ *argv += optind;
+ *argc -= optind;
+ return true;
+}
- private:
- LinePrinter printer_;
- int tests_started_;
- int test_count_;
- int iteration_;
-};
+} // namespace
+
+bool testing::Test::Check(bool condition, const char* file, int line,
+ const char* error) {
+ if (!condition) {
+ printer.PrintOnNewLine(
+ StringPrintf("*** Failure in %s:%d\n%s\n", file, line, error));
+ failed_ = true;
+ }
+ return condition;
+}
int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
+ int tests_started = 0;
- testing::TestEventListeners& listeners =
- testing::UnitTest::GetInstance()->listeners();
- delete listeners.Release(listeners.default_result_printer());
- listeners.Append(new LaconicPrinter);
+ const char* test_filter = "*";
+ if (!ReadFlags(&argc, &argv, &test_filter))
+ return 1;
+
+ int nactivetests = 0;
+ for (int i = 0; i < ntests; i++)
+ if ((tests[i].should_run = TestMatchesFilter(tests[i].name, test_filter)))
+ ++nactivetests;
+
+ bool passed = true;
+ for (int i = 0; i < ntests; i++) {
+ if (!tests[i].should_run) continue;
+
+ ++tests_started;
+ testing::Test* test = tests[i].factory();
+ printer.Print(
+ StringPrintf("[%d/%d] %s", tests_started, nactivetests, tests[i].name),
+ LinePrinter::ELIDE);
+ test->SetUp();
+ test->Run();
+ test->TearDown();
+ if (test->Failed())
+ passed = false;
+ delete test;
+ }
- return RUN_ALL_TESTS();
+ printer.PrintOnNewLine(passed ? "passed\n" : "failed\n");
+ return passed ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/src/state_test.cc b/src/state_test.cc
index af2bff1..a4fafa1 100644
--- a/src/state_test.cc
+++ b/src/state_test.cc
@@ -12,10 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include <gtest/gtest.h>
-
#include "graph.h"
#include "state.h"
+#include "test.h"
namespace {
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index 775a13a..fe53748 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -18,6 +18,7 @@
#ifndef _WIN32
// SetWithLots need setrlimit.
+#include <stdio.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
@@ -92,7 +93,7 @@ TEST_F(SubprocessTest, InterruptParent) {
return;
}
- ADD_FAILURE() << "We should have been interrupted";
+ ASSERT_FALSE("We should have been interrupted");
}
TEST_F(SubprocessTest, Console) {
@@ -176,9 +177,10 @@ TEST_F(SubprocessTest, SetWithLots) {
// Make sure [ulimit -n] isn't going to stop us from working.
rlimit rlim;
ASSERT_EQ(0, getrlimit(RLIMIT_NOFILE, &rlim));
- ASSERT_GT(rlim.rlim_cur, kNumProcs)
- << "Raise [ulimit -n] well above " << kNumProcs
- << " to make this test go";
+ if (!EXPECT_GT(rlim.rlim_cur, kNumProcs)) {
+ printf("Raise [ulimit -n] well above %u to make this test go\n", kNumProcs);
+ return;
+ }
vector<Subprocess*> procs;
for (size_t i = 0; i < kNumProcs; ++i) {
diff --git a/src/test.cc b/src/test.cc
index 21015ed..ed2b910 100644
--- a/src/test.cc
+++ b/src/test.cc
@@ -24,6 +24,8 @@
#ifdef _WIN32
#include <windows.h>
+#else
+#include <unistd.h>
#endif
namespace {
@@ -90,7 +92,7 @@ Node* StateTestWithBuiltinRules::GetNode(const string& path) {
void AssertParse(State* state, const char* input) {
ManifestParser parser(state, NULL);
string err;
- ASSERT_TRUE(parser.ParseTest(input, &err)) << err;
+ EXPECT_TRUE(parser.ParseTest(input, &err));
ASSERT_EQ("", err);
}
diff --git a/src/test.h b/src/test.h
index f34b877..4c15203 100644
--- a/src/test.h
+++ b/src/test.h
@@ -15,12 +15,94 @@
#ifndef NINJA_TEST_H_
#define NINJA_TEST_H_
-#include <gtest/gtest.h>
-
#include "disk_interface.h"
#include "state.h"
#include "util.h"
+// A tiny testing framework inspired by googletest, but much simpler and
+// faster to compile. It supports most things commonly used from googltest. The
+// most noticeable things missing: EXPECT_* and ASSERT_* don't support
+// streaming notes to them with operator<<, and for failing tests the lhs and
+// rhs are not printed. That's so that this header does not have to include
+// sstream, which slows down building ninja_test almost 20%.
+namespace testing {
+class Test {
+ bool failed_;
+ int assertion_failures_;
+ public:
+ Test() : failed_(false), assertion_failures_(0) {}
+ virtual ~Test() {}
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+ virtual void Run() = 0;
+
+ bool Failed() const { return failed_; }
+ int AssertionFailures() const { return assertion_failures_; }
+ void AddAssertionFailure() { assertion_failures_++; }
+ bool Check(bool condition, const char* file, int line, const char* error);
+};
+}
+
+void RegisterTest(testing::Test* (*)(), const char*);
+
+extern testing::Test* g_current_test;
+#define TEST_F_(x, y, name) \
+ struct y : public x { \
+ static testing::Test* Create() { return g_current_test = new y; } \
+ virtual void Run(); \
+ }; \
+ struct Register##y { \
+ Register##y() { RegisterTest(y::Create, name); } \
+ }; \
+ Register##y g_register_##y; \
+ void y::Run()
+
+#define TEST_F(x, y) TEST_F_(x, x##y, #x "." #y)
+#define TEST(x, y) TEST_F_(testing::Test, x##y, #x "." #y)
+
+#define EXPECT_EQ(a, b) \
+ g_current_test->Check(a == b, __FILE__, __LINE__, #a " == " #b)
+#define EXPECT_NE(a, b) \
+ g_current_test->Check(a != b, __FILE__, __LINE__, #a " != " #b)
+#define EXPECT_GT(a, b) \
+ g_current_test->Check(a > b, __FILE__, __LINE__, #a " > " #b)
+#define EXPECT_LT(a, b) \
+ g_current_test->Check(a < b, __FILE__, __LINE__, #a " < " #b)
+#define EXPECT_GE(a, b) \
+ g_current_test->Check(a >= b, __FILE__, __LINE__, #a " >= " #b)
+#define EXPECT_LE(a, b) \
+ g_current_test->Check(a <= b, __FILE__, __LINE__, #a " <= " #b)
+#define EXPECT_TRUE(a) \
+ g_current_test->Check(static_cast<bool>(a), __FILE__, __LINE__, #a)
+#define EXPECT_FALSE(a) \
+ g_current_test->Check(!static_cast<bool>(a), __FILE__, __LINE__, #a)
+
+#define ASSERT_EQ(a, b) \
+ if (!EXPECT_EQ(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_NE(a, b) \
+ if (!EXPECT_NE(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_GT(a, b) \
+ if (!EXPECT_GT(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_LT(a, b) \
+ if (!EXPECT_LT(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_GE(a, b) \
+ if (!EXPECT_GE(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_LE(a, b) \
+ if (!EXPECT_LE(a, b)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_TRUE(a) \
+ if (!EXPECT_TRUE(a)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_FALSE(a) \
+ if (!EXPECT_FALSE(a)) { g_current_test->AddAssertionFailure(); return; }
+#define ASSERT_NO_FATAL_FAILURE(a) \
+ { \
+ int f = g_current_test->AssertionFailures(); \
+ a; \
+ if (f != g_current_test->AssertionFailures()) { \
+ g_current_test->AddAssertionFailure(); \
+ return; \
+ } \
+ }
+
// Support utilites for tests.
struct Node;