Google test源码阅读(二):参数化测试执行流程

来源:互联网 发布:阿里云系统格机 编辑:程序博客网 时间:2024/06/03 22:59

参数化测试or数据驱动可以利用大量的数据跑一个具体的Case,有利于发现问题。至于Google test如何写数据驱动,请参考google的文档。

先介绍求Prime素数的类:

// The prime table interface.class PrimeTable { public:  virtual ~PrimeTable() {}  // Returns true iff n is a prime number.  virtual bool IsPrime(int n) const = 0;  // Returns the smallest prime number greater than p; or returns -1  // if the next prime is beyond the capacity of the table.  virtual int GetNextPrime(int p) const = 0;};// Implementation #1 calculates the primes on-the-fly.class OnTheFlyPrimeTable : public PrimeTable { public:  virtual bool IsPrime(int n) const {    if (n <= 1) return false;    for (int i = 2; i*i <= n; i++) {      // n is divisible by an integer other than 1 and itself.      if ((n % i) == 0) return false;    }    return true;  }  virtual int GetNextPrime(int p) const {    for (int n = p + 1; n > 0; n++) {      if (IsPrime(n)) return n;    }    return -1;  }};// Implementation #2 pre-calculates the primes and stores the result// in an array.class PreCalculatedPrimeTable : public PrimeTable { public:  // 'max' specifies the maximum number the prime table holds.  explicit PreCalculatedPrimeTable(int max)      : is_prime_size_(max + 1), is_prime_(new bool[max + 1]) {    CalculatePrimesUpTo(max);  }  virtual ~PreCalculatedPrimeTable() { delete[] is_prime_; }  virtual bool IsPrime(int n) const {    return 0 <= n && n < is_prime_size_ && is_prime_[n];  }  virtual int GetNextPrime(int p) const {    for (int n = p + 1; n < is_prime_size_; n++) {      if (is_prime_[n]) return n;    }    return -1;  } private:  void CalculatePrimesUpTo(int max) {    ::std::fill(is_prime_, is_prime_ + is_prime_size_, true);    is_prime_[0] = is_prime_[1] = false;    for (int i = 2; i <= max; i++) {      if (!is_prime_[i]) continue;      // Marks all multiples of i (except i itself) as non-prime.      for (int j = 2*i; j <= max; j += i) {        is_prime_[j] = false;      }    }  }  const int is_prime_size_;  bool* const is_prime_;  // Disables compiler warning "assignment operator could not be generated."  void operator=(const PreCalculatedPrimeTable& rhs);};

下面开始写具体的Case:

 

typedef PrimeTable* CreatePrimeTableFunc();PrimeTable* CreateOnTheFlyPrimeTable() {  return new OnTheFlyPrimeTable();}template <size_t max_precalculated>PrimeTable* CreatePreCalculatedPrimeTable() {  return new PreCalculatedPrimeTable(max_precalculated);}class PrimeTableTest : public TestWithParam<CreatePrimeTableFunc*> { public:  virtual ~PrimeTableTest() { delete table_; }  virtual void SetUp() { table_ = (*GetParam())(); }  virtual void TearDown() {    delete table_;    table_ = NULL;  } protected:  PrimeTable* table_;

测试的Case如下所示:

TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {  EXPECT_FALSE(table_->IsPrime(-5));}TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {  EXPECT_TRUE(table_->IsPrime(2));}TEST_P(PrimeTableTest, CanGetNextPrime) {  EXPECT_EQ(2, table_->GetNextPrime(0));}INSTANTIATE_TEST_CASE_P(    OnTheFlyAndPreCalculated,    PrimeTableTest,    Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>));

按照上一篇文档的方法进行宏扩展,扩展后Case的具体实现如下:

