]> git.tdb.fi Git - libs/datafile.git/blob - tests/collection.cpp
Move token-to-argument conversion to Statement
[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_future();
28         void names();
29         void names_base();
30         void names_future();
31         void fetch();
32         void nonexistent();
33         void type_mismatch();
34         void create();
35         void list_future();
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 };
86
87
88 class TestCollection: public DataFile::Collection
89 {
90 private:
91         TestSource source;
92
93 public:
94         TestCollection();
95
96 private:
97         Foo *create_foo(const string &);
98 };
99
100
101 CollectionTests::CollectionTests()
102 {
103         add(&CollectionTests::load, "Load objects");
104         add(&CollectionTests::contains, "Containment test");
105         add(&CollectionTests::contains_base, "Base class containment test");
106         add(&CollectionTests::contains_future, "Future containment test");
107         add(&CollectionTests::names, "List object names");
108         add(&CollectionTests::names_base, "List base class object names");
109         add(&CollectionTests::names_future, "List future object names");
110         add(&CollectionTests::fetch, "Fetch objects");
111         add(&CollectionTests::nonexistent, "Nonexistent object").expect_throw<key_error>();
112         add(&CollectionTests::type_mismatch, "Type mismatch").expect_throw<Msp::type_mismatch>();
113         add(&CollectionTests::create, "Create object");
114         add(&CollectionTests::list_future, "List future objects");
115         add(&CollectionTests::name_collision, "Name collision").expect_throw<Msp::key_error>();
116
117         collection = new TestCollection;
118 }
119
120 CollectionTests::~CollectionTests()
121 {
122         delete collection;
123 }
124
125 void CollectionTests::load()
126 {
127         const char input[] =
128                 "foo \"a\" { tag 1; };\n"
129                 "foo \"b\" { tag 2; };\n"
130                 "bar \"c\" { tag 3; };\n"
131                 "sub \"d\" { tag 4; };\n"
132                 "bus \"e\" { tag 5; };\n";
133
134         IO::Memory mem(input, sizeof(input)-1);
135         DataFile::Parser parser(mem, "-");
136         TestCollection::Loader loader(*collection);
137         loader.load(parser);
138 }
139
140 void CollectionTests::contains()
141 {
142         const TestCollection *ccoll = collection;
143         EXPECT(ccoll->contains<Foo>("a"));
144         EXPECT(ccoll->contains<Bar>("c"));
145         EXPECT(!ccoll->contains<Foo>("c"));
146 }
147
148 void CollectionTests::contains_base()
149 {
150         const TestCollection *ccoll = collection;
151         EXPECT(ccoll->contains<Bar>("d"));
152         EXPECT(ccoll->contains<Sub>("d"));
153 }
154
155 void CollectionTests::contains_future()
156 {
157         const TestCollection *ccoll = collection;
158         EXPECT(!ccoll->contains<Foo>("f"));
159         EXPECT(collection->contains<Foo>("f"));
160 }
161
162 void CollectionTests::names()
163 {
164         const TestCollection *ccoll = collection;
165         list<string> nm = ccoll->get_names<Foo>();
166         EXPECT_EQUAL(nm.size(), 2);
167         set<string> nm_set(nm.begin(), nm.end());
168         EXPECT_EQUAL(nm_set.count("a"), 1);
169         EXPECT_EQUAL(nm_set.count("b"), 1);
170 }
171
172 void CollectionTests::names_base()
173 {
174         const TestCollection *ccoll = collection;
175         list<string> nm = ccoll->get_names<Bar>();
176         EXPECT_EQUAL(nm.size(), 3);
177         set<string> nm_set(nm.begin(), nm.end());
178         EXPECT_EQUAL(nm_set.count("c"), 1);
179         EXPECT_EQUAL(nm_set.count("d"), 1);
180         EXPECT_EQUAL(nm_set.count("e"), 1);
181 }
182
183 void CollectionTests::names_future()
184 {
185         list<string> nm = collection->get_names<Foo>();
186         EXPECT_EQUAL(nm.size(), 3);
187         set<string> nm_set(nm.begin(), nm.end());
188         EXPECT_EQUAL(nm_set.count("f"), 1);
189 }
190
191 void CollectionTests::fetch()
192 {
193         const TestCollection *ccoll = collection;
194         EXPECT_EQUAL(ccoll->get<Foo>("a").get_tag(), 1);
195         EXPECT_EQUAL(ccoll->get<Foo>("b").get_tag(), 2);
196         EXPECT_EQUAL(ccoll->get<Bar>("c").get_tag(), 3);
197         EXPECT_EQUAL(ccoll->get<Bar>("d").get_tag(), 4);
198         EXPECT_EQUAL(ccoll->get<Sub>("d").get_tag(), 4);
199 }
200
201 void CollectionTests::nonexistent()
202 {
203         collection->get<Bar>("z");
204 }
205
206 void CollectionTests::type_mismatch()
207 {
208         collection->get<Foo>("c");
209 }
210
211 void CollectionTests::create()
212 {
213         unsigned foo_count = Foo::get_create_count();
214         Foo &f = collection->get<Foo>("f");
215         Foo &f2 = collection->get<Foo>("f");
216         EXPECT_EQUAL(&f2, &f);
217         EXPECT(Foo::get_create_count()>foo_count);
218 }
219
220 void CollectionTests::list_future()
221 {
222         list<Foo *> nm = collection->get_list<Foo>();
223         EXPECT_EQUAL(nm.size(), 3);
224         set<Foo *> nm_set(nm.begin(), nm.end());
225         EXPECT_EQUAL(nm_set.size(), nm.size());
226 }
227
228 void CollectionTests::name_collision()
229 {
230         RefPtr<Foo> a = new Foo;
231         collection->add("a", a.get());
232         a.release();
233 }
234
235
236 Base::Base():
237         tag(0)
238 { }
239
240
241 Base::Loader::Loader(Base &b):
242         DataFile::ObjectLoader<Base>(b)
243 {
244         add("tag", &Base::tag);
245 }
246
247
248 unsigned Foo::create_count = 0;
249
250 Foo::Foo()
251 {
252         ++create_count;
253 }
254
255
256 bool TestSource::is_loadable(const DataFile::CollectionItemTypeBase &, const string &name) const
257 {
258         return name=="f";
259 }
260
261 DataFile::CollectionSource::NameList TestSource::get_names(const DataFile::CollectionItemTypeBase &) const
262 {
263         NameList names;
264         names.push_back("f");
265         return names;
266 }
267
268 void TestSource::load(DataFile::Collection &coll, const DataFile::CollectionItemTypeBase &, const string &name) const
269 {
270         if(name=="f")
271                 coll.add("f", new Foo);
272 }
273
274
275 TestCollection::TestCollection()
276 {
277         add_type<Foo>().keyword("foo").creator(&TestCollection::create_foo);
278         add_type<Bar>().keyword("bar");
279         add_type<Sub>().keyword("sub").base<Bar>();
280         add_type<Bus>().keyword("bus").base<Bar>();
281         add_source(source);
282 }
283
284 Foo *TestCollection::create_foo(const string &)
285 {
286         return new Foo;
287 }