brintos

brintos / llvm-project-archived public Read only

0
0
Text · 56.2 KiB · 3cad4a4 Raw
1893 lines · cpp
1//===- llvm/unittest/Support/MustacheTest.cpp ----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Test conforming to Mustache 1.4.2 spec found here:10// https://github.com/mustache/spec11//12//===----------------------------------------------------------------------===//13 14#include "llvm/Support/Mustache.h"15#include "llvm/Support/raw_ostream.h"16#include "gtest/gtest.h"17 18using namespace llvm;19using namespace llvm::mustache;20using namespace llvm::json;21 22TEST(MustacheInterpolation, NoInterpolation) {23  // Mustache-free templates should render as-is.24  Value D = {};25  BumpPtrAllocator Allocator;26  StringSaver Saver(Allocator);27  MustacheContext Ctx(Allocator, Saver);28  Template T("Hello from {Mustache}!\n", Ctx);29  std::string Out;30  raw_string_ostream OS(Out);31  T.render(D, OS);32  EXPECT_EQ("Hello from {Mustache}!\n", Out);33}34 35TEST(MustacheInterpolation, BasicInterpolation) {36  // Unadorned tags should interpolate content into the template.37  Value D = Object{{"subject", "World"}};38  BumpPtrAllocator Allocator;39  StringSaver Saver(Allocator);40  MustacheContext Ctx(Allocator, Saver);41  Template T("Hello, {{subject}}!", Ctx);42  std::string Out;43  raw_string_ostream OS(Out);44  T.render(D, OS);45  EXPECT_EQ("Hello, World!", Out);46}47 48TEST(MustacheInterpolation, NoReinterpolation) {49  // Interpolated tag output should not be re-interpolated.50  Value D = Object{{"template", "{{planet}}"}, {"planet", "Earth"}};51  BumpPtrAllocator Allocator;52  StringSaver Saver(Allocator);53  MustacheContext Ctx(Allocator, Saver);54  Template T("{{template}}: {{planet}}", Ctx);55  std::string Out;56  raw_string_ostream OS(Out);57  T.render(D, OS);58  EXPECT_EQ("{{planet}}: Earth", Out);59}60 61TEST(MustacheInterpolation, HTMLEscaping) {62  // Interpolated tag output should not be re-interpolated.63  Value D = Object{64      {"forbidden", "& \" < >"},65  };66  BumpPtrAllocator Allocator;67  StringSaver Saver(Allocator);68  MustacheContext Ctx(Allocator, Saver);69  Template T("These characters should be HTML escaped: {{forbidden}}\n", Ctx);70  std::string Out;71  raw_string_ostream OS(Out);72  T.render(D, OS);73  EXPECT_EQ("These characters should be HTML escaped: &amp; &quot; &lt; &gt;\n",74            Out);75}76 77TEST(MustacheInterpolation, Ampersand) {78  // Interpolated tag output should not be re-interpolated.79  Value D = Object{80      {"forbidden", "& \" < >"},81  };82  BumpPtrAllocator Allocator;83  StringSaver Saver(Allocator);84  MustacheContext Ctx(Allocator, Saver);85  Template T("These characters should not be HTML escaped: {{&forbidden}}\n",86             Ctx);87  std::string Out;88  raw_string_ostream OS(Out);89  T.render(D, OS);90  EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);91}92 93TEST(MustacheInterpolation, BasicIntegerInterpolation) {94  // Integers should interpolate seamlessly.95  Value D = Object{{"mph", 85}};96  BumpPtrAllocator Allocator;97  StringSaver Saver(Allocator);98  MustacheContext Ctx(Allocator, Saver);99  Template T("{{mph}} miles an hour!", Ctx);100  std::string Out;101  raw_string_ostream OS(Out);102  T.render(D, OS);103  EXPECT_EQ("85 miles an hour!", Out);104}105 106TEST(MustacheInterpolation, AmpersandIntegerInterpolation) {107  // Integers should interpolate seamlessly.108  Value D = Object{{"mph", 85}};109  BumpPtrAllocator Allocator;110  StringSaver Saver(Allocator);111  MustacheContext Ctx(Allocator, Saver);112  Template T("{{&mph}} miles an hour!", Ctx);113  std::string Out;114  raw_string_ostream OS(Out);115  T.render(D, OS);116  EXPECT_EQ("85 miles an hour!", Out);117}118 119TEST(MustacheInterpolation, BasicDecimalInterpolation) {120  // Decimals should interpolate seamlessly with proper significance.121  Value D = Object{{"power", 1.21}};122  BumpPtrAllocator Allocator;123  StringSaver Saver(Allocator);124  MustacheContext Ctx(Allocator, Saver);125  Template T("{{power}} jiggawatts!", Ctx);126  std::string Out;127  raw_string_ostream OS(Out);128  T.render(D, OS);129  EXPECT_EQ("1.21 jiggawatts!", Out);130}131 132TEST(MustacheInterpolation, BasicNullInterpolation) {133  // Nulls should interpolate as the empty string.134  Value D = Object{{"cannot", nullptr}};135  BumpPtrAllocator Allocator;136  StringSaver Saver(Allocator);137  MustacheContext Ctx(Allocator, Saver);138  Template T("I ({{cannot}}) be seen!", Ctx);139  std::string Out;140  raw_string_ostream OS(Out);141  T.render(D, OS);142  EXPECT_EQ("I () be seen!", Out);143}144 145TEST(MustacheInterpolation, AmpersandNullInterpolation) {146  // Nulls should interpolate as the empty string.147  Value D = Object{{"cannot", nullptr}};148  BumpPtrAllocator Allocator;149  StringSaver Saver(Allocator);150  MustacheContext Ctx(Allocator, Saver);151  Template T("I ({{&cannot}}) be seen!", Ctx);152  std::string Out;153  raw_string_ostream OS(Out);154  T.render(D, OS);155  EXPECT_EQ("I () be seen!", Out);156}157 158TEST(MustacheInterpolation, BasicContextMissInterpolation) {159  // Failed context lookups should default to empty strings.160  Value D = Object{};161  BumpPtrAllocator Allocator;162  StringSaver Saver(Allocator);163  MustacheContext Ctx(Allocator, Saver);164  Template T("I ({{cannot}}) be seen!", Ctx);165  std::string Out;166  raw_string_ostream OS(Out);167  T.render(D, OS);168  EXPECT_EQ("I () be seen!", Out);169}170 171TEST(MustacheInterpolation, DottedNamesBasicInterpolation) {172  // Dotted names should be considered a form of shorthand for sections.173  Value D = Object{{"person", Object{{"name", "Joe"}}}};174  BumpPtrAllocator Allocator;175  StringSaver Saver(Allocator);176  MustacheContext Ctx(Allocator, Saver);177  Template T("{{person.name}} == {{#person}}{{name}}{{/person}}", Ctx);178  std::string Out;179  raw_string_ostream OS(Out);180  T.render(D, OS);181  EXPECT_EQ("Joe == Joe", Out);182}183 184TEST(MustacheInterpolation, DottedNamesAmpersandInterpolation) {185  // Dotted names should be considered a form of shorthand for sections.186  Value D = Object{{"person", Object{{"name", "Joe"}}}};187  BumpPtrAllocator Allocator;188  StringSaver Saver(Allocator);189  MustacheContext Ctx(Allocator, Saver);190  Template T("{{&person.name}} == {{#person}}{{&name}}{{/person}}", Ctx);191  std::string Out;192  raw_string_ostream OS(Out);193  T.render(D, OS);194  EXPECT_EQ("Joe == Joe", Out);195}196 197TEST(MustacheInterpolation, DottedNamesArbitraryDepth) {198  // Dotted names should be functional to any level of nesting.199  Value D = Object{200      {"a",201       Object{{"b",202               Object{{"c",203                       Object{{"d",204                               Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}};205  BumpPtrAllocator Allocator;206  StringSaver Saver(Allocator);207  MustacheContext Ctx(Allocator, Saver);208  Template T("{{a.b.c.d.e.name}}", Ctx);209  std::string Out;210  raw_string_ostream OS(Out);211  T.render(D, OS);212  EXPECT_EQ("Phil", Out);213}214 215TEST(MustacheInterpolation, DottedNamesBrokenChains) {216  // Any falsey value prior to the last part of the name should yield ''.217  Value D = Object{{"a", Object{}}};218  BumpPtrAllocator Allocator;219  StringSaver Saver(Allocator);220  MustacheContext Ctx(Allocator, Saver);221  Template T("{{a.b.c}} == ", Ctx);222  std::string Out;223  raw_string_ostream OS(Out);224  T.render(D, OS);225  EXPECT_EQ(" == ", Out);226}227 228TEST(MustacheInterpolation, DottedNamesBrokenChainResolution) {229  // Each part of a dotted name should resolve only against its parent.230  Value D =231      Object{{"a", Object{{"b", Object{}}}}, {"c", Object{{"name", "Jim"}}}};232  BumpPtrAllocator Allocator;233  StringSaver Saver(Allocator);234  MustacheContext Ctx(Allocator, Saver);235  Template T("{{a.b.c.name}} == ", Ctx);236  std::string Out;237  raw_string_ostream OS(Out);238  T.render(D, OS);239  EXPECT_EQ(" == ", Out);240}241 242TEST(MustacheInterpolation, DottedNamesInitialResolution) {243  // The first part of a dotted name should resolve as any other name.244  Value D = Object{245      {"a",246       Object{247           {"b",248            Object{{"c",249                    Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}},250      {"b",251       Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Wrong"}}}}}}}}}};252  BumpPtrAllocator Allocator;253  StringSaver Saver(Allocator);254  MustacheContext Ctx(Allocator, Saver);255  Template T("{{#a}}{{b.c.d.e.name}}{{/a}}", Ctx);256  std::string Out;257  raw_string_ostream OS(Out);258  T.render(D, OS);259  EXPECT_EQ("Phil", Out);260}261 262TEST(MustacheInterpolation, DottedNamesContextPrecedence) {263  // Dotted names should be resolved against former resolutions.264  Value D =265      Object{{"a", Object{{"b", Object{}}}}, {"b", Object{{"c", "ERROR"}}}};266  BumpPtrAllocator Allocator;267  StringSaver Saver(Allocator);268  MustacheContext Ctx(Allocator, Saver);269  Template T("{{#a}}{{b.c}}{{/a}}", Ctx);270  std::string Out;271  raw_string_ostream OS(Out);272  T.render(D, OS);273  EXPECT_EQ("", Out);274}275 276TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) {277  // Dotted names shall not be parsed as single, atomic keys278  Value D = Object{{"a.b", "c"}};279  BumpPtrAllocator Allocator;280  StringSaver Saver(Allocator);281  MustacheContext Ctx(Allocator, Saver);282  Template T("{{a.b}}", Ctx);283  std::string Out;284  raw_string_ostream OS(Out);285  T.render(D, OS);286  EXPECT_EQ("", Out);287}288 289TEST(MustacheInterpolation, DottedNamesNoMasking) {290  // Dotted Names in a given context are unavailable due to dot splitting291  Value D = Object{{"a.b", "c"}, {"a", Object{{"b", "d"}}}};292  BumpPtrAllocator Allocator;293  StringSaver Saver(Allocator);294  MustacheContext Ctx(Allocator, Saver);295  Template T("{{a.b}}", Ctx);296  std::string Out;297  raw_string_ostream OS(Out);298  T.render(D, OS);299  EXPECT_EQ("d", Out);300}301 302TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) {303  // Unadorned tags should interpolate content into the template.304  Value D = "world";305  BumpPtrAllocator Allocator;306  StringSaver Saver(Allocator);307  MustacheContext Ctx(Allocator, Saver);308  Template T("Hello, {{.}}!\n", Ctx);309  std::string Out;310  raw_string_ostream OS(Out);311  T.render(D, OS);312  EXPECT_EQ("Hello, world!\n", Out);313}314 315TEST(MustacheInterpolation, ImplicitIteratorsAmersand) {316  // Basic interpolation should be HTML escaped.317  Value D = "& \" < >";318  BumpPtrAllocator Allocator;319  StringSaver Saver(Allocator);320  MustacheContext Ctx(Allocator, Saver);321  Template T("These characters should not be HTML escaped: {{&.}}\n", Ctx);322  std::string Out;323  raw_string_ostream OS(Out);324  T.render(D, OS);325  EXPECT_EQ("These characters should not be HTML escaped: & \" < >\n", Out);326}327 328TEST(MustacheInterpolation, ImplicitIteratorsInteger) {329  // Integers should interpolate seamlessly.330  Value D = 85;331  BumpPtrAllocator Allocator;332  StringSaver Saver(Allocator);333  MustacheContext Ctx(Allocator, Saver);334  Template T("{{.}} miles an hour!\n", Ctx);335  std::string Out;336  raw_string_ostream OS(Out);337  T.render(D, OS);338  EXPECT_EQ("85 miles an hour!\n", Out);339}340 341TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) {342  // Interpolation should not alter surrounding whitespace.343  Value D = Object{{"string", "---"}};344  BumpPtrAllocator Allocator;345  StringSaver Saver(Allocator);346  MustacheContext Ctx(Allocator, Saver);347  Template T("| {{string}} |", Ctx);348  std::string Out;349  raw_string_ostream OS(Out);350  T.render(D, OS);351  EXPECT_EQ("| --- |", Out);352}353 354TEST(MustacheInterpolation, AmersandSurroundingWhitespace) {355  // Interpolation should not alter surrounding whitespace.356  Value D = Object{{"string", "---"}};357  BumpPtrAllocator Allocator;358  StringSaver Saver(Allocator);359  MustacheContext Ctx(Allocator, Saver);360  Template T("| {{&string}} |", Ctx);361  std::string Out;362  raw_string_ostream OS(Out);363  T.render(D, OS);364  EXPECT_EQ("| --- |", Out);365}366 367TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) {368  // Standalone interpolation should not alter surrounding whitespace.369  Value D = Object{{"string", "---"}};370  BumpPtrAllocator Allocator;371  StringSaver Saver(Allocator);372  MustacheContext Ctx(Allocator, Saver);373  Template T("  {{string}}\n", Ctx);374  std::string Out;375  raw_string_ostream OS(Out);376  T.render(D, OS);377  EXPECT_EQ("  ---\n", Out);378}379 380TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) {381  // Standalone interpolation should not alter surrounding whitespace.382  Value D = Object{{"string", "---"}};383  BumpPtrAllocator Allocator;384  StringSaver Saver(Allocator);385  MustacheContext Ctx(Allocator, Saver);386  Template T("  {{&string}}\n", Ctx);387  std::string Out;388  raw_string_ostream OS(Out);389  T.render(D, OS);390  EXPECT_EQ("  ---\n", Out);391}392 393TEST(MustacheInterpolation, InterpolationWithPadding) {394  // Superfluous in-tag whitespace should be ignored.395  Value D = Object{{"string", "---"}};396  BumpPtrAllocator Allocator;397  StringSaver Saver(Allocator);398  MustacheContext Ctx(Allocator, Saver);399  Template T("|{{ string }}|", Ctx);400  std::string Out;401  raw_string_ostream OS(Out);402  T.render(D, OS);403  EXPECT_EQ("|---|", Out);404}405 406TEST(MustacheInterpolation, AmpersandWithPadding) {407  // Superfluous in-tag whitespace should be ignored.408  Value D = Object{{"string", "---"}};409  BumpPtrAllocator Allocator;410  StringSaver Saver(Allocator);411  MustacheContext Ctx(Allocator, Saver);412  Template T("|{{& string }}|", Ctx);413  std::string Out;414  raw_string_ostream OS(Out);415  T.render(D, OS);416  EXPECT_EQ("|---|", Out);417}418 419TEST(MustacheInterpolation, InterpolationWithPaddingAndNewlines) {420  // Superfluous in-tag whitespace should be ignored.421  Value D = Object{{"string", "---"}};422  BumpPtrAllocator Allocator;423  StringSaver Saver(Allocator);424  MustacheContext Ctx(Allocator, Saver);425  Template T("|{{ string \n\n\n }}|", Ctx);426  std::string Out;427  raw_string_ostream OS(Out);428  T.render(D, OS);429  EXPECT_EQ("|---|", Out);430}431 432TEST(MustacheSections, Truthy) {433  Value D = Object{{"boolean", true}};434  BumpPtrAllocator Allocator;435  StringSaver Saver(Allocator);436  MustacheContext Ctx(Allocator, Saver);437  Template T("{{#boolean}}This should be rendered.{{/boolean}}", Ctx);438  std::string Out;439  raw_string_ostream OS(Out);440  T.render(D, OS);441  EXPECT_EQ("This should be rendered.", Out);442}443 444TEST(MustacheSections, Falsey) {445  Value D = Object{{"boolean", false}};446  BumpPtrAllocator Allocator;447  StringSaver Saver(Allocator);448  MustacheContext Ctx(Allocator, Saver);449  Template T("{{#boolean}}This should not be rendered.{{/boolean}}", Ctx);450  std::string Out;451  raw_string_ostream OS(Out);452  T.render(D, OS);453  EXPECT_EQ("", Out);454}455 456TEST(MustacheInterpolation, IsFalseyNull) {457  // Mustache-free templates should render as-is.458  Value D = Object{{"boolean", nullptr}};459  BumpPtrAllocator Allocator;460  StringSaver Saver(Allocator);461  MustacheContext Ctx(Allocator, Saver);462  Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx);463  std::string Out;464  raw_string_ostream OS(Out);465  T.render(D, OS);466  EXPECT_EQ("Hello, ", Out);467}468 469TEST(MustacheInterpolation, IsFalseyArray) {470  // Mustache-free templates should render as-is.471  Value D = Object{{"boolean", Array()}};472  BumpPtrAllocator Allocator;473  StringSaver Saver(Allocator);474  MustacheContext Ctx(Allocator, Saver);475  Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx);476  std::string Out;477  raw_string_ostream OS(Out);478  T.render(D, OS);479  EXPECT_EQ("Hello, ", Out);480}481 482TEST(MustacheInterpolation, IsFalseyObject) {483  // Mustache-free templates should render as-is.484  Value D = Object{{"boolean", Object{}}};485  BumpPtrAllocator Allocator;486  StringSaver Saver(Allocator);487  MustacheContext Ctx(Allocator, Saver);488  Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx);489  std::string Out;490  raw_string_ostream OS(Out);491  T.render(D, OS);492  EXPECT_EQ("Hello, World", Out);493}494 495TEST(MustacheInterpolation, DoubleRendering) {496  // Mustache-free templates should render as-is.497  Value D1 = Object{{"subject", "World"}};498  BumpPtrAllocator Allocator;499  StringSaver Saver(Allocator);500  MustacheContext Ctx(Allocator, Saver);501  Template T("Hello, {{subject}}!", Ctx);502  std::string Out1;503  raw_string_ostream OS1(Out1);504  T.render(D1, OS1);505  EXPECT_EQ("Hello, World!", Out1);506  std::string Out2;507  raw_string_ostream OS2(Out2);508  Value D2 = Object{{"subject", "New World"}};509  T.render(D2, OS2);510  EXPECT_EQ("Hello, New World!", Out2);511}512 513TEST(MustacheSections, NullIsFalsey) {514  Value D = Object{{"null", nullptr}};515  BumpPtrAllocator Allocator;516  StringSaver Saver(Allocator);517  MustacheContext Ctx(Allocator, Saver);518  Template T("{{#null}}This should not be rendered.{{/null}}", Ctx);519  std::string Out;520  raw_string_ostream OS(Out);521  T.render(D, OS);522  EXPECT_EQ("", Out);523}524 525TEST(MustacheSections, Context) {526  Value D = Object{{"context", Object{{"name", "Joe"}}}};527  BumpPtrAllocator Allocator;528  StringSaver Saver(Allocator);529  MustacheContext Ctx(Allocator, Saver);530  Template T("{{#context}}Hi {{name}}.{{/context}}", Ctx);531  std::string Out;532  raw_string_ostream OS(Out);533  T.render(D, OS);534  EXPECT_EQ("Hi Joe.", Out);535}536 537TEST(MustacheSections, ParentContexts) {538  Value D = Object{{"a", "foo"},539                   {"b", "wrong"},540                   {"sec", Object{{"b", "bar"}}},541                   {"c", Object{{"d", "baz"}}}};542  BumpPtrAllocator Allocator;543  StringSaver Saver(Allocator);544  MustacheContext Ctx(Allocator, Saver);545  Template T("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}", Ctx);546  std::string Out;547  raw_string_ostream OS(Out);548  T.render(D, OS);549  EXPECT_EQ("foo, bar, baz", Out);550}551 552TEST(MustacheSections, VariableTest) {553  Value D = Object{{"foo", "bar"}};554  BumpPtrAllocator Allocator;555  StringSaver Saver(Allocator);556  MustacheContext Ctx(Allocator, Saver);557  Template T("{{#foo}}{{.}} is {{foo}}{{/foo}}", Ctx);558  std::string Out;559  raw_string_ostream OS(Out);560  T.render(D, OS);561  EXPECT_EQ("bar is bar", Out);562}563 564TEST(MustacheSections, ListContexts) {565  Value D = Object{566      {"tops",567       Array{Object{568           {"tname", Object{{"upper", "A"}, {"lower", "a"}}},569           {"middles",570            Array{Object{{"mname", "1"},571                         {"bottoms", Array{Object{{"bname", "x"}},572                                           Object{{"bname", "y"}}}}}}}}}}};573  BumpPtrAllocator Allocator;574  StringSaver Saver(Allocator);575  MustacheContext Ctx(Allocator, Saver);576  Template T("{{#tops}}"577             "{{#middles}}"578             "{{tname.lower}}{{mname}}."579             "{{#bottoms}}"580             "{{tname.upper}}{{mname}}{{bname}}."581             "{{/bottoms}}"582             "{{/middles}}"583             "{{/tops}}",584             Ctx);585  std::string Out;586  raw_string_ostream OS(Out);587  T.render(D, OS);588  EXPECT_EQ("a1.A1x.A1y.", Out);589}590 591TEST(MustacheSections, DeeplyNestedContexts) {592  Value D = Object{593      {"a", Object{{"one", 1}}},594      {"b", Object{{"two", 2}}},595      {"c", Object{{"three", 3}, {"d", Object{{"four", 4}, {"five", 5}}}}}};596  BumpPtrAllocator Allocator;597  StringSaver Saver(Allocator);598  MustacheContext Ctx(Allocator, Saver);599  Template T(600      "{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{"601      "three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{"602      "{two}}{{one}}\n{{#five}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{four}"603      "}{{three}}{{two}}{{one}}\n{{one}}{{two}}{{three}}{{four}}{{.}}6{{.}}{{"604      "four}}{{three}}{{two}}{{one}}\n{{one}}{{two}}{{three}}{{four}}{{five}}{{"605      "four}}{{three}}{{two}}{{one}}\n{{/"606      "five}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/"607      "d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/"608      "c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n",609      Ctx);610  std::string Out;611  raw_string_ostream OS(Out);612  T.render(D, OS);613  EXPECT_EQ("1\n121\n12321\n1234321\n123454321\n12345654321\n123454321\n1234321"614            "\n12321\n121\n1\n",615            Out);616}617 618TEST(MustacheSections, List) {619  Value D = Object{{"list", Array{Object{{"item", 1}}, Object{{"item", 2}},620                                  Object{{"item", 3}}}}};621  BumpPtrAllocator Allocator;622  StringSaver Saver(Allocator);623  MustacheContext Ctx(Allocator, Saver);624  Template T("{{#list}}{{item}}{{/list}}", Ctx);625  std::string Out;626  raw_string_ostream OS(Out);627  T.render(D, OS);628  EXPECT_EQ("123", Out);629}630 631TEST(MustacheSections, EmptyList) {632  Value D = Object{{"list", Array{}}};633  BumpPtrAllocator Allocator;634  StringSaver Saver(Allocator);635  MustacheContext Ctx(Allocator, Saver);636  Template T("{{#list}}Yay lists!{{/list}}", Ctx);637  std::string Out;638  raw_string_ostream OS(Out);639  T.render(D, OS);640  EXPECT_EQ("", Out);641}642 643TEST(MustacheSections, Doubled) {644  Value D = Object{{"bool", true}, {"two", "second"}};645  BumpPtrAllocator Allocator;646  StringSaver Saver(Allocator);647  MustacheContext Ctx(Allocator, Saver);648  Template T("{{#bool}}\n* first\n{{/bool}}\n* "649             "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n",650             Ctx);651  std::string Out;652  raw_string_ostream OS(Out);653  T.render(D, OS);654  EXPECT_EQ("* first\n* second\n* third\n", Out);655}656 657TEST(MustacheSections, NestedTruthy) {658  Value D = Object{{"bool", true}};659  BumpPtrAllocator Allocator;660  StringSaver Saver(Allocator);661  MustacheContext Ctx(Allocator, Saver);662  Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |", Ctx);663  std::string Out;664  raw_string_ostream OS(Out);665  T.render(D, OS);666  EXPECT_EQ("| A B C D E |", Out);667}668 669TEST(MustacheSections, NestedFalsey) {670  Value D = Object{{"bool", false}};671  BumpPtrAllocator Allocator;672  StringSaver Saver(Allocator);673  MustacheContext Ctx(Allocator, Saver);674  Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |", Ctx);675  std::string Out;676  raw_string_ostream OS(Out);677  T.render(D, OS);678  EXPECT_EQ("| A  E |", Out);679}680 681TEST(MustacheSections, ContextMisses) {682  Value D = Object{};683  BumpPtrAllocator Allocator;684  StringSaver Saver(Allocator);685  MustacheContext Ctx(Allocator, Saver);686  Template T("[{{#missing}}Found key 'missing'!{{/missing}}]", Ctx);687  std::string Out;688  raw_string_ostream OS(Out);689  T.render(D, OS);690  EXPECT_EQ("[]", Out);691}692 693TEST(MustacheSections, ImplicitIteratorString) {694  Value D = Object{{"list", Array{"a", "b", "c", "d", "e"}}};695  BumpPtrAllocator Allocator;696  StringSaver Saver(Allocator);697  MustacheContext Ctx(Allocator, Saver);698  Template T("{{#list}}({{.}}){{/list}}", Ctx);699  std::string Out;700  raw_string_ostream OS(Out);701  T.render(D, OS);702  EXPECT_EQ("(a)(b)(c)(d)(e)", Out);703}704 705TEST(MustacheSections, ImplicitIteratorInteger) {706  Value D = Object{{"list", Array{1, 2, 3, 4, 5}}};707  BumpPtrAllocator Allocator;708  StringSaver Saver(Allocator);709  MustacheContext Ctx(Allocator, Saver);710  Template T("{{#list}}({{.}}){{/list}}", Ctx);711  std::string Out;712  raw_string_ostream OS(Out);713  T.render(D, OS);714  EXPECT_EQ("(1)(2)(3)(4)(5)", Out);715}716 717TEST(MustacheSections, ImplicitIteratorArray) {718  Value D = Object{{"list", Array{Array{1, 2, 3}, Array{"a", "b", "c"}}}};719  BumpPtrAllocator Allocator;720  StringSaver Saver(Allocator);721  MustacheContext Ctx(Allocator, Saver);722  Template T("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}", Ctx);723  std::string Out;724  raw_string_ostream OS(Out);725  T.render(D, OS);726  EXPECT_EQ("(123)(abc)", Out);727}728 729TEST(MustacheSections, ImplicitIteratorHTMLEscaping) {730  Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};731  BumpPtrAllocator Allocator;732  StringSaver Saver(Allocator);733  MustacheContext Ctx(Allocator, Saver);734  Template T("{{#list}}({{.}}){{/list}}", Ctx);735  std::string Out;736  raw_string_ostream OS(Out);737  T.render(D, OS);738  EXPECT_EQ("(&amp;)(&quot;)(&lt;)(&gt;)", Out);739}740 741TEST(MustacheSections, ImplicitIteratorAmpersand) {742  Value D = Object{{"list", Array{"&", "\"", "<", ">"}}};743  BumpPtrAllocator Allocator;744  StringSaver Saver(Allocator);745  MustacheContext Ctx(Allocator, Saver);746  Template T("{{#list}}({{&.}}){{/list}}", Ctx);747  std::string Out;748  raw_string_ostream OS(Out);749  T.render(D, OS);750  EXPECT_EQ("(&)(\")(<)(>)", Out);751}752 753TEST(MustacheSections, ImplicitIteratorRootLevel) {754  Value D = Array{Object{{"value", "a"}}, Object{{"value", "b"}}};755  BumpPtrAllocator Allocator;756  StringSaver Saver(Allocator);757  MustacheContext Ctx(Allocator, Saver);758  Template T("{{#.}}({{value}}){{/.}}", Ctx);759  std::string Out;760  raw_string_ostream OS(Out);761  T.render(D, OS);762  EXPECT_EQ("(a)(b)", Out);763}764 765TEST(MustacheSections, DottedNamesTruthy) {766  Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};767  BumpPtrAllocator Allocator;768  StringSaver Saver(Allocator);769  MustacheContext Ctx(Allocator, Saver);770  Template T("{{#a.b.c}}Here{{/a.b.c}} == Here", Ctx);771  std::string Out;772  raw_string_ostream OS(Out);773  T.render(D, OS);774  EXPECT_EQ("Here == Here", Out);775}776 777TEST(MustacheSections, DottedNamesFalsey) {778  Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};779  BumpPtrAllocator Allocator;780  StringSaver Saver(Allocator);781  MustacheContext Ctx(Allocator, Saver);782  Template T("{{#a.b.c}}Here{{/a.b.c}} == ", Ctx);783  std::string Out;784  raw_string_ostream OS(Out);785  T.render(D, OS);786  EXPECT_EQ(" == ", Out);787}788 789TEST(MustacheSections, DottedNamesBrokenChains) {790  Value D = Object{{"a", Object{{}}}};791  BumpPtrAllocator Allocator;792  StringSaver Saver(Allocator);793  MustacheContext Ctx(Allocator, Saver);794  Template T("{{#a.b.c}}Here{{/a.b.c}} == ", Ctx);795  std::string Out;796  raw_string_ostream OS(Out);797  T.render(D, OS);798  EXPECT_EQ(" == ", Out);799}800 801TEST(MustacheSections, SurroundingWhitespace) {802  Value D = Object{{"boolean", true}};803  BumpPtrAllocator Allocator;804  StringSaver Saver(Allocator);805  MustacheContext Ctx(Allocator, Saver);806  Template T(" | {{#boolean}}\t|\t{{/boolean}} | \n", Ctx);807  std::string Out;808  raw_string_ostream OS(Out);809  T.render(D, OS);810  EXPECT_EQ(" | \t|\t | \n", Out);811}812 813TEST(MustacheSections, InternalWhitespace) {814  Value D = Object{{"boolean", true}};815  BumpPtrAllocator Allocator;816  StringSaver Saver(Allocator);817  MustacheContext Ctx(Allocator, Saver);818  Template T(" | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n",819             Ctx);820  std::string Out;821  raw_string_ostream OS(Out);822  T.render(D, OS);823  EXPECT_EQ(" |  \n  | \n", Out);824}825 826TEST(MustacheSections, IndentedInlineSections) {827  Value D = Object{{"boolean", true}};828  BumpPtrAllocator Allocator;829  StringSaver Saver(Allocator);830  MustacheContext Ctx(Allocator, Saver);831  Template T(" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n",832             Ctx);833  std::string Out;834  raw_string_ostream OS(Out);835  T.render(D, OS);836  EXPECT_EQ(" YES\n GOOD\n", Out);837}838 839TEST(MustacheSections, StandaloneLines) {840  Value D = Object{{"boolean", true}};841  BumpPtrAllocator Allocator;842  StringSaver Saver(Allocator);843  MustacheContext Ctx(Allocator, Saver);844  Template T("| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n", Ctx);845  std::string Out;846  raw_string_ostream OS(Out);847  T.render(D, OS);848  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);849}850 851TEST(MustacheSections, IndentedStandaloneLines) {852  Value D = Object{{"boolean", true}};853  BumpPtrAllocator Allocator;854  StringSaver Saver(Allocator);855  MustacheContext Ctx(Allocator, Saver);856  Template T("| This Is\n  {{#boolean}}\n|\n  {{/boolean}}\n| A Line\n", Ctx);857  std::string Out;858  raw_string_ostream OS(Out);859  T.render(D, OS);860  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);861}862 863TEST(MustacheSections, StandaloneLineEndings) {864  Value D = Object{{"boolean", true}};865  BumpPtrAllocator Allocator;866  StringSaver Saver(Allocator);867  MustacheContext Ctx(Allocator, Saver);868  Template T("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|", Ctx);869  std::string Out;870  raw_string_ostream OS(Out);871  T.render(D, OS);872  EXPECT_EQ("|\r\n|", Out);873}874 875TEST(MustacheSections, StandaloneWithoutPreviousLine) {876  Value D = Object{{"boolean", true}};877  BumpPtrAllocator Allocator;878  StringSaver Saver(Allocator);879  MustacheContext Ctx(Allocator, Saver);880  Template T("  {{#boolean}}\n#{{/boolean}}\n/", Ctx);881  std::string Out;882  raw_string_ostream OS(Out);883  T.render(D, OS);884  EXPECT_EQ("#\n/", Out);885}886 887TEST(MustacheSections, StandaloneWithoutNewline) {888  Value D = Object{{"boolean", true}};889  BumpPtrAllocator Allocator;890  StringSaver Saver(Allocator);891  MustacheContext Ctx(Allocator, Saver);892  Template T("#{{#boolean}}\n/\n  {{/boolean}}", Ctx);893  std::string Out;894  raw_string_ostream OS(Out);895  T.render(D, OS);896  EXPECT_EQ("#\n/\n", Out);897}898 899TEST(MustacheSections, Padding) {900  Value D = Object{{"boolean", true}};901  BumpPtrAllocator Allocator;902  StringSaver Saver(Allocator);903  MustacheContext Ctx(Allocator, Saver);904  Template T("|{{# boolean }}={{/ boolean }}|", Ctx);905  std::string Out;906  raw_string_ostream OS(Out);907  T.render(D, OS);908  EXPECT_EQ("|=|", Out);909}910 911TEST(MustacheInvertedSections, Falsey) {912  Value D = Object{{"boolean", false}};913  BumpPtrAllocator Allocator;914  StringSaver Saver(Allocator);915  MustacheContext Ctx(Allocator, Saver);916  Template T("{{^boolean}}This should be rendered.{{/boolean}}", Ctx);917  std::string Out;918  raw_string_ostream OS(Out);919  T.render(D, OS);920  EXPECT_EQ("This should be rendered.", Out);921}922 923TEST(MustacheInvertedSections, Truthy) {924  Value D = Object{{"boolean", true}};925  BumpPtrAllocator Allocator;926  StringSaver Saver(Allocator);927  MustacheContext Ctx(Allocator, Saver);928  Template T("{{^boolean}}This should not be rendered.{{/boolean}}", Ctx);929  std::string Out;930  raw_string_ostream OS(Out);931  T.render(D, OS);932  EXPECT_EQ("", Out);933}934 935TEST(MustacheInvertedSections, NullIsFalsey) {936  Value D = Object{{"null", nullptr}};937  BumpPtrAllocator Allocator;938  StringSaver Saver(Allocator);939  MustacheContext Ctx(Allocator, Saver);940  Template T("{{^null}}This should be rendered.{{/null}}", Ctx);941  std::string Out;942  raw_string_ostream OS(Out);943  T.render(D, OS);944  EXPECT_EQ("This should be rendered.", Out);945}946 947TEST(MustacheInvertedSections, Context) {948  Value D = Object{{"context", Object{{"name", "Joe"}}}};949  BumpPtrAllocator Allocator;950  StringSaver Saver(Allocator);951  MustacheContext Ctx(Allocator, Saver);952  Template T("{{^context}}Hi {{name}}.{{/context}}", Ctx);953  std::string Out;954  raw_string_ostream OS(Out);955  T.render(D, OS);956  EXPECT_EQ("", Out);957}958 959TEST(MustacheInvertedSections, List) {960  Value D = Object{961      {"list", Array{Object{{"n", 1}}, Object{{"n", 2}}, Object{{"n", 3}}}}};962  BumpPtrAllocator Allocator;963  StringSaver Saver(Allocator);964  MustacheContext Ctx(Allocator, Saver);965  Template T("{{^list}}{{n}}{{/list}}", Ctx);966  std::string Out;967  raw_string_ostream OS(Out);968  T.render(D, OS);969  EXPECT_EQ("", Out);970}971 972TEST(MustacheInvertedSections, EmptyList) {973  Value D = Object{{"list", Array{}}};974  BumpPtrAllocator Allocator;975  StringSaver Saver(Allocator);976  MustacheContext Ctx(Allocator, Saver);977  Template T("{{^list}}Yay lists!{{/list}}", Ctx);978  std::string Out;979  raw_string_ostream OS(Out);980  T.render(D, OS);981  EXPECT_EQ("Yay lists!", Out);982}983 984TEST(MustacheInvertedSections, Doubled) {985  Value D = Object{{"bool", false}, {"two", "second"}};986  BumpPtrAllocator Allocator;987  StringSaver Saver(Allocator);988  MustacheContext Ctx(Allocator, Saver);989  Template T("{{^bool}}\n* first\n{{/bool}}\n* "990             "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n",991             Ctx);992  std::string Out;993  raw_string_ostream OS(Out);994  T.render(D, OS);995  EXPECT_EQ("* first\n* second\n* third\n", Out);996}997 998TEST(MustacheInvertedSections, NestedFalsey) {999  Value D = Object{{"bool", false}};1000  BumpPtrAllocator Allocator;1001  StringSaver Saver(Allocator);1002  MustacheContext Ctx(Allocator, Saver);1003  Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |", Ctx);1004  std::string Out;1005  raw_string_ostream OS(Out);1006  T.render(D, OS);1007  EXPECT_EQ("| A B C D E |", Out);1008}1009 1010TEST(MustacheInvertedSections, NestedTruthy) {1011  Value D = Object{{"bool", true}};1012  BumpPtrAllocator Allocator;1013  StringSaver Saver(Allocator);1014  MustacheContext Ctx(Allocator, Saver);1015  Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |", Ctx);1016  std::string Out;1017  raw_string_ostream OS(Out);1018  T.render(D, OS);1019  EXPECT_EQ("| A  E |", Out);1020}1021 1022TEST(MustacheInvertedSections, ContextMisses) {1023  Value D = Object{};1024  BumpPtrAllocator Allocator;1025  StringSaver Saver(Allocator);1026  MustacheContext Ctx(Allocator, Saver);1027  Template T("[{{^missing}}Cannot find key 'missing'!{{/missing}}]", Ctx);1028  std::string Out;1029  raw_string_ostream OS(Out);1030  T.render(D, OS);1031  EXPECT_EQ("[Cannot find key 'missing'!]", Out);1032}1033 1034TEST(MustacheInvertedSections, DottedNamesTruthy) {1035  Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}};1036  BumpPtrAllocator Allocator;1037  StringSaver Saver(Allocator);1038  MustacheContext Ctx(Allocator, Saver);1039  Template T("{{^a.b.c}}Not Here{{/a.b.c}} == ", Ctx);1040  std::string Out;1041  raw_string_ostream OS(Out);1042  T.render(D, OS);1043  EXPECT_EQ(" == ", Out);1044}1045 1046TEST(MustacheInvertedSections, DottedNamesFalsey) {1047  Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}};1048  BumpPtrAllocator Allocator;1049  StringSaver Saver(Allocator);1050  MustacheContext Ctx(Allocator, Saver);1051  Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here", Ctx);1052  std::string Out;1053  raw_string_ostream OS(Out);1054  T.render(D, OS);1055  EXPECT_EQ("Not Here == Not Here", Out);1056}1057 1058TEST(MustacheInvertedSections, DottedNamesBrokenChains) {1059  Value D = Object{{"a", Object{}}};1060  BumpPtrAllocator Allocator;1061  StringSaver Saver(Allocator);1062  MustacheContext Ctx(Allocator, Saver);1063  Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here", Ctx);1064  std::string Out;1065  raw_string_ostream OS(Out);1066  T.render(D, OS);1067  EXPECT_EQ("Not Here == Not Here", Out);1068}1069 1070TEST(MustacheInvertedSections, SurroundingWhitespace) {1071  Value D = Object{{"boolean", false}};1072  BumpPtrAllocator Allocator;1073  StringSaver Saver(Allocator);1074  MustacheContext Ctx(Allocator, Saver);1075  Template T(" | {{^boolean}}\t|\t{{/boolean}} | \n", Ctx);1076  std::string Out;1077  raw_string_ostream OS(Out);1078  T.render(D, OS);1079  EXPECT_EQ(" | \t|\t | \n", Out);1080}1081 1082TEST(MustacheInvertedSections, InternalWhitespace) {1083  Value D = Object{{"boolean", false}};1084  BumpPtrAllocator Allocator;1085  StringSaver Saver(Allocator);1086  MustacheContext Ctx(Allocator, Saver);1087  Template T(" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n",1088             Ctx);1089  std::string Out;1090  raw_string_ostream OS(Out);1091  T.render(D, OS);1092  EXPECT_EQ(" |  \n  | \n", Out);1093}1094 1095TEST(MustacheInvertedSections, IndentedInlineSections) {1096  Value D = Object{{"boolean", false}};1097  BumpPtrAllocator Allocator;1098  StringSaver Saver(Allocator);1099  MustacheContext Ctx(Allocator, Saver);1100  Template T(" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n",1101             Ctx);1102  std::string Out;1103  raw_string_ostream OS(Out);1104  T.render(D, OS);1105  EXPECT_EQ(" NO\n WAY\n", Out);1106}1107 1108TEST(MustacheInvertedSections, StandaloneLines) {1109  Value D = Object{{"boolean", false}};1110  BumpPtrAllocator Allocator;1111  StringSaver Saver(Allocator);1112  MustacheContext Ctx(Allocator, Saver);1113  Template T("| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n", Ctx);1114  std::string Out;1115  raw_string_ostream OS(Out);1116  T.render(D, OS);1117  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);1118}1119 1120TEST(MustacheInvertedSections, StandaloneIndentedLines) {1121  Value D = Object{{"boolean", false}};1122  BumpPtrAllocator Allocator;1123  StringSaver Saver(Allocator);1124  MustacheContext Ctx(Allocator, Saver);1125  Template T("| This Is\n  {{^boolean}}\n|\n  {{/boolean}}\n| A Line\n", Ctx);1126  std::string Out;1127  raw_string_ostream OS(Out);1128  T.render(D, OS);1129  EXPECT_EQ("| This Is\n|\n| A Line\n", Out);1130}1131 1132TEST(MustacheInvertedSections, StandaloneLineEndings) {1133  Value D = Object{{"boolean", false}};1134  BumpPtrAllocator Allocator;1135  StringSaver Saver(Allocator);1136  MustacheContext Ctx(Allocator, Saver);1137  Template T("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|", Ctx);1138  std::string Out;1139  raw_string_ostream OS(Out);1140  T.render(D, OS);1141  EXPECT_EQ("|\r\n|", Out);1142}1143 1144TEST(MustacheInvertedSections, StandaloneWithoutPreviousLine) {1145  Value D = Object{{"boolean", false}};1146  BumpPtrAllocator Allocator;1147  StringSaver Saver(Allocator);1148  MustacheContext Ctx(Allocator, Saver);1149  Template T("  {{^boolean}}\n^{{/boolean}}\n/", Ctx);1150  std::string Out;1151  raw_string_ostream OS(Out);1152  T.render(D, OS);1153  EXPECT_EQ("^\n/", Out);1154}1155 1156TEST(MustacheInvertedSections, StandaloneWithoutNewline) {1157  Value D = Object{{"boolean", false}};1158  BumpPtrAllocator Allocator;1159  StringSaver Saver(Allocator);1160  MustacheContext Ctx(Allocator, Saver);1161  Template T("^{{^boolean}}\n/\n  {{/boolean}}", Ctx);1162  std::string Out;1163  raw_string_ostream OS(Out);1164  T.render(D, OS);1165  EXPECT_EQ("^\n/\n", Out);1166}1167 1168TEST(MustacheInvertedSections, Padding) {1169  Value D = Object{{"boolean", false}};1170  BumpPtrAllocator Allocator;1171  StringSaver Saver(Allocator);1172  MustacheContext Ctx(Allocator, Saver);1173  Template T("|{{^ boolean }}={{/ boolean }}|", Ctx);1174  std::string Out;1175  raw_string_ostream OS(Out);1176  T.render(D, OS);1177  EXPECT_EQ("|=|", Out);1178}1179 1180TEST(MustachePartials, BasicBehavior) {1181  Value D = Object{};1182  BumpPtrAllocator Allocator;1183  StringSaver Saver(Allocator);1184  MustacheContext Ctx(Allocator, Saver);1185  Template T("{{>text}}", Ctx);1186  T.registerPartial("text", "from partial");1187  std::string Out;1188  raw_string_ostream OS(Out);1189  T.render(D, OS);1190  EXPECT_EQ("from partial", Out);1191}1192 1193TEST(MustachePartials, FailedLookup) {1194  Value D = Object{};1195  BumpPtrAllocator Allocator;1196  StringSaver Saver(Allocator);1197  MustacheContext Ctx(Allocator, Saver);1198  Template T("{{>text}}", Ctx);1199  std::string Out;1200  raw_string_ostream OS(Out);1201  T.render(D, OS);1202  EXPECT_EQ("", Out);1203}1204 1205TEST(MustachePartials, Context) {1206  Value D = Object{{"text", "content"}};1207  BumpPtrAllocator Allocator;1208  StringSaver Saver(Allocator);1209  MustacheContext Ctx(Allocator, Saver);1210  Template T("{{>partial}}", Ctx);1211  T.registerPartial("partial", "*{{text}}*");1212  std::string Out;1213  raw_string_ostream OS(Out);1214  T.render(D, OS);1215  EXPECT_EQ("*content*", Out);1216}1217 1218TEST(MustachePartials, Recursion) {1219  Value D =1220      Object{{"content", "X"},1221             {"nodes", Array{Object{{"content", "Y"}, {"nodes", Array{}}}}}};1222  BumpPtrAllocator Allocator;1223  StringSaver Saver(Allocator);1224  MustacheContext Ctx(Allocator, Saver);1225  Template T("{{>node}}", Ctx);1226  T.registerPartial("node", "{{content}}({{#nodes}}{{>node}}{{/nodes}})");1227  std::string Out;1228  raw_string_ostream OS(Out);1229  T.render(D, OS);1230  EXPECT_EQ("X(Y())", Out);1231}1232 1233TEST(MustachePartials, Nested) {1234  Value D = Object{{"a", "hello"}, {"b", "world"}};1235  BumpPtrAllocator Allocator;1236  StringSaver Saver(Allocator);1237  MustacheContext Ctx(Allocator, Saver);1238  Template T("{{>outer}}", Ctx);1239  T.registerPartial("outer", "*{{a}} {{>inner}}*");1240  T.registerPartial("inner", "{{b}}!");1241  std::string Out;1242  raw_string_ostream OS(Out);1243  T.render(D, OS);1244  EXPECT_EQ("*hello world!*", Out);1245}1246 1247TEST(MustachePartials, SurroundingWhitespace) {1248  Value D = Object{};1249  BumpPtrAllocator Allocator;1250  StringSaver Saver(Allocator);1251  MustacheContext Ctx(Allocator, Saver);1252  Template T("| {{>partial}} |", Ctx);1253  T.registerPartial("partial", "\t|\t");1254  std::string Out;1255  raw_string_ostream OS(Out);1256  T.render(D, OS);1257  EXPECT_EQ("| \t|\t |", Out);1258}1259 1260TEST(MustachePartials, InlineIndentation) {1261  Value D = Object{{"data", "|"}};1262  BumpPtrAllocator Allocator;1263  StringSaver Saver(Allocator);1264  MustacheContext Ctx(Allocator, Saver);1265  Template T("  {{data}}  {{> partial}}\n", Ctx);1266  T.registerPartial("partial", "<\n<");1267  std::string Out;1268  raw_string_ostream OS(Out);1269  T.render(D, OS);1270  EXPECT_EQ("  |  <\n<\n", Out);1271}1272 1273TEST(MustachePartials, PaddingWhitespace) {1274  Value D = Object{{"boolean", true}};1275  BumpPtrAllocator Allocator;1276  StringSaver Saver(Allocator);1277  MustacheContext Ctx(Allocator, Saver);1278  Template T("|{{> partial }}|", Ctx);1279  T.registerPartial("partial", "[]");1280  std::string Out;1281  raw_string_ostream OS(Out);1282  T.render(D, OS);1283  EXPECT_EQ("|[]|", Out);1284}1285 1286TEST(MustachePartials, StandaloneIndentation) {1287  BumpPtrAllocator Allocator;1288  StringSaver Saver(Allocator);1289  MustacheContext Ctx(Allocator, Saver);1290  mustache::Template T("\\\n {{>partial}}\n/\n", Ctx);1291  T.registerPartial("partial", "|\n{{{content}}}\n|\n");1292  std::string O;1293  raw_string_ostream OS(O);1294  Value DataContext = Object{{"content", "<\n->"}};1295  T.render(DataContext, OS);1296  EXPECT_EQ("\\\n |\n <\n->\n |\n/\n", OS.str());1297}1298 1299TEST(MustacheLambdas, BasicInterpolation) {1300  Value D = Object{};1301  BumpPtrAllocator Allocator;1302  StringSaver Saver(Allocator);1303  MustacheContext Ctx(Allocator, Saver);1304  Template T("Hello, {{lambda}}!", Ctx);1305  Lambda L = []() -> llvm::json::Value { return "World"; };1306  T.registerLambda("lambda", L);1307  std::string Out;1308  raw_string_ostream OS(Out);1309  T.render(D, OS);1310  EXPECT_EQ("Hello, World!", Out);1311}1312 1313TEST(MustacheLambdas, InterpolationExpansion) {1314  Value D = Object{{"planet", "World"}};1315  BumpPtrAllocator Allocator;1316  StringSaver Saver(Allocator);1317  MustacheContext Ctx(Allocator, Saver);1318  Template T("Hello, {{lambda}}!", Ctx);1319  Lambda L = []() -> llvm::json::Value { return "{{planet}}"; };1320  T.registerLambda("lambda", L);1321  std::string Out;1322  raw_string_ostream OS(Out);1323  T.render(D, OS);1324  EXPECT_EQ("Hello, World!", Out);1325}1326 1327TEST(MustacheLambdas, BasicMultipleCalls) {1328  Value D = Object{};1329  BumpPtrAllocator Allocator;1330  StringSaver Saver(Allocator);1331  MustacheContext Ctx(Allocator, Saver);1332  Template T("{{lambda}} == {{lambda}} == {{lambda}}", Ctx);1333  int I = 0;1334  Lambda L = [&I]() -> llvm::json::Value {1335    I += 1;1336    return I;1337  };1338  T.registerLambda("lambda", L);1339  std::string Out;1340  raw_string_ostream OS(Out);1341  T.render(D, OS);1342  EXPECT_EQ("1 == 2 == 3", Out);1343}1344 1345TEST(MustacheLambdas, Escaping) {1346  Value D = Object{};1347  BumpPtrAllocator Allocator;1348  StringSaver Saver(Allocator);1349  MustacheContext Ctx(Allocator, Saver);1350  Template T("<{{lambda}}{{&lambda}}", Ctx);1351  Lambda L = []() -> llvm::json::Value { return ">"; };1352  T.registerLambda("lambda", L);1353  std::string Out;1354  raw_string_ostream OS(Out);1355  T.render(D, OS);1356  EXPECT_EQ("<&gt;>", Out);1357}1358 1359TEST(MustacheLambdas, Sections) {1360  Value D = Object{};1361  BumpPtrAllocator Allocator;1362  StringSaver Saver(Allocator);1363  MustacheContext Ctx(Allocator, Saver);1364  Template T("<{{#lambda}}{{x}}{{/lambda}}>", Ctx);1365  SectionLambda L = [](StringRef Text) -> llvm::json::Value {1366    if (Text == "{{x}}") {1367      return "yes";1368    }1369    return "no";1370  };1371  T.registerLambda("lambda", L);1372  std::string Out;1373  raw_string_ostream OS(Out);1374  T.render(D, OS);1375  EXPECT_EQ("<yes>", Out);1376}1377 1378TEST(MustacheLambdas, SectionExpansion) {1379  Value D = Object{1380      {"planet", "Earth"},1381  };1382  BumpPtrAllocator Allocator;1383  StringSaver Saver(Allocator);1384  MustacheContext Ctx(Allocator, Saver);1385  Template T("<{{#lambda}}-{{/lambda}}>", Ctx);1386  SectionLambda L = [](StringRef Text) -> llvm::json::Value {1387    SmallString<128> Result;1388    Result += Text;1389    Result += "{{planet}}";1390    Result += Text;1391    return Result;1392  };1393  T.registerLambda("lambda", L);1394  std::string Out;1395  raw_string_ostream OS(Out);1396  T.render(D, OS);1397  EXPECT_EQ("<-Earth->", Out);1398}1399 1400TEST(MustacheLambdas, SectionsMultipleCalls) {1401  Value D = Object{};1402  BumpPtrAllocator Allocator;1403  StringSaver Saver(Allocator);1404  MustacheContext Ctx(Allocator, Saver);1405  Template T("{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}", Ctx);1406  SectionLambda L = [](StringRef Text) -> llvm::json::Value {1407    SmallString<128> Result;1408    Result += "__";1409    Result += Text;1410    Result += "__";1411    return Result;1412  };1413  T.registerLambda("lambda", L);1414  std::string Out;1415  raw_string_ostream OS(Out);1416  T.render(D, OS);1417  EXPECT_EQ("__FILE__ != __LINE__", Out);1418}1419 1420TEST(MustacheLambdas, InvertedSections) {1421  Value D = Object{{"static", "static"}};1422  BumpPtrAllocator Allocator;1423  StringSaver Saver(Allocator);1424  MustacheContext Ctx(Allocator, Saver);1425  Template T("<{{^lambda}}{{static}}{{/lambda}}>", Ctx);1426  SectionLambda L = [](StringRef Text) -> llvm::json::Value { return false; };1427  T.registerLambda("lambda", L);1428  std::string Out;1429  raw_string_ostream OS(Out);1430  T.render(D, OS);1431  EXPECT_EQ("<>", Out);1432}1433 1434TEST(MustacheComments, Inline) {1435  // Comment blocks should be removed from the template.1436  Value D = {};1437  BumpPtrAllocator Allocator;1438  StringSaver Saver(Allocator);1439  MustacheContext Ctx(Allocator, Saver);1440  Template T("12345{{! Comment Block! }}67890", Ctx);1441  std::string Out;1442  raw_string_ostream OS(Out);1443  T.render(D, OS);1444  EXPECT_EQ("1234567890", Out);1445}1446 1447TEST(MustacheComments, Multiline) {1448  // Multiline comments should be permitted.1449  Value D = {};1450  BumpPtrAllocator Allocator;1451  StringSaver Saver(Allocator);1452  MustacheContext Ctx(Allocator, Saver);1453  Template T("12345{{!\n  This is a\n  multi-line comment...\n}}67890\n", Ctx);1454  std::string Out;1455  raw_string_ostream OS(Out);1456  T.render(D, OS);1457  EXPECT_EQ("1234567890\n", Out);1458}1459 1460TEST(MustacheComments, Standalone) {1461  // All standalone comment lines should be removed.1462  Value D = {};1463  BumpPtrAllocator Allocator;1464  StringSaver Saver(Allocator);1465  MustacheContext Ctx(Allocator, Saver);1466  Template T("Begin.\n{{! Comment Block! }}\nEnd.\n", Ctx);1467  std::string Out;1468  raw_string_ostream OS(Out);1469  T.render(D, OS);1470  EXPECT_EQ("Begin.\nEnd.\n", Out);1471}1472 1473TEST(MustacheComments, IndentedStandalone) {1474  // All standalone comment lines should be removed.1475  Value D = {};1476  BumpPtrAllocator Allocator;1477  StringSaver Saver(Allocator);1478  MustacheContext Ctx(Allocator, Saver);1479  Template T("Begin.\n  {{! Indented Comment Block! }}\nEnd.\n", Ctx);1480  std::string Out;1481  raw_string_ostream OS(Out);1482  T.render(D, OS);1483  EXPECT_EQ("Begin.\nEnd.\n", Out);1484}1485 1486TEST(MustacheComments, StandaloneLineEndings) {1487  // "\r\n" should be considered a newline for standalone tags.1488  Value D = {};1489  BumpPtrAllocator Allocator;1490  StringSaver Saver(Allocator);1491  MustacheContext Ctx(Allocator, Saver);1492  Template T("|\r\n{{! Standalone Comment }}\r\n|", Ctx);1493  std::string Out;1494  raw_string_ostream OS(Out);1495  T.render(D, OS);1496  EXPECT_EQ("|\r\n|", Out);1497}1498 1499TEST(MustacheComments, StandaloneWithoutPreviousLine) {1500  // Standalone tags should not require a newline to precede them.1501  Value D = {};1502  BumpPtrAllocator Allocator;1503  StringSaver Saver(Allocator);1504  MustacheContext Ctx(Allocator, Saver);1505  Template T("  {{! I'm Still Standalone }}\n!", Ctx);1506  std::string Out;1507  raw_string_ostream OS(Out);1508  T.render(D, OS);1509  EXPECT_EQ("!", Out);1510}1511 1512TEST(MustacheComments, StandaloneWithoutNewline) {1513  // Standalone tags should not require a newline to follow them.1514  Value D = {};1515  BumpPtrAllocator Allocator;1516  StringSaver Saver(Allocator);1517  MustacheContext Ctx(Allocator, Saver);1518  Template T("!\n  {{! I'm Still Standalone }}", Ctx);1519  std::string Out;1520  raw_string_ostream OS(Out);1521  T.render(D, OS);1522  EXPECT_EQ("!\n", Out);1523}1524 1525TEST(MustacheComments, MultilineStandalone) {1526  // All standalone comment lines should be removed.1527  Value D = {};1528  BumpPtrAllocator Allocator;1529  StringSaver Saver(Allocator);1530  MustacheContext Ctx(Allocator, Saver);1531  Template T("Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n", Ctx);1532  std::string Out;1533  raw_string_ostream OS(Out);1534  T.render(D, OS);1535  EXPECT_EQ("Begin.\nEnd.\n", Out);1536}1537 1538TEST(MustacheComments, IndentedMultilineStandalone) {1539  // All standalone comment lines should be removed.1540  Value D = {};1541  BumpPtrAllocator Allocator;1542  StringSaver Saver(Allocator);1543  MustacheContext Ctx(Allocator, Saver);1544  Template T("Begin.\n  {{!\n    Something's going on here...\n  }}\nEnd.\n",1545             Ctx);1546  std::string Out;1547  raw_string_ostream OS(Out);1548  T.render(D, OS);1549  EXPECT_EQ("Begin.\nEnd.\n", Out);1550}1551 1552TEST(MustacheComments, IndentedInline) {1553  // Inline comments should not strip whitespace.1554  Value D = {};1555  BumpPtrAllocator Allocator;1556  StringSaver Saver(Allocator);1557  MustacheContext Ctx(Allocator, Saver);1558  Template T("  12 {{! 34 }}\n", Ctx);1559  std::string Out;1560  raw_string_ostream OS(Out);1561  T.render(D, OS);1562  EXPECT_EQ("  12 \n", Out);1563}1564 1565TEST(MustacheComments, SurroundingWhitespace) {1566  // Comment removal should preserve surrounding whitespace.1567  Value D = {};1568  BumpPtrAllocator Allocator;1569  StringSaver Saver(Allocator);1570  MustacheContext Ctx(Allocator, Saver);1571  Template T("12345 {{! Comment Block! }} 67890", Ctx);1572  std::string Out;1573  raw_string_ostream OS(Out);1574  T.render(D, OS);1575  EXPECT_EQ("12345  67890", Out);1576}1577 1578TEST(MustacheComments, VariableNameCollision) {1579  // Comments must never render, even if a variable with the same name exists.1580  Value D = Object{1581      {"! comment", 1}, {"! comment ", 2}, {"!comment", 3}, {"comment", 4}};1582  BumpPtrAllocator Allocator;1583  StringSaver Saver(Allocator);1584  MustacheContext Ctx(Allocator, Saver);1585  Template T("comments never show: >{{! comment }}<", Ctx);1586  std::string Out;1587  raw_string_ostream OS(Out);1588  T.render(D, OS);1589  EXPECT_EQ("comments never show: ><", Out);1590}1591 1592// XFAIL: The following tests for the Triple Mustache feature are expected to1593// fail. The assertions have been inverted from EXPECT_EQ to EXPECT_NE to allow1594// them to pass against the current implementation. Once Triple Mustache is1595// implemented, these assertions should be changed back to EXPECT_EQ.1596TEST(MustacheTripleMustache, Basic) {1597  Value D = Object{{"subject", "<b>World</b>"}};1598  BumpPtrAllocator Allocator;1599  StringSaver Saver(Allocator);1600  MustacheContext Ctx(Allocator, Saver);1601  Template T("Hello, {{{subject}}}!", Ctx);1602  std::string Out;1603  raw_string_ostream OS(Out);1604  T.render(D, OS);1605  EXPECT_EQ("Hello, <b>World</b>!", Out);1606}1607 1608TEST(MustacheTripleMustache, IntegerInterpolation) {1609  Value D = Object{{"mph", 85}};1610  BumpPtrAllocator Allocator;1611  StringSaver Saver(Allocator);1612  MustacheContext Ctx(Allocator, Saver);1613  Template T("{{{mph}}} miles an hour!", Ctx);1614  std::string Out;1615  raw_string_ostream OS(Out);1616  T.render(D, OS);1617  EXPECT_EQ("85 miles an hour!", Out);1618}1619 1620TEST(MustacheTripleMustache, DecimalInterpolation) {1621  Value D = Object{{"power", 1.21}};1622  BumpPtrAllocator Allocator;1623  StringSaver Saver(Allocator);1624  MustacheContext Ctx(Allocator, Saver);1625  Template T("{{{power}}} jiggawatts!", Ctx);1626  std::string Out;1627  raw_string_ostream OS(Out);1628  T.render(D, OS);1629  EXPECT_EQ("1.21 jiggawatts!", Out);1630}1631 1632TEST(MustacheTripleMustache, NullInterpolation) {1633  Value D = Object{{"cannot", nullptr}};1634  BumpPtrAllocator Allocator;1635  StringSaver Saver(Allocator);1636  MustacheContext Ctx(Allocator, Saver);1637  Template T("I ({{{cannot}}}) be seen!", Ctx);1638  std::string Out;1639  raw_string_ostream OS(Out);1640  T.render(D, OS);1641  EXPECT_EQ("I () be seen!", Out);1642}1643 1644TEST(MustacheTripleMustache, ContextMissInterpolation) {1645  Value D = Object{};1646  BumpPtrAllocator Allocator;1647  StringSaver Saver(Allocator);1648  MustacheContext Ctx(Allocator, Saver);1649  Template T("I ({{{cannot}}}) be seen!", Ctx);1650  std::string Out;1651  raw_string_ostream OS(Out);1652  T.render(D, OS);1653  EXPECT_EQ("I () be seen!", Out);1654}1655 1656TEST(MustacheTripleMustache, DottedNames) {1657  Value D = Object{{"person", Object{{"name", "<b>Joe</b>"}}}};1658  BumpPtrAllocator Allocator;1659  StringSaver Saver(Allocator);1660  MustacheContext Ctx(Allocator, Saver);1661  Template T("{{{person.name}}}", Ctx);1662  std::string Out;1663  raw_string_ostream OS(Out);1664  T.render(D, OS);1665  EXPECT_EQ("<b>Joe</b>", Out);1666}1667 1668TEST(MustacheTripleMustache, ImplicitIterator) {1669  Value D = Object{{"list", Array{"<a>", "<b>"}}};1670  BumpPtrAllocator Allocator;1671  StringSaver Saver(Allocator);1672  MustacheContext Ctx(Allocator, Saver);1673  Template T("{{#list}}({{{.}}}){{/list}}", Ctx);1674  std::string Out;1675  raw_string_ostream OS(Out);1676  T.render(D, OS);1677  EXPECT_EQ("(<a>)(<b>)", Out);1678}1679 1680TEST(MustacheTripleMustache, SurroundingWhitespace) {1681  Value D = Object{{"string", "---"}};1682  BumpPtrAllocator Allocator;1683  StringSaver Saver(Allocator);1684  MustacheContext Ctx(Allocator, Saver);1685  Template T("| {{{string}}} |", Ctx);1686  std::string Out;1687  raw_string_ostream OS(Out);1688  T.render(D, OS);1689  EXPECT_EQ("| --- |", Out);1690}1691 1692TEST(MustacheTripleMustache, Standalone) {1693  Value D = Object{{"string", "---"}};1694  BumpPtrAllocator Allocator;1695  StringSaver Saver(Allocator);1696  MustacheContext Ctx(Allocator, Saver);1697  Template T("  {{{string}}}\n", Ctx);1698  std::string Out;1699  raw_string_ostream OS(Out);1700  T.render(D, OS);1701  EXPECT_EQ("  ---\n", Out);1702}1703 1704TEST(MustacheTripleMustache, WithPadding) {1705  Value D = Object{{"string", "---"}};1706  BumpPtrAllocator Allocator;1707  StringSaver Saver(Allocator);1708  MustacheContext Ctx(Allocator, Saver);1709  Template T("|{{{ string }}}|", Ctx);1710  std::string Out;1711  raw_string_ostream OS(Out);1712  T.render(D, OS);1713  EXPECT_EQ("|---|", Out);1714}1715 1716TEST(MustacheDelimiters, PairBehavior) {1717  Value D = Object{{"text", "Hey!"}};1718  BumpPtrAllocator Allocator;1719  StringSaver Saver(Allocator);1720  MustacheContext Ctx(Allocator, Saver);1721  Template T("{{=<% %>=}}(<%text%>)", Ctx);1722  std::string Out;1723  raw_string_ostream OS(Out);1724  T.render(D, OS);1725  EXPECT_EQ("(Hey!)", Out);1726}1727 1728TEST(MustacheDelimiters, SpecialCharacters) {1729  Value D = Object{{"text", "It worked!"}};1730  BumpPtrAllocator Allocator;1731  StringSaver Saver(Allocator);1732  MustacheContext Ctx(Allocator, Saver);1733  Template T("({{=[ ]=}}[text])", Ctx);1734  std::string Out;1735  raw_string_ostream OS(Out);1736  T.render(D, OS);1737  EXPECT_EQ("(It worked!)", Out);1738}1739 1740TEST(MustacheDelimiters, Sections) {1741  Value D = Object{{"section", true}, {"data", "I got interpolated."}};1742  BumpPtrAllocator Allocator;1743  StringSaver Saver(Allocator);1744  MustacheContext Ctx(Allocator, Saver);1745  Template T("[\n{{#section}}\n  {{data}}\n  |data|\n{{/section}}\n\n{{= "1746             "| | =}}\n|#section|\n  {{data}}\n  |data|\n|/section|\n]\n",1747             Ctx);1748  std::string Out;1749  raw_string_ostream OS(Out);1750  T.render(D, OS);1751  EXPECT_EQ("[\n  I got interpolated.\n  |data|\n\n  {{data}}\n  I got "1752            "interpolated.\n]\n",1753            Out);1754}1755 1756TEST(MustacheDelimiters, InvertedSections) {1757  Value D = Object{{"section", false}, {"data", "I got interpolated."}};1758  BumpPtrAllocator Allocator;1759  StringSaver Saver(Allocator);1760  MustacheContext Ctx(Allocator, Saver);1761  Template T("[\n{{^section}}\n  {{data}}\n  |data|\n{{/section}}\n\n{{= "1762             "| | =}}\n|^section|\n  {{data}}\n  |data|\n|/section|\n]\n",1763             Ctx);1764  std::string Out;1765  raw_string_ostream OS(Out);1766  T.render(D, OS);1767  EXPECT_EQ("[\n  I got interpolated.\n  |data|\n\n  {{data}}\n  I got "1768            "interpolated.\n]\n",1769            Out);1770}1771 1772TEST(MustacheDelimiters, PartialInheritence) {1773  Value D = Object{{"value", "yes"}};1774  BumpPtrAllocator Allocator;1775  StringSaver Saver(Allocator);1776  MustacheContext Ctx(Allocator, Saver);1777  Template T("[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n", Ctx);1778  T.registerPartial("include", ".{{value}}.");1779  std::string Out;1780  raw_string_ostream OS(Out);1781  T.render(D, OS);1782  EXPECT_EQ("[ .yes. ]\n[ .yes. ]\n", Out);1783}1784 1785TEST(MustacheDelimiters, PostPartialBehavior) {1786  Value D = Object{{"value", "yes"}};1787  BumpPtrAllocator Allocator;1788  StringSaver Saver(Allocator);1789  MustacheContext Ctx(Allocator, Saver);1790  Template T("[ {{>include}} ]\n[ .{{value}}.  .|value|. ]\n", Ctx);1791  T.registerPartial("include", ".{{value}}. {{= | | =}} .|value|.");1792  std::string Out;1793  raw_string_ostream OS(Out);1794  T.render(D, OS);1795  EXPECT_EQ("[ .yes.  .yes. ]\n[ .yes.  .|value|. ]\n", Out);1796}1797 1798TEST(MustacheDelimiters, SurroundingWhitespace) {1799  Value D = Object{};1800  BumpPtrAllocator Allocator;1801  StringSaver Saver(Allocator);1802  MustacheContext Ctx(Allocator, Saver);1803  Template T("| {{=@ @=}} |", Ctx);1804  std::string Out;1805  raw_string_ostream OS(Out);1806  T.render(D, OS);1807  EXPECT_EQ("|  |", Out);1808}1809 1810TEST(MustacheDelimiters, OutlyingWhitespaceInline) {1811  Value D = Object{};1812  BumpPtrAllocator Allocator;1813  StringSaver Saver(Allocator);1814  MustacheContext Ctx(Allocator, Saver);1815  Template T(" | {{=@ @=}}\n", Ctx);1816  std::string Out;1817  raw_string_ostream OS(Out);1818  T.render(D, OS);1819  EXPECT_EQ(" | \n", Out);1820}1821 1822TEST(MustacheDelimiters, StandaloneTag) {1823  Value D = Object{};1824  BumpPtrAllocator Allocator;1825  StringSaver Saver(Allocator);1826  MustacheContext Ctx(Allocator, Saver);1827  Template T("Begin.\n{{=@ @=}}\nEnd.\n", Ctx);1828  std::string Out;1829  raw_string_ostream OS(Out);1830  T.render(D, OS);1831  EXPECT_EQ("Begin.\nEnd.\n", Out);1832}1833 1834TEST(MustacheDelimiters, IndentedStandaloneTag) {1835  Value D = Object{};1836  BumpPtrAllocator Allocator;1837  StringSaver Saver(Allocator);1838  MustacheContext Ctx(Allocator, Saver);1839  Template T("Begin.\n  {{=@ @=}}\nEnd.\n", Ctx);1840  std::string Out;1841  raw_string_ostream OS(Out);1842  T.render(D, OS);1843  EXPECT_EQ("Begin.\nEnd.\n", Out);1844}1845 1846TEST(MustacheDelimiters, StandaloneLineEndings) {1847  Value D = Object{};1848  BumpPtrAllocator Allocator;1849  StringSaver Saver(Allocator);1850  MustacheContext Ctx(Allocator, Saver);1851  Template T("|\r\n{{= @ @ =}}\r\n|", Ctx);1852  std::string Out;1853  raw_string_ostream OS(Out);1854  T.render(D, OS);1855  EXPECT_EQ("|\r\n|", Out);1856}1857 1858TEST(MustacheDelimiters, StandaloneWithoutPreviousLine) {1859  Value D = Object{};1860  BumpPtrAllocator Allocator;1861  StringSaver Saver(Allocator);1862  MustacheContext Ctx(Allocator, Saver);1863  Template T("  {{=@ @=}}\n=", Ctx);1864  std::string Out;1865  raw_string_ostream OS(Out);1866  T.render(D, OS);1867  EXPECT_EQ("=", Out);1868}1869 1870TEST(MustacheDelimiters, StandaloneWithoutNewline) {1871  Value D = Object{};1872  BumpPtrAllocator Allocator;1873  StringSaver Saver(Allocator);1874  MustacheContext Ctx(Allocator, Saver);1875  Template T("=\n  {{=@ @=}}", Ctx);1876  std::string Out;1877  raw_string_ostream OS(Out);1878  T.render(D, OS);1879  EXPECT_EQ("=\n", Out);1880}1881 1882TEST(MustacheDelimiters, PairwithPadding) {1883  Value D = Object{};1884  BumpPtrAllocator Allocator;1885  StringSaver Saver(Allocator);1886  MustacheContext Ctx(Allocator, Saver);1887  Template T("|{{= @   @ =}}|", Ctx);1888  std::string Out;1889  raw_string_ostream OS(Out);1890  T.render(D, OS);1891  EXPECT_EQ("||", Out);1892}1893