]> git.tdb.fi Git - libs/datafile.git/blob - tests/collection.cpp
Require C++11 for building
[libs/datafile.git] / tests / collection.cpp
1 #include <set>
2 #include <msp/datafile/collection.h>
3 #include <msp/datafile/objectloader.h>
4 #include <msp/io/memory.h>
5 #include <msp/test/test.h>
6
7 using namespace std;
8 using namespace Msp;
9
10 class TestCollection;
11
12 class CollectionTests: public Test::RegisteredTest<CollectionTests>
13 {
14 private:
15         TestCollection *collection;
16
17 public:
18         CollectionTests();
19         ~CollectionTests();
20
21         static const char *get_name() { return "Collection"; }
22
23 private:
24         void load();
25         void contains();
26         void contains_base();
27         void contains_loadable();
28         void names();
29         void names_base();
30         void names_loadable();
31         void fetch();
32         void nonexistent();
33         void type_mismatch();
34         void create();
35         void list_loadable();
36         void name_collision();
37 };
38
39
40 class Base
41 {
42 public:
43         class Loader: public DataFile::ObjectLoader<Base>
44         {
45         public:
46                 Loader(Base &);
47         };
48
49 private:
50         int tag;
51
52 public:
53         Base();
54
55         int get_tag() const { return tag; }
56 };
57
58 class Foo: public Base
59 {
60 private:
61         static unsigned create_count;
62
63 public:
64         Foo();
65
66         static unsigned get_create_count() { return create_count; }
67 };
68
69 class Bar: public Base
70 { };
71
72 class Sub: public Bar
73 { };
74
75 class Bus: public Bar
76 { };
77
78
79 class TestSource: public DataFile::CollectionSource
80 {
81 public:
82         virtual bool is_loadable(const DataFile::CollectionItemTypeBase &, const std::string &) const;
83         virtual NameList get_names(const DataFile::CollectionItemTypeBase &) const;
84         virtual void load(DataFile::Collection &, const DataFile::CollectionItemTypeBase &, const std::string &) const;
85         virtual IO::Seekable *open(const string &) const { return 0; }
86 };
87
88
89 class TestCollection: public DataFile::Collection
90 {
91 private:
92         TestSource source;
93
94 public:
95         TestCollection();
96
97 private:
98         Foo *create_foo(const string &);
99 };
100
101
102 CollectionTests::CollectionTests()
103 {
104         add(&CollectionTests::load, "Load objects");
105         add(&CollectionTests::contains, "Containment test");
106         add(&CollectionTests::contains_base, "Base class containment test");
107         add(&CollectionTests::contains_loadable, "Loadable containment test");
108         add(&CollectionTests::names, "List object names");
109         add(&CollectionTests::names_base, "List base class object names");
110         add(&CollectionTests::names_loadable, "List loadable object names");
111         add(&CollectionTests::fetch, "Fetch objects");
112         add(&CollectionTests::nonexistent, "Nonexistent object").expect_throw<key_error>();
113         add(&CollectionTests::type_mismatch, "Type mismatch").expect_throw<Msp::type_mismatch>();
114         add(&CollectionTests::create, "Create object");
115         add(&CollectionTests::list_loadable, "List loadable objects");
116         add(&CollectionTests::name_collision, "Name collision").expect_throw<Msp::key_error>();
117
118         collection = new TestCollection;
119 }
120
121 CollectionTests::~CollectionTests()
122 {
123         delete collection;
124 }
125
126 void CollectionTests::load()
127 {
128         const char input[] =
129                 "foo \"a\" { tag 1; };\n"
130                 "foo \"b\" { tag 2; };\n"
131                 "bar \"c\" { tag 3; };\n"
132                 "sub \"d\" { tag 4; };\n"
133                 "bus \"e\" { tag 5; };\n";
134
135         IO::Memory mem(input, sizeof(input)-1);
136         DataFile::Parser parser(mem, "-");
137         TestCollection::Loader loader(*collection);
138         loader.load(parser);
139 }
140
141 void CollectionTests::contains()
142 {
143         const TestCollection *ccoll = collection;
144         EXPECT(ccoll->contains<Foo>("a"));
145         EXPECT(ccoll->contains<Bar>("c"));
146         EXPECT(!ccoll->contains<Foo>("c"));
147 }
148
149 void CollectionTests::contains_base()
150 {
151         const TestCollection *ccoll = collection;
152         EXPECT(ccoll->contains<Bar>("d"));
153         EXPECT(ccoll->contains<Sub>("d"));
154 }
155
156 void CollectionTests::contains_loadable()
157 {
158         const TestCollection *ccoll = collection;
159         EXPECT(!ccoll->contains<Foo>("f"));
160         EXPECT(collection->contains<Foo>("f"));
161 }
162
163 void CollectionTests::names()
164 {
165         const TestCollection *ccoll = collection;
166         list<string> nm = ccoll->get_names<Foo>();
167         EXPECT_EQUAL(nm.size(), 2);
168         set<string> nm_set(nm.begin(), nm.end());
169         EXPECT_EQUAL(nm_set.count("a"), 1);
170         EXPECT_EQUAL(nm_set.count("b"), 1);
171 }
172
173 void CollectionTests::names_base()
174 {
175         const TestCollection *ccoll = collection;
176         list<string> nm = ccoll->get_names<Bar>();
177         EXPECT_EQUAL(nm.size(), 3);
178         set<string> nm_set(nm.begin(), nm.end());
179         EXPECT_EQUAL(nm_set.count("c"), 1);
180         EXPECT_EQUAL(nm_set.count("d"), 1);
181         EXPECT_EQUAL(nm_set.count("e"), 1);
182 }
183
184 void CollectionTests::names_loadable()
185 {
186         list<string> nm = collection->get_names<Foo>();
187         EXPECT_EQUAL(nm.size(), 3);
188         set<string> nm_set(nm.begin(), nm.end());
189         EXPECT_EQUAL(nm_set.count("f"), 1);
190 }
191
192 void CollectionTests::fetch()
193 {
194         const TestCollection *ccoll = collection;
195         EXPECT_EQUAL(ccoll->get<Foo>("a").get_tag(), 1);
196         EXPECT_EQUAL(ccoll->get<Foo>("b").get_tag(), 2);
197         EXPECT_EQUAL(ccoll->get<Bar>("c").get_tag(), 3);
198         EXPECT_EQUAL(ccoll->get<Bar>("d").get_tag(), 4);
199         EXPECT_EQUAL(ccoll->get<Sub>("d").get_tag(), 4);
200 }
201
202 void CollectionTests::nonexistent()
203 {
204         collection->get<Bar>("z");
205 }
206
207 void CollectionTests::type_mismatch()
208 {
209         collection->get<Foo>("c");
210 }
211
212 void CollectionTests::create()
213 {
214         unsigned foo_count = Foo::get_create_count();
215         Foo &f = collection->get<Foo>("f");
216         Foo &f2 = collection->get<Foo>("f");
217         EXPECT_EQUAL(&f2, &f);
218         EXPECT(Foo::get_create_count()>foo_count);
219 }
220
221 void CollectionTests::list_loadable()
222 {
223         list<Foo *> nm = collection->get_list<Foo>();
224         EXPECT_EQUAL(nm.size(), 3);
225         set<Foo *> nm_set(nm.begin(), nm.end());
226         EXPECT_EQUAL(nm_set.size(), nm.size());
227 }
228
229 void CollectionTests::name_collision()
230 {
231         RefPtr<Foo> a = new Foo;
232         collection->add("a", a.get());
233         a.release();
234 }
235
236
237 Base::Base():
238         tag(0)
239 { }
240
241
242 Base::Loader::Loader(Base &b):
243         DataFile::ObjectLoader<Base>(b)
244 {
245         add("tag", &Base::tag);
246 }
247
248
249 unsigned Foo::create_count = 0;
250
251 Foo::Foo()
252 {
253         ++create_count;
254 }
255
256
257 bool TestSource::is_loadable(const DataFile::CollectionItemTypeBase &, const string &name) const
258 {
259         return name=="f";
260 }
261
262 DataFile::CollectionSource::NameList TestSource::get_names(const DataFile::CollectionItemTypeBase &) const
263 {
264         NameList names;
265         names.push_back("f");
266         return names;
267 }
268
269 void TestSource::load(DataFile::Collection &coll, const DataFile::CollectionItemTypeBase &, const string &name) const
270 {
271         if(name=="f")
272                 coll.add("f", new Foo);
273 }
274
275
276 TestCollection::TestCollection()
277 {
278         add_type<Foo>().keyword("foo").creator(&TestCollection::create_foo);
279         add_type<Bar>().keyword("bar");
280         add_type<Sub>().keyword("sub").base<Bar>();
281         add_type<Bus>().keyword("bus").base<Bar>();
282         add_source(source);
283 }
284
285 Foo *TestCollection::create_foo(const string &)
286 {
287         return new Foo;
288 }