1b89a7cc2SEnji Cooper // Copyright 2008 Google Inc.
2b89a7cc2SEnji Cooper // All Rights Reserved.
3b89a7cc2SEnji Cooper //
4b89a7cc2SEnji Cooper // Redistribution and use in source and binary forms, with or without
5b89a7cc2SEnji Cooper // modification, are permitted provided that the following conditions are
6b89a7cc2SEnji Cooper // met:
7b89a7cc2SEnji Cooper //
8b89a7cc2SEnji Cooper //     * Redistributions of source code must retain the above copyright
9b89a7cc2SEnji Cooper // notice, this list of conditions and the following disclaimer.
10b89a7cc2SEnji Cooper //     * Redistributions in binary form must reproduce the above
11b89a7cc2SEnji Cooper // copyright notice, this list of conditions and the following disclaimer
12b89a7cc2SEnji Cooper // in the documentation and/or other materials provided with the
13b89a7cc2SEnji Cooper // distribution.
14b89a7cc2SEnji Cooper //     * Neither the name of Google Inc. nor the names of its
15b89a7cc2SEnji Cooper // contributors may be used to endorse or promote products derived from
16b89a7cc2SEnji Cooper // this software without specific prior written permission.
17b89a7cc2SEnji Cooper //
18b89a7cc2SEnji Cooper // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19b89a7cc2SEnji Cooper // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20b89a7cc2SEnji Cooper // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21b89a7cc2SEnji Cooper // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22b89a7cc2SEnji Cooper // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23b89a7cc2SEnji Cooper // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24b89a7cc2SEnji Cooper // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25b89a7cc2SEnji Cooper // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26b89a7cc2SEnji Cooper // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27b89a7cc2SEnji Cooper // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28b89a7cc2SEnji Cooper // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29b89a7cc2SEnji Cooper 
30b89a7cc2SEnji Cooper // This sample shows how to test code relying on some global flag variables.
31b89a7cc2SEnji Cooper // Combine() helps with generating all possible combinations of such flags,
32b89a7cc2SEnji Cooper // and each test is given one combination as a parameter.
33b89a7cc2SEnji Cooper 
34b89a7cc2SEnji Cooper // Use class definitions to test from this header.
3528f6c2f2SEnji Cooper #include <tuple>
36b89a7cc2SEnji Cooper 
3728f6c2f2SEnji Cooper #include "prime_tables.h"
38b89a7cc2SEnji Cooper #include "gtest/gtest.h"
39b89a7cc2SEnji Cooper namespace {
40b89a7cc2SEnji Cooper 
41b89a7cc2SEnji Cooper // Suppose we want to introduce a new, improved implementation of PrimeTable
42b89a7cc2SEnji Cooper // which combines speed of PrecalcPrimeTable and versatility of
43b89a7cc2SEnji Cooper // OnTheFlyPrimeTable (see prime_tables.h). Inside it instantiates both
44b89a7cc2SEnji Cooper // PrecalcPrimeTable and OnTheFlyPrimeTable and uses the one that is more
45b89a7cc2SEnji Cooper // appropriate under the circumstances. But in low memory conditions, it can be
46b89a7cc2SEnji Cooper // told to instantiate without PrecalcPrimeTable instance at all and use only
47b89a7cc2SEnji Cooper // OnTheFlyPrimeTable.
48b89a7cc2SEnji Cooper class HybridPrimeTable : public PrimeTable {
49b89a7cc2SEnji Cooper  public:
HybridPrimeTable(bool force_on_the_fly,int max_precalculated)50b89a7cc2SEnji Cooper   HybridPrimeTable(bool force_on_the_fly, int max_precalculated)
51b89a7cc2SEnji Cooper       : on_the_fly_impl_(new OnTheFlyPrimeTable),
5228f6c2f2SEnji Cooper         precalc_impl_(force_on_the_fly
5328f6c2f2SEnji Cooper                           ? nullptr
5428f6c2f2SEnji Cooper                           : new PreCalculatedPrimeTable(max_precalculated)),
55b89a7cc2SEnji Cooper         max_precalculated_(max_precalculated) {}
~HybridPrimeTable()5628f6c2f2SEnji Cooper   ~HybridPrimeTable() override {
57b89a7cc2SEnji Cooper     delete on_the_fly_impl_;
58b89a7cc2SEnji Cooper     delete precalc_impl_;
59b89a7cc2SEnji Cooper   }
60b89a7cc2SEnji Cooper 
IsPrime(int n) const6128f6c2f2SEnji Cooper   bool IsPrime(int n) const override {
6228f6c2f2SEnji Cooper     if (precalc_impl_ != nullptr && n < max_precalculated_)
63b89a7cc2SEnji Cooper       return precalc_impl_->IsPrime(n);
64b89a7cc2SEnji Cooper     else
65b89a7cc2SEnji Cooper       return on_the_fly_impl_->IsPrime(n);
66b89a7cc2SEnji Cooper   }
67b89a7cc2SEnji Cooper 
GetNextPrime(int p) const6828f6c2f2SEnji Cooper   int GetNextPrime(int p) const override {
69b89a7cc2SEnji Cooper     int next_prime = -1;
7028f6c2f2SEnji Cooper     if (precalc_impl_ != nullptr && p < max_precalculated_)
71b89a7cc2SEnji Cooper       next_prime = precalc_impl_->GetNextPrime(p);
72b89a7cc2SEnji Cooper 
73b89a7cc2SEnji Cooper     return next_prime != -1 ? next_prime : on_the_fly_impl_->GetNextPrime(p);
74b89a7cc2SEnji Cooper   }
75b89a7cc2SEnji Cooper 
76b89a7cc2SEnji Cooper  private:
77b89a7cc2SEnji Cooper   OnTheFlyPrimeTable* on_the_fly_impl_;
78b89a7cc2SEnji Cooper   PreCalculatedPrimeTable* precalc_impl_;
79b89a7cc2SEnji Cooper   int max_precalculated_;
80b89a7cc2SEnji Cooper };
81b89a7cc2SEnji Cooper 
82b89a7cc2SEnji Cooper using ::testing::Bool;
83b89a7cc2SEnji Cooper using ::testing::Combine;
8428f6c2f2SEnji Cooper using ::testing::TestWithParam;
8528f6c2f2SEnji Cooper using ::testing::Values;
86b89a7cc2SEnji Cooper 
87b89a7cc2SEnji Cooper // To test all code paths for HybridPrimeTable we must test it with numbers
88b89a7cc2SEnji Cooper // both within and outside PreCalculatedPrimeTable's capacity and also with
89b89a7cc2SEnji Cooper // PreCalculatedPrimeTable disabled. We do this by defining fixture which will
90b89a7cc2SEnji Cooper // accept different combinations of parameters for instantiating a
91b89a7cc2SEnji Cooper // HybridPrimeTable instance.
9228f6c2f2SEnji Cooper class PrimeTableTest : public TestWithParam< ::std::tuple<bool, int> > {
93b89a7cc2SEnji Cooper  protected:
SetUp()9428f6c2f2SEnji Cooper   void SetUp() override {
9528f6c2f2SEnji Cooper     bool force_on_the_fly;
9628f6c2f2SEnji Cooper     int max_precalculated;
9728f6c2f2SEnji Cooper     std::tie(force_on_the_fly, max_precalculated) = GetParam();
98b89a7cc2SEnji Cooper     table_ = new HybridPrimeTable(force_on_the_fly, max_precalculated);
99b89a7cc2SEnji Cooper   }
TearDown()10028f6c2f2SEnji Cooper   void TearDown() override {
101b89a7cc2SEnji Cooper     delete table_;
10228f6c2f2SEnji Cooper     table_ = nullptr;
103b89a7cc2SEnji Cooper   }
104b89a7cc2SEnji Cooper   HybridPrimeTable* table_;
105b89a7cc2SEnji Cooper };
106b89a7cc2SEnji Cooper 
TEST_P(PrimeTableTest,ReturnsFalseForNonPrimes)107b89a7cc2SEnji Cooper TEST_P(PrimeTableTest, ReturnsFalseForNonPrimes) {
108b89a7cc2SEnji Cooper   // Inside the test body, you can refer to the test parameter by GetParam().
109b89a7cc2SEnji Cooper   // In this case, the test parameter is a PrimeTable interface pointer which
110b89a7cc2SEnji Cooper   // we can use directly.
111b89a7cc2SEnji Cooper   // Please note that you can also save it in the fixture's SetUp() method
112b89a7cc2SEnji Cooper   // or constructor and use saved copy in the tests.
113b89a7cc2SEnji Cooper 
114b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(-5));
115b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(0));
116b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(1));
117b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(4));
118b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(6));
119b89a7cc2SEnji Cooper   EXPECT_FALSE(table_->IsPrime(100));
120b89a7cc2SEnji Cooper }
121b89a7cc2SEnji Cooper 
TEST_P(PrimeTableTest,ReturnsTrueForPrimes)122b89a7cc2SEnji Cooper TEST_P(PrimeTableTest, ReturnsTrueForPrimes) {
123b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(2));
124b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(3));
125b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(5));
126b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(7));
127b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(11));
128b89a7cc2SEnji Cooper   EXPECT_TRUE(table_->IsPrime(131));
129b89a7cc2SEnji Cooper }
130b89a7cc2SEnji Cooper 
TEST_P(PrimeTableTest,CanGetNextPrime)131b89a7cc2SEnji Cooper TEST_P(PrimeTableTest, CanGetNextPrime) {
132b89a7cc2SEnji Cooper   EXPECT_EQ(2, table_->GetNextPrime(0));
133b89a7cc2SEnji Cooper   EXPECT_EQ(3, table_->GetNextPrime(2));
134b89a7cc2SEnji Cooper   EXPECT_EQ(5, table_->GetNextPrime(3));
135b89a7cc2SEnji Cooper   EXPECT_EQ(7, table_->GetNextPrime(5));
136b89a7cc2SEnji Cooper   EXPECT_EQ(11, table_->GetNextPrime(7));
137b89a7cc2SEnji Cooper   EXPECT_EQ(131, table_->GetNextPrime(128));
138b89a7cc2SEnji Cooper }
139b89a7cc2SEnji Cooper 
140b89a7cc2SEnji Cooper // In order to run value-parameterized tests, you need to instantiate them,
141b89a7cc2SEnji Cooper // or bind them to a list of values which will be used as test parameters.
142b89a7cc2SEnji Cooper // You can instantiate them in a different translation module, or even
143b89a7cc2SEnji Cooper // instantiate them several times.
144b89a7cc2SEnji Cooper //
145b89a7cc2SEnji Cooper // Here, we instantiate our tests with a list of parameters. We must combine
146b89a7cc2SEnji Cooper // all variations of the boolean flag suppressing PrecalcPrimeTable and some
147b89a7cc2SEnji Cooper // meaningful values for tests. We choose a small value (1), and a value that
148b89a7cc2SEnji Cooper // will put some of the tested numbers beyond the capability of the
149b89a7cc2SEnji Cooper // PrecalcPrimeTable instance and some inside it (10). Combine will produce all
150b89a7cc2SEnji Cooper // possible combinations.
15128f6c2f2SEnji Cooper INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest,
152b89a7cc2SEnji Cooper                          Combine(Bool(), Values(1, 10)));
153b89a7cc2SEnji Cooper 
154b89a7cc2SEnji Cooper }  // namespace
155