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.
5 #include "extensions/browser/api/declarative/deduping_factory.h"
7 #include "base/values.h"
8 #include "testing/gtest/include/gtest/gtest.h"
12 const char kTypeName
[] = "Foo";
13 const char kTypeName2
[] = "Foo2";
15 // This serves as an example how to use the DedupingFactory.
16 class BaseClass
: public base::RefCounted
<BaseClass
> {
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
23 explicit BaseClass(Type type
) : type_(type
) {}
25 Type
type() const { return type_
; }
27 // For BaseClassT template:
28 virtual bool Equals(const BaseClass
* other
) const = 0;
31 friend class base::RefCounted
<BaseClass
>;
32 virtual ~BaseClass() {}
38 class Foo
: public BaseClass
{
40 explicit Foo(int parameter
) : BaseClass(FOO
), parameter_(parameter
) {}
41 bool Equals(const BaseClass
* other
) const override
{
42 return other
->type() == type() &&
43 static_cast<const Foo
*>(other
)->parameter_
== parameter_
;
45 int parameter() const {
50 friend class base::RefCounted
<BaseClass
>;
53 // Note that this class must be immutable.
55 DISALLOW_COPY_AND_ASSIGN(Foo
);
58 scoped_refptr
<const BaseClass
> CreateFoo(const std::string
& /*instance_type*/,
59 const base::Value
* value
,
62 const base::DictionaryValue
* dict
= NULL
;
63 CHECK(value
->GetAsDictionary(&dict
));
65 if (!dict
->GetInteger("parameter", ¶meter
)) {
66 *error
= "No parameter";
68 return scoped_refptr
<const BaseClass
>(NULL
);
70 return scoped_refptr
<const BaseClass
>(new Foo(parameter
));
73 scoped_ptr
<base::DictionaryValue
> CreateDictWithParameter(int parameter
) {
74 scoped_ptr
<base::DictionaryValue
> dict(new base::DictionaryValue
);
75 dict
->SetInteger("parameter", parameter
);
81 namespace extensions
{
83 TEST(DedupingFactoryTest
, InstantiationParameterized
) {
84 DedupingFactory
<BaseClass
> factory(2);
85 factory
.RegisterFactoryMethod(
86 kTypeName
, DedupingFactory
<BaseClass
>::IS_PARAMETERIZED
, &CreateFoo
);
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));
94 bool bad_message
= false;
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());
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());
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());
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
));
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());
130 TEST(DedupingFactoryTest
, InstantiationNonParameterized
) {
131 DedupingFactory
<BaseClass
> factory(2);
132 factory
.RegisterFactoryMethod(
133 kTypeName
, DedupingFactory
<BaseClass
>::IS_NOT_PARAMETERIZED
, &CreateFoo
);
135 scoped_ptr
<base::DictionaryValue
> d1(CreateDictWithParameter(1));
136 scoped_ptr
<base::DictionaryValue
> d2(CreateDictWithParameter(2));
139 bool bad_message
= false;
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());
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
);
161 scoped_ptr
<base::DictionaryValue
> d1(CreateDictWithParameter(1));
164 bool bad_message
= false;
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
));
171 ASSERT_TRUE(c1_a
.get());
172 ASSERT_TRUE(c1_b
.get());
173 EXPECT_NE(c1_a
, c1_b
);
176 TEST(DedupingFactoryTest
, Clear
) {
177 DedupingFactory
<BaseClass
> factory(2);
178 factory
.RegisterFactoryMethod(
179 kTypeName
, DedupingFactory
<BaseClass
>::IS_PARAMETERIZED
, &CreateFoo
);
181 scoped_ptr
<base::DictionaryValue
> d1(CreateDictWithParameter(1));
184 bool bad_message
= false;
186 scoped_refptr
<const BaseClass
> c1_a(
187 factory
.Instantiate(kTypeName
, d1
.get(), &error
, &bad_message
));
189 factory
.ClearPrototypes();
191 scoped_refptr
<const BaseClass
> c1_b(
192 factory
.Instantiate(kTypeName
, d1
.get(), &error
, &bad_message
));
194 ASSERT_TRUE(c1_a
.get());
195 ASSERT_TRUE(c1_b
.get());
196 EXPECT_NE(c1_a
, c1_b
);
199 } // namespace extensions