class PrimeTableTest_ReturnsFalseForNonPrimes_Test : public PrimeTableTest { public: PrimeTableTest_ReturnsFalseForNonPrimes_Test() {}         virtual void TestBody(); private: static int AddToRegistry()          {              ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(                  "PrimeTableTest",                  "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                  50)->AddTestPattern(                     "PrimeTableTest",                     "ReturnsFalseForNonPrimes",                     new ::testing::internal::TestMetaFactory< PrimeTableTest_ReturnsFalseForNonPrimes_Test>()                    );              return 0;          }          static int gtest_registering_dummy_;          PrimeTableTest_ReturnsFalseForNonPrimes_Test(PrimeTableTest_ReturnsFalseForNonPrimes_Test const &);          void operator=(PrimeTableTest_ReturnsFalseForNonPrimes_Test const &); }; int PrimeTableTest_ReturnsFalseForNonPrimes_Test::gtest_registering_dummy_ =     PrimeTableTest_ReturnsFalseForNonPrimes_Test::AddToRegistry(); void PrimeTableTest_ReturnsFalseForNonPrimes_Test::TestBody() {    switch (0)     case 0:     default: if (const ::testing::AssertionResult gtest_ar_ =                     ::testing::AssertionResult(!(table_->IsPrime(-5)))) ;              else                  ::testing::internal::AssertHelper(                    ::testing::TestPartResult::kNonFatalFailure,                     "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                     51,                     ::testing::internal::GetBoolAssertionFailureMessage(                         gtest_ar_,                         "table_->IsPrime(-5)",                         "true",                         "false"                    ).c_str()                ) = ::testing::Message();}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class PrimeTableTest_ReturnsTrueForPrimes_Test : public PrimeTableTest { public: PrimeTableTest_ReturnsTrueForPrimes_Test() {}     virtual void TestBody();     private: static int AddToRegistry()              {                  ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(                     "PrimeTableTest",                     "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                     59)->AddTestPattern(                             "PrimeTableTest",                             "ReturnsTrueForPrimes",                             new ::testing::internal::TestMetaFactory< PrimeTableTest_ReturnsTrueForPrimes_Test>());                 return 0;              }              static int gtest_registering_dummy_;              PrimeTableTest_ReturnsTrueForPrimes_Test(PrimeTableTest_ReturnsTrueForPrimes_Test const &);              void operator=(PrimeTableTest_ReturnsTrueForPrimes_Test const &); }; int PrimeTableTest_ReturnsTrueForPrimes_Test::gtest_registering_dummy_ =     PrimeTableTest_ReturnsTrueForPrimes_Test::AddToRegistry(); void PrimeTableTest_ReturnsTrueForPrimes_Test::TestBody() {    switch (0)     case 0:     default: if (const ::testing::AssertionResult gtest_ar_ =                  ::testing::AssertionResult(table_->IsPrime(2))) ;              else                  ::testing::internal::AssertHelper(                    ::testing::TestPartResult::kNonFatalFailure,                     "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                     60,                     ::testing::internal::GetBoolAssertionFailureMessage(                         gtest_ar_,                         "table_->IsPrime(2)",                         "false",                         "true"                    ).c_str()                ) = ::testing::Message();}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class PrimeTableTest_CanGetNextPrime_Test : public PrimeTableTest { public: PrimeTableTest_CanGetNextPrime_Test() {}         virtual void TestBody(); private: static int AddToRegistry()          {             ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(                  "PrimeTableTest",                  "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                  68)->AddTestPattern(                         "PrimeTableTest",                         "CanGetNextPrime",                         new ::testing::internal::TestMetaFactory< PrimeTableTest_CanGetNextPrime_Test>());              return 0;          }          static int gtest_registering_dummy_;          PrimeTableTest_CanGetNextPrime_Test(PrimeTableTest_CanGetNextPrime_Test const &);          void operator=(PrimeTableTest_CanGetNextPrime_Test const &); }; int PrimeTableTest_CanGetNextPrime_Test::gtest_registering_dummy_ =     PrimeTableTest_CanGetNextPrime_Test::AddToRegistry(); void PrimeTableTest_CanGetNextPrime_Test::TestBody() {    switch (0)     case 0:     default:         if (const ::testing::AssertionResult gtest_ar =             (::testing::internal:: EqHelper<(sizeof(::testing::internal::IsNullLiteralHelper(2)) == 1)>::Compare(                "2",                 "table_->GetNextPrime(0)",                 2,                 table_->GetNextPrime(0)                )            )        ) ;         else             ::testing::internal::AssertHelper(                ::testing::TestPartResult::kNonFatalFailure,                 "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                 69,                 gtest_ar.failure_message()            ) = ::testing::Message();}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////::testing::internal::ParamGenerator<PrimeTableTest::ParamType> gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_() {     return Values(&CreateOnTheFlyPrimeTable, &CreatePreCalculatedPrimeTable<1000>); } int gtest_OnTheFlyAndPreCalculatedPrimeTableTest_dummy_ =     ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(         "PrimeTableTest",         "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",         87)->AddTestCaseInstantiation(                 "OnTheFlyAndPreCalculated",                 &gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_,                 "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                 87);

(一)在主线程进入main函数之前首先初始化类中的静态变量。因此首先会执行:

int PrimeTableTest_ReturnsFalseForNonPrimes_Test::gtest_registering_dummy_ =     PrimeTableTest_ReturnsFalseForNonPrimes_Test::AddToRegistry(); 
AddToRegistry的对应代码如下:
static int AddToRegistry()              {                  ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(                     "PrimeTableTest",                     "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                     59)->AddTestPattern(                             "PrimeTableTest",                             "ReturnsTrueForPrimes",                             new ::testing::internal::TestMetaFactory< PrimeTableTest_ReturnsTrueForPrimes_Test>());                 return 0;              } 
GetTestCasePatternHolder和AddTestPattern方法如下:
class ParameterizedTestCaseRegistry {…  …// Looks up or creates and returns a structure containing information about  // tests and instantiations of a particular test case.  template <class TestCase>  ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(      const char* test_case_name,      const char* file,      int line) {    ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();         it != test_case_infos_.end(); ++it) {      if ((*it)->GetTestCaseName() == test_case_name) {        if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {          // Complain about incorrect usage of Google Test facilities          // and terminate the program since we cannot guaranty correct          // test case setup and tear-down in this case.          ReportInvalidTestCaseType(test_case_name,  file, line);          posix::Abort();        } else {         // At this point we are sure that the object we found is of the same         // type we are looking for, so we downcast it to that type         // without further checks.          typed_test_info = CheckedDowncastToActualType<              ParameterizedTestCaseInfo<TestCase> >(*it);        }        break;      }    }    if (typed_test_info == NULL) {      typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);      test_case_infos_.push_back(typed_test_info);    }    return typed_test_info;  }… …}

 

template <class TestCase>class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {…void AddTestPattern(const char* test_case_name,                      const char* test_base_name,                      TestMetaFactoryBase<ParamType>* meta_factory) {    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,                                                       test_base_name,                                                       meta_factory)));  }…}

 

(二)在进入main函数之前,在初始化上面的类中静态变量之后,将初始化全局变量:
int gtest_OnTheFlyAndPreCalculatedPrimeTableTest_dummy_ =     ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(         "PrimeTableTest",         "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",         87)->AddTestCaseInstantiation(                 "OnTheFlyAndPreCalculated",                 &gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_,                 "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                 87);

 

AddTestCaseInstantiation的方法实现如下:
template <class TestCase>class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase  {…// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information  // about a generator.  int AddTestCaseInstantiation(const string& instantiation_name,                               GeneratorCreationFunc* func,                               const char* /* file */,                               int /* line */) {    instantiations_.push_back(::std::make_pair(instantiation_name, func));    return 0;  // Return value used only to run this method in namespace scope.  }…}

 

(三)进入main函数之后的执行流程如下:
int main(int argc, char **argv) {    //testing::FLAGS_gtest_filter = "OnTheFlyAndPreCalculated*";    testing::InitGoogleTest(&argc, argv);    return (::testing::UnitTest::GetInstance()->Run());}
void InitGoogleTest(int* argc, char** argv) {  internal::InitGoogleTestImpl(argc, argv);}
// The internal implementation of InitGoogleTest().//// The type parameter CharType can be instantiated to either char or// wchar_t.template <typename CharType>void InitGoogleTestImpl(int* argc, CharType** argv) {  …  GetUnitTestImpl()->PostFlagParsingInit();}// Performs initialization dependent upon flag values obtained in// ParseGoogleTestFlagsOnly.  Is called from InitGoogleTest after the call to// ParseGoogleTestFlagsOnly.  In case a user neglects to call InitGoogleTest// this function is also called from RunAllTests.  Since this function can be// called more than once, it has to be idempotent.void UnitTestImpl::PostFlagParsingInit() {…    // Registers parameterized tests. This makes parameterized tests    // available to the UnitTest reflection API without running    // RUN_ALL_TESTS.    RegisterParameterizedTests();…  }

 

 

// This method expands all parameterized tests registered with macros TEST_P// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.// This will be done just once during the program runtime.void UnitTestImpl::RegisterParameterizedTests() {#if GTEST_HAS_PARAM_TEST  if (!parameterized_tests_registered_) {    parameterized_test_registry_.RegisterTests();    parameterized_tests_registered_ = true;  }#endif}

 

// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.//// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P// macros use it to locate their corresponding ParameterizedTestCaseInfo// descriptors.class ParameterizedTestCaseRegistry {…   void RegisterTests() {    for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();         it != test_case_infos_.end(); ++it) {      (*it)->RegisterTests();    }  }//注意对照上面的ParameterizedTestCaseRegistry::GetTestCasePatternHolder方法…};

 注意:下面的RegisterTests方法和上面已经介绍的AddTestPattern,AddTestCaseInstantiation同属于类ParameterizedTestCaseInfo。

template <class TestCase>class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { public:…  // TEST_P macro uses AddTestPattern() to record information  // about a single test in a LocalTestInfo structure.  // test_case_name is the base name of the test case (without invocation  // prefix). test_base_name is the name of an individual test without  // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is  // test case base name and DoBar is test base name.  void AddTestPattern(const char* test_case_name,                      const char* test_base_name,                      TestMetaFactoryBase<ParamType>* meta_factory) {    tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,                                                       test_base_name,                                                       meta_factory)));  }  // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information  // about a generator.  int AddTestCaseInstantiation(const string& instantiation_name,                               GeneratorCreationFunc* func,                               const char* /* file */,                               int /* line */) {    instantiations_.push_back(::std::make_pair(instantiation_name, func));    return 0;  // Return value used only to run this method in namespace scope.  }  // UnitTest class invokes this method to register tests in this test case  // test cases right before running tests in RUN_ALL_TESTS macro.  // This method should not be called more then once on any single  // instance of a ParameterizedTestCaseInfoBase derived class.  // UnitTest has a guard to prevent from calling this method more then once.  virtual void RegisterTests() {    for (typename TestInfoContainer::iterator test_it = tests_.begin();         test_it != tests_.end(); ++test_it) {////很显然,tests_是在AddTestPattern方法中增加元素的。      linked_ptr<TestInfo> test_info = *test_it;      for (typename InstantiationContainer::iterator gen_it =               instantiations_.begin(); gen_it != instantiations_.end();               ++gen_it) { //很显然,instantiations_是在AddTestCaseInstantiation方法中增加元素的。        const string& instantiation_name = gen_it->first;        ParamGenerator<ParamType> generator((*gen_it->second)());        Message test_case_name_stream;        if ( !instantiation_name.empty() )          test_case_name_stream << instantiation_name << "/";        test_case_name_stream << test_info->test_case_base_name;        int i = 0;        for (typename ParamGenerator<ParamType>::iterator param_it =                 generator.begin();             param_it != generator.end(); ++param_it, ++i) {          Message test_name_stream;          test_name_stream << test_info->test_base_name << "/" << i;          MakeAndRegisterTestInfo(              test_case_name_stream.GetString().c_str(),              test_name_stream.GetString().c_str(),              NULL,  // No type parameter.              PrintToString(*param_it).c_str(),              GetTestCaseTypeId(),              TestCase::SetUpTestCase,              TestCase::TearDownTestCase,              test_info->test_meta_factory->CreateTestFactory(*param_it));        }  // for param_it      }  // for gen_it    }  // for test_it  }  // RegisterTests private:  // LocalTestInfo structure keeps information about a single test registered  // with TEST_P macro.  struct TestInfo {    TestInfo(const char* a_test_case_base_name,             const char* a_test_base_name,             TestMetaFactoryBase<ParamType>* a_test_meta_factory) :        test_case_base_name(a_test_case_base_name),        test_base_name(a_test_base_name),        test_meta_factory(a_test_meta_factory) {}    const string test_case_base_name;    const string test_base_name;    const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;  };  typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;  // Keeps pairs of <Instantiation name, Sequence generator creation function>  // received from INSTANTIATE_TEST_CASE_P macros.  typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >      InstantiationContainer;  InstantiationContainer instantiations_;  … };  // class ParameterizedTestCaseInfo

 

 MakeAndRegisterTestInfo方法正是我们在上一篇分析中介绍的方法。

TestInfo* MakeAndRegisterTestInfo(    const char* test_case_name, const char* name,    const char* type_param,    const char* value_param,    TypeId fixture_class_id,    SetUpTestCaseFunc set_up_tc,    TearDownTestCaseFunc tear_down_tc,    TestFactoryBase* factory) {  TestInfo* const test_info =      new TestInfo(test_case_name, name, type_param, value_param,                   fixture_class_id, factory);  GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);  return test_info;}

 

 在结束本文之前, 我们对ParameterizedTestCaseInfo::RegisterTests方法中的一段代码感兴趣。

ParamGenerator<ParamType> generator((*gen_it->second)());首先看刚开始的一段代码:
int gtest_OnTheFlyAndPreCalculatedPrimeTableTest_dummy_ =     ::testing::UnitTest::GetInstance()->parameterized_test_registry(). GetTestCasePatternHolder<PrimeTableTest>(         "PrimeTableTest",         "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",         87)->AddTestCaseInstantiation(                 "OnTheFlyAndPreCalculated",                 &gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_,                 "d:\\gtest\\gtest_all\\gtest_all\\sample7_unittest.cc",                 87);
查看一下AddTestCaseInstantiation方法。我们知道,(*gen_it->second)()实际上就是执行gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_方法。
::testing::internal::ParamGenerator<PrimeTableTest::ParamType> gtest_OnTheFlyAndPreCalculatedPrimeTableTest_EvalGenerator_() { return Values(&CreateOnTheFlyPrimeTable,&reatePreCalculatedPrimeTable<1000>); }
template <typename T1, typename T2>internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {  return internal::ValueArray2<T1, T2>(v1, v2);}
template <typename T1, typename T2>class ValueArray2 { public:  ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}  template <typename T>  operator ParamGenerator<T>() const {    const T array[] = {v1_, v2_};    return ValuesIn(array);  } private:  // No implementation - assignment is unsupported.  void operator=(const ValueArray2& other);  const T1 v1_;  const T2 v2_;};
template <typename T, size_t N>internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {  return ValuesIn(array, array + N);}
template <typename ForwardIterator>internal::ParamGenerator<  typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>ValuesIn(ForwardIterator begin, ForwardIterator end) {  typedef typename ::testing::internal::IteratorTraits<ForwardIterator>      ::value_type ParamType;  return internal::ParamGenerator<ParamType>(      new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));}
// Generates values from a pair of STL-style iterators. Used in the// ValuesIn() function. The elements are copied from the source range// since the source can be located on the stack, and the generator// is likely to persist beyond that stack frame.template <typename T>class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> { public:  template <typename ForwardIterator>  ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)      : container_(begin, end) {}  virtual ~ValuesInIteratorRangeGenerator() {}  virtual ParamIteratorInterface<T>* Begin() const {    return new Iterator(this, container_.begin());  }  virtual ParamIteratorInterface<T>* End() const {    return new Iterator(this, container_.end());  } private:  typedef typename ::std::vector<T> ContainerType;  //内部类,并且是一个迭代器的实现class Iterator : public ParamIteratorInterface<T> {   public:    Iterator(const ParamGeneratorInterface<T>* base,             typename ContainerType::const_iterator iterator)        : base_(base), iterator_(iterator) {}    virtual ~Iterator() {}    virtual const ParamGeneratorInterface<T>* BaseGenerator() const {      return base_;    }    virtual void Advance() {      ++iterator_;      value_.reset();    }    virtual ParamIteratorInterface<T>* Clone() const {      return new Iterator(*this);    }    // We need to use cached value referenced by iterator_ because *iterator_    // can return a temporary object (and of type other then T), so just    // having "return &*iterator_;" doesn't work.    // value_ is updated here and not in Advance() because Advance()    // can advance iterator_ beyond the end of the range, and we cannot    // detect that fact. The client code, on the other hand, is    // responsible for not calling Current() on an out-of-range iterator.    virtual const T* Current() const {      if (value_.get() == NULL)        value_.reset(new T(*iterator_));      return value_.get();    }    virtual bool Equals(const ParamIteratorInterface<T>& other) const {      // Having the same base generator guarantees that the other      // iterator is of the same type and we can downcast.      GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())          << "The program attempted to compare iterators "          << "from different generators." << std::endl;      return iterator_ ==          CheckedDowncastToActualType<const Iterator>(&other)->iterator_;    }   private:    Iterator(const Iterator& other)          // The explicit constructor call suppresses a false warning          // emitted by gcc when supplied with the -Wextra option.        : ParamIteratorInterface<T>(),          base_(other.base_),          iterator_(other.iterator_) {}    const ParamGeneratorInterface<T>* const base_;    typename ContainerType::const_iterator iterator_;    // A cached value of *iterator_. We keep it here to allow access by    // pointer in the wrapping iterator's operator->().    // value_ needs to be mutable to be accessed in Current().    // Use of scoped_ptr helps manage cached value's lifetime,    // which is bound by the lifespan of the iterator itself.    mutable scoped_ptr<const T> value_;  };  // class ValuesInIteratorRangeGenerator::Iterator  // No implementation - assignment is unsupported.  void operator=(const ValuesInIteratorRangeGenerator& other);  const ContainerType container_;};  // class ValuesInIteratorRangeGenerator

 

 
// Wraps ParamGeneratorInterface<T> and provides general generator syntax// compatible with the STL Container concept.// This class implements copy initialization semantics and the contained// ParamGeneratorInterface<T> instance is shared among all copies// of the original object. This is possible because that instance is immutable.template<typename T>class ParamGenerator { public:  typedef ParamIterator<T> iterator;  explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}  ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}  ParamGenerator& operator=(const ParamGenerator& other) {    impl_ = other.impl_;    return *this;  }  iterator begin() const { return iterator(impl_->Begin()); }  iterator end() const { return iterator(impl_->End()); } private:  linked_ptr<const ParamGeneratorInterface<T> > impl_;};

 

                                             
0 0
原创粉丝点击