moved wxFileConfig test to config directory together with wxConfig test
[wxWidgets.git] / tests / config / fileconf.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/fileconf/fileconf.cpp
3 // Purpose: wxFileConf unit test
4 // Author: Vadim Zeitlin
5 // Created: 2004-09-19
6 // RCS-ID: $Id$
7 // Copyright: (c) 2004 Vadim Zeitlin
8 ///////////////////////////////////////////////////////////////////////////////
9
10 // ----------------------------------------------------------------------------
11 // headers
12 // ----------------------------------------------------------------------------
13
14 #include "testprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #if wxUSE_FILECONFIG
21
22 #ifndef WX_PRECOMP
23 #endif // WX_PRECOMP
24
25 #include "wx/fileconf.h"
26 #include "wx/sstream.h"
27 #include "wx/log.h"
28
29 static const wxChar *testconfig =
30 _T("[root]\n")
31 _T("entry=value\n")
32 _T("[root/group1]\n")
33 _T("[root/group1/subgroup]\n")
34 _T("subentry=subvalue\n")
35 _T("subentry2=subvalue2\n")
36 _T("[root/group2]\n")
37 ;
38
39 // ----------------------------------------------------------------------------
40 // local functions
41 // ----------------------------------------------------------------------------
42
43 static wxString Dump(wxFileConfig& fc)
44 {
45 wxStringOutputStream sos;
46 fc.Save(sos);
47 return wxTextFile::Translate(sos.GetString(), wxTextFileType_Unix);
48 }
49
50 // helper macro to test wxFileConfig contents
51 #define wxVERIFY_FILECONFIG(t, fc) CPPUNIT_ASSERT_EQUAL(wxString(t), Dump(fc))
52
53 // ----------------------------------------------------------------------------
54 // test class
55 // ----------------------------------------------------------------------------
56
57 class FileConfigTestCase : public CppUnit::TestCase
58 {
59 public:
60 FileConfigTestCase() { }
61
62 private:
63 CPPUNIT_TEST_SUITE( FileConfigTestCase );
64 CPPUNIT_TEST( Path );
65 CPPUNIT_TEST( AddEntries );
66 CPPUNIT_TEST( GetEntries );
67 CPPUNIT_TEST( GetGroups );
68 CPPUNIT_TEST( HasEntry );
69 CPPUNIT_TEST( HasGroup );
70 CPPUNIT_TEST( Binary );
71 CPPUNIT_TEST( Save );
72 CPPUNIT_TEST( DeleteEntry );
73 CPPUNIT_TEST( DeleteGroup );
74 CPPUNIT_TEST( DeleteAll );
75 CPPUNIT_TEST( RenameEntry );
76 CPPUNIT_TEST( RenameGroup );
77 CPPUNIT_TEST( CreateEntriesAndSubgroup );
78 CPPUNIT_TEST( CreateSubgroupAndEntries );
79 CPPUNIT_TEST( DeleteLastGroup );
80 CPPUNIT_TEST( DeleteAndRecreateGroup );
81 CPPUNIT_TEST_SUITE_END();
82
83 void Path();
84 void AddEntries();
85 void GetEntries();
86 void GetGroups();
87 void HasEntry();
88 void HasGroup();
89 void Binary();
90 void Save();
91 void DeleteEntry();
92 void DeleteGroup();
93 void DeleteAll();
94 void RenameEntry();
95 void RenameGroup();
96 void CreateEntriesAndSubgroup();
97 void CreateSubgroupAndEntries();
98 void DeleteLastGroup();
99 void DeleteAndRecreateGroup();
100
101 static wxString ChangePath(wxFileConfig& fc, const wxChar *path)
102 {
103 fc.SetPath(path);
104
105 return fc.GetPath();
106 }
107
108 void CheckGroupEntries(const wxFileConfig& fc,
109 const wxChar *path,
110 size_t nEntries,
111 ...);
112 void CheckGroupSubgroups(const wxFileConfig& fc,
113 const wxChar *path,
114 size_t nGroups,
115 ...);
116
117 DECLARE_NO_COPY_CLASS(FileConfigTestCase)
118 };
119
120 // register in the unnamed registry so that these tests are run by default
121 CPPUNIT_TEST_SUITE_REGISTRATION( FileConfigTestCase );
122
123 // also include in it's own registry so that these tests can be run alone
124 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( FileConfigTestCase, "FileConfigTestCase" );
125
126 void FileConfigTestCase::Path()
127 {
128 wxStringInputStream sis(testconfig);
129 wxFileConfig fc(sis);
130
131 CPPUNIT_ASSERT( ChangePath(fc, _T("")) == _T("") );
132 CPPUNIT_ASSERT( ChangePath(fc, _T("/")) == _T("") );
133 CPPUNIT_ASSERT( ChangePath(fc, _T("root")) == _T("/root") );
134 CPPUNIT_ASSERT( ChangePath(fc, _T("/root")) == _T("/root") );
135 CPPUNIT_ASSERT( ChangePath(fc, _T("/root/group1/subgroup")) == _T("/root/group1/subgroup") );
136 CPPUNIT_ASSERT( ChangePath(fc, _T("/root/group2")) == _T("/root/group2") );
137 }
138
139 void FileConfigTestCase::AddEntries()
140 {
141 wxFileConfig fc;
142
143 wxVERIFY_FILECONFIG( _T(""), fc );
144
145 fc.Write(_T("/Foo"), _T("foo"));
146 wxVERIFY_FILECONFIG( _T("Foo=foo\n"), fc );
147
148 fc.Write(_T("/Bar/Baz"), _T("baz"));
149 wxVERIFY_FILECONFIG( _T("Foo=foo\n[Bar]\nBaz=baz\n"), fc );
150
151 fc.DeleteAll();
152 wxVERIFY_FILECONFIG( _T(""), fc );
153
154 fc.Write(_T("/Bar/Baz"), _T("baz"));
155 wxVERIFY_FILECONFIG( _T("[Bar]\nBaz=baz\n"), fc );
156
157 fc.Write(_T("/Foo"), _T("foo"));
158 wxVERIFY_FILECONFIG( _T("Foo=foo\n[Bar]\nBaz=baz\n"), fc );
159 }
160
161 void
162 FileConfigTestCase::CheckGroupEntries(const wxFileConfig& fc,
163 const wxChar *path,
164 size_t nEntries,
165 ...)
166 {
167 wxConfigPathChanger change(&fc, wxString(path) + _T("/"));
168
169 CPPUNIT_ASSERT( fc.GetNumberOfEntries() == nEntries );
170
171 va_list ap;
172 va_start(ap, nEntries);
173
174 long cookie;
175 wxString name;
176 for ( bool cont = fc.GetFirstEntry(name, cookie);
177 cont;
178 cont = fc.GetNextEntry(name, cookie), nEntries-- )
179 {
180 CPPUNIT_ASSERT( name == va_arg(ap, wxChar *) );
181 }
182
183 CPPUNIT_ASSERT( nEntries == 0 );
184
185 va_end(ap);
186 }
187
188 void
189 FileConfigTestCase::CheckGroupSubgroups(const wxFileConfig& fc,
190 const wxChar *path,
191 size_t nGroups,
192 ...)
193 {
194 wxConfigPathChanger change(&fc, wxString(path) + _T("/"));
195
196 CPPUNIT_ASSERT( fc.GetNumberOfGroups() == nGroups );
197
198 va_list ap;
199 va_start(ap, nGroups);
200
201 long cookie;
202 wxString name;
203 for ( bool cont = fc.GetFirstGroup(name, cookie);
204 cont;
205 cont = fc.GetNextGroup(name, cookie), nGroups-- )
206 {
207 CPPUNIT_ASSERT( name == va_arg(ap, wxChar *) );
208 }
209
210 CPPUNIT_ASSERT( nGroups == 0 );
211
212 va_end(ap);
213 }
214
215 void FileConfigTestCase::GetEntries()
216 {
217 wxStringInputStream sis(testconfig);
218 wxFileConfig fc(sis);
219
220 CheckGroupEntries(fc, _T(""), 0);
221 CheckGroupEntries(fc, _T("/root"), 1, _T("entry"));
222 CheckGroupEntries(fc, _T("/root/group1"), 0);
223 CheckGroupEntries(fc, _T("/root/group1/subgroup"),
224 2, _T("subentry"), _T("subentry2"));
225 }
226
227 void FileConfigTestCase::GetGroups()
228 {
229 wxStringInputStream sis(testconfig);
230 wxFileConfig fc(sis);
231
232 CheckGroupSubgroups(fc, _T(""), 1, _T("root"));
233 CheckGroupSubgroups(fc, _T("/root"), 2, _T("group1"), _T("group2"));
234 CheckGroupSubgroups(fc, _T("/root/group1"), 1, _T("subgroup"));
235 CheckGroupSubgroups(fc, _T("/root/group2"), 0);
236 }
237
238 void FileConfigTestCase::HasEntry()
239 {
240 wxStringInputStream sis(testconfig);
241 wxFileConfig fc(sis);
242
243 CPPUNIT_ASSERT( !fc.HasEntry(_T("root")) );
244 CPPUNIT_ASSERT( fc.HasEntry(_T("root/entry")) );
245 CPPUNIT_ASSERT( fc.HasEntry(_T("/root/entry")) );
246 CPPUNIT_ASSERT( fc.HasEntry(_T("root/group1/subgroup/subentry")) );
247 CPPUNIT_ASSERT( !fc.HasEntry(_T("")) );
248 CPPUNIT_ASSERT( !fc.HasEntry(_T("root/group1")) );
249 CPPUNIT_ASSERT( !fc.HasEntry(_T("subgroup/subentry")) );
250 CPPUNIT_ASSERT( !fc.HasEntry(_T("/root/no_such_group/entry")) );
251 CPPUNIT_ASSERT( !fc.HasGroup(_T("/root/no_such_group")) );
252 }
253
254 void FileConfigTestCase::HasGroup()
255 {
256 wxStringInputStream sis(testconfig);
257 wxFileConfig fc(sis);
258
259 CPPUNIT_ASSERT( fc.HasGroup(_T("root")) );
260 CPPUNIT_ASSERT( fc.HasGroup(_T("root/group1")) );
261 CPPUNIT_ASSERT( fc.HasGroup(_T("root/group1/subgroup")) );
262 CPPUNIT_ASSERT( fc.HasGroup(_T("root/group2")) );
263 CPPUNIT_ASSERT( !fc.HasGroup(_T("")) );
264 CPPUNIT_ASSERT( !fc.HasGroup(_T("root/group")) );
265 CPPUNIT_ASSERT( !fc.HasGroup(_T("root//subgroup")) );
266 CPPUNIT_ASSERT( !fc.HasGroup(_T("foot/subgroup")) );
267 CPPUNIT_ASSERT( !fc.HasGroup(_T("foot")) );
268 }
269
270 void FileConfigTestCase::Binary()
271 {
272 wxStringInputStream sis(
273 "[root]\n"
274 "binary=Zm9vCg==\n"
275 );
276 wxFileConfig fc(sis);
277
278 wxMemoryBuffer buf;
279 fc.Read("/root/binary", &buf);
280
281 CPPUNIT_ASSERT( memcmp("foo\n", buf.GetData(), buf.GetDataLen()) == 0 );
282
283 buf.SetDataLen(0);
284 buf.AppendData("\0\1\2", 3);
285 fc.Write("/root/012", buf);
286 wxVERIFY_FILECONFIG(
287 "[root]\n"
288 "binary=Zm9vCg==\n"
289 "012=AAEC\n",
290 fc
291 );
292 }
293
294 void FileConfigTestCase::Save()
295 {
296 wxStringInputStream sis(testconfig);
297 wxFileConfig fc(sis);
298 wxVERIFY_FILECONFIG( testconfig, fc );
299 }
300
301 void FileConfigTestCase::DeleteEntry()
302 {
303 wxStringInputStream sis(testconfig);
304 wxFileConfig fc(sis);
305
306 CPPUNIT_ASSERT( !fc.DeleteEntry(_T("foo")) );
307
308 CPPUNIT_ASSERT( fc.DeleteEntry(_T("root/group1/subgroup/subentry")) );
309 wxVERIFY_FILECONFIG( _T("[root]\n")
310 _T("entry=value\n")
311 _T("[root/group1]\n")
312 _T("[root/group1/subgroup]\n")
313 _T("subentry2=subvalue2\n")
314 _T("[root/group2]\n"),
315 fc );
316
317 // group should be deleted now as well as it became empty
318 wxConfigPathChanger change(&fc, _T("root/group1/subgroup/subentry2"));
319 CPPUNIT_ASSERT( fc.DeleteEntry(_T("subentry2")) );
320 wxVERIFY_FILECONFIG( _T("[root]\n")
321 _T("entry=value\n")
322 _T("[root/group1]\n")
323 _T("[root/group2]\n"),
324 fc );
325 }
326
327 void FileConfigTestCase::DeleteGroup()
328 {
329 wxStringInputStream sis(testconfig);
330 wxFileConfig fc(sis);
331
332 CPPUNIT_ASSERT( !fc.DeleteGroup(_T("foo")) );
333
334 CPPUNIT_ASSERT( fc.DeleteGroup(_T("root/group1")) );
335 wxVERIFY_FILECONFIG( _T("[root]\n")
336 _T("entry=value\n")
337 _T("[root/group2]\n"),
338 fc );
339
340 // notice trailing slash: it should be ignored
341 CPPUNIT_ASSERT( fc.DeleteGroup(_T("root/group2/")) );
342 wxVERIFY_FILECONFIG( _T("[root]\n")
343 _T("entry=value\n"),
344 fc );
345
346 CPPUNIT_ASSERT( fc.DeleteGroup(_T("root")) );
347 CPPUNIT_ASSERT( Dump(fc).empty() );
348 }
349
350 void FileConfigTestCase::DeleteAll()
351 {
352 wxStringInputStream sis(testconfig);
353 wxFileConfig fc(sis);
354
355 CPPUNIT_ASSERT( fc.DeleteAll() );
356 CPPUNIT_ASSERT( Dump(fc).empty() );
357 }
358
359 void FileConfigTestCase::RenameEntry()
360 {
361 wxStringInputStream sis(testconfig);
362 wxFileConfig fc(sis);
363
364 fc.SetPath(_T("root"));
365 CPPUNIT_ASSERT( fc.RenameEntry(_T("entry"), _T("newname")) );
366 wxVERIFY_FILECONFIG( _T("[root]\n")
367 _T("newname=value\n")
368 _T("[root/group1]\n")
369 _T("[root/group1/subgroup]\n")
370 _T("subentry=subvalue\n")
371 _T("subentry2=subvalue2\n")
372 _T("[root/group2]\n"),
373 fc );
374
375 fc.SetPath(_T("group1/subgroup"));
376 CPPUNIT_ASSERT( !fc.RenameEntry(_T("entry"), _T("newname")) );
377 CPPUNIT_ASSERT( !fc.RenameEntry(_T("subentry"), _T("subentry2")) );
378
379 CPPUNIT_ASSERT( fc.RenameEntry(_T("subentry"), _T("subentry1")) );
380 wxVERIFY_FILECONFIG( _T("[root]\n")
381 _T("newname=value\n")
382 _T("[root/group1]\n")
383 _T("[root/group1/subgroup]\n")
384 _T("subentry2=subvalue2\n")
385 _T("subentry1=subvalue\n")
386 _T("[root/group2]\n"),
387 fc );
388 }
389
390 void FileConfigTestCase::RenameGroup()
391 {
392 wxStringInputStream sis(testconfig);
393 wxFileConfig fc(sis);
394
395 CPPUNIT_ASSERT( fc.RenameGroup(_T("root"), _T("foot")) );
396 wxVERIFY_FILECONFIG( _T("[foot]\n")
397 _T("entry=value\n")
398 _T("[foot/group1]\n")
399 _T("[foot/group1/subgroup]\n")
400 _T("subentry=subvalue\n")
401 _T("subentry2=subvalue2\n")
402 _T("[foot/group2]\n"),
403 fc );
404
405 // renaming a path doesn't work, it must be the immediate group
406 CPPUNIT_ASSERT( !fc.RenameGroup(_T("foot/group1"), _T("group2")) );
407
408
409 fc.SetPath(_T("foot"));
410
411 // renaming to a name of existing group doesn't work
412 CPPUNIT_ASSERT( !fc.RenameGroup(_T("group1"), _T("group2")) );
413
414 // try exchanging the groups names and then restore them back
415 CPPUNIT_ASSERT( fc.RenameGroup(_T("group1"), _T("groupTmp")) );
416 wxVERIFY_FILECONFIG( _T("[foot]\n")
417 _T("entry=value\n")
418 _T("[foot/groupTmp]\n")
419 _T("[foot/groupTmp/subgroup]\n")
420 _T("subentry=subvalue\n")
421 _T("subentry2=subvalue2\n")
422 _T("[foot/group2]\n"),
423 fc );
424
425 CPPUNIT_ASSERT( fc.RenameGroup(_T("group2"), _T("group1")) );
426 wxVERIFY_FILECONFIG( _T("[foot]\n")
427 _T("entry=value\n")
428 _T("[foot/groupTmp]\n")
429 _T("[foot/groupTmp/subgroup]\n")
430 _T("subentry=subvalue\n")
431 _T("subentry2=subvalue2\n")
432 _T("[foot/group1]\n"),
433 fc );
434
435 CPPUNIT_ASSERT( fc.RenameGroup(_T("groupTmp"), _T("group2")) );
436 wxVERIFY_FILECONFIG( _T("[foot]\n")
437 _T("entry=value\n")
438 _T("[foot/group2]\n")
439 _T("[foot/group2/subgroup]\n")
440 _T("subentry=subvalue\n")
441 _T("subentry2=subvalue2\n")
442 _T("[foot/group1]\n"),
443 fc );
444
445 CPPUNIT_ASSERT( fc.RenameGroup(_T("group1"), _T("groupTmp")) );
446 wxVERIFY_FILECONFIG( _T("[foot]\n")
447 _T("entry=value\n")
448 _T("[foot/group2]\n")
449 _T("[foot/group2/subgroup]\n")
450 _T("subentry=subvalue\n")
451 _T("subentry2=subvalue2\n")
452 _T("[foot/groupTmp]\n"),
453 fc );
454
455 CPPUNIT_ASSERT( fc.RenameGroup(_T("group2"), _T("group1")) );
456 wxVERIFY_FILECONFIG( _T("[foot]\n")
457 _T("entry=value\n")
458 _T("[foot/group1]\n")
459 _T("[foot/group1/subgroup]\n")
460 _T("subentry=subvalue\n")
461 _T("subentry2=subvalue2\n")
462 _T("[foot/groupTmp]\n"),
463 fc );
464
465 CPPUNIT_ASSERT( fc.RenameGroup(_T("groupTmp"), _T("group2")) );
466 wxVERIFY_FILECONFIG( _T("[foot]\n")
467 _T("entry=value\n")
468 _T("[foot/group1]\n")
469 _T("[foot/group1/subgroup]\n")
470 _T("subentry=subvalue\n")
471 _T("subentry2=subvalue2\n")
472 _T("[foot/group2]\n"),
473 fc );
474 }
475
476 void FileConfigTestCase::CreateSubgroupAndEntries()
477 {
478 wxFileConfig fc;
479 fc.Write(_T("sub/sub_first"), _T("sub_one"));
480 fc.Write(_T("first"), _T("one"));
481
482 wxVERIFY_FILECONFIG( _T("first=one\n")
483 _T("[sub]\n")
484 _T("sub_first=sub_one\n"),
485 fc );
486 }
487
488 void FileConfigTestCase::CreateEntriesAndSubgroup()
489 {
490 wxFileConfig fc;
491 fc.Write(_T("first"), _T("one"));
492 fc.Write(_T("second"), _T("two"));
493 fc.Write(_T("sub/sub_first"), _T("sub_one"));
494
495 wxVERIFY_FILECONFIG( _T("first=one\n")
496 _T("second=two\n")
497 _T("[sub]\n")
498 _T("sub_first=sub_one\n"),
499 fc );
500 }
501
502 static void EmptyConfigAndWriteKey()
503 {
504 wxFileConfig fc(_T("deleteconftest"));
505
506 const wxString groupPath = _T("/root");
507
508 if ( fc.Exists(groupPath) )
509 {
510 // using DeleteGroup exposes the problem, using DeleteAll doesn't
511 CPPUNIT_ASSERT( fc.DeleteGroup(groupPath) );
512 }
513
514 // the config must be empty for the problem to arise
515 CPPUNIT_ASSERT( !fc.GetNumberOfEntries(true) );
516 CPPUNIT_ASSERT( !fc.GetNumberOfGroups(true) );
517
518
519 // this crashes on second call of this function
520 CPPUNIT_ASSERT( fc.Write(groupPath + _T("/entry"), _T("value")) );
521 }
522
523 void FileConfigTestCase::DeleteLastGroup()
524 {
525 /*
526 We make 2 of the same calls, first to create a file config with a single
527 group and key...
528 */
529 ::EmptyConfigAndWriteKey();
530
531 /*
532 ... then the same but this time the key's group is deleted before the
533 key is written again. This causes a crash.
534 */
535 ::EmptyConfigAndWriteKey();
536
537
538 // clean up
539 wxLogNull noLogging;
540 (void) ::wxRemoveFile(wxFileConfig::GetLocalFileName(_T("deleteconftest")));
541 }
542
543 void FileConfigTestCase::DeleteAndRecreateGroup()
544 {
545 static const wxChar *confInitial =
546 _T("[First]\n")
547 _T("Value1=Foo\n")
548 _T("[Second]\n")
549 _T("Value2=Bar\n");
550
551 wxStringInputStream sis(confInitial);
552 wxFileConfig fc(sis);
553
554 fc.DeleteGroup(_T("Second"));
555 wxVERIFY_FILECONFIG( _T("[First]\n")
556 _T("Value1=Foo\n"),
557 fc );
558
559 fc.Write(_T("Second/Value2"), _T("New"));
560 wxVERIFY_FILECONFIG( _T("[First]\n")
561 _T("Value1=Foo\n")
562 _T("[Second]\n")
563 _T("Value2=New\n"),
564 fc );
565 }
566
567 #endif // wxUSE_FILECONFIG
568