// Copyright (C) 2013 The Android Open Source Project // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // // Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // // Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in // the documentation and/or other materials provided with the // distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF // SUCH DAMAGE. #ifndef MINITEST_MINITEST_H #define MINITEST_MINITEST_H // Minitest is a minimalistic unit testing framework designed specifically // for the Android support library. // // - Unit tests must be written in C++, but no C++ runtime implementation // is either required or _supported_. This is by design. // // _ Inspired by GoogleTest, you can use the TEST macro to define a new // test case easily, and it can contain EXPECT_XX|ASSERT_XX statements. // // For example: // // TEST(stdio, strlen) { // EXPECT_EQ(3, strlen("foo")); // EXPECT_EQ(1, srlen("a")); // } // // However, there are important differences / limitations: // // o You cannot stream strings into an except or assert statement. // Minitest provides a TEST_TEXT macro to do that instead. // // In other words, replace: // // EXPECT_EQ(expected, expression) << "When checking 'foo'"; // // With: // TEST_TEXT << "When checking 'foo'"; // EXPECT_EQ(expected, expression); // // The context text is only printed on failure. // // o TEST_F() is not supported (for now). // // o EXPECT/ASSERT statements only work inside a TESET() function, not // in a function called by it. // // o No test death detection. // // - You can use minitest::Format() to stream formatted output into // a TEST_TEXT context, as in: // // for (size_t n = 0; n < kMaxCount; n++) { // TEST_TEXT << "Checking string : " // << minitest;:Format("%z/%z", n+1, kMaxCount); // EXPECT_EQ(kExpected[n], Foo(kString[n])); // } // #include #include namespace minitest { namespace internal { // AddConst::type adds a 'const' qualifier to type T. // Examples: // int -> const int // char* -> const char* const // const char* -> const char* const // char* const -> const char* const template struct AddConst { typedef const T type; }; template struct AddConst { typedef const T type; }; template struct AddConst { typedef const T* const type; }; template struct AddConst { typedef const T* const type; }; // String class used to accumulate error messages. // Very similar to std::string but also supports streaming into it // for easier formatted output, as in: // // String str; // int x = 42; // str << "x is '" << x << "'\n"; // // You can also use minitest::Format() as in: // // str << minitest::Format("Hex value %08x\n", x); // class String { public: String() : str_(NULL), size_(0), capacity_(0) {} String(const char* str, size_t len); explicit String(const char* str) { String(str, ::strlen(str)); } String(const String& other) { String(other.str_, other.size_); } String& operator=(const String& other) { (*this) += other; return *this; } char& operator[](size_t index) { return str_[index]; } ~String() { Clear(); } const char* c_str() const { return str_; } const char* data() const { return str_; } size_t size() const { return size_; } bool empty() const { return size_ == 0; } String& operator+=(const String& other); String& operator+=(const char* str); String& operator+=(char ch); String operator+(const String& other) const { String result(*this); result += other; return result; } String operator+(const char* str) const { String result(*this); result += str; return result; } // Basic formatting operators. String& operator<<(const String& other); String& operator<<(const char* str); #define MINITEST_OPERATOR_LL_(ParamType) String& operator<<(ParamType v) MINITEST_OPERATOR_LL_(bool); MINITEST_OPERATOR_LL_(char); MINITEST_OPERATOR_LL_(signed char); MINITEST_OPERATOR_LL_(short); MINITEST_OPERATOR_LL_(int); MINITEST_OPERATOR_LL_(long); MINITEST_OPERATOR_LL_(long long); MINITEST_OPERATOR_LL_(unsigned char); MINITEST_OPERATOR_LL_(unsigned short); MINITEST_OPERATOR_LL_(unsigned int); MINITEST_OPERATOR_LL_(unsigned long); MINITEST_OPERATOR_LL_(unsigned long long); MINITEST_OPERATOR_LL_(float); MINITEST_OPERATOR_LL_(double); MINITEST_OPERATOR_LL_(long double); MINITEST_OPERATOR_LL_(const void*); #undef MINITEST_OPERATOR_LL_ void Clear(); void Resize(size_t new_size); private: void Reserve(size_t new_capacity); char* str_; size_t size_; size_t capacity_; }; } // namespace internal // A helper function that can be used to generate formatted output // as a temporary string. Use like printf(), but returns a new String // object. Useful to stream into TEST_TEXT() objects, as in: // // TEST_TEXT << "Using " // << minitest::Format("%08d", bytes) // << " bytes"; // internal::String Format(const char* format, ...); class TestCase { public: enum Result { PASS = 0, FAIL, FATAL }; TestCase() : result_(PASS) {} ~TestCase() {} void Failure(); void FatalFailure(); Result result() { return result_; } internal::String& GetText(); private: Result result_; internal::String text_; }; // Type of a function defined through the TEST(,) macro. typedef void(TestFunction)(TestCase* testcase); // Used internally to register new test functions. void RegisterTest(const char* test_name, const char* case_name, TestFunction* test_function); #define MINITEST_TEST_FUNCTION(testname, casename) \ MINITEST_TEST_FUNCTION_(testname, casename) #define MINITEST_TEST_FUNCTION_(testname, casename) \ minitest_##testname##_##casename #define TEST(testname, casename) \ static void MINITEST_TEST_FUNCTION(testname, casename)(minitest::TestCase*); \ static void \ __attribute__((constructor)) RegisterMiniTest##testname##_##casename() { \ minitest::RegisterTest( \ #testname, #casename, &MINITEST_TEST_FUNCTION(testname, casename)); \ } \ void MINITEST_TEST_FUNCTION(testname, \ casename)(minitest::TestCase* minitest_testcase) // Use this macro to add context text before an EXPECT or ASSERT statement // For example: // // for (size_t n = 0; n < MAX; ++n) { // TEST_TEXT << "When checking " << kStrings[n]; // EXPECT_STREQ(kExpected[n], kStrings[n]); // } // // The text will only be printed in case of failure in the next // EXPECT/ASSERT statement. // #define TEST_TEXT minitest_testcase->GetText() // EXPECT_TRUE() must evaluate to something that supports the << operator // to receive debugging strings only in case of failure. #define EXPECT_TRUE(expression) \ do { \ if (!(expression)) { \ printf( \ "EXPECT_TRUE:%s:%d: expression '%s' returned 'false', expected " \ "'true'\n", \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->Failure(); \ } \ } while (0) #define EXPECT_FALSE(expression) \ do { \ if (!!(expression)) { \ printf( \ "EXPECT_FALSE:%s:%d: expression '%s' returned 'true', expected " \ "'false'\n", \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->Failure(); \ } \ } while (0) #define MINITEST_DEFINE_LOCAL_EXPR_(varname, expr) \ typedef minitest::internal::AddConst<__typeof__(expr)>::type varname##Type; \ const varname##Type varname = (expr); #define MINITEST_EXPECT_ASSERT_BINOP_( \ opname, op, expected, expression, is_assert) \ do { \ MINITEST_DEFINE_LOCAL_EXPR_(minitest_expected, expected); \ MINITEST_DEFINE_LOCAL_EXPR_(minitest_actual, expression); \ if (!(minitest_actual op minitest_expected)) { \ printf("%s" #opname ":%s:%d: with expression '%s'\n", \ is_assert ? "ASSERT_" : "EXPECT_", \ __FILE__, \ __LINE__, \ #expression); \ minitest::internal::String minitest_str; \ minitest_str << minitest_actual; \ printf("actual : %s\n", minitest_str.c_str()); \ minitest_str.Clear(); \ minitest_str << minitest_expected; \ printf("expected : %s\n", minitest_str.c_str()); \ if (is_assert) { \ minitest_testcase->FatalFailure(); \ return; \ } \ minitest_testcase->Failure(); \ } \ } while (0) #define MINITEST_EXPECT_BINOP_(opname, op, expected, expression) \ MINITEST_EXPECT_ASSERT_BINOP_(opname, op, expected, expression, false) #define EXPECT_EQ(expected, expression) \ MINITEST_EXPECT_BINOP_(EQ, ==, expected, expression) #define EXPECT_NE(expected, expression) \ MINITEST_EXPECT_BINOP_(NE, !=, expected, expression) #define EXPECT_LE(expected, expression) \ MINITEST_EXPECT_BINOP_(LE, <=, expected, expression) #define EXPECT_LT(expected, expression) \ MINITEST_EXPECT_BINOP_(LT, <, expected, expression) #define EXPECT_GE(expected, expression) \ MINITEST_EXPECT_BINOP_(GE, >=, expected, expression) #define EXPECT_GT(expected, expression) \ MINITEST_EXPECT_BINOP_(GT, >, expected, expression) #define MINITEST_EXPECT_ASSERT_STR_(expected, expression, is_eq, is_assert) \ do { \ const char* minitest_prefix = is_assert ? "ASSERT_STR" : "EXPECT_STR"; \ const char* minitest_suffix = is_eq ? "EQ" : "NEQ"; \ const char* minitest_expected = (expected); \ const char* minitest_actual = (expression); \ if (minitest_actual == NULL) { \ printf("%s%s:%s:%d: expression '%s' is NULL!\n", \ minitest_prefix, \ minitest_suffix, \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->Failure(); \ } else { \ bool minitest_eq = !strcmp(minitest_expected, minitest_actual); \ if (minitest_eq != is_eq) { \ printf("%s%s:%s:%d: with expression '%s'\n", \ minitest_prefix, \ minitest_suffix, \ __FILE__, \ __LINE__, \ #expression); \ printf("actual : %s\n", minitest_actual); \ printf("expected : %s\n", minitest_expected); \ minitest_testcase->Failure(); \ } \ } \ } while (0) #define EXPECT_STREQ(expected, expression) \ MINITEST_EXPECT_ASSERT_STR_(expected, expression, true, false) #define EXPECT_STRNEQ(expected, expression) \ MINITEST_EXPECT_ASSERT_STR_(expected, expression, false, false) #define MINITEST_EXPECT_ASSERT_MEM_( \ expected, expected_len, expression, expression_len, is_eq, is_assert) \ do { \ const char* minitest_prefix = is_assert ? "ASSERT_MEM" : "EXPECT_MEM"; \ const char* minitest_suffix = is_eq ? "EQ" : "NEQ"; \ const char* minitest_expected = (expected); \ size_t minitest_expected_len = static_cast(expected_len); \ const char* minitest_actual = (expression); \ size_t minitest_actual_len = static_cast(expression_len); \ if (minitest_actual == NULL) { \ printf("%s%s:%s:%d: expression '%s' is NULL!\n", \ minitest_prefix, \ minitest_suffix, \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->Failure(); \ } else if (minitest_actual_len != minitest_expected_len) { \ printf("%s:%s:%s:%d: size mistmatch for expression '%s'\n", \ minitest_prefix, \ minitest_suffix, \ __FILE__, \ __LINE__, \ #expression); \ printf("actual size : %zu (0x%zx)\n", \ minitest_actual_len, \ minitest_actual_len); \ printf("expected size : %zu (0x%zx)\n", \ minitest_expected_len, \ minitest_expected_len); \ minitest_testcase->Failure(); \ } else { \ bool minitest_eq = \ !memcmp(minitest_expected, minitest_actual, minitest_expected_len); \ if (minitest_eq != is_eq) { \ printf("%s%s:%s:%d: with expression '%s' of %zu bytes\n", \ minitest_prefix, \ minitest_suffix, \ __FILE__, \ __LINE__, \ #expression, \ minitest_expected_len); \ printf("actual : '%.*s'\n", (int)minitest_expected_len, \ minitest_actual); \ printf( \ "expected : '%.*s'\n", (int)minitest_expected_len, \ minitest_expected); \ minitest_testcase->Failure(); \ } \ } \ } while (0) #define EXPECT_MEMEQ(expected, expected_len, expression, expression_len) \ MINITEST_EXPECT_ASSERT_MEM_( \ expected, expected_len, expression, expression_len, true, false) #define EXPECT_MEMNEQ(expected, expected_len, expression, expression_len) \ MINITEST_EXPECT_ASSERT_MEM_( \ expected, expected_len, expression, expression_len, false, false) #define ASSERT_TRUE(expression) \ do { \ if (!(expression)) { \ printf( \ "ASSERT_TRUE:%s:%d: expression '%s' return 'false', expected " \ "'true'\n", \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->FatalFailure(); \ return; \ } \ } while (0) #define ASSERT_FALSE(expression) \ do { \ if (!!(expression)) { \ printf( \ "ASSERT_FALSE:%s:%d: expression '%s' return 'true', expected " \ "'false'\n", \ __FILE__, \ __LINE__, \ #expression); \ minitest_testcase->FatalFailure(); \ return; \ } \ } while (0) #define MINITEST_ASSERT_BINOP_(opname, op, expected, expression) \ MINITEST_EXPECT_ASSERT_BINOP_(opname, op, expected, expression, true) #define ASSERT_EQ(expected, expression) \ MINITEST_ASSERT_BINOP_(EQ, ==, expected, expression) #define ASSERT_NE(expected, expression) \ MINITEST_ASSERT_BINOP_(NE, !=, expected, expression) #define ASSERT_LE(expected, expression) \ MINITEST_ASSERT_BINOP_(LE, <=, expected, expression) #define ASSERT_LT(expected, expression) \ MINITEST_ASSERT_BINOP_(LT, <, expected, expression) #define ASSERT_GE(expected, expression) \ MINITEST_ASSERT_BINOP_(GE, >=, expected, expression) #define ASSERT_GT(expected, expression) \ MINITEST_ASSERT_BINOP_(GT, >, expected, expression) #define ASSERT_STREQ(expected, expression) \ MINITEST_EXPECT_ASSERT_STR_(expected, expression, true, true) #define ASSERT_STRNEQ(expected, expression) \ MINITEST_EXPECT_ASSERT_STR_(expected, expression, false, true) #define ASSERT_MEMEQ(expected, expected_len, expression, expression_len) \ MINITEST_EXPECT_ASSERT_MEM_( \ expected, expected_len, expression, expression_len, true, true) #define ASSERT_MEMNEQ(expected, expected_len, expression, expression_len) \ MINITEST_EXPECT_ASSERT_MEM_( \ expected, expected_len, expression, expression_len, false, true) #define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0])) } // namespace minitest #endif // MINITEST_MINITEST_H