blob: f524a21e06b7ac660be36ff5812dbb11cd2b0995 [file] [log] [blame]
Brian Silverman70325d62015-09-20 17:00:43 -04001// Copyright (c) 2005, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: csilvers@google.com (Craig Silverstein)
32//
33// This code is written to not use the google testing framework
34// as much as possible, to make it easier to opensource.
35
36#include "config_for_unittests.h"
37#include <stdio.h>
38#include <string.h>
39#include <assert.h>
40#include <vector>
41#include "base/arena.h"
42#include <ctemplate/template_dictionary.h>
43#include <ctemplate/template_modifiers.h>
44#include <ctemplate/per_expand_data.h>
45#include "tests/template_test_util.h"
46#include "base/util.h"
47TEST_INIT // defines RUN_ALL_TESTS
48
49using std::string;
50using std::vector;
51using GOOGLE_NAMESPACE::UnsafeArena;
52using GOOGLE_NAMESPACE::DO_NOT_STRIP;
53using GOOGLE_NAMESPACE::ExpandEmitter;
54using GOOGLE_NAMESPACE::PerExpandData;
55using GOOGLE_NAMESPACE::StaticTemplateString;
56using GOOGLE_NAMESPACE::StringToTemplateCache;
57using GOOGLE_NAMESPACE::TemplateDictionary;
58using GOOGLE_NAMESPACE::TemplateDictionaryInterface;
59using GOOGLE_NAMESPACE::TemplateDictionaryPeer;
60using GOOGLE_NAMESPACE::TemplateString;
61
62#define ASSERT_STRSTR(text, substr) do { \
63 if (!strstr((text), (substr))) { \
64 printf("%s: %d: ASSERT FAILED: '%s' not in '%s'\n", \
65 __FILE__, __LINE__, (substr), (text)); \
66 assert(strstr((text), (substr))); \
67 exit(1); \
68 } \
69} while (0)
70
71
72// test escape-functor that replaces all input with "foo"
73class FooEscaper : public GOOGLE_NAMESPACE::TemplateModifier {
74 public:
75 void Modify(const char* in, size_t inlen,
76 const PerExpandData*,
77 ExpandEmitter* outbuf, const string& arg) const {
78 assert(arg.empty()); // we don't take an argument
79 outbuf->Emit("foo");
80 }
81};
82
83// test escape-functor that replaces all input with ""
84class NullEscaper : public GOOGLE_NAMESPACE::TemplateModifier {
85 public:
86 void Modify(const char* in, size_t inlen,
87 const PerExpandData*,
88 ExpandEmitter* outbuf, const string& arg) const {
89 assert(arg.empty()); // we don't take an argument
90 }
91};
92
93// first does javascript-escaping, then html-escaping
94class DoubleEscaper : public GOOGLE_NAMESPACE::TemplateModifier {
95 public:
96 void Modify(const char* in, size_t inlen,
97 const PerExpandData* data,
98 ExpandEmitter* outbuf, const string& arg) const {
99 assert(arg.empty()); // we don't take an argument
100 string tmp = GOOGLE_NAMESPACE::javascript_escape(in, inlen);
101 GOOGLE_NAMESPACE::html_escape.Modify(tmp.data(), tmp.size(), data, outbuf, "");
102 }
103};
104
105namespace {
106
107static const TemplateDictionary* GetSectionDict(
108 const TemplateDictionary* d, const char* name, int i) {
109 TemplateDictionaryPeer peer(d);
110 vector<const TemplateDictionary*> dicts;
111 EXPECT_GE(peer.GetSectionDictionaries(name, &dicts), i);
112 return dicts[i];
113}
114static const TemplateDictionary* GetIncludeDict(
115 const TemplateDictionary* d, const char* name, int i) {
116 TemplateDictionaryPeer peer(d);
117 vector<const TemplateDictionary*> dicts;
118 EXPECT_GE(peer.GetIncludeDictionaries(name, &dicts), i);
119 return dicts[i];
120}
121
122static void SetUp() {
123 TemplateDictionary::SetGlobalValue("GLOBAL", "top");
124}
125
126TEST(TemplateDictionary, SetValueAndTemplateStringAndArena) {
127 // Try both with the arena, and without.
128 UnsafeArena arena(100);
129 // We run the test with arena twice to double-check we don't ever delete it
130 UnsafeArena* arenas[] = {&arena, &arena, NULL};
131 for (int i = 0; i < sizeof(arenas)/sizeof(*arenas); ++i) {
132 TemplateDictionary dict(string("test_arena") + char('0'+i), arenas[i]);
133
134 // Test copying char*s, strings, and explicit TemplateStrings
135 dict.SetValue("FOO", "foo");
136 dict.SetValue(string("FOO2"), TemplateString("foo2andmore", 4));
137 dict["FOO3"] = "foo3";
138 dict[string("FOO4")] = TemplateString("foo4andmore", 4);
139 dict["FOO5"] = string("Olaf");
140 dict["FOO6"] = 6;
141 dict["FOO7"] = long(7);
142
143 TemplateDictionaryPeer peer(&dict);
144 // verify what happened
145 EXPECT_TRUE(peer.ValueIs("FOO", "foo"));
146 EXPECT_TRUE(peer.ValueIs("FOO2", "foo2"));
147 string dump;
148 dict.DumpToString(&dump);
149 char expected[256];
150 snprintf(expected, sizeof(expected),
151 ("global dictionary {\n"
152 " BI_NEWLINE: >\n"
153 "<\n"
154 " BI_SPACE: > <\n"
155 " GLOBAL: >top<\n"
156 "};\n"
157 "dictionary 'test_arena%d' {\n"
158 " FOO: >foo<\n"
159 " FOO2: >foo2<\n"
160 " FOO3: >foo3<\n"
161 " FOO4: >foo4<\n"
162 " FOO5: >Olaf<\n"
163 " FOO6: >6<\n"
164 " FOO7: >7<\n"
165 "}\n"), i);
166 EXPECT_STREQ(dump.c_str(), expected);
167 }
168}
169
170TEST(TemplateDictionary, SetValueWithoutCopy) {
171 UnsafeArena arena(100);
172 TemplateDictionary dict("Test arena", &arena);
173
174 char value[32];
175 snprintf(value, sizeof(value), "%s", "value");
176
177 const void* const ptr = arena.Alloc(0);
178 dict.SetValueWithoutCopy("key", value);
179 // We shouldn't have copied the value string.
180 EXPECT_EQ(ptr, arena.Alloc(0));
181
182 TemplateDictionaryPeer peer(&dict);
183 EXPECT_TRUE(peer.ValueIs("key", "value"));
184 // If our content changes, so does what's in the dictionary -- but
185 // only the contents of the buffer, not its length!
186 snprintf(value, sizeof(value), "%s", "not_value");
187 EXPECT_TRUE(peer.ValueIs("key", "not_v")); // sizeof("not_v") == sizeof("value")
188}
189
190TEST(TemplateDictionary, SetIntValue) {
191 TemplateDictionary dict("test_SetIntValue", NULL);
192 TemplateDictionaryPeer peer(&dict);
193
194 dict.SetIntValue("INT", 5);
195 // - is an illegal varname in templates, but perfectly fine in dicts
196 dict.SetIntValue("-INT", -5);
197
198 EXPECT_TRUE(peer.ValueIs("INT", "5"));
199 EXPECT_TRUE(peer.ValueIs("-INT", "-5"));
200 string dump;
201 dict.DumpToString(&dump);
202 ASSERT_STRSTR(dump.c_str(), "\n INT: >5<\n");
203 ASSERT_STRSTR(dump.c_str(), "\n -INT: >-5<\n");
204
205}
206
207TEST(TemplateDictionary, SetFormattedValue) {
208 TemplateDictionary dict("test_SetFormattedValue", NULL);
209 TemplateDictionaryPeer peer(&dict);
210
211 dict.SetFormattedValue(TemplateString("PRINTF", sizeof("PRINTF")-1),
212 "%s test %04d", "template test", 1);
213
214 EXPECT_TRUE(peer.ValueIs("PRINTF", "template test test 0001"));
215 string dump;
216 dict.DumpToString(&dump);
217 ASSERT_STRSTR(dump.c_str(), "\n PRINTF: >template test test 0001<\n");
218
219 // Now test something of size 4k or so, where we can't use scratchbuf
220 dict.SetFormattedValue(TemplateString("PRINTF", sizeof("PRINTF")-1),
221 "%s test %04444d", "template test", 2);
222 string expected("template test test ");
223 for (int i = 0; i < 4443; ++i)
224 expected.append("0");
225 expected.append("2");
226 EXPECT_TRUE(peer.ValueIs("PRINTF", expected));
227 string dump2;
228 dict.DumpToString(&dump2);
229 expected = string("\n PRINTF: >") + expected + string("<\n");
230 ASSERT_STRSTR(dump2.c_str(), expected.c_str());
231}
232
233TEST(TemplateDictionary, SetEscapedValue) {
234 TemplateDictionary dict("test_SetEscapedValue", NULL);
235 TemplateDictionaryPeer peer(&dict);
236
237 dict.SetEscapedValue("hardest HTML",
238 "<A HREF='foo'\nid=\"bar\t\t&&\vbaz\">",
239 GOOGLE_NAMESPACE::html_escape);
240 dict.SetEscapedValue("hardest JS",
241 ("f = 'foo';\r\n\tprint \"\\&foo = \b\", \"foo\""),
242 GOOGLE_NAMESPACE::javascript_escape);
243 dict.SetEscapedValue("query escape 0", "",
244 GOOGLE_NAMESPACE::url_query_escape);
245
246 EXPECT_TRUE(peer.ValueIs("hardest HTML",
247 "&lt;A HREF=&#39;foo&#39; id=&quot;bar &amp;&amp; "
248 "baz&quot;&gt;"));
249 EXPECT_TRUE(peer.ValueIs("hardest JS",
250 "f \\x3d \\x27foo\\x27;\\r\\n\\tprint \\x22\\\\\\x26"
251 "foo \\x3d \\b\\x22, \\x22foo\\x22"));
252 EXPECT_TRUE(peer.ValueIs("query escape 0", ""));
253
254 // Test using hand-made modifiers.
255 FooEscaper foo_escaper;
256 dict.SetEscapedValue("easy foo", "hello there!",
257 FooEscaper());
258 dict.SetEscapedValue("harder foo", "so much to say\nso many foos",
259 foo_escaper);
260 DoubleEscaper double_escaper;
261 dict.SetEscapedValue("easy double", "doo",
262 double_escaper);
263 dict.SetEscapedValue("harder double", "<A HREF='foo'>\n",
264 DoubleEscaper());
265 dict.SetEscapedValue("hardest double",
266 "print \"<A HREF='foo'>\";\r\n\\1;",
267 double_escaper);
268
269 EXPECT_TRUE(peer.ValueIs("easy foo", "foo"));
270 EXPECT_TRUE(peer.ValueIs("harder foo", "foo"));
271 EXPECT_TRUE(peer.ValueIs("easy double", "doo"));
272 EXPECT_TRUE(peer.ValueIs("harder double",
273 "\\x3cA HREF\\x3d\\x27foo\\x27\\x3e\\n"));
274 EXPECT_TRUE(peer.ValueIs("hardest double",
275 "print \\x22\\x3cA HREF\\x3d\\x27foo\\x27\\x3e\\x22;"
276 "\\r\\n\\\\1;"));
277}
278
279TEST(TemplateDictionary, SetEscapedFormattedValue) {
280 TemplateDictionary dict("test_SetEscapedFormattedValue", NULL);
281 TemplateDictionaryPeer peer(&dict);
282
283 dict.SetEscapedFormattedValue("HTML", GOOGLE_NAMESPACE::html_escape,
284 "This is <%s> #%.4f", "a & b", 1.0/3);
285 dict.SetEscapedFormattedValue("PRE", GOOGLE_NAMESPACE::pre_escape,
286 "if %s x = %.4f;", "(a < 1 && b > 2)\n\t", 1.0/3);
287 dict.SetEscapedFormattedValue("URL", GOOGLE_NAMESPACE::url_query_escape,
288 "pageviews-%s", "r?egex");
289 dict.SetEscapedFormattedValue("XML", GOOGLE_NAMESPACE::xml_escape,
290 "This&is%s -- ok?", "just&");
291
292 EXPECT_TRUE(peer.ValueIs("HTML",
293 "This is &lt;a &amp; b&gt; #0.3333"));
294 EXPECT_TRUE(peer.ValueIs("PRE",
295 "if (a &lt; 1 &amp;&amp; b &gt; 2)\n\t x = 0.3333;"));
296 EXPECT_TRUE(peer.ValueIs("URL", "pageviews-r%3Fegex"));
297
298 EXPECT_TRUE(peer.ValueIs("XML", "This&amp;isjust&amp; -- ok?"));
299}
300
301static const StaticTemplateString kSectName =
302 STS_INIT(kSectName, "test_SetAddSectionDictionary");
303
304TEST(TemplateDictionary, AddSectionDictionary) {
305 // For fun, we'll make this constructor take a static template string.
306 TemplateDictionary dict(kSectName, NULL);
307 TemplateDictionaryPeer peer(&dict);
308 dict.SetValue("TOPLEVEL", "foo");
309 dict.SetValue("TOPLEVEL2", "foo2");
310
311 TemplateDictionary* subdict_1a = dict.AddSectionDictionary("section1");
312 // This is the same dict, but name is specified a different way.
313 TemplateDictionary* subdict_1b = dict.AddSectionDictionary(
314 TemplateString("section1__ignored__", strlen("section1")));
315 TemplateDictionaryPeer subdict_1a_peer(subdict_1a);
316 TemplateDictionaryPeer subdict_1b_peer(subdict_1b);
317 subdict_1a->SetValue("SUBLEVEL", "subfoo");
318 subdict_1b->SetValue("SUBLEVEL", "subbar");
319
320 TemplateDictionary* subdict_2 = dict.AddSectionDictionary("section2");
321 TemplateDictionaryPeer subdict_2_peer(subdict_2);
322 subdict_2->SetValue("TOPLEVEL", "bar"); // overriding top dict
323 TemplateDictionary* subdict_2_1 = subdict_2->AddSectionDictionary("sub");
324 TemplateDictionaryPeer subdict_2_1_peer(subdict_2_1);
325 subdict_2_1->SetIntValue("GLOBAL", 21); // overrides value in setUp()
326
327 // Verify that all variables that should be look-up-able are, and that
328 // we have proper precedence.
329 EXPECT_TRUE(peer.ValueIs("GLOBAL", "top"));
330 EXPECT_TRUE(peer.ValueIs("TOPLEVEL", "foo"));
331 EXPECT_TRUE(peer.ValueIs("TOPLEVEL2", "foo2"));
332 EXPECT_TRUE(peer.ValueIs("SUBLEVEL", ""));
333
334 EXPECT_TRUE(subdict_1a_peer.ValueIs("GLOBAL", "top"));
335 EXPECT_TRUE(subdict_1a_peer.ValueIs("TOPLEVEL", "foo"));
336 EXPECT_TRUE(subdict_1a_peer.ValueIs("TOPLEVEL2", "foo2"));
337 EXPECT_TRUE(subdict_1a_peer.ValueIs("SUBLEVEL", "subfoo"));
338
339 EXPECT_TRUE(subdict_1b_peer.ValueIs("GLOBAL", "top"));
340 EXPECT_TRUE(subdict_1b_peer.ValueIs("TOPLEVEL", "foo"));
341 EXPECT_TRUE(subdict_1b_peer.ValueIs("TOPLEVEL2", "foo2"));
342 EXPECT_TRUE(subdict_1b_peer.ValueIs("SUBLEVEL", "subbar"));
343
344 EXPECT_TRUE(subdict_2_peer.ValueIs("GLOBAL", "top"));
345 EXPECT_TRUE(subdict_2_peer.ValueIs("TOPLEVEL", "bar"));
346 EXPECT_TRUE(subdict_2_peer.ValueIs("TOPLEVEL2", "foo2"));
347 EXPECT_TRUE(subdict_2_peer.ValueIs("SUBLEVEL", ""));
348
349 EXPECT_TRUE(subdict_2_1_peer.ValueIs("GLOBAL", "21"));
350 EXPECT_TRUE(subdict_2_1_peer.ValueIs("TOPLEVEL", "bar"));
351 EXPECT_TRUE(subdict_2_1_peer.ValueIs("TOPLEVEL2", "foo2"));
352 EXPECT_TRUE(subdict_2_1_peer.ValueIs("SUBLEVEL", ""));
353
354 // Verify that everyone knows about its sub-dictionaries, and also
355 // that these go 'up the chain' on lookup failure
356 EXPECT_FALSE(peer.IsHiddenSection("section1"));
357 EXPECT_FALSE(peer.IsHiddenSection("section2"));
358 EXPECT_TRUE(peer.IsHiddenSection("section3"));
359 EXPECT_TRUE(peer.IsHiddenSection("sub"));
360 EXPECT_FALSE(subdict_1a_peer.IsHiddenSection("section1"));
361 EXPECT_TRUE(subdict_1a_peer.IsHiddenSection("sub"));
362 EXPECT_FALSE(subdict_2_peer.IsHiddenSection("sub"));
363 EXPECT_FALSE(subdict_2_1_peer.IsHiddenSection("sub"));
364
365 // We should get the dictionary-lengths right as well
366 vector<const TemplateDictionary*> dummy;
367 EXPECT_EQ(2, peer.GetSectionDictionaries("section1", &dummy));
368 EXPECT_EQ(1, peer.GetSectionDictionaries("section2", &dummy));
369 EXPECT_EQ(1, subdict_2_peer.GetSectionDictionaries("sub", &dummy));
370 // Test some of the values
371 EXPECT_TRUE(TemplateDictionaryPeer(GetSectionDict(&dict, "section1", 0))
372 .ValueIs("SUBLEVEL", "subfoo"));
373 EXPECT_TRUE(TemplateDictionaryPeer(GetSectionDict(&dict, "section1", 1))
374 .ValueIs("SUBLEVEL", "subbar"));
375 EXPECT_TRUE(TemplateDictionaryPeer(GetSectionDict(&dict, "section2", 0))
376 .ValueIs("TOPLEVEL", "bar"));
377 EXPECT_TRUE(TemplateDictionaryPeer(
378 GetSectionDict(GetSectionDict(&dict, "section2", 0), "sub", 0))
379 .ValueIs("TOPLEVEL", "bar"));
380 EXPECT_TRUE(TemplateDictionaryPeer(
381 GetSectionDict(GetSectionDict(&dict, "section2", 0), "sub", 0))
382 .ValueIs("GLOBAL", "21"));
383
384 // Make sure we're making descriptive names
385 EXPECT_STREQ(dict.name().c_str(),
386 "test_SetAddSectionDictionary");
387 EXPECT_STREQ(subdict_1a->name().c_str(),
388 "test_SetAddSectionDictionary/section1#1");
389 EXPECT_STREQ(subdict_1b->name().c_str(),
390 "test_SetAddSectionDictionary/section1#2");
391 EXPECT_STREQ(subdict_2->name().c_str(),
392 "test_SetAddSectionDictionary/section2#1");
393 EXPECT_STREQ(subdict_2_1->name().c_str(),
394 "test_SetAddSectionDictionary/section2#1/sub#1");
395
396 // Finally, we can test the whole kit and kaboodle
397 string dump;
398 dict.DumpToString(&dump);
399 const char* const expected =
400 ("global dictionary {\n"
401 " BI_NEWLINE: >\n"
402 "<\n"
403 " BI_SPACE: > <\n"
404 " GLOBAL: >top<\n"
405 "};\n"
406 "dictionary 'test_SetAddSectionDictionary' {\n"
407 " TOPLEVEL: >foo<\n"
408 " TOPLEVEL2: >foo2<\n"
409 " section section1 (dict 1 of 2) -->\n"
410 " dictionary 'test_SetAddSectionDictionary/section1#1' {\n"
411 " SUBLEVEL: >subfoo<\n"
412 " }\n"
413 " section section1 (dict 2 of 2) -->\n"
414 " dictionary 'test_SetAddSectionDictionary/section1#2' {\n"
415 " SUBLEVEL: >subbar<\n"
416 " }\n"
417 " section section2 (dict 1 of 1) -->\n"
418 " dictionary 'test_SetAddSectionDictionary/section2#1' {\n"
419 " TOPLEVEL: >bar<\n"
420 " section sub (dict 1 of 1) -->\n"
421 " dictionary 'test_SetAddSectionDictionary/section2#1/sub#1' {\n"
422 " GLOBAL: >21<\n"
423 " }\n"
424 " }\n"
425 "}\n");
426 EXPECT_STREQ(dump.c_str(), expected);
427}
428
429TEST(TemplateDictionary, ShowSection) {
430 TemplateDictionary dict("test_SetShowSection", NULL);
431 // Let's say what filename dict is associated with
432 dict.SetFilename("bigmamainclude!.tpl");
433 dict.SetValue("TOPLEVEL", "foo");
434 dict.SetValue("TOPLEVEL2", "foo2");
435 dict.ShowSection("section1");
436 dict.ShowSection("section2");
437 // Test calling ShowSection twice on the same section
438 dict.ShowSection("section2");
439 // Test that ShowSection is a no-op if called after AddSectionDictionary()
440 TemplateDictionary* subdict = dict.AddSectionDictionary("section3");
441 TemplateDictionaryPeer subdict_peer(subdict);
442 subdict->SetValue("TOPLEVEL", "bar");
443 dict.ShowSection("section3");
444
445 EXPECT_TRUE(subdict_peer.ValueIs("TOPLEVEL", "bar"));
446
447 // Since ShowSection() doesn't return a sub-dict, the only way to
448 // probe what the dicts look like is via Dump()
449 string dump;
450 dict.DumpToString(&dump);
451 const char* const expected =
452 ("global dictionary {\n"
453 " BI_NEWLINE: >\n"
454 "<\n"
455 " BI_SPACE: > <\n"
456 " GLOBAL: >top<\n"
457 "};\n"
458 "dictionary 'test_SetShowSection (intended for bigmamainclude!.tpl)' {\n"
459 " TOPLEVEL: >foo<\n"
460 " TOPLEVEL2: >foo2<\n"
461 " section section1 (dict 1 of 1) -->\n"
462 " dictionary 'empty dictionary' {\n"
463 " }\n"
464 " section section2 (dict 1 of 1) -->\n"
465 " dictionary 'empty dictionary' {\n"
466 " }\n"
467 " section section3 (dict 1 of 1) -->\n"
468 " dictionary 'test_SetShowSection/section3#1' {\n"
469 " TOPLEVEL: >bar<\n"
470 " }\n"
471 "}\n");
472 EXPECT_STREQ(dump.c_str(), expected);
473}
474
475TEST(TemplateDictionary, SetValueAndShowSection) {
476 TemplateDictionary dict("test_SetValueAndShowSection");
477 TemplateDictionaryPeer peer(&dict);
478 dict.SetValue("TOPLEVEL", "foo");
479
480 dict.SetValueAndShowSection("INSEC", "bar", "SEC1");
481 dict.SetValueAndShowSection("NOTINSEC", "", "SEC2");
482 dict.SetValueAndShowSection("NOTINSEC2", NULL, "SEC3");
483
484 EXPECT_FALSE(peer.IsHiddenSection("SEC1"));
485 EXPECT_TRUE(peer.IsHiddenSection("SEC2"));
486 EXPECT_TRUE(peer.IsHiddenSection("SEC3"));
487
488 // Again, we don't get subdicts, so we have to dump to check values
489 string dump;
490 dict.DumpToString(&dump);
491 const char* const expected =
492 ("global dictionary {\n"
493 " BI_NEWLINE: >\n"
494 "<\n"
495 " BI_SPACE: > <\n"
496 " GLOBAL: >top<\n"
497 "};\n"
498 "dictionary 'test_SetValueAndShowSection' {\n"
499 " TOPLEVEL: >foo<\n"
500 " section SEC1 (dict 1 of 1) -->\n"
501 " dictionary 'test_SetValueAndShowSection/SEC1#1' {\n"
502 " INSEC: >bar<\n"
503 " }\n"
504 "}\n");
505 EXPECT_STREQ(dump.c_str(), expected);
506}
507
508TEST(TemplateDictionary, SetTemplateGlobalValue) {
509 // The functionality involving it passing across the included dictionaries
510 // is also tested in TestAddIncludeDictionary
511 TemplateDictionary dict("test_SetTemplateGlobalValue", NULL);
512 TemplateDictionary* subdict = dict.AddSectionDictionary("section1");
513 TemplateDictionary* subsubdict =
514 subdict->AddSectionDictionary("section1's child");
515 TemplateDictionary* includedict = dict.AddIncludeDictionary("include1");
516
517 TemplateDictionaryPeer peer(&dict);
518 TemplateDictionaryPeer subdict_peer(subdict);
519 TemplateDictionaryPeer subsubdict_peer(subsubdict);
520 TemplateDictionaryPeer includedict_peer(includedict);
521
522 // Setting a template value after sub dictionaries are created should
523 // affect the sub dictionaries as well.
524 dict.SetTemplateGlobalValue("TEMPLATEVAL", "templateval");
525 EXPECT_TRUE(peer.ValueIs("TEMPLATEVAL", "templateval"));
526 EXPECT_TRUE(subdict_peer.ValueIs("TEMPLATEVAL", "templateval"));
527 EXPECT_TRUE(subsubdict_peer.ValueIs("TEMPLATEVAL", "templateval"));
528 EXPECT_TRUE(includedict_peer.ValueIs("TEMPLATEVAL", "templateval"));
529
530 // sub dictionaries after you set the template value should also
531 // get the template value
532 TemplateDictionary* subdict2 = dict.AddSectionDictionary("section2");
533 TemplateDictionary* includedict2 = dict.AddIncludeDictionary("include2");
534 TemplateDictionaryPeer subdict2_peer(subdict2);
535 TemplateDictionaryPeer includedict2_peer(includedict2);
536
537 EXPECT_TRUE(subdict2_peer.ValueIs("TEMPLATEVAL", "templateval"));
538 EXPECT_TRUE(includedict2_peer.ValueIs("TEMPLATEVAL", "templateval"));
539
540 // setting a template value on a sub dictionary should affect all the other
541 // sub dictionaries and the parent as well
542 subdict->SetTemplateGlobalValue("TEMPLATEVAL2", "templateval2");
543 EXPECT_TRUE(peer.ValueIs("TEMPLATEVAL2", "templateval2"));
544 EXPECT_TRUE(subdict_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
545 EXPECT_TRUE(subsubdict_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
546 EXPECT_TRUE(includedict_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
547 EXPECT_TRUE(subdict2_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
548 EXPECT_TRUE(includedict2_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
549
550 includedict->SetTemplateGlobalValue("TEMPLATEVAL3", "templateval3");
551 EXPECT_TRUE(peer.ValueIs("TEMPLATEVAL3", "templateval3"));
552 EXPECT_TRUE(subdict_peer.ValueIs("TEMPLATEVAL3", "templateval3"));
553 EXPECT_TRUE(subsubdict_peer.ValueIs("TEMPLATEVAL3", "templateval3"));
554 EXPECT_TRUE(includedict_peer.ValueIs("TEMPLATEVAL3", "templateval3"));
555 EXPECT_TRUE(subdict2_peer.ValueIs("TEMPLATEVAL3", "templateval3"));
556 EXPECT_TRUE(includedict2_peer.ValueIs("TEMPLATEVAL3", "templateval3"));
557
558 // you should be able to override a template value with a regular value
559 // and the overwritten regular value should pass on to its children
560 subdict->SetValue("TEMPLATEVAL2", "subdictval");
561 includedict->SetValue("TEMPLATEVAL2", "includedictval");
562 EXPECT_TRUE(peer.ValueIs("TEMPLATEVAL2", "templateval2"));
563 EXPECT_TRUE(subdict_peer.ValueIs("TEMPLATEVAL2", "subdictval"));
564 EXPECT_TRUE(subsubdict_peer.ValueIs("TEMPLATEVAL2", "subdictval"));
565 EXPECT_TRUE(includedict_peer.ValueIs("TEMPLATEVAL2", "includedictval"));
566 EXPECT_TRUE(subdict2_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
567 EXPECT_TRUE(includedict2_peer.ValueIs("TEMPLATEVAL2", "templateval2"));
568
569 // A section shown template-globally will be shown in all its children.
570 dict.ShowTemplateGlobalSection("ShownTemplateGlobalSection");
571 EXPECT_FALSE(peer.IsHiddenSection("ShownTemplateGlobalSection"));
572
573 EXPECT_FALSE(subdict2_peer.IsHiddenSection("ShownTemplateGlobalSection"));
574 EXPECT_FALSE(subsubdict_peer.IsHiddenSection("ShownTemplateGlobalSection"));
575
576 // Showing a template-global section in a child will show it in all templates
577 // in the tree
578 subdict->ShowTemplateGlobalSection("ShownFromAChild");
579 EXPECT_FALSE(peer.IsHiddenSection("ShownFromAChild"));
580 EXPECT_FALSE(subsubdict_peer.IsHiddenSection("ShownFromAChild"));
581
582 // Asking for a section that doesn't exist shouldn't cause infinite recursion
583 peer.IsHiddenSection("NAVBAR_SECTION");
584}
585
586TEST(TemplateDictionary, SetTemplateGlobalValueWithoutCopy) {
587 UnsafeArena arena(100);
588 TemplateDictionary dict("Test arena", &arena);
589 TemplateDictionaryPeer peer(&dict);
590
591 char value[32];
592 snprintf(value, sizeof(value), "%s", "value");
593
594 const void* const ptr = arena.Alloc(0);
595 dict.SetTemplateGlobalValueWithoutCopy("key", value);
596 // We shouldn't have copied the value string.
597 EXPECT_EQ(ptr, arena.Alloc(0));
598
599 EXPECT_TRUE(peer.ValueIs("key", "value"));
600 // If our content changes, so does what's in the dictionary -- but
601 // only the contents of the buffer, not its length!
602 snprintf(value, sizeof(value), "%s", "not_value");
603 EXPECT_TRUE(peer.ValueIs("key", "not_v")); // "not_v" size == value" size
604}
605
606TEST(TemplateDictionary, AddIncludeDictionary) {
607 TemplateDictionary dict("test_SetAddIncludeDictionary", NULL);
608 TemplateDictionaryPeer peer(&dict);
609 dict.SetValue("TOPLEVEL", "foo");
610 dict.SetValue("TOPLEVEL2", "foo2");
611 dict.SetTemplateGlobalValue("TEMPLATELEVEL", "foo3");
612
613 TemplateDictionary* subdict_1a = dict.AddIncludeDictionary("include1");
614 TemplateDictionaryPeer subdict_1a_peer(subdict_1a);
615 subdict_1a->SetFilename("incfile1a");
616 // This is the same dict, but name is specified a different way.
617 TemplateDictionary* subdict_1b = dict.AddIncludeDictionary(
618 TemplateString("include1__ignored__", strlen("include1")));
619 TemplateDictionaryPeer subdict_1b_peer(subdict_1b);
620 // Let's try not calling SetFilename on this one.
621 subdict_1a->SetValue("SUBLEVEL", "subfoo");
622 subdict_1b->SetValue("SUBLEVEL", "subbar");
623
624 TemplateDictionary* subdict_2 = dict.AddIncludeDictionary("include2");
625 TemplateDictionaryPeer subdict_2_peer(subdict_2);
626 subdict_2->SetFilename("foo/bar");
627 subdict_2->SetValue("TOPLEVEL", "bar"); // overriding top dict
628 // overriding template dict
629 subdict_2->SetValue("TEMPLATELEVEL", "subfoo3");
630 TemplateDictionary* subdict_2_1 = subdict_2->AddIncludeDictionary("sub");
631 TemplateDictionaryPeer subdict_2_1_peer(subdict_2_1);
632 subdict_2_1->SetFilename("baz");
633 subdict_2_1->SetIntValue("GLOBAL", 21); // overrides value in setUp()
634
635 // Verify that all variables that should be look-up-able are, and that
636 // we have proper precedence. Unlike with sections, includes lookups
637 // do not go 'up the chain'.
638 EXPECT_TRUE(peer.ValueIs("GLOBAL", "top"));
639 EXPECT_TRUE(peer.ValueIs("TOPLEVEL", "foo"));
640 EXPECT_TRUE(peer.ValueIs("TOPLEVEL2", "foo2"));
641 EXPECT_TRUE(peer.ValueIs("TEMPLATELEVEL", "foo3"));
642 EXPECT_TRUE(peer.ValueIs("SUBLEVEL", ""));
643
644 EXPECT_TRUE(subdict_1a_peer.ValueIs("GLOBAL", "top"));
645 EXPECT_TRUE(subdict_1a_peer.ValueIs("TOPLEVEL", ""));
646 EXPECT_TRUE(subdict_1a_peer.ValueIs("TOPLEVEL2", ""));
647 EXPECT_TRUE(subdict_1a_peer.ValueIs("TEMPLATELEVEL", "foo3"));
648 EXPECT_TRUE(subdict_1a_peer.ValueIs("SUBLEVEL", "subfoo"));
649
650 EXPECT_TRUE(subdict_1b_peer.ValueIs("GLOBAL", "top"));
651 EXPECT_TRUE(subdict_1b_peer.ValueIs("TOPLEVEL", ""));
652 EXPECT_TRUE(subdict_1b_peer.ValueIs("TOPLEVEL2", ""));
653 EXPECT_TRUE(subdict_1b_peer.ValueIs("SUBLEVEL", "subbar"));
654
655 EXPECT_TRUE(subdict_2_peer.ValueIs("GLOBAL", "top"));
656 EXPECT_TRUE(subdict_2_peer.ValueIs("TOPLEVEL", "bar"));
657 EXPECT_TRUE(subdict_2_peer.ValueIs("TOPLEVEL2", ""));
658 EXPECT_TRUE(subdict_2_peer.ValueIs("TEMPLATELEVEL", "subfoo3"));
659 EXPECT_TRUE(subdict_2_peer.ValueIs("SUBLEVEL", ""));
660
661 EXPECT_TRUE(subdict_2_1_peer.ValueIs("GLOBAL", "21"));
662 EXPECT_TRUE(subdict_2_1_peer.ValueIs("TOPLEVEL", ""));
663 EXPECT_TRUE(subdict_2_1_peer.ValueIs("TOPLEVEL2", ""));
664 EXPECT_TRUE(subdict_2_1_peer.ValueIs("SUBLEVEL", ""));
665
666 // Verify that everyone knows about its sub-dictionaries, but that
667 // these do not try to go 'up the chain' on lookup failure
668 EXPECT_FALSE(peer.IsHiddenTemplate("include1"));
669 EXPECT_FALSE(peer.IsHiddenTemplate("include2"));
670 EXPECT_TRUE(peer.IsHiddenTemplate("include3"));
671 EXPECT_TRUE(peer.IsHiddenTemplate("sub"));
672 EXPECT_TRUE(subdict_1a_peer.IsHiddenTemplate("include1"));
673 EXPECT_TRUE(subdict_1a_peer.IsHiddenTemplate("sub"));
674 EXPECT_FALSE(subdict_2_peer.IsHiddenTemplate("sub"));
675 EXPECT_TRUE(subdict_2_1_peer.IsHiddenTemplate("sub"));
676
677 // We should get the dictionary-lengths right as well
678 vector<const TemplateDictionary*> dummy;
679 EXPECT_EQ(2, peer.GetIncludeDictionaries("include1", &dummy));
680 EXPECT_EQ(1, peer.GetIncludeDictionaries("include2", &dummy));
681 EXPECT_EQ(1, subdict_2_peer.GetIncludeDictionaries("sub", &dummy));
682
683 // We can also test the include-files are right
684 EXPECT_EQ(2, peer.GetIncludeDictionaries("include1", &dummy));
685 EXPECT_EQ(1, peer.GetIncludeDictionaries("include2", &dummy));
686 EXPECT_EQ(1, subdict_2_peer.GetIncludeDictionaries("sub", &dummy));
687 // Test some of the values
688 EXPECT_TRUE(TemplateDictionaryPeer(GetIncludeDict(&dict, "include1", 0))
689 .ValueIs("SUBLEVEL", "subfoo"));
690 EXPECT_TRUE(TemplateDictionaryPeer(GetIncludeDict(&dict, "include1", 1))
691 .ValueIs("SUBLEVEL", "subbar"));
692 EXPECT_TRUE(TemplateDictionaryPeer(GetIncludeDict(&dict, "include2", 0))
693 .ValueIs("TOPLEVEL", "bar"));
694 EXPECT_TRUE(TemplateDictionaryPeer(
695 GetIncludeDict(GetIncludeDict(&dict, "include2", 0), "sub", 0))
696 .ValueIs("TOPLEVEL", ""));
697 EXPECT_TRUE(TemplateDictionaryPeer(
698 GetIncludeDict(GetIncludeDict(&dict, "include2", 0), "sub", 0))
699 .ValueIs("GLOBAL", "21"));
700 // We can test the include-names as well
701 EXPECT_STREQ(peer.GetIncludeTemplateName("include1", 0), "incfile1a");
702 EXPECT_STREQ(peer.GetIncludeTemplateName("include1", 1), "");
703 EXPECT_STREQ(peer.GetIncludeTemplateName("include2", 0), "foo/bar");
704 EXPECT_STREQ(TemplateDictionaryPeer(GetIncludeDict(&dict, "include2", 0))
705 .GetIncludeTemplateName("sub", 0),
706 "baz");
707
708 // Make sure we're making descriptive names
709 EXPECT_STREQ(dict.name().c_str(),
710 "test_SetAddIncludeDictionary");
711 EXPECT_STREQ(subdict_1a->name().c_str(),
712 "test_SetAddIncludeDictionary/include1#1");
713 EXPECT_STREQ(subdict_1b->name().c_str(),
714 "test_SetAddIncludeDictionary/include1#2");
715 EXPECT_STREQ(subdict_2->name().c_str(),
716 "test_SetAddIncludeDictionary/include2#1");
717 EXPECT_STREQ(subdict_2_1->name().c_str(),
718 "test_SetAddIncludeDictionary/include2#1/sub#1");
719
720 // Finally, we can test the whole kit and kaboodle
721 string dump;
722 dict.DumpToString(&dump);
723 const char* const expected =
724 ("global dictionary {\n"
725 " BI_NEWLINE: >\n"
726 "<\n"
727 " BI_SPACE: > <\n"
728 " GLOBAL: >top<\n"
729 "};\n"
730 "template dictionary {\n"
731 " TEMPLATELEVEL: >foo3<\n"
732 "};\n"
733 "dictionary 'test_SetAddIncludeDictionary' {\n"
734 " TOPLEVEL: >foo<\n"
735 " TOPLEVEL2: >foo2<\n"
736 " include-template include1 (dict 1 of 2, from incfile1a) -->\n"
737 " global dictionary {\n"
738 " BI_NEWLINE: >\n"
739 "<\n"
740 " BI_SPACE: > <\n"
741 " GLOBAL: >top<\n"
742 " };\n"
743 " dictionary 'test_SetAddIncludeDictionary/include1#1 (intended for incfile1a)' {\n"
744 " SUBLEVEL: >subfoo<\n"
745 " }\n"
746 " include-template include1 (dict 2 of 2, **NO FILENAME SET; THIS DICT WILL BE IGNORED**) -->\n"
747 " global dictionary {\n"
748 " BI_NEWLINE: >\n"
749 "<\n"
750 " BI_SPACE: > <\n"
751 " GLOBAL: >top<\n"
752 " };\n"
753 " dictionary 'test_SetAddIncludeDictionary/include1#2' {\n"
754 " SUBLEVEL: >subbar<\n"
755 " }\n"
756 " include-template include2 (dict 1 of 1, from foo/bar) -->\n"
757 " global dictionary {\n"
758 " BI_NEWLINE: >\n"
759 "<\n"
760 " BI_SPACE: > <\n"
761 " GLOBAL: >top<\n"
762 " };\n"
763 " dictionary 'test_SetAddIncludeDictionary/include2#1 (intended for foo/bar)' {\n"
764 " TEMPLATELEVEL: >subfoo3<\n"
765 " TOPLEVEL: >bar<\n"
766 " include-template sub (dict 1 of 1, from baz) -->\n"
767 " global dictionary {\n"
768 " BI_NEWLINE: >\n"
769 "<\n"
770 " BI_SPACE: > <\n"
771 " GLOBAL: >top<\n"
772 " };\n"
773 " dictionary 'test_SetAddIncludeDictionary/include2#1/sub#1 (intended for baz)' {\n"
774 " GLOBAL: >21<\n"
775 " }\n"
776 " }\n"
777 "}\n");
778 EXPECT_STREQ(dump.c_str(), expected);
779}
780
781static void TestMakeCopy(bool use_local_arena) {
782 UnsafeArena local_arena(1024);
783 UnsafeArena* arena = NULL;
784 if (use_local_arena)
785 arena = &local_arena;
786
787 // First, let's make a non-trivial template dictionary (We use
788 // 'new' because later we'll test deleting this dict but keeping
789 // around the copy.)
790 TemplateDictionary* dict = new TemplateDictionary("testdict", arena);
791
792 dict->SetValue("TOPLEVEL", "foo");
793
794 dict->SetTemplateGlobalValue("TEMPLATELEVEL", "foo3");
795
796 TemplateDictionary* subdict_1a = dict->AddIncludeDictionary("include1");
797 subdict_1a->SetFilename("incfile1a");
798 subdict_1a->SetValue("SUBLEVEL", "subfoo");
799 TemplateDictionary* subdict_1b = dict->AddIncludeDictionary("include1");
800 // Let's try not calling SetFilename on this one.
801 subdict_1b->SetValue("SUBLEVEL", "subbar");
802
803 TemplateDictionary* subdict_2a = dict->AddSectionDictionary("section1");
804 TemplateDictionary* subdict_2b = dict->AddSectionDictionary("section1");
805 subdict_2a->SetValue("SUBLEVEL", "subfoo");
806 subdict_2b->SetValue("SUBLEVEL", "subbar");
807 TemplateDictionary* subdict_3 = dict->AddSectionDictionary("section2");
808 subdict_3->SetValue("TOPLEVEL", "bar"); // overriding top dict
809 TemplateDictionary* subdict_3_1 = subdict_3->AddSectionDictionary("sub");
810 subdict_3_1->SetIntValue("GLOBAL", 21); // overrides value in setUp()
811
812 string orig;
813 dict->DumpToString(&orig);
814
815 // Make a copy
816 TemplateDictionary* dict_copy = dict->MakeCopy("testdict", NULL);
817 // Make sure it doesn't work to copy a sub-dictionary
818 EXPECT_TRUE(subdict_1a->MakeCopy("copy of subdict") == NULL);
819 EXPECT_TRUE(subdict_2a->MakeCopy("copy of subdict") == NULL);
820
821 // Delete the original dict, to make sure the copy really is independent
822 delete dict;
823 dict = NULL;
824 string copy;
825 dict_copy->DumpToString(&copy);
826 delete dict_copy;
827
828 EXPECT_STREQ(orig.c_str(), copy.c_str());
829}
830
831TEST(MakeCopy, UseLocalArena) {
832 TestMakeCopy(true);
833}
834
835TEST(MakeCopy, DoNotUseLocalArena) {
836 TestMakeCopy(false);
837}
838
839TEST(TemplateDictionary, SetModifierData) {
840 PerExpandData per_expand_data;
841 const void* data = "test";
842 per_expand_data.InsertForModifiers("a", data);
843 EXPECT_EQ(data, per_expand_data.LookupForModifiers("a"));
844}
845
846TEST(TemplateDictionary, Iterator) {
847 // Build up a nice community of TemplateDictionaries.
848 TemplateDictionary farm("Farm");
849 TemplateDictionaryPeer farm_peer(&farm);
850 TemplateDictionaryInterface* grey_barn =
851 farm.AddIncludeDictionary("BARN");
852 TemplateDictionaryInterface* duck_pond =
853 farm.AddIncludeDictionary("POND");
854 TemplateDictionaryInterface* cattle_pond =
855 farm.AddIncludeDictionary("POND");
856 TemplateDictionaryInterface* irrigation_pond =
857 farm.AddIncludeDictionary("POND");
858
859 // A section name with repeated sections
860 TemplateDictionaryInterface* lillies = farm.AddSectionDictionary("FLOWERS");
861 TemplateDictionaryInterface* lilacs = farm.AddSectionDictionary("FLOWERS");
862 TemplateDictionaryInterface* daisies = farm.AddSectionDictionary("FLOWERS");
863 // A section name with one repeat
864 TemplateDictionaryInterface* wheat = farm.AddSectionDictionary("WHEAT");
865 // A section name, just shown
866 farm.ShowSection("CORN");
867
868 // Check that the iterators expose all of the dictionaries.
869 TemplateDictionaryPeer::Iterator* barns =
870 farm_peer.CreateTemplateIterator("BARN");
871 EXPECT_TRUE(barns->HasNext());
872 EXPECT_EQ(&barns->Next(), grey_barn);
873 EXPECT_FALSE(barns->HasNext());
874 delete barns;
875
876 TemplateDictionaryPeer::Iterator* ponds =
877 farm_peer.CreateTemplateIterator("POND");
878 EXPECT_TRUE(ponds->HasNext());
879 EXPECT_EQ(&ponds->Next(), duck_pond);
880 EXPECT_TRUE(ponds->HasNext());
881 EXPECT_EQ(&ponds->Next(), cattle_pond);
882 EXPECT_TRUE(ponds->HasNext());
883 EXPECT_EQ(&ponds->Next(), irrigation_pond);
884 EXPECT_FALSE(ponds->HasNext());
885 delete ponds;
886
887 TemplateDictionaryPeer::Iterator* flowers =
888 farm_peer.CreateSectionIterator("FLOWERS");
889 EXPECT_TRUE(flowers->HasNext());
890 EXPECT_EQ(&flowers->Next(), lillies);
891 EXPECT_TRUE(flowers->HasNext());
892 EXPECT_EQ(&flowers->Next(), lilacs);
893 EXPECT_TRUE(flowers->HasNext());
894 EXPECT_EQ(&flowers->Next(), daisies);
895 EXPECT_FALSE(flowers->HasNext());
896 delete flowers;
897
898 TemplateDictionaryPeer::Iterator* crop =
899 farm_peer.CreateSectionIterator("WHEAT");
900 EXPECT_TRUE(crop->HasNext());
901 EXPECT_EQ(&crop->Next(), wheat);
902 EXPECT_FALSE(crop->HasNext());
903 delete crop;
904
905 TemplateDictionaryPeer::Iterator* corn_crop =
906 farm_peer.CreateSectionIterator("CORN");
907 EXPECT_TRUE(corn_crop->HasNext());
908 EXPECT_TRUE(&corn_crop->Next()); // ShowSection doesn't give us the dict back
909 EXPECT_FALSE(corn_crop->HasNext());
910 delete corn_crop;
911}
912
913TEST(TemplateDictionary, IsHiddenSectionDefault) {
914 TemplateDictionary dict("dict");
915 TemplateDictionaryPeer peer(&dict);
916 EXPECT_TRUE(peer.IsHiddenSection("UNDEFINED"));
917 EXPECT_FALSE(peer.IsUnhiddenSection("UNDEFINED"));
918 dict.ShowSection("VISIBLE");
919 EXPECT_FALSE(peer.IsHiddenSection("VISIBLE"));
920 EXPECT_TRUE(peer.IsUnhiddenSection("VISIBLE"));
921}
922
923// This has to run last, since its SetGlobalValue modifies the global
924// state, which can affect other tests (especially given the embedded
925// NUL!) So we don't use the normal TEST() here, and call it manually
926// in main().
927
928void TestSetValueWithNUL() {
929 TemplateDictionary dict("test_SetValueWithNUL", NULL);
930 TemplateDictionaryPeer peer(&dict);
931
932 // Test copying char*s, strings, and explicit TemplateStrings
933 dict.SetValue(string("FOO\0BAR", 7), string("QUX\0QUUX", 8));
934 dict.SetGlobalValue(string("GOO\0GAR", 7), string("GUX\0GUUX", 8));
935
936 // FOO should not match FOO\0BAR
937 EXPECT_TRUE(peer.ValueIs("FOO", ""));
938 EXPECT_TRUE(peer.ValueIs("GOO", ""));
939
940 EXPECT_TRUE(peer.ValueIs(string("FOO\0BAR", 7), string("QUX\0QUUX", 8)));
941 EXPECT_TRUE(peer.ValueIs(string("GOO\0GAR", 7), string("GUX\0GUUX", 8)));
942
943 string dump;
944 dict.DumpToString(&dump);
945 // We can't use EXPECT_STREQ here because of the embedded NULs.
946 // They also require I count the length of the string by hand. :-(
947 string expected(("global dictionary {\n"
948 " BI_NEWLINE: >\n"
949 "<\n"
950 " BI_SPACE: > <\n"
951 " GLOBAL: >top<\n"
952 " GOO\0GAR: >GUX\0GUUX<\n"
953 "};\n"
954 "dictionary 'test_SetValueWithNUL' {\n"
955 " FOO\0BAR: >QUX\0QUUX<\n"
956 "}\n"),
957 160);
958 EXPECT_EQ(dump, expected);
959}
960
961TEST(TemplateDictionary, TestShowTemplateGlobalSection) {
962 StringToTemplateCache("test.tpl", "{{#sect}}OK{{/sect}}", DO_NOT_STRIP);
963
964 TemplateDictionary dict("mydict");
965 dict.ShowTemplateGlobalSection("sect");
966
967 string out;
968 ExpandTemplate("test.tpl", DO_NOT_STRIP, &dict, &out);
969}
970
971TEST(TemplateDictionary, TestShowTemplateGlobalSection_Child) {
972 // The TemplateDictionary::template_global_dict_ behaves differently for child
973 // dictionaries than for the root parent dictionary.
974 StringToTemplateCache("test2.tpl",
975 "{{#foo}}{{#sect}}OK{{/sect}}{{/foo}}",
976 DO_NOT_STRIP);
977
978 TemplateDictionary dict("mydict");
979 dict.ShowTemplateGlobalSection("sect");
980
981 dict.AddSectionDictionary("foo");
982
983 string out;
984 ExpandTemplate("test2.tpl", DO_NOT_STRIP, &dict, &out);
985}
986
987TEST(TemplateDictionary, TestShowTemplateGlobalSection_SectionDoesntExist) {
988 StringToTemplateCache("test3.tpl",
989 "{{#bad}}bad{{/bad}}",
990 DO_NOT_STRIP);
991
992 TemplateDictionary dict("mydict");
993
994 string out;
995 ExpandTemplate("test3.tpl", DO_NOT_STRIP, &dict, &out);
996}
997
998
999} // unnamed namespace
1000
1001
1002int main(int argc, char** argv) {
1003
1004 SetUp();
1005
1006 const int retval = RUN_ALL_TESTS();
1007
1008 // This has to run last, so we run it manually
1009 TestSetValueWithNUL();
1010
1011 return retval;
1012}