Google test源碼閱讀(二):參數化測試執行流程

參數化測試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_;
};

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章