Fix several warnings that appear in gcc 4.3.2.
[wvstreams.git] / uniconf / t / uniinigen.t.cc
blobe546a390f50c1d3b2877822a5e86c75cfcb2286d
1 #include "uniinigen.h"
2 #include "wvfile.h"
3 #include "wvfileutils.h"
4 #include "uniconfroot.h"
5 #ifdef _WIN32
6 #include <sys/stat.h>
7 #endif
8 #include "uniwatch.h"
9 #include "wvsystem.h"
10 #include "wvtest.h"
11 #include "uniconfgen-sanitytest.h"
13 #ifdef _WIN32
14 static inline int mkdir(const char *x, int y) { return mkdir(x); }
15 #endif
17 // Returns the filename where the content was written. This file must be
18 // deleted when no longer needed. Returns WvString::null if unable to create
19 // the file.
20 WvString inigen(WvStringParm content)
22 WvString ininame = wvtmpfilename("inigen_test.ini");
23 WvFile file;
24 WVPASS(file.open(ininame, O_CREAT|O_RDWR));
25 file.write(content);
26 WVPASS(file.isok());
28 return ininame;
31 static int childcount(UniConf cfg)
33 int count = 0;
34 UniConf::Iter i(cfg);
35 for (i.rewind(); i.next(); )
36 count++;
37 return count;
41 WVTEST_MAIN("UniIniGen Sanity Test")
43 WvString inifile("/tmp/inigen-test-%s.ini", getpid());
44 UniIniGen *gen = new UniIniGen(inifile);
45 UniConfGenSanityTester::sanity_test(gen, WvString("ini:%s", inifile));
46 WVRELEASE(gen);
47 unlink(inifile);
50 WVTEST_MAIN("commit-without-refresh")
53 UniConfRoot cfg("ini:/dev/does-not-exist");
54 cfg.commit();
55 cfg.refresh();
56 cfg.commit();
57 WVFAIL(cfg.haschildren());
60 #ifndef _WIN32
61 WVTEST_MAIN("ini file permissions")
63 system("rm -f perm.ini");
64 system("touch perm.ini");
65 UniConfRoot cfg("ini:perm.ini");
66 cfg["foo"].setme("bar");
67 mode_t oldmask = umask(02);
68 cfg.commit();
69 umask(oldmask);
71 struct stat statbuf;
72 WVPASS(stat("perm.ini", &statbuf) == 0);
73 WVPASSEQ(statbuf.st_mode, 0100664); //file and permissions 0664
75 system("rm -f perm.ini");
77 #endif
79 WVTEST_MAIN("parsing1")
81 WvString ininame = inigen("[S1]\n"
82 "a = b\n"
83 "[{S2}] \n"
84 "c=d \n"
85 "[{S\n3}]\n"
86 "e=f\n");
87 UniConfRoot cfg(WvString("ini:%s", ininame));
89 WVPASSEQ(cfg["S1/a"].getme(), "b");
90 WVPASSEQ(cfg["S2/c"].getme(), "d");
91 WVPASSEQ(cfg["S\n3/e"].getme(), "f");
92 WVPASSEQ(childcount(cfg), 3);
94 ::unlink(ininame);
98 WVTEST_MAIN("parsing2")
100 WvString ininame = inigen("[x]\n"
101 "[]\n"
102 " a = b c \n"
103 " { a\n b} {c } = { a\n b2} {c }\n"
104 "apenwarr = {OBFU}scation!");
105 UniConfRoot cfg(WvString("ini:%s", ininame));
107 WVPASSEQ(cfg["a"].getme(), "b c");
108 WVPASSEQ(cfg[" a\n b} {c "].getme(), " a\n b2} {c ");
109 WVPASSEQ(cfg["apenwarr"].getme(), "{OBFU}scation!");
111 ::unlink(ininame);
115 WVTEST_MAIN("parsing3")
117 WvString ininame = inigen("/ = foo\n");
118 UniConfRoot cfg(WvString("ini:%s", ininame));
119 WVPASSEQ(cfg.getme(), "foo");
120 WVFAIL(cfg.haschildren());
122 ::unlink(ininame);
126 WVTEST_MAIN("parsing4")
128 // first line should be dropped to try to recover, since the entire
129 // file is invalid tcl-encoding.
130 WvString ininame = inigen("{ broken\n/ = boo\n");
131 UniConfRoot cfg(WvString("ini:%s", ininame));
132 WVPASSEQ(cfg.getme(), "boo");
133 WVFAIL(cfg.haschildren());
137 WVTEST_MAIN("Setting and getting (bug 6090)")
139 WvString ininame = inigen("");
140 UniConfRoot cfg(WvString("ini:%s", ininame));
142 cfg["mrwise"].setme("{{bork!");
143 cfg.commit();
144 WVPASSEQ(cfg["mrwise"].getme(), "{{bork!");
146 UniConfRoot cfg2(WvString("ini:%s", ininame));
147 WVPASSEQ(cfg2["mrwise"].getme(), "{{bork!");
149 ::unlink(ininame);
152 // This is probably covered by sanity tests now. OTOH, more tests is more
153 // better.
154 WVTEST_MAIN("Trailing slashes")
156 UniConfRoot cfg("ini:tmp.ini");
158 cfg["sfllaw"].setme("law");
159 WVPASSEQ(cfg["sfllaw"].getme(), "law");
160 WVPASSEQ(cfg["sfllaw/"].getme(), "");
162 cfg["sfllaw/"].setme("LAW");
163 WVPASSEQ(cfg["sfllaw"].getme(), "law");
164 WVPASSEQ(cfg["sfllaw/"].getme(), "");
167 static void count_cb(int *i, const UniConf &cfg, const UniConfKey &key)
169 (*i)++;
173 WVTEST_MAIN("ini callbacks")
175 int i = 0;
176 WvString ininame = inigen("a/b/c/1 = 11\n"
177 "a/b/c/2 = 22\n");
178 UniConfRoot cfg(WvString("ini:%s", ininame));
179 UniWatch w(cfg, wv::bind(&count_cb, &i, _1, _2), true);
181 WVPASSEQ(i, 0);
182 cfg.refresh();
183 WVPASSEQ(i, 0);
186 WvFile f(ininame, O_WRONLY|O_TRUNC);
187 f.print("a/b/c/1 = 111\n"
188 "a/b/c/2 = 222\n");
189 cfg.refresh();
190 WVPASSEQ(i, 2);
192 f.print("a/b/c/3 = 333\n");
193 cfg.refresh();
194 WVPASSEQ(i, 3);
196 f.print("\n");
197 cfg.refresh();
198 WVPASSEQ(i, 3);
201 cfg.xset("x", "y");
202 WVPASSEQ(i, 4);
203 cfg.commit();
204 WVPASSEQ(i, 4);
205 cfg.refresh();
206 WVPASSEQ(i, 4);
208 ::unlink(ininame);
212 static void inicmp(WvStringParm key, WvStringParm val, WvStringParm content)
214 WvString ininame = inigen("");
215 UniConfRoot cfg(WvString("ini:%s", ininame));
216 cfg[key].setme(val);
217 cfg.commit();
219 WvFile f(ininame, O_RDONLY);
220 WvDynBuf buf;
221 f.read(buf, 128*1024);
222 WVPASSEQ(content, buf.getstr());
223 ::unlink(ininame);
227 WVTEST_MAIN("writing")
229 inicmp("/", "test",
230 "/ = test\n");
232 inicmp("x/y", "z",
233 "\n[x]\ny = z\n");
235 inicmp("x/y/z", "abc",
236 "\n[x]\ny/z = abc\n");
238 inicmp("x\n/y/z", "abc",
239 "\n[{x\n}]\ny/z = abc\n");
241 inicmp("/users/apenwarr", "{OBFU}scation!",
242 "\n[users]\napenwarr = {OBFU}scation!\n");
244 inicmp("/users/ apenwarr", "pbc ",
245 "\n[users]\n{ apenwarr} = {pbc }\n");
247 // FIXME: empty-string keys probably *should* be printed, but we don't,
248 // for compatibility with WvConf. This test makes sure it stays that
249 // way (until we think of something better?)
250 inicmp("/foo/blah", "",
251 "");
255 static ino_t inode_of(const char *fname)
257 struct stat st;
258 if (stat(fname, &st) != 0)
259 return 0;
260 else
261 return st.st_ino;
265 static off_t size_of(const char *fname)
267 struct stat st;
268 if (stat(fname, &st) != 0)
269 return 0;
270 else
271 return st.st_size;
275 WVTEST_MAIN("atomic updates")
277 WvString dirname("atomic-update-dir.tmp"), fname("%s/test.ini", dirname);
278 chmod(dirname, 0700);
279 rm_rf(dirname);
280 WVPASS(!mkdir(dirname, 0700)); // honours umask
281 WVPASS(!chmod(dirname, 0700)); // doesn't include umask
283 // the directory is writable, so we can safely do atomic file replacement.
284 // That means the file inode number will be *different* after doing
285 // a second commit().
286 UniConfRoot ini(WvString("ini:%s", fname));
287 ini.xset("useless key", "useless value");
288 ini.commit();
289 ino_t inode1 = inode_of(fname);
290 off_t size1 = size_of(fname);
291 WVFAILEQ(inode1, 0);
292 WVFAILEQ(size1, 0);
293 ini.xset("1", "2");
294 ini.commit();
295 ino_t inode2 = inode_of(fname);
296 off_t size2 = size_of(fname);
297 WVFAILEQ(inode2, 0);
298 WVFAILEQ(inode1, inode2);
299 WVPASS(size2 > size1);
301 // now let's make the directory non-writable. The inifile inside the
302 // directory is still writable, which means we can update it, but not
303 // atomically. Therefore its inode number *won't* change.
304 WVPASS(!chmod(dirname, 0500));
305 ini.xset("3", "4");
306 ini.commit();
307 ino_t inode3 = inode_of(fname);
308 off_t size3 = size_of(fname);
309 WVFAILEQ(inode3, 0);
310 WVPASSEQ(inode2, inode3);
311 WVPASS(size3 > size2);
313 // clean up
314 chmod(dirname, 0700);
315 rm_rf(dirname);
319 WVTEST_MAIN("do not refresh if not requested")
321 WvString ininame = inigen("[foo]\n"
322 "bar = baz\n");
323 UniConfRoot cfg(WvString("ini:%s", ininame), false);
325 WVFAIL(cfg["foo/bar"].exists());
326 WVFAILEQ(cfg["foo/bar"].getme(), "baz");
327 WVPASSEQ(childcount(cfg), 0);
329 ::unlink(ininame);