Home | History | Annotate | Download | only in declarative
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/declarative/deduping_factory.h"
      6 
      7 #include "base/values.h"
      8 #include "testing/gtest/include/gtest/gtest.h"
      9 
     10 namespace {
     11 
     12 const char kTypeName[] = "Foo";
     13 const char kTypeName2[] = "Foo2";
     14 
     15 // This serves as an example how to use the DedupingFactory.
     16 class BaseClass : public base::RefCounted<BaseClass> {
     17  public:
     18   // The type is introduced so that we can compare derived classes even though
     19   // Equals takes a parameter of type BaseClass. Each derived class gets an
     20   // entry in Type.
     21   enum Type { FOO };
     22 
     23   explicit BaseClass(Type type) : type_(type) {}
     24 
     25   Type type() const { return type_; }
     26 
     27   // For BaseClassT template:
     28   virtual bool Equals(const BaseClass* other) const = 0;
     29 
     30  protected:
     31   friend class base::RefCounted<BaseClass>;
     32   virtual ~BaseClass() {}
     33 
     34  private:
     35   const Type type_;
     36 };
     37 
     38 class Foo : public BaseClass {
     39  public:
     40   explicit Foo(int parameter) : BaseClass(FOO), parameter_(parameter) {}
     41   virtual bool Equals(const BaseClass* other) const OVERRIDE {
     42     return other->type() == type() &&
     43            static_cast<const Foo*>(other)->parameter_ == parameter_;
     44   }
     45   int parameter() const {
     46     return parameter_;
     47   }
     48 
     49  private:
     50   friend class base::RefCounted<BaseClass>;
     51   virtual ~Foo() {}
     52 
     53   // Note that this class must be immutable.
     54   const int parameter_;
     55   DISALLOW_COPY_AND_ASSIGN(Foo);
     56 };
     57 
     58 scoped_refptr<const BaseClass> CreateFoo(const std::string& /*instance_type*/,
     59                                          const base::Value* value,
     60                                          std::string* error,
     61                                          bool* bad_message) {
     62   const base::DictionaryValue* dict = NULL;
     63   CHECK(value->GetAsDictionary(&dict));
     64   int parameter = 0;
     65   if (!dict->GetInteger("parameter", &parameter)) {
     66     *error = "No parameter";
     67     *bad_message = true;
     68     return scoped_refptr<const BaseClass>(NULL);
     69   }
     70   return scoped_refptr<const BaseClass>(new Foo(parameter));
     71 }
     72 
     73 scoped_ptr<base::DictionaryValue> CreateDictWithParameter(int parameter) {
     74   scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
     75   dict->SetInteger("parameter", parameter);
     76   return dict.Pass();
     77 }
     78 
     79 }  // namespace
     80 
     81 namespace extensions {
     82 
     83 TEST(DedupingFactoryTest, InstantiationParameterized) {
     84   DedupingFactory<BaseClass> factory(2);
     85   factory.RegisterFactoryMethod(
     86       kTypeName, DedupingFactory<BaseClass>::IS_PARAMETERIZED, &CreateFoo);
     87 
     88   scoped_ptr<base::DictionaryValue> d1(CreateDictWithParameter(1));
     89   scoped_ptr<base::DictionaryValue> d2(CreateDictWithParameter(2));
     90   scoped_ptr<base::DictionaryValue> d3(CreateDictWithParameter(3));
     91   scoped_ptr<base::DictionaryValue> d4(CreateDictWithParameter(4));
     92 
     93   std::string error;
     94   bool bad_message = false;
     95 
     96   // Fill factory with 2 different types.
     97   scoped_refptr<const BaseClass> c1(
     98       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
     99   scoped_refptr<const BaseClass> c2(
    100       factory.Instantiate(kTypeName, d2.get(), &error, &bad_message));
    101   ASSERT_TRUE(c1.get());
    102   ASSERT_TRUE(c2.get());
    103   EXPECT_EQ(1, static_cast<const Foo*>(c1.get())->parameter());
    104   EXPECT_EQ(2, static_cast<const Foo*>(c2.get())->parameter());
    105 
    106   // This one produces an overflow, now the cache contains [2, 3]
    107   scoped_refptr<const BaseClass> c3(
    108       factory.Instantiate(kTypeName, d3.get(), &error, &bad_message));
    109   ASSERT_TRUE(c3.get());
    110   EXPECT_EQ(3, static_cast<const Foo*>(c3.get())->parameter());
    111 
    112   // Reuse 2, this should give the same instance as c2.
    113   scoped_refptr<const BaseClass> c2_b(
    114       factory.Instantiate(kTypeName, d2.get(), &error, &bad_message));
    115   EXPECT_EQ(2, static_cast<const Foo*>(c2_b.get())->parameter());
    116   EXPECT_EQ(c2, c2_b);
    117 
    118   // Also check that the reuse of 2 moved it to the end, so that the cache is
    119   // now [3, 2] and 3 is discarded before 2.
    120   // This discards 3, so the cache becomes [2, 1]
    121   scoped_refptr<const BaseClass> c1_b(
    122       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
    123 
    124   scoped_refptr<const BaseClass> c2_c(
    125       factory.Instantiate(kTypeName, d2.get(), &error, &bad_message));
    126   EXPECT_EQ(2, static_cast<const Foo*>(c2_c.get())->parameter());
    127   EXPECT_EQ(c2, c2_c);
    128 }
    129 
    130 TEST(DedupingFactoryTest, InstantiationNonParameterized) {
    131   DedupingFactory<BaseClass> factory(2);
    132   factory.RegisterFactoryMethod(
    133       kTypeName, DedupingFactory<BaseClass>::IS_NOT_PARAMETERIZED, &CreateFoo);
    134 
    135   scoped_ptr<base::DictionaryValue> d1(CreateDictWithParameter(1));
    136   scoped_ptr<base::DictionaryValue> d2(CreateDictWithParameter(2));
    137 
    138   std::string error;
    139   bool bad_message = false;
    140 
    141   // We create two instances with different dictionaries but because the type is
    142   // declared to be not parameterized, we should get the same instance.
    143   scoped_refptr<const BaseClass> c1(
    144       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
    145   scoped_refptr<const BaseClass> c2(
    146       factory.Instantiate(kTypeName, d2.get(), &error, &bad_message));
    147   ASSERT_TRUE(c1.get());
    148   ASSERT_TRUE(c2.get());
    149   EXPECT_EQ(1, static_cast<const Foo*>(c1.get())->parameter());
    150   EXPECT_EQ(1, static_cast<const Foo*>(c2.get())->parameter());
    151   EXPECT_EQ(c1, c2);
    152 }
    153 
    154 TEST(DedupingFactoryTest, TypeNames) {
    155   DedupingFactory<BaseClass> factory(2);
    156   factory.RegisterFactoryMethod(
    157       kTypeName, DedupingFactory<BaseClass>::IS_PARAMETERIZED, &CreateFoo);
    158   factory.RegisterFactoryMethod(
    159       kTypeName2, DedupingFactory<BaseClass>::IS_PARAMETERIZED, &CreateFoo);
    160 
    161   scoped_ptr<base::DictionaryValue> d1(CreateDictWithParameter(1));
    162 
    163   std::string error;
    164   bool bad_message = false;
    165 
    166   scoped_refptr<const BaseClass> c1_a(
    167       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
    168   scoped_refptr<const BaseClass> c1_b(
    169       factory.Instantiate(kTypeName2, d1.get(), &error, &bad_message));
    170 
    171   ASSERT_TRUE(c1_a.get());
    172   ASSERT_TRUE(c1_b.get());
    173   EXPECT_NE(c1_a, c1_b);
    174 }
    175 
    176 TEST(DedupingFactoryTest, Clear) {
    177   DedupingFactory<BaseClass> factory(2);
    178   factory.RegisterFactoryMethod(
    179       kTypeName, DedupingFactory<BaseClass>::IS_PARAMETERIZED, &CreateFoo);
    180 
    181   scoped_ptr<base::DictionaryValue> d1(CreateDictWithParameter(1));
    182 
    183   std::string error;
    184   bool bad_message = false;
    185 
    186   scoped_refptr<const BaseClass> c1_a(
    187       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
    188 
    189   factory.ClearPrototypes();
    190 
    191   scoped_refptr<const BaseClass> c1_b(
    192       factory.Instantiate(kTypeName, d1.get(), &error, &bad_message));
    193 
    194   ASSERT_TRUE(c1_a.get());
    195   ASSERT_TRUE(c1_b.get());
    196   EXPECT_NE(c1_a, c1_b);
    197 }
    198 
    199 }  // namespace extensions
    200