diff options
author | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-07-01 22:55:05 +0000 |
---|---|---|
committer | zhanyong.wan <zhanyong.wan@861a406c-534a-0410-8894-cb66d6ee9925> | 2009-07-01 22:55:05 +0000 |
commit | 449f84de9b0c48289e20f63c6d08a39bcee2021b (patch) | |
tree | e321c70ebc0eb178e91fcbf9993cdbeb5606c8e2 | |
parent | b7ec0f7b3b21338babc9a6ab5a593a40634a8062 (diff) | |
download | googletest-449f84de9b0c48289e20f63c6d08a39bcee2021b.tar.gz |
Makes List a random-access data structure. This simplifies the implementation and makes it easier to implement test shuffling.
git-svn-id: http://googletest.googlecode.com/svn/trunk@280 861a406c-534a-0410-8894-cb66d6ee9925
-rw-r--r-- | include/gtest/gtest.h | 11 | ||||
-rw-r--r-- | include/gtest/internal/gtest-internal.h | 2 | ||||
-rw-r--r-- | src/gtest-internal-inl.h | 311 | ||||
-rw-r--r-- | src/gtest-test-part.cc | 7 | ||||
-rw-r--r-- | src/gtest.cc | 118 | ||||
-rw-r--r-- | test/gtest_stress_test.cc | 8 | ||||
-rw-r--r-- | test/gtest_unittest.cc | 310 |
7 files changed, 326 insertions, 441 deletions
diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h index 7d06078..f8aa91e 100644 --- a/include/gtest/gtest.h +++ b/include/gtest/gtest.h @@ -434,13 +434,14 @@ class TestResult { TimeInMillis elapsed_time() const { return elapsed_time_; } // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, returns - // NULL. - const TestPartResult* GetTestPartResult(int i) const; + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; // Returns the i-th test property. i can range from 0 to - // test_property_count() - 1. If i is not in that range, returns NULL. - const TestProperty* GetTestProperty(int i) const; + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; private: friend class DefaultGlobalTestPartResultReporter; diff --git a/include/gtest/internal/gtest-internal.h b/include/gtest/internal/gtest-internal.h index a4c3736..91b386f 100644 --- a/include/gtest/internal/gtest-internal.h +++ b/include/gtest/internal/gtest-internal.h @@ -116,9 +116,7 @@ class ScopedTrace; // Implements scoped trace. class TestInfoImpl; // Opaque implementation of TestInfo class TestResult; // Result of a single Test. class UnitTestImpl; // Opaque implementation of UnitTest - template <typename E> class List; // A generic list. -template <typename E> class ListNode; // A node in a generic list. // How many times InitGoogleTest() has been called. extern int g_init_gtest_count; diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h index 3c9a8d9..b4f6de6 100644 --- a/src/gtest-internal-inl.h +++ b/src/gtest-internal-inl.h @@ -49,7 +49,8 @@ #include <errno.h> #endif // !_WIN32_WCE #include <stddef.h> -#include <stdlib.h> // For strtoll/_strtoul64. +#include <stdlib.h> // For strtoll/_strtoul64/malloc/free. +#include <string.h> // For memmove. #include <string> @@ -198,199 +199,74 @@ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); // method. Assumes that 0 <= shard_index < total_shards. bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id); -// List is a simple singly-linked list container. +// List is an ordered container that supports random access to the +// elements. // -// We cannot use std::list as Microsoft's implementation of STL has -// problems when exception is disabled. There is a hack to work -// around this, but we've seen cases where the hack fails to work. +// We cannot use std::vector, as Visual C++ 7.1's implementation of +// STL has problems compiling when exceptions are disabled. There is +// a hack to work around the problems, but we've seen cases where the +// hack fails to work. // -// TODO(wan): switch to std::list when we have a reliable fix for the -// STL problem, e.g. when we upgrade to the next version of Visual -// C++, or (more likely) switch to STLport. -// -// The element type must support copy constructor. - -// Forward declare List -template <typename E> // E is the element type. -class List; - -// ListNode is a node in a singly-linked list. It consists of an -// element and a pointer to the next node. The last node in the list -// has a NULL value for its next pointer. -template <typename E> // E is the element type. -class ListNode { - friend class List<E>; - - private: - - E element_; - ListNode * next_; - - // The c'tor is private s.t. only in the ListNode class and in its - // friend class List we can create a ListNode object. - // - // Creates a node with a given element value. The next pointer is - // set to NULL. - // - // ListNode does NOT have a default constructor. Always use this - // constructor (with parameter) to create a ListNode object. - explicit ListNode(const E & element) : element_(element), next_(NULL) {} - - // We disallow copying ListNode - GTEST_DISALLOW_COPY_AND_ASSIGN_(ListNode); - - public: - - // Gets the element in this node. - E & element() { return element_; } - const E & element() const { return element_; } - - // Gets the next node in the list. - ListNode * next() { return next_; } - const ListNode * next() const { return next_; } -}; - - -// List is a simple singly-linked list container. +// The element type must support copy constructor and operator=. template <typename E> // E is the element type. class List { public: - // Creates an empty list. - List() : head_(NULL), last_(NULL), size_(0), - last_read_index_(-1), last_read_(NULL) {} + List() : elements_(NULL), capacity_(0), size_(0) {} // D'tor. - virtual ~List(); + virtual ~List() { Clear(); } // Clears the list. void Clear() { - if ( size_ > 0 ) { - // 1. Deletes every node. - ListNode<E> * node = head_; - ListNode<E> * next = node->next(); - for ( ; ; ) { - delete node; - node = next; - if ( node == NULL ) break; - next = node->next(); + if (elements_ != NULL) { + for (int i = 0; i < size_; i++) { + delete elements_[i]; } - // 2. Resets the member variables. - last_read_ = head_ = last_ = NULL; - size_ = 0; - last_read_index_ = -1; + free(elements_); + elements_ = NULL; + capacity_ = size_ = 0; } } // Gets the number of elements. int size() const { return size_; } - // Returns true if the list is empty. - bool IsEmpty() const { return size() == 0; } - - // Gets the first element of the list, or NULL if the list is empty. - ListNode<E> * Head() { return head_; } - const ListNode<E> * Head() const { return head_; } - - // Gets the last element of the list, or NULL if the list is empty. - ListNode<E> * Last() { return last_; } - const ListNode<E> * Last() const { return last_; } - // Adds an element to the end of the list. A copy of the element is // created using the copy constructor, and then stored in the list. // Changes made to the element in the list doesn't affect the source - // object, and vice versa. This does not affect the "last read" - // index. - void PushBack(const E & element) { - ListNode<E> * new_node = new ListNode<E>(element); - - if ( size_ == 0 ) { - head_ = last_ = new_node; - size_ = 1; - } else { - last_->next_ = new_node; - last_ = new_node; - size_++; - } - } + // object, and vice versa. + void PushBack(const E & element) { Insert(element, size_); } - // Adds an element to the beginning of this list. The "last read" - // index is adjusted accordingly. - void PushFront(const E& element) { - ListNode<E>* const new_node = new ListNode<E>(element); - - if ( size_ == 0 ) { - head_ = last_ = new_node; - size_ = 1; - } else { - new_node->next_ = head_; - head_ = new_node; - size_++; - } - - if (last_read_index_ >= 0) { - // A new element at the head bumps up an existing index by 1. - last_read_index_++; - } - } + // Adds an element to the beginning of this list. + void PushFront(const E& element) { Insert(element, 0); } // Removes an element from the beginning of this list. If the // result argument is not NULL, the removed element is stored in the // memory it points to. Otherwise the element is thrown away. - // Returns true iff the list wasn't empty before the operation. The - // "last read" index is adjusted accordingly. + // Returns true iff the list wasn't empty before the operation. bool PopFront(E* result) { - if (size_ == 0) return false; + if (size_ == 0) + return false; - if (result != NULL) { - *result = head_->element_; - } + if (result != NULL) + *result = *(elements_[0]); - ListNode<E>* const old_head = head_; + delete elements_[0]; size_--; - if (size_ == 0) { - head_ = last_ = NULL; - } else { - head_ = head_->next_; - } - delete old_head; - - if (last_read_index_ > 0) { - last_read_index_--; - } else if (last_read_index_ == 0) { - last_read_index_ = -1; - last_read_ = NULL; - } - + MoveElements(1, size_, 0); return true; } - // Inserts an element after a given node in the list. It's the - // caller's responsibility to ensure that the given node is in the - // list. If the given node is NULL, inserts the element at the - // front of the list. The "last read" index is adjusted - // accordingly. - ListNode<E>* InsertAfter(ListNode<E>* node, const E& element) { - if (node == NULL) { - PushFront(element); - return Head(); - } - - ListNode<E>* const new_node = new ListNode<E>(element); - new_node->next_ = node->next_; - node->next_ = new_node; + // Inserts an element at the given index. It's the caller's + // responsibility to ensure that the given index is in the range [0, + // size()]. + void Insert(const E& element, int index) { + GrowIfNeeded(); + MoveElements(index, size_ - index, index + 1); + elements_[index] = new E(element); size_++; - if (node == last_) { - last_ = new_node; - } - - // We aren't sure whether this insertion will affect the last read - // index, so we invalidate it to be safe. - last_read_index_ = -1; - last_read_ = NULL; - - return new_node; } // Returns the number of elements that satisfy a given predicate. @@ -399,10 +275,8 @@ class List { template <typename P> // P is the type of the predicate function/functor int CountIf(P predicate) const { int count = 0; - for ( const ListNode<E> * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element()) ) { + for (int i = 0; i < size_; i++) { + if (predicate(*(elements_[i]))) { count++; } } @@ -416,10 +290,8 @@ class List { // the elements. template <typename F> // F is the type of the function/functor void ForEach(F functor) const { - for ( const ListNode<E> * node = Head(); - node != NULL; - node = node->next() ) { - functor(node->element()); + for (int i = 0; i < size_; i++) { + functor(*(elements_[i])); } } @@ -428,81 +300,70 @@ class List { // function/functor that accepts a 'const E &', where E is the // element type. This method does not change the elements. template <typename P> // P is the type of the predicate function/functor. - const ListNode<E> * FindIf(P predicate) const { - for ( const ListNode<E> * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element()) ) { - return node; + const E* FindIf(P predicate) const { + for (int i = 0; i < size_; i++) { + if (predicate(*elements_[i])) { + return elements_[i]; } } - return NULL; } template <typename P> - ListNode<E> * FindIf(P predicate) { - for ( ListNode<E> * node = Head(); - node != NULL; - node = node->next() ) { - if ( predicate(node->element() ) ) { - return node; + E* FindIf(P predicate) { + for (int i = 0; i < size_; i++) { + if (predicate(*elements_[i])) { + return elements_[i]; } } - return NULL; } - // Returns a pointer to the i-th element of the list, or NULL if i is not - // in range [0, size()). The "last read" index is adjusted accordingly. - const E* GetElement(int i) const { - if (i < 0 || i >= size()) - return NULL; - - if (last_read_index_ < 0 || last_read_index_ > i) { - // We have to count from the start. - last_read_index_ = 0; - last_read_ = Head(); - } + // Returns the i-th element of the list, or aborts the program if i + // is not in range [0, size()). + const E& GetElement(int i) const { + GTEST_CHECK_(0 <= i && i < size_) + << "Invalid list index " << i << ": must be in range [0, " + << (size_ - 1) << "]."; - while (last_read_index_ < i) { - last_read_ = last_read_->next(); - last_read_index_++; - } - - return &(last_read_->element()); + return *(elements_[i]); } // Returns the i-th element of the list, or default_value if i is not - // in range [0, size()). The "last read" index is adjusted accordingly. + // in range [0, size()). E GetElementOr(int i, E default_value) const { - const E* element = GetElement(i); - return element ? *element : default_value; + return (i < 0 || i >= size_) ? default_value : *(elements_[i]); } private: - ListNode<E>* head_; // The first node of the list. - ListNode<E>* last_; // The last node of the list. - int size_; // The number of elements in the list. - - // These fields point to the last element read via GetElement(i) or - // GetElementOr(i). They are used to speed up list traversal as - // often they allow us to find the wanted element by looking from - // the last visited one instead of the list head. This means a - // sequential traversal of the list can be done in O(N) time instead - // of O(N^2). - mutable int last_read_index_; - mutable const ListNode<E>* last_read_; + // Grows the buffer if it is not big enough to hold one more element. + void GrowIfNeeded() { + if (size_ < capacity_) + return; + + // Exponential bump-up is necessary to ensure that inserting N + // elements is O(N) instead of O(N^2). The factor 3/2 means that + // no more than 1/3 of the slots are wasted. + const int new_capacity = 3*(capacity_/2 + 1); + GTEST_CHECK_(new_capacity > capacity_) // Does the new capacity overflow? + << "Cannot grow a list with " << capacity_ << " elements already."; + capacity_ = new_capacity; + elements_ = static_cast<E**>( + realloc(elements_, capacity_*sizeof(elements_[0]))); + } + + // Moves the give consecutive elements to a new index in the list. + void MoveElements(int source, int count, int dest) { + memmove(elements_ + dest, elements_ + source, count*sizeof(elements_[0])); + } + + E** elements_; + int capacity_; // The number of elements allocated for elements_. + int size_; // The number of elements; in the range [0, capacity_]. // We disallow copying List. GTEST_DISALLOW_COPY_AND_ASSIGN_(List); -}; - -// The virtual destructor of List. -template <typename E> -List<E>::~List() { - Clear(); -} +}; // class List // A function for deleting an object. Handy for being used as a // functor. @@ -907,10 +768,8 @@ class UnitTestImpl { // before main() is reached. if (original_working_dir_.IsEmpty()) { original_working_dir_.Set(FilePath::GetCurrentDir()); - if (original_working_dir_.IsEmpty()) { - printf("%s\n", "Failed to get the current working directory."); - posix::Abort(); - } + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; } GetTestCase(test_info->test_case_name(), @@ -1057,8 +916,8 @@ class UnitTestImpl { bool parameterized_tests_registered_; #endif // GTEST_HAS_PARAM_TEST - // Points to the last death test case registered. Initially NULL. - internal::ListNode<TestCase*>* last_death_test_case_; + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; // This points to the TestCase for the currently running test. It // changes as Google Test goes through one test case after another. diff --git a/src/gtest-test-part.cc b/src/gtest-test-part.cc index 49a6fe5..472b8c5 100644 --- a/src/gtest-test-part.cc +++ b/src/gtest-test-part.cc @@ -86,12 +86,7 @@ const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { internal::posix::Abort(); } - const internal::ListNode<TestPartResult>* p = list_->Head(); - for (int i = 0; i < index; i++) { - p = p->next(); - } - - return p->element(); + return list_->GetElement(index); } // Returns the number of TestPartResult objects in the array. diff --git a/src/gtest.cc b/src/gtest.cc index a1d8ac0..845fb90 100644 --- a/src/gtest.cc +++ b/src/gtest.cc @@ -264,10 +264,8 @@ static bool GTestIsInitialized() { return g_init_gtest_count != 0; } static int SumOverTestCaseList(const internal::List<TestCase*>& case_list, int (TestCase::*method)() const) { int sum = 0; - for (const internal::ListNode<TestCase*>* node = case_list.Head(); - node != NULL; - node = node->next()) { - sum += (node->element()->*method)(); + for (int i = 0; i < case_list.size(); i++) { + sum += (case_list.GetElement(i)->*method)(); } return sum; } @@ -1830,16 +1828,17 @@ TestResult::TestResult() TestResult::~TestResult() { } -// Returns the i-th test part result among all the results. i can range -// from 0 to total_part_count() - 1. If i is not in that range, returns -// NULL. -const TestPartResult* TestResult::GetTestPartResult(int i) const { +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { return test_part_results_->GetElement(i); } // Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, returns NULL. -const TestProperty* TestResult::GetTestProperty(int i) const { +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { return test_properties_->GetElement(i); } @@ -1861,14 +1860,13 @@ void TestResult::RecordProperty(const TestProperty& test_property) { return; } MutexLock lock(&test_properites_mutex_); - ListNode<TestProperty>* const node_with_matching_key = + TestProperty* const property_with_matching_key = test_properties_->FindIf(TestPropertyKeyIs(test_property.key())); - if (node_with_matching_key == NULL) { + if (property_with_matching_key == NULL) { test_properties_->PushBack(test_property); return; } - TestProperty& property_with_matching_key = node_with_matching_key->element(); - property_with_matching_key.SetValue(test_property.value()); + property_with_matching_key->SetValue(test_property.value()); } // Adds a failure if the key is a reserved attribute of Google Test @@ -2028,7 +2026,7 @@ bool Test::HasSameFixtureClass() { // Info about the first test in the current test case. const internal::TestInfoImpl* const first_test_info = - test_case->test_info_list().Head()->element()->impl(); + test_case->test_info_list().GetElement(0)->impl(); const internal::TypeId first_fixture_id = first_test_info->fixture_class_id(); const char* const first_test_name = first_test_info->name(); @@ -2884,7 +2882,6 @@ void PrettyUnitTestResultPrinter::OnUnitTestEnd(const UnitTest& unit_test) { class UnitTestEventsRepeater : public UnitTestEventListenerInterface { public: typedef internal::List<UnitTestEventListenerInterface *> Listeners; - typedef internal::ListNode<UnitTestEventListenerInterface *> ListenersNode; UnitTestEventsRepeater() {} virtual ~UnitTestEventsRepeater(); void AddListener(UnitTestEventListenerInterface *listener); @@ -2908,10 +2905,8 @@ class UnitTestEventsRepeater : public UnitTestEventListenerInterface { }; UnitTestEventsRepeater::~UnitTestEventsRepeater() { - for (ListenersNode* listener = listeners_.Head(); - listener != NULL; - listener = listener->next()) { - delete listener->element(); + for (int i = 0; i < listeners_.size(); i++) { + delete listeners_.GetElement(i); } } @@ -2924,10 +2919,8 @@ void UnitTestEventsRepeater::AddListener( // This defines a member that repeats the call to all listeners. #define GTEST_REPEATER_METHOD_(Name, Type) \ void UnitTestEventsRepeater::Name(const Type& parameter) { \ - for (ListenersNode* listener = listeners_.Head(); \ - listener != NULL; \ - listener = listener->next()) { \ - listener->element()->Name(parameter); \ + for (int i = 0; i < listeners_.size(); i++) { \ + listeners_.GetElement(i)->Name(parameter); \ } \ } @@ -3150,7 +3143,7 @@ void XmlUnitTestResultPrinter::PrintXmlTestInfo(FILE* out, int failures = 0; for (int i = 0; i < result.total_part_count(); ++i) { - const TestPartResult& part = *result.GetTestPartResult(i); + const TestPartResult& part = result.GetTestPartResult(i); if (part.failed()) { const internal::String message = internal::String::Format("%s:%d\n%s", part.file_name(), @@ -3212,7 +3205,7 @@ internal::String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( using internal::TestProperty; Message attributes; for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = *result.GetTestProperty(i); + const TestProperty& property = result.GetTestProperty(i); attributes << " " << property.key() << "=" << "\"" << EscapeXmlAttribute(property.value()) << "\""; } @@ -3407,11 +3400,9 @@ void UnitTest::AddTestPartResult(TestPartResultType result_type, if (impl_->gtest_trace_stack()->size() > 0) { msg << "\n" << GTEST_NAME_ << " trace:"; - for (internal::ListNode<internal::TraceInfo>* node = - impl_->gtest_trace_stack()->Head(); - node != NULL; - node = node->next()) { - const internal::TraceInfo& trace = node->element(); + for (int i = 0; i < impl_->gtest_trace_stack()->size(); i++) { + const internal::TraceInfo& trace = + impl_->gtest_trace_stack()->GetElement(i); msg << "\n" << trace.file << ":" << trace.line << ": " << trace.message; } } @@ -3606,7 +3597,7 @@ UnitTestImpl::UnitTestImpl(UnitTest* parent) parameterized_test_registry_(), parameterized_tests_registered_(false), #endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(NULL), + last_death_test_case_(-1), current_test_case_(NULL), current_test_info_(NULL), ad_hoc_test_result_(), @@ -3670,30 +3661,27 @@ TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? - internal::ListNode<TestCase*>* node = test_cases_.FindIf( - TestCaseNameIs(test_case_name)); + TestCase** test_case = test_cases_.FindIf(TestCaseNameIs(test_case_name)); - if (node == NULL) { - // No. Let's create one. - TestCase* const test_case = + if (test_case != NULL) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = new TestCase(test_case_name, comment, set_up_tc, tear_down_tc); - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. - node = test_cases_.InsertAfter(last_death_test_case_, test_case); - last_death_test_case_ = node; - } else { - // No. Appends to the end of the list. - test_cases_.PushBack(test_case); - node = test_cases_.Last(); - } + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(String(test_case_name), + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. + test_cases_.Insert(new_test_case, ++last_death_test_case_); + } else { + // No. Appends to the end of the list. + test_cases_.PushBack(new_test_case); } - // Returns the TestCase found. - return node->element(); + return new_test_case; } // Helpers for setting up / tearing down the given environment. They @@ -3925,19 +3913,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // this shard. int num_runnable_tests = 0; int num_selected_tests = 0; - for (const internal::ListNode<TestCase *> *test_case_node = - test_cases_.Head(); - test_case_node != NULL; - test_case_node = test_case_node->next()) { - TestCase * const test_case = test_case_node->element(); + for (int i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_.GetElement(i); const String &test_case_name = test_case->name(); test_case->set_should_run(false); - for (const internal::ListNode<TestInfo *> *test_info_node = - test_case->test_info_list().Head(); - test_info_node != NULL; - test_info_node = test_info_node->next()) { - TestInfo * const test_info = test_info_node->element(); + for (int j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list().GetElement(j); const String test_name(test_info->name()); // A test is disabled if test case name or test name matches // kDisableTestFilter. @@ -3974,17 +3956,13 @@ int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { - for (const internal::ListNode<TestCase*>* test_case_node = test_cases_.Head(); - test_case_node != NULL; - test_case_node = test_case_node->next()) { - const TestCase* const test_case = test_case_node->element(); + for (int i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_.GetElement(i); bool printed_test_case_name = false; - for (const internal::ListNode<TestInfo*>* test_info_node = - test_case->test_info_list().Head(); - test_info_node != NULL; - test_info_node = test_info_node->next()) { - const TestInfo* const test_info = test_info_node->element(); + for (int j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list().GetElement(j); if (test_info->matches_filter()) { if (!printed_test_case_name) { printed_test_case_name = true; diff --git a/test/gtest_stress_test.cc b/test/gtest_stress_test.cc index 55e8bf4..3e02131 100644 --- a/test/gtest_stress_test.cc +++ b/test/gtest_stress_test.cc @@ -46,7 +46,6 @@ namespace testing { namespace { using internal::List; -using internal::ListNode; using internal::String; using internal::TestProperty; using internal::TestPropertyKeyIs; @@ -70,9 +69,10 @@ void ExpectKeyAndValueWereRecordedForId(const List<TestProperty>& properties, int id, const char* suffix) { TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); - const ListNode<TestProperty>* node = properties.FindIf(matches_key); - EXPECT_TRUE(node != NULL) << "expecting " << suffix << " node for id " << id; - EXPECT_STREQ(IdToString(id).c_str(), node->element().value()); + const TestProperty* property = properties.FindIf(matches_key); + ASSERT_TRUE(property != NULL) + << "expecting " << suffix << " value for id " << id; + EXPECT_STREQ(IdToString(id).c_str(), property->value()); } // Calls a large number of Google Test assertions, where exactly one of them diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc index bd9fa18..37e799f 100644 --- a/test/gtest_unittest.cc +++ b/test/gtest_unittest.cc @@ -76,6 +76,16 @@ TEST(CommandLineFlagsTest, CanBeAccessedInCodeOnceGTestHIsIncluded) { #include <map> #endif +// GTEST_EXPECT_DEATH_IF_SUPPORTED_(statement, regex) expands to a +// real death test if death tests are supported; otherwise it expands +// to empty. +#if GTEST_HAS_DEATH_TEST +#define GTEST_EXPECT_DEATH_IF_SUPPORTED_(statement, regex) \ + EXPECT_DEATH(statement, regex) +#else +#define GTEST_EXPECT_DEATH_IF_SUPPORTED_(statement, regex) +#endif + namespace testing { namespace internal { const char* FormatTimeInMillisAsSeconds(TimeInMillis ms); @@ -448,31 +458,56 @@ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { } #endif // !GTEST_WIDE_STRING_USES_UTF16_ -// Tests the List template class. +// Tests the List class template. + +// Tests List::Clear(). +TEST(ListTest, Clear) { + List<int> a; + a.PushBack(1); + a.Clear(); + EXPECT_EQ(0, a.size()); + + a.PushBack(2); + a.PushBack(3); + a.Clear(); + EXPECT_EQ(0, a.size()); +} + +// Tests List::PushBack(). +TEST(ListTest, PushBack) { + List<char> a; + a.PushBack('a'); + ASSERT_EQ(1, a.size()); + EXPECT_EQ('a', a.GetElement(0)); + + a.PushBack('b'); + ASSERT_EQ(2, a.size()); + EXPECT_EQ('a', a.GetElement(0)); + EXPECT_EQ('b', a.GetElement(1)); +} // Tests List::PushFront(). TEST(ListTest, PushFront) { List<int> a; - ASSERT_EQ(0u, a.size()); + ASSERT_EQ(0, a.size()); // Calls PushFront() on an empty list. a.PushFront(1); - ASSERT_EQ(1u, a.size()); - EXPECT_EQ(1, a.Head()->element()); - ASSERT_EQ(a.Head(), a.Last()); + ASSERT_EQ(1, a.size()); + EXPECT_EQ(1, a.GetElement(0)); // Calls PushFront() on a singleton list. a.PushFront(2); - ASSERT_EQ(2u, a.size()); - EXPECT_EQ(2, a.Head()->element()); - EXPECT_EQ(1, a.Last()->element()); + ASSERT_EQ(2, a.size()); + EXPECT_EQ(2, a.GetElement(0)); + EXPECT_EQ(1, a.GetElement(1)); // Calls PushFront() on a list with more than one elements. a.PushFront(3); - ASSERT_EQ(3u, a.size()); - EXPECT_EQ(3, a.Head()->element()); - EXPECT_EQ(2, a.Head()->next()->element()); - EXPECT_EQ(1, a.Last()->element()); + ASSERT_EQ(3, a.size()); + EXPECT_EQ(3, a.GetElement(0)); + EXPECT_EQ(2, a.GetElement(1)); + EXPECT_EQ(1, a.GetElement(2)); } // Tests List::PopFront(). @@ -497,75 +532,91 @@ TEST(ListTest, PopFront) { // After popping the last element, the list should be empty. EXPECT_TRUE(a.PopFront(NULL)); - EXPECT_EQ(0u, a.size()); + EXPECT_EQ(0, a.size()); } -// Tests inserting at the beginning using List::InsertAfter(). -TEST(ListTest, InsertAfterAtBeginning) { +// Tests inserting at the beginning using List::Insert(). +TEST(ListTest, InsertAtBeginning) { List<int> a; - ASSERT_EQ(0u, a.size()); + ASSERT_EQ(0, a.size()); // Inserts into an empty list. - a.InsertAfter(NULL, 1); - ASSERT_EQ(1u, a.size()); - EXPECT_EQ(1, a.Head()->element()); - ASSERT_EQ(a.Head(), a.Last()); + a.Insert(1, 0); + ASSERT_EQ(1, a.size()); + EXPECT_EQ(1, a.GetElement(0)); // Inserts at the beginning of a singleton list. - a.InsertAfter(NULL, 2); - ASSERT_EQ(2u, a.size()); - EXPECT_EQ(2, a.Head()->element()); - EXPECT_EQ(1, a.Last()->element()); + a.Insert(2, 0); + ASSERT_EQ(2, a.size()); + EXPECT_EQ(2, a.GetElement(0)); + EXPECT_EQ(1, a.GetElement(1)); // Inserts at the beginning of a list with more than one elements. - a.InsertAfter(NULL, 3); - ASSERT_EQ(3u, a.size()); - EXPECT_EQ(3, a.Head()->element()); - EXPECT_EQ(2, a.Head()->next()->element()); - EXPECT_EQ(1, a.Last()->element()); + a.Insert(3, 0); + ASSERT_EQ(3, a.size()); + EXPECT_EQ(3, a.GetElement(0)); + EXPECT_EQ(2, a.GetElement(1)); + EXPECT_EQ(1, a.GetElement(2)); } // Tests inserting at a location other than the beginning using -// List::InsertAfter(). -TEST(ListTest, InsertAfterNotAtBeginning) { +// List::Insert(). +TEST(ListTest, InsertNotAtBeginning) { // Prepares a singleton list. List<int> a; a.PushBack(1); // Inserts at the end of a singleton list. - a.InsertAfter(a.Last(), 2); - ASSERT_EQ(2u, a.size()); - EXPECT_EQ(1, a.Head()->element()); - EXPECT_EQ(2, a.Last()->element()); + a.Insert(2, a.size()); + ASSERT_EQ(2, a.size()); + EXPECT_EQ(1, a.GetElement(0)); + EXPECT_EQ(2, a.GetElement(1)); // Inserts at the end of a list with more than one elements. - a.InsertAfter(a.Last(), 3); - ASSERT_EQ(3u, a.size()); - EXPECT_EQ(1, a.Head()->element()); - EXPECT_EQ(2, a.Head()->next()->element()); - EXPECT_EQ(3, a.Last()->element()); + a.Insert(3, a.size()); + ASSERT_EQ(3, a.size()); + EXPECT_EQ(1, a.GetElement(0)); + EXPECT_EQ(2, a.GetElement(1)); + EXPECT_EQ(3, a.GetElement(2)); // Inserts in the middle of a list. - a.InsertAfter(a.Head(), 4); - ASSERT_EQ(4u, a.size()); - EXPECT_EQ(1, a.Head()->element()); - EXPECT_EQ(4, a.Head()->next()->element()); - EXPECT_EQ(2, a.Head()->next()->next()->element()); - EXPECT_EQ(3, a.Last()->element()); + a.Insert(4, 1); + ASSERT_EQ(4, a.size()); + EXPECT_EQ(1, a.GetElement(0)); + EXPECT_EQ(4, a.GetElement(1)); + EXPECT_EQ(2, a.GetElement(2)); + EXPECT_EQ(3, a.GetElement(3)); +} + +// Tests List::GetElementOr(). +TEST(ListTest, GetElementOr) { + List<char> a; + EXPECT_EQ('x', a.GetElementOr(0, 'x')); + + a.PushBack('a'); + a.PushBack('b'); + EXPECT_EQ('a', a.GetElementOr(0, 'x')); + EXPECT_EQ('b', a.GetElementOr(1, 'x')); + EXPECT_EQ('x', a.GetElementOr(-2, 'x')); + EXPECT_EQ('x', a.GetElementOr(2, 'x')); } // Tests the GetElement accessor. -TEST(ListTest, GetElement) { +TEST(ListDeathTest, GetElement) { List<int> a; a.PushBack(0); a.PushBack(1); a.PushBack(2); - EXPECT_EQ(&(a.Head()->element()), a.GetElement(0)); - EXPECT_EQ(&(a.Head()->next()->element()), a.GetElement(1)); - EXPECT_EQ(&(a.Head()->next()->next()->element()), a.GetElement(2)); - EXPECT_TRUE(a.GetElement(3) == NULL); - EXPECT_TRUE(a.GetElement(-1) == NULL); + EXPECT_EQ(0, a.GetElement(0)); + EXPECT_EQ(1, a.GetElement(1)); + EXPECT_EQ(2, a.GetElement(2)); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + a.GetElement(3), + "Invalid list index 3: must be in range \\[0, 2\\]\\."); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + a.GetElement(-1), + "Invalid list index -1: must be in range \\[0, 2\\]\\."); } // Tests the String class. @@ -1128,18 +1179,17 @@ class TestResultTest : public Test { } // Helper that compares two two TestPartResults. - static void CompareTestPartResult(const TestPartResult* expected, - const TestPartResult* actual) { - ASSERT_TRUE(actual != NULL); - EXPECT_EQ(expected->type(), actual->type()); - EXPECT_STREQ(expected->file_name(), actual->file_name()); - EXPECT_EQ(expected->line_number(), actual->line_number()); - EXPECT_STREQ(expected->summary(), actual->summary()); - EXPECT_STREQ(expected->message(), actual->message()); - EXPECT_EQ(expected->passed(), actual->passed()); - EXPECT_EQ(expected->failed(), actual->failed()); - EXPECT_EQ(expected->nonfatally_failed(), actual->nonfatally_failed()); - EXPECT_EQ(expected->fatally_failed(), actual->fatally_failed()); + static void CompareTestPartResult(const TestPartResult& expected, + const TestPartResult& actual) { + EXPECT_EQ(expected.type(), actual.type()); + EXPECT_STREQ(expected.file_name(), actual.file_name()); + EXPECT_EQ(expected.line_number(), actual.line_number()); + EXPECT_STREQ(expected.summary(), actual.summary()); + EXPECT_STREQ(expected.message(), actual.message()); + EXPECT_EQ(expected.passed(), actual.passed()); + EXPECT_EQ(expected.failed(), actual.failed()); + EXPECT_EQ(expected.nonfatally_failed(), actual.nonfatally_failed()); + EXPECT_EQ(expected.fatally_failed(), actual.fatally_failed()); } }; @@ -1193,11 +1243,18 @@ TEST_F(TestResultTest, Failed) { } // Tests TestResult::GetTestPartResult(). -TEST_F(TestResultTest, GetTestPartResult) { - CompareTestPartResult(pr1, r2->GetTestPartResult(0)); - CompareTestPartResult(pr2, r2->GetTestPartResult(1)); - EXPECT_TRUE(r2->GetTestPartResult(2) == NULL); - EXPECT_TRUE(r2->GetTestPartResult(-1) == NULL); + +typedef TestResultTest TestResultDeathTest; + +TEST_F(TestResultDeathTest, GetTestPartResult) { + CompareTestPartResult(*pr1, r2->GetTestPartResult(0)); + CompareTestPartResult(*pr2, r2->GetTestPartResult(1)); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + r2->GetTestPartResult(2), + "Invalid list index 2: must be in range \\[0, 1\\]\\."); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + r2->GetTestPartResult(-1), + "Invalid list index -1: must be in range \\[0, 1\\]\\."); } // Tests TestResult has no properties when none are added. @@ -1212,9 +1269,9 @@ TEST(TestResultPropertyTest, OnePropertyFoundWhenAdded) { TestProperty property("key_1", "1"); TestResultAccessor::RecordProperty(&test_result, property); ASSERT_EQ(1, test_result.test_property_count()); - const TestProperty* actual_property = test_result.GetTestProperty(0); - EXPECT_STREQ("key_1", actual_property->key()); - EXPECT_STREQ("1", actual_property->value()); + const TestProperty& actual_property = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property.key()); + EXPECT_STREQ("1", actual_property.value()); } // Tests TestResult has multiple properties when added. @@ -1225,13 +1282,13 @@ TEST(TestResultPropertyTest, MultiplePropertiesFoundWhenAdded) { TestResultAccessor::RecordProperty(&test_result, property_1); TestResultAccessor::RecordProperty(&test_result, property_2); ASSERT_EQ(2, test_result.test_property_count()); - const TestProperty* actual_property_1 = test_result.GetTestProperty(0); - EXPECT_STREQ("key_1", actual_property_1->key()); - EXPECT_STREQ("1", actual_property_1->value()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("1", actual_property_1.value()); - const TestProperty* actual_property_2 = test_result.GetTestProperty(1); - EXPECT_STREQ("key_2", actual_property_2->key()); - EXPECT_STREQ("2", actual_property_2->value()); + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("2", actual_property_2.value()); } // Tests TestResult::RecordProperty() overrides values for duplicate keys. @@ -1247,17 +1304,17 @@ TEST(TestResultPropertyTest, OverridesValuesForDuplicateKeys) { TestResultAccessor::RecordProperty(&test_result, property_2_2); ASSERT_EQ(2, test_result.test_property_count()); - const TestProperty* actual_property_1 = test_result.GetTestProperty(0); - EXPECT_STREQ("key_1", actual_property_1->key()); - EXPECT_STREQ("12", actual_property_1->value()); + const TestProperty& actual_property_1 = test_result.GetTestProperty(0); + EXPECT_STREQ("key_1", actual_property_1.key()); + EXPECT_STREQ("12", actual_property_1.value()); - const TestProperty* actual_property_2 = test_result.GetTestProperty(1); - EXPECT_STREQ("key_2", actual_property_2->key()); - EXPECT_STREQ("22", actual_property_2->value()); + const TestProperty& actual_property_2 = test_result.GetTestProperty(1); + EXPECT_STREQ("key_2", actual_property_2.key()); + EXPECT_STREQ("22", actual_property_2.value()); } // Tests TestResult::GetTestProperty(). -TEST(TestResultPropertyTest, GetTestProperty) { +TEST(TestResultPropertyDeathTest, GetTestProperty) { TestResult test_result; TestProperty property_1("key_1", "1"); TestProperty property_2("key_2", "2"); @@ -1266,24 +1323,25 @@ TEST(TestResultPropertyTest, GetTestProperty) { TestResultAccessor::RecordProperty(&test_result, property_2); TestResultAccessor::RecordProperty(&test_result, property_3); - const TestProperty* fetched_property_1 = test_result.GetTestProperty(0); - const TestProperty* fetched_property_2 = test_result.GetTestProperty(1); - const TestProperty* fetched_property_3 = test_result.GetTestProperty(2); + const TestProperty& fetched_property_1 = test_result.GetTestProperty(0); + const TestProperty& fetched_property_2 = test_result.GetTestProperty(1); + const TestProperty& fetched_property_3 = test_result.GetTestProperty(2); - ASSERT_TRUE(fetched_property_1 != NULL); - EXPECT_STREQ("key_1", fetched_property_1->key()); - EXPECT_STREQ("1", fetched_property_1->value()); + EXPECT_STREQ("key_1", fetched_property_1.key()); + EXPECT_STREQ("1", fetched_property_1.value()); - ASSERT_TRUE(fetched_property_2 != NULL); - EXPECT_STREQ("key_2", fetched_property_2->key()); - EXPECT_STREQ("2", fetched_property_2->value()); + EXPECT_STREQ("key_2", fetched_property_2.key()); + EXPECT_STREQ("2", fetched_property_2.value()); - ASSERT_TRUE(fetched_property_3 != NULL); - EXPECT_STREQ("key_3", fetched_property_3->key()); - EXPECT_STREQ("3", fetched_property_3->value()); + EXPECT_STREQ("key_3", fetched_property_3.key()); + EXPECT_STREQ("3", fetched_property_3.value()); - ASSERT_TRUE(test_result.GetTestProperty(3) == NULL); - ASSERT_TRUE(test_result.GetTestProperty(-1) == NULL); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + test_result.GetTestProperty(3), + "Invalid list index 3: must be in range \\[0, 2\\]\\."); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + test_result.GetTestProperty(-1), + "Invalid list index -1: must be in range \\[0, 2\\]\\."); } // When a property using a reserved key is supplied to this function, it tests @@ -1548,29 +1606,26 @@ TEST(Int32FromEnvOrDieTest, ParsesAndReturnsValidValue) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", "-123"); EXPECT_EQ(-123, Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "UnsetVar", 333)); } -#endif // _WIN32_WCE - -#if GTEST_HAS_DEATH_TEST +#endif // _WIN32_WCE // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable is not an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnFailure) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "xxx"); - EXPECT_DEATH({Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); } // Tests that Int32FromEnvOrDie() aborts with an error message // if the variable cannot be represnted by an Int32. TEST(Int32FromEnvOrDieDeathTest, AbortsOnInt32Overflow) { SetEnv(GTEST_FLAG_PREFIX_UPPER_ "VAR", "1234567891234567891234"); - EXPECT_DEATH({Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_( + Int32FromEnvOrDie(GTEST_FLAG_PREFIX_UPPER_ "VAR", 123), + ".*"); } -#endif // GTEST_HAS_DEATH_TEST - - // Tests that ShouldRunTestOnShard() selects all tests // where there is 1 shard. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereIsOneShard) { @@ -1635,35 +1690,34 @@ TEST_F(ShouldShardTest, WorksWhenShardEnvVarsAreValid) { EXPECT_TRUE(ShouldShard(total_var_, index_var_, false)); EXPECT_FALSE(ShouldShard(total_var_, index_var_, true)); } -#endif // _WIN32_WCE - -#if GTEST_HAS_DEATH_TEST +#endif // _WIN32_WCE // Tests that we exit in error if the sharding values are not valid. -TEST_F(ShouldShardTest, AbortsWhenShardingEnvVarsAreInvalid) { + +typedef ShouldShardTest ShouldShardDeathTest; + +TEST_F(ShouldShardDeathTest, AbortsWhenShardingEnvVarsAreInvalid) { SetEnv(index_var_, "4"); SetEnv(total_var_, "4"); - EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_(ShouldShard(total_var_, index_var_, false), + ".*"); SetEnv(index_var_, "4"); SetEnv(total_var_, "-2"); - EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_(ShouldShard(total_var_, index_var_, false), + ".*"); SetEnv(index_var_, "5"); SetEnv(total_var_, ""); - EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_(ShouldShard(total_var_, index_var_, false), + ".*"); SetEnv(index_var_, ""); SetEnv(total_var_, "5"); - EXPECT_DEATH({ShouldShard(total_var_, index_var_, false);}, - ".*"); + GTEST_EXPECT_DEATH_IF_SUPPORTED_(ShouldShard(total_var_, index_var_, false), + ".*"); } -#endif // GTEST_HAS_DEATH_TEST - // Tests that ShouldRunTestOnShard is a partition when 5 // shards are used. TEST(ShouldRunTestOnShardTest, IsPartitionWhenThereAreFiveShards) { @@ -3624,31 +3678,31 @@ namespace testing { TEST(SuccessfulAssertionTest, SUCCEED) { SUCCEED(); SUCCEED() << "OK"; - EXPECT_EQ(2u, GetSuccessfulPartCount()); + EXPECT_EQ(2, GetSuccessfulPartCount()); } // Tests that Google Test doesn't track successful EXPECT_*. TEST(SuccessfulAssertionTest, EXPECT) { EXPECT_TRUE(true); - EXPECT_EQ(0u, GetSuccessfulPartCount()); + EXPECT_EQ(0, GetSuccessfulPartCount()); } // Tests that Google Test doesn't track successful EXPECT_STR*. TEST(SuccessfulAssertionTest, EXPECT_STR) { EXPECT_STREQ("", ""); - EXPECT_EQ(0u, GetSuccessfulPartCount()); + EXPECT_EQ(0, GetSuccessfulPartCount()); } // Tests that Google Test doesn't track successful ASSERT_*. TEST(SuccessfulAssertionTest, ASSERT) { ASSERT_TRUE(true); - EXPECT_EQ(0u, GetSuccessfulPartCount()); + EXPECT_EQ(0, GetSuccessfulPartCount()); } // Tests that Google Test doesn't track successful ASSERT_STR*. TEST(SuccessfulAssertionTest, ASSERT_STR) { ASSERT_STREQ("", ""); - EXPECT_EQ(0u, GetSuccessfulPartCount()); + EXPECT_EQ(0, GetSuccessfulPartCount()); } } // namespace testing |