diff --git a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp index b37dc272ea156..b4b9322b0500a 100644 --- a/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLMustacheGenerator.cpp @@ -46,7 +46,13 @@ class MustacheHTMLGenerator : public Generator { const ClangDocContext &CDCtx) override; }; -class MustacheTemplateFile : public Template { +class MustacheTemplateFile { + BumpPtrAllocator Allocator; + StringSaver Saver; + MustacheContext Ctx; + Template T; + std::unique_ptr Buffer; + public: static Expected> createMustacheFile(StringRef FileName) { @@ -54,10 +60,8 @@ class MustacheTemplateFile : public Template { MemoryBuffer::getFile(FileName); if (auto EC = BufferOrError.getError()) return createFileOpenError(FileName, EC); - - std::unique_ptr Buffer = std::move(BufferOrError.get()); - StringRef FileContent = Buffer->getBuffer(); - return std::make_unique(FileContent); + return std::make_unique( + std::move(BufferOrError.get())); } Error registerPartialFile(StringRef Name, StringRef FileName) { @@ -68,11 +72,15 @@ class MustacheTemplateFile : public Template { std::unique_ptr Buffer = std::move(BufferOrError.get()); StringRef FileContent = Buffer->getBuffer(); - registerPartial(Name.str(), FileContent.str()); + T.registerPartial(Name.str(), FileContent.str()); return Error::success(); } - MustacheTemplateFile(StringRef TemplateStr) : Template(TemplateStr) {} + void render(json::Value &V, raw_ostream &OS) { T.render(V, OS); } + + MustacheTemplateFile(std::unique_ptr &&B) + : Saver(Allocator), Ctx(Allocator, Saver), T(B->getBuffer(), Ctx), + Buffer(std::move(B)) {} }; static std::unique_ptr NamespaceTemplate = nullptr; diff --git a/llvm/include/llvm/Support/Mustache.h b/llvm/include/llvm/Support/Mustache.h index ee9f40638fd12..83047f2aafff6 100644 --- a/llvm/include/llvm/Support/Mustache.h +++ b/llvm/include/llvm/Support/Mustache.h @@ -71,6 +71,8 @@ #include "Error.h" #include "llvm/ADT/StringMap.h" +#include "llvm/ADT/ilist.h" +#include "llvm/ADT/ilist_node.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/JSON.h" @@ -84,10 +86,15 @@ using Lambda = std::function; using SectionLambda = std::function; class ASTNode; -using AstPtr = std::unique_ptr; +using AstPtr = ASTNode *; using EscapeMap = DenseMap; +using ASTNodeList = iplist; struct MustacheContext { + MustacheContext(BumpPtrAllocator &Allocator, StringSaver &Saver) + : Allocator(Allocator), Saver(Saver) {} + BumpPtrAllocator &Allocator; + StringSaver &Saver; StringMap Partials; StringMap Lambdas; StringMap SectionLambdas; @@ -98,7 +105,7 @@ struct MustacheContext { // and Lambdas that are registered with it. class Template { public: - LLVM_ABI Template(StringRef TemplateStr); + LLVM_ABI Template(StringRef TemplateStr, MustacheContext &Ctx); Template(const Template &) = delete; @@ -110,7 +117,7 @@ class Template { // type. LLVM_ABI ~Template(); - LLVM_ABI Template &operator=(Template &&Other) noexcept; + Template &operator=(Template &&) = delete; LLVM_ABI void render(const llvm::json::Value &Data, llvm::raw_ostream &OS); @@ -126,7 +133,7 @@ class Template { LLVM_ABI void overrideEscapeCharacters(DenseMap Escapes); private: - MustacheContext Ctx; + MustacheContext &Ctx; AstPtr Tree; }; } // namespace llvm::mustache diff --git a/llvm/lib/Support/Mustache.cpp b/llvm/lib/Support/Mustache.cpp index 4fc807b800f52..ab6af1138f902 100644 --- a/llvm/lib/Support/Mustache.cpp +++ b/llvm/lib/Support/Mustache.cpp @@ -21,7 +21,7 @@ using namespace llvm::mustache; namespace { -using Accessor = SmallVector; +using Accessor = ArrayRef; static bool isFalsey(const json::Value &V) { return V.getAsNull() || (V.getAsBoolean() && !V.getAsBoolean().value()) || @@ -35,23 +35,32 @@ static bool isContextFalsey(const json::Value *V) { return isFalsey(*V); } -static Accessor splitMustacheString(StringRef Str) { +static Accessor splitMustacheString(StringRef Str, MustacheContext &Ctx) { // We split the mustache string into an accessor. // For example: // "a.b.c" would be split into {"a", "b", "c"} // We make an exception for a single dot which // refers to the current context. - Accessor Tokens; + SmallVector Tokens; if (Str == ".") { - Tokens.emplace_back(Str); - return Tokens; - } - while (!Str.empty()) { - StringRef Part; - std::tie(Part, Str) = Str.split("."); - Tokens.emplace_back(Part.trim()); + // "." is a special accessor that refers to the current context. + // It's a literal, so it doesn't need to be saved. + Tokens.push_back("."); + } else { + while (!Str.empty()) { + StringRef Part; + std::tie(Part, Str) = Str.split('.'); + // Each part of the accessor needs to be saved to the arena + // to ensure it has a stable address. + Tokens.push_back(Ctx.Saver.save(Part.trim())); + } } - return Tokens; + // Now, allocate memory for the array of StringRefs in the arena. + StringRef *ArenaTokens = Ctx.Allocator.Allocate(Tokens.size()); + // Copy the StringRefs from the stack vector to the arena. + std::copy(Tokens.begin(), Tokens.end(), ArenaTokens); + // Return an ArrayRef pointing to the stable arena memory. + return ArrayRef(ArenaTokens, Tokens.size()); } } // namespace @@ -98,23 +107,23 @@ class Token { SetDelimiter, }; - Token(std::string Str) - : TokenType(Type::Text), RawBody(std::move(Str)), TokenBody(RawBody), + Token(StringRef Str) + : TokenType(Type::Text), RawBody(Str), TokenBody(RawBody), AccessorValue({}), Indentation(0) {}; - Token(std::string RawBody, std::string TokenBody, char Identifier) - : RawBody(std::move(RawBody)), TokenBody(std::move(TokenBody)), - Indentation(0) { + Token(StringRef RawBody, StringRef TokenBody, char Identifier, + MustacheContext &Ctx) + : RawBody(RawBody), TokenBody(TokenBody), Indentation(0) { TokenType = getTokenType(Identifier); if (TokenType == Type::Comment) return; StringRef AccessorStr(this->TokenBody); if (TokenType != Type::Variable) AccessorStr = AccessorStr.substr(1); - AccessorValue = splitMustacheString(StringRef(AccessorStr).trim()); + AccessorValue = splitMustacheString(StringRef(AccessorStr).trim(), Ctx); } - Accessor getAccessor() const { return AccessorValue; } + ArrayRef getAccessor() const { return AccessorValue; } Type getType() const { return TokenType; } @@ -145,16 +154,16 @@ class Token { Type TokenType; // RawBody is the original string that was tokenized. - std::string RawBody; + StringRef RawBody; // TokenBody is the original string with the identifier removed. - std::string TokenBody; - Accessor AccessorValue; + StringRef TokenBody; + ArrayRef AccessorValue; size_t Indentation; }; using EscapeMap = DenseMap; -class ASTNode { +class ASTNode : public ilist_node { public: enum Type { Root, @@ -169,18 +178,19 @@ class ASTNode { ASTNode(MustacheContext &Ctx) : Ctx(Ctx), Ty(Type::Root), Parent(nullptr), ParentContext(nullptr) {} - ASTNode(MustacheContext &Ctx, std::string Body, ASTNode *Parent) - : Ctx(Ctx), Ty(Type::Text), Body(std::move(Body)), Parent(Parent), + ASTNode(MustacheContext &Ctx, StringRef Body, ASTNode *Parent) + : Ctx(Ctx), Ty(Type::Text), Body(Body), Parent(Parent), ParentContext(nullptr) {} // Constructor for Section/InvertSection/Variable/UnescapeVariable Nodes - ASTNode(MustacheContext &Ctx, Type Ty, Accessor Accessor, ASTNode *Parent) - : Ctx(Ctx), Ty(Ty), Parent(Parent), AccessorValue(std::move(Accessor)), + ASTNode(MustacheContext &Ctx, Type Ty, ArrayRef Accessor, + ASTNode *Parent) + : Ctx(Ctx), Ty(Ty), Parent(Parent), AccessorValue(Accessor), ParentContext(nullptr) {} - void addChild(AstPtr Child) { Children.emplace_back(std::move(Child)); }; + void addChild(AstPtr Child) { Children.push_back(Child); }; - void setRawBody(std::string NewBody) { RawBody = std::move(NewBody); }; + void setRawBody(StringRef NewBody) { RawBody = NewBody; }; void setIndentation(size_t NewIndentation) { Indentation = NewIndentation; }; @@ -213,28 +223,27 @@ class ASTNode { MustacheContext &Ctx; Type Ty; size_t Indentation = 0; - std::string RawBody; - std::string Body; + StringRef RawBody; + StringRef Body; ASTNode *Parent; - // TODO: switch implementation to SmallVector - std::vector Children; - const Accessor AccessorValue; + ASTNodeList Children; + const ArrayRef AccessorValue; const llvm::json::Value *ParentContext; }; // A wrapper for arena allocator for ASTNodes static AstPtr createRootNode(MustacheContext &Ctx) { - return std::make_unique(Ctx); + return new (Ctx.Allocator.Allocate()) ASTNode(Ctx); } -static AstPtr createNode(MustacheContext &Ctx, ASTNode::Type T, Accessor A, - ASTNode *Parent) { - return std::make_unique(Ctx, T, std::move(A), Parent); +static AstPtr createNode(MustacheContext &Ctx, ASTNode::Type T, + ArrayRef A, ASTNode *Parent) { + return new (Ctx.Allocator.Allocate()) ASTNode(Ctx, T, A, Parent); } -static AstPtr createTextNode(MustacheContext &Ctx, std::string Body, +static AstPtr createTextNode(MustacheContext &Ctx, StringRef Body, ASTNode *Parent) { - return std::make_unique(Ctx, std::move(Body), Parent); + return new (Ctx.Allocator.Allocate()) ASTNode(Ctx, Body, Parent); } // Function to check if there is meaningful text behind. @@ -296,9 +305,9 @@ static void stripTokenAhead(SmallVectorImpl &Tokens, size_t Idx) { StringRef NextTokenBody = NextToken.TokenBody; // Cut off the leading newline which could be \n or \r\n. if (NextTokenBody.starts_with("\r\n")) - NextToken.TokenBody = NextTokenBody.substr(2).str(); + NextToken.TokenBody = NextTokenBody.substr(2); else if (NextTokenBody.starts_with("\n")) - NextToken.TokenBody = NextTokenBody.substr(1).str(); + NextToken.TokenBody = NextTokenBody.substr(1); } // Adjust previous token body if there no text behind. @@ -315,7 +324,7 @@ static void stripTokenBefore(SmallVectorImpl &Tokens, size_t Idx, StringRef PrevTokenBody = PrevToken.TokenBody; StringRef Unindented = PrevTokenBody.rtrim(" \r\t\v"); size_t Indentation = PrevTokenBody.size() - Unindented.size(); - PrevToken.TokenBody = Unindented.str(); + PrevToken.TokenBody = Unindented; CurrentToken.setIndentation(Indentation); } @@ -405,21 +414,20 @@ static Tag findNextTag(StringRef Template, size_t StartPos, StringRef Open, } static std::optional> -processTag(const Tag &T, SmallVectorImpl &Tokens) { +processTag(const Tag &T, SmallVectorImpl &Tokens, MustacheContext &Ctx) { LLVM_DEBUG(dbgs() << "[Tag] " << T.FullMatch << ", Content: " << T.Content << ", Kind: " << tagKindToString(T.TagKind) << "\n"); if (T.TagKind == Tag::Kind::Triple) { - Tokens.emplace_back(T.FullMatch.str(), "&" + T.Content.str(), '&'); + Tokens.emplace_back(T.FullMatch, Ctx.Saver.save("&" + T.Content), '&', Ctx); return std::nullopt; } StringRef Interpolated = T.Content; - std::string RawBody = T.FullMatch.str(); if (!Interpolated.trim().starts_with("=")) { char Front = Interpolated.empty() ? ' ' : Interpolated.trim().front(); - Tokens.emplace_back(RawBody, Interpolated.str(), Front); + Tokens.emplace_back(T.FullMatch, Interpolated, Front, Ctx); return std::nullopt; } - Tokens.emplace_back(RawBody, Interpolated.str(), '='); + Tokens.emplace_back(T.FullMatch, Interpolated, '=', Ctx); StringRef DelimSpec = Interpolated.trim(); DelimSpec = DelimSpec.drop_front(1); DelimSpec = DelimSpec.take_until([](char C) { return C == '='; }); @@ -435,7 +443,7 @@ processTag(const Tag &T, SmallVectorImpl &Tokens) { // The mustache spec allows {{{ }}} to unescape variables, // but we don't support that here. An unescape variable // is represented only by {{& variable}}. -static SmallVector tokenize(StringRef Template) { +static SmallVector tokenize(StringRef Template, MustacheContext &Ctx) { LLVM_DEBUG(dbgs() << "[Tokenize Template] \"" << Template << "\"\n"); SmallVector Tokens; SmallString<8> Open("{{"); @@ -449,19 +457,17 @@ static SmallVector tokenize(StringRef Template) { if (T.TagKind == Tag::Kind::None) { // No more tags, the rest is text. - Tokens.emplace_back(Template.substr(Start).str()); - LLVM_DEBUG(dbgs() << " No more tags. Created final Text token: \"" - << Template.substr(Start) << "\"\n"); + Tokens.emplace_back(Template.substr(Start)); break; } // Add the text before the tag. if (T.StartPosition > Start) { StringRef Text = Template.substr(Start, T.StartPosition - Start); - Tokens.emplace_back(Text.str()); + Tokens.emplace_back(Text); } - if (auto NewDelims = processTag(T, Tokens)) { + if (auto NewDelims = processTag(T, Tokens, Ctx)) { std::tie(Open, Close) = *NewDelims; } @@ -602,20 +608,20 @@ void Parser::parseSection(ASTNode *Parent, ASTNode::Type Ty, const Accessor &A) { AstPtr CurrentNode = createNode(Ctx, Ty, A, Parent); size_t Start = CurrentPtr; - parseMustache(CurrentNode.get()); + parseMustache(CurrentNode); const size_t End = CurrentPtr - 1; - std::string RawBody; + SmallString<128> RawBody; for (std::size_t I = Start; I < End; I++) RawBody += Tokens[I].RawBody; - CurrentNode->setRawBody(std::move(RawBody)); - Parent->addChild(std::move(CurrentNode)); + CurrentNode->setRawBody(Ctx.Saver.save(StringRef(RawBody))); + Parent->addChild(CurrentNode); } AstPtr Parser::parse() { - Tokens = tokenize(TemplateStr); + Tokens = tokenize(TemplateStr, Ctx); CurrentPtr = 0; AstPtr RootNode = createRootNode(Ctx); - parseMustache(RootNode.get()); + parseMustache(RootNode); return RootNode; } @@ -624,31 +630,29 @@ void Parser::parseMustache(ASTNode *Parent) { while (CurrentPtr < Tokens.size()) { Token CurrentToken = Tokens[CurrentPtr]; CurrentPtr++; - Accessor A = CurrentToken.getAccessor(); + ArrayRef A = CurrentToken.getAccessor(); AstPtr CurrentNode; switch (CurrentToken.getType()) { case Token::Type::Text: { - CurrentNode = - createTextNode(Ctx, std::move(CurrentToken.TokenBody), Parent); - Parent->addChild(std::move(CurrentNode)); + CurrentNode = createTextNode(Ctx, CurrentToken.TokenBody, Parent); + Parent->addChild(CurrentNode); break; } case Token::Type::Variable: { - CurrentNode = createNode(Ctx, ASTNode::Variable, std::move(A), Parent); - Parent->addChild(std::move(CurrentNode)); + CurrentNode = createNode(Ctx, ASTNode::Variable, A, Parent); + Parent->addChild(CurrentNode); break; } case Token::Type::UnescapeVariable: { - CurrentNode = - createNode(Ctx, ASTNode::UnescapeVariable, std::move(A), Parent); - Parent->addChild(std::move(CurrentNode)); + CurrentNode = createNode(Ctx, ASTNode::UnescapeVariable, A, Parent); + Parent->addChild(CurrentNode); break; } case Token::Type::Partial: { - CurrentNode = createNode(Ctx, ASTNode::Partial, std::move(A), Parent); + CurrentNode = createNode(Ctx, ASTNode::Partial, A, Parent); CurrentNode->setIndentation(CurrentToken.getIndentation()); - Parent->addChild(std::move(CurrentNode)); + Parent->addChild(CurrentNode); break; } case Token::Type::SectionOpen: { @@ -715,7 +719,7 @@ void ASTNode::renderPartial(const json::Value &CurrentCtx, << ", Indentation=" << Indentation << "\n"); auto Partial = Ctx.Partials.find(AccessorValue[0]); if (Partial != Ctx.Partials.end()) - renderPartial(CurrentCtx, OS, Partial->getValue().get()); + renderPartial(CurrentCtx, OS, Partial->getValue()); } void ASTNode::renderVariable(const json::Value &CurrentCtx, @@ -846,8 +850,8 @@ const json::Value *ASTNode::findContext() { void ASTNode::renderChild(const json::Value &Contexts, MustacheOutputStream &OS) { - for (AstPtr &Child : Children) - Child->render(Contexts, OS); + for (ASTNode &Child : Children) + Child.render(Contexts, OS); } void ASTNode::renderPartial(const json::Value &Contexts, @@ -857,7 +861,7 @@ void ASTNode::renderPartial(const json::Value &Contexts, Partial->render(Contexts, IS); } -void ASTNode::renderLambdas(const json::Value &Contexts, +void ASTNode::renderLambdas(const llvm::json::Value &Contexts, MustacheOutputStream &OS, Lambda &L) { json::Value LambdaResult = L(); std::string LambdaStr; @@ -874,9 +878,9 @@ void ASTNode::renderLambdas(const json::Value &Contexts, LambdaNode->render(Contexts, OS); } -void ASTNode::renderSectionLambdas(const json::Value &Contexts, +void ASTNode::renderSectionLambdas(const llvm::json::Value &Contexts, MustacheOutputStream &OS, SectionLambda &L) { - json::Value Return = L(RawBody); + json::Value Return = L(RawBody.str()); if (isFalsey(Return)) return; std::string LambdaStr; @@ -887,15 +891,16 @@ void ASTNode::renderSectionLambdas(const json::Value &Contexts, LambdaNode->render(Contexts, OS); } -void Template::render(const json::Value &Data, llvm::raw_ostream &OS) { +void Template::render(const llvm::json::Value &Data, llvm::raw_ostream &OS) { RawMustacheOutputStream MOS(OS); Tree->render(Data, MOS); } void Template::registerPartial(std::string Name, std::string Partial) { - Parser P(Partial, Ctx); + StringRef SavedPartial = Ctx.Saver.save(Partial); + Parser P(SavedPartial, Ctx); AstPtr PartialTree = P.parse(); - Ctx.Partials.insert(std::make_pair(Name, std::move(PartialTree))); + Ctx.Partials.insert(std::make_pair(Name, PartialTree)); } void Template::registerLambda(std::string Name, Lambda L) { @@ -910,7 +915,7 @@ void Template::overrideEscapeCharacters(EscapeMap E) { Ctx.Escapes = std::move(E); } -Template::Template(StringRef TemplateStr) { +Template::Template(StringRef TemplateStr, MustacheContext &Ctx) : Ctx(Ctx) { Parser P(TemplateStr, Ctx); Tree = P.parse(); // The default behavior is to escape html entities. @@ -923,18 +928,12 @@ Template::Template(StringRef TemplateStr) { } Template::Template(Template &&Other) noexcept - : Ctx(std::move(Other.Ctx)), Tree(std::move(Other.Tree)) {} + : Ctx(Other.Ctx), Tree(Other.Tree) { + Other.Tree = nullptr; +} Template::~Template() = default; -Template &Template::operator=(Template &&Other) noexcept { - if (this != &Other) { - Ctx = std::move(Other.Ctx); - Tree = std::move(Other.Tree); - Other.Tree = nullptr; - } - return *this; -} } // namespace llvm::mustache #undef DEBUG_TYPE diff --git a/llvm/unittests/Support/MustacheTest.cpp b/llvm/unittests/Support/MustacheTest.cpp index e2c4422f32fd1..3cad4a4562c2b 100644 --- a/llvm/unittests/Support/MustacheTest.cpp +++ b/llvm/unittests/Support/MustacheTest.cpp @@ -22,7 +22,10 @@ using namespace llvm::json; TEST(MustacheInterpolation, NoInterpolation) { // Mustache-free templates should render as-is. Value D = {}; - Template T("Hello from {Mustache}!\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello from {Mustache}!\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -32,7 +35,10 @@ TEST(MustacheInterpolation, NoInterpolation) { TEST(MustacheInterpolation, BasicInterpolation) { // Unadorned tags should interpolate content into the template. Value D = Object{{"subject", "World"}}; - Template T("Hello, {{subject}}!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{subject}}!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -42,7 +48,10 @@ TEST(MustacheInterpolation, BasicInterpolation) { TEST(MustacheInterpolation, NoReinterpolation) { // Interpolated tag output should not be re-interpolated. Value D = Object{{"template", "{{planet}}"}, {"planet", "Earth"}}; - Template T("{{template}}: {{planet}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{template}}: {{planet}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -54,7 +63,10 @@ TEST(MustacheInterpolation, HTMLEscaping) { Value D = Object{ {"forbidden", "& \" < >"}, }; - Template T("These characters should be HTML escaped: {{forbidden}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("These characters should be HTML escaped: {{forbidden}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -67,7 +79,11 @@ TEST(MustacheInterpolation, Ampersand) { Value D = Object{ {"forbidden", "& \" < >"}, }; - Template T("These characters should not be HTML escaped: {{&forbidden}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("These characters should not be HTML escaped: {{&forbidden}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -77,7 +93,10 @@ TEST(MustacheInterpolation, Ampersand) { TEST(MustacheInterpolation, BasicIntegerInterpolation) { // Integers should interpolate seamlessly. Value D = Object{{"mph", 85}}; - Template T("{{mph}} miles an hour!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{mph}} miles an hour!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -87,7 +106,10 @@ TEST(MustacheInterpolation, BasicIntegerInterpolation) { TEST(MustacheInterpolation, AmpersandIntegerInterpolation) { // Integers should interpolate seamlessly. Value D = Object{{"mph", 85}}; - Template T("{{&mph}} miles an hour!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{&mph}} miles an hour!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -97,7 +119,10 @@ TEST(MustacheInterpolation, AmpersandIntegerInterpolation) { TEST(MustacheInterpolation, BasicDecimalInterpolation) { // Decimals should interpolate seamlessly with proper significance. Value D = Object{{"power", 1.21}}; - Template T("{{power}} jiggawatts!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{power}} jiggawatts!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -107,7 +132,10 @@ TEST(MustacheInterpolation, BasicDecimalInterpolation) { TEST(MustacheInterpolation, BasicNullInterpolation) { // Nulls should interpolate as the empty string. Value D = Object{{"cannot", nullptr}}; - Template T("I ({{cannot}}) be seen!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("I ({{cannot}}) be seen!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -117,7 +145,10 @@ TEST(MustacheInterpolation, BasicNullInterpolation) { TEST(MustacheInterpolation, AmpersandNullInterpolation) { // Nulls should interpolate as the empty string. Value D = Object{{"cannot", nullptr}}; - Template T("I ({{&cannot}}) be seen!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("I ({{&cannot}}) be seen!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -127,7 +158,10 @@ TEST(MustacheInterpolation, AmpersandNullInterpolation) { TEST(MustacheInterpolation, BasicContextMissInterpolation) { // Failed context lookups should default to empty strings. Value D = Object{}; - Template T("I ({{cannot}}) be seen!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("I ({{cannot}}) be seen!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -137,7 +171,10 @@ TEST(MustacheInterpolation, BasicContextMissInterpolation) { TEST(MustacheInterpolation, DottedNamesBasicInterpolation) { // Dotted names should be considered a form of shorthand for sections. Value D = Object{{"person", Object{{"name", "Joe"}}}}; - Template T("{{person.name}} == {{#person}}{{name}}{{/person}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{person.name}} == {{#person}}{{name}}{{/person}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -147,7 +184,10 @@ TEST(MustacheInterpolation, DottedNamesBasicInterpolation) { TEST(MustacheInterpolation, DottedNamesAmpersandInterpolation) { // Dotted names should be considered a form of shorthand for sections. Value D = Object{{"person", Object{{"name", "Joe"}}}}; - Template T("{{&person.name}} == {{#person}}{{&name}}{{/person}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{&person.name}} == {{#person}}{{&name}}{{/person}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -162,7 +202,10 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) { Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}}; - Template T("{{a.b.c.d.e.name}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{a.b.c.d.e.name}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -172,7 +215,10 @@ TEST(MustacheInterpolation, DottedNamesArbitraryDepth) { TEST(MustacheInterpolation, DottedNamesBrokenChains) { // Any falsey value prior to the last part of the name should yield ''. Value D = Object{{"a", Object{}}}; - Template T("{{a.b.c}} == "); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{a.b.c}} == ", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -183,7 +229,10 @@ TEST(MustacheInterpolation, DottedNamesBrokenChainResolution) { // Each part of a dotted name should resolve only against its parent. Value D = Object{{"a", Object{{"b", Object{}}}}, {"c", Object{{"name", "Jim"}}}}; - Template T("{{a.b.c.name}} == "); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{a.b.c.name}} == ", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -200,7 +249,10 @@ TEST(MustacheInterpolation, DottedNamesInitialResolution) { Object{{"d", Object{{"e", Object{{"name", "Phil"}}}}}}}}}}}, {"b", Object{{"c", Object{{"d", Object{{"e", Object{{"name", "Wrong"}}}}}}}}}}; - Template T("{{#a}}{{b.c.d.e.name}}{{/a}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#a}}{{b.c.d.e.name}}{{/a}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -211,7 +263,10 @@ TEST(MustacheInterpolation, DottedNamesContextPrecedence) { // Dotted names should be resolved against former resolutions. Value D = Object{{"a", Object{{"b", Object{}}}}, {"b", Object{{"c", "ERROR"}}}}; - Template T("{{#a}}{{b.c}}{{/a}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#a}}{{b.c}}{{/a}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -221,7 +276,10 @@ TEST(MustacheInterpolation, DottedNamesContextPrecedence) { TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) { // Dotted names shall not be parsed as single, atomic keys Value D = Object{{"a.b", "c"}}; - Template T("{{a.b}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{a.b}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -231,7 +289,10 @@ TEST(MustacheInterpolation, DottedNamesAreNotSingleKeys) { TEST(MustacheInterpolation, DottedNamesNoMasking) { // Dotted Names in a given context are unavailable due to dot splitting Value D = Object{{"a.b", "c"}, {"a", Object{{"b", "d"}}}}; - Template T("{{a.b}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{a.b}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -241,7 +302,10 @@ TEST(MustacheInterpolation, DottedNamesNoMasking) { TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) { // Unadorned tags should interpolate content into the template. Value D = "world"; - Template T("Hello, {{.}}!\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{.}}!\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -251,7 +315,10 @@ TEST(MustacheInterpolation, ImplicitIteratorsBasicInterpolation) { TEST(MustacheInterpolation, ImplicitIteratorsAmersand) { // Basic interpolation should be HTML escaped. Value D = "& \" < >"; - Template T("These characters should not be HTML escaped: {{&.}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("These characters should not be HTML escaped: {{&.}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -261,7 +328,10 @@ TEST(MustacheInterpolation, ImplicitIteratorsAmersand) { TEST(MustacheInterpolation, ImplicitIteratorsInteger) { // Integers should interpolate seamlessly. Value D = 85; - Template T("{{.}} miles an hour!\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{.}} miles an hour!\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -271,7 +341,10 @@ TEST(MustacheInterpolation, ImplicitIteratorsInteger) { TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) { // Interpolation should not alter surrounding whitespace. Value D = Object{{"string", "---"}}; - Template T("| {{string}} |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| {{string}} |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -281,7 +354,10 @@ TEST(MustacheInterpolation, InterpolationSurroundingWhitespace) { TEST(MustacheInterpolation, AmersandSurroundingWhitespace) { // Interpolation should not alter surrounding whitespace. Value D = Object{{"string", "---"}}; - Template T("| {{&string}} |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| {{&string}} |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -291,7 +367,10 @@ TEST(MustacheInterpolation, AmersandSurroundingWhitespace) { TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) { // Standalone interpolation should not alter surrounding whitespace. Value D = Object{{"string", "---"}}; - Template T(" {{string}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{string}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -301,7 +380,10 @@ TEST(MustacheInterpolation, StandaloneInterpolationWithWhitespace) { TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) { // Standalone interpolation should not alter surrounding whitespace. Value D = Object{{"string", "---"}}; - Template T(" {{&string}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{&string}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -311,7 +393,10 @@ TEST(MustacheInterpolation, StandaloneAmpersandWithWhitespace) { TEST(MustacheInterpolation, InterpolationWithPadding) { // Superfluous in-tag whitespace should be ignored. Value D = Object{{"string", "---"}}; - Template T("|{{ string }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{ string }}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -321,7 +406,10 @@ TEST(MustacheInterpolation, InterpolationWithPadding) { TEST(MustacheInterpolation, AmpersandWithPadding) { // Superfluous in-tag whitespace should be ignored. Value D = Object{{"string", "---"}}; - Template T("|{{& string }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{& string }}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -331,7 +419,10 @@ TEST(MustacheInterpolation, AmpersandWithPadding) { TEST(MustacheInterpolation, InterpolationWithPaddingAndNewlines) { // Superfluous in-tag whitespace should be ignored. Value D = Object{{"string", "---"}}; - Template T("|{{ string \n\n\n }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{ string \n\n\n }}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -340,7 +431,10 @@ TEST(MustacheInterpolation, InterpolationWithPaddingAndNewlines) { TEST(MustacheSections, Truthy) { Value D = Object{{"boolean", true}}; - Template T("{{#boolean}}This should be rendered.{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#boolean}}This should be rendered.{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -349,7 +443,10 @@ TEST(MustacheSections, Truthy) { TEST(MustacheSections, Falsey) { Value D = Object{{"boolean", false}}; - Template T("{{#boolean}}This should not be rendered.{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#boolean}}This should not be rendered.{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -359,7 +456,10 @@ TEST(MustacheSections, Falsey) { TEST(MustacheInterpolation, IsFalseyNull) { // Mustache-free templates should render as-is. Value D = Object{{"boolean", nullptr}}; - Template T("Hello, {{#boolean}}World{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -369,7 +469,10 @@ TEST(MustacheInterpolation, IsFalseyNull) { TEST(MustacheInterpolation, IsFalseyArray) { // Mustache-free templates should render as-is. Value D = Object{{"boolean", Array()}}; - Template T("Hello, {{#boolean}}World{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -379,7 +482,10 @@ TEST(MustacheInterpolation, IsFalseyArray) { TEST(MustacheInterpolation, IsFalseyObject) { // Mustache-free templates should render as-is. Value D = Object{{"boolean", Object{}}}; - Template T("Hello, {{#boolean}}World{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{#boolean}}World{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -389,7 +495,10 @@ TEST(MustacheInterpolation, IsFalseyObject) { TEST(MustacheInterpolation, DoubleRendering) { // Mustache-free templates should render as-is. Value D1 = Object{{"subject", "World"}}; - Template T("Hello, {{subject}}!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{subject}}!", Ctx); std::string Out1; raw_string_ostream OS1(Out1); T.render(D1, OS1); @@ -403,7 +512,10 @@ TEST(MustacheInterpolation, DoubleRendering) { TEST(MustacheSections, NullIsFalsey) { Value D = Object{{"null", nullptr}}; - Template T("{{#null}}This should not be rendered.{{/null}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#null}}This should not be rendered.{{/null}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -412,7 +524,10 @@ TEST(MustacheSections, NullIsFalsey) { TEST(MustacheSections, Context) { Value D = Object{{"context", Object{{"name", "Joe"}}}}; - Template T("{{#context}}Hi {{name}}.{{/context}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#context}}Hi {{name}}.{{/context}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -424,7 +539,10 @@ TEST(MustacheSections, ParentContexts) { {"b", "wrong"}, {"sec", Object{{"b", "bar"}}}, {"c", Object{{"d", "baz"}}}}; - Template T("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#sec}}{{a}}, {{b}}, {{c.d}}{{/sec}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -433,7 +551,10 @@ TEST(MustacheSections, ParentContexts) { TEST(MustacheSections, VariableTest) { Value D = Object{{"foo", "bar"}}; - Template T("{{#foo}}{{.}} is {{foo}}{{/foo}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#foo}}{{.}} is {{foo}}{{/foo}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -449,6 +570,9 @@ TEST(MustacheSections, ListContexts) { Array{Object{{"mname", "1"}, {"bottoms", Array{Object{{"bname", "x"}}, Object{{"bname", "y"}}}}}}}}}}}; + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); Template T("{{#tops}}" "{{#middles}}" "{{tname.lower}}{{mname}}." @@ -456,7 +580,8 @@ TEST(MustacheSections, ListContexts) { "{{tname.upper}}{{mname}}{{bname}}." "{{/bottoms}}" "{{/middles}}" - "{{/tops}}"); + "{{/tops}}", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -468,6 +593,9 @@ TEST(MustacheSections, DeeplyNestedContexts) { {"a", Object{{"one", 1}}}, {"b", Object{{"two", 2}}}, {"c", Object{{"three", 3}, {"d", Object{{"four", 4}, {"five", 5}}}}}}; + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); Template T( "{{#a}}\n{{one}}\n{{#b}}\n{{one}}{{two}}{{one}}\n{{#c}}\n{{one}}{{two}}{{" "three}}{{two}}{{one}}\n{{#d}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{" @@ -477,7 +605,8 @@ TEST(MustacheSections, DeeplyNestedContexts) { "four}}{{three}}{{two}}{{one}}\n{{/" "five}}\n{{one}}{{two}}{{three}}{{four}}{{three}}{{two}}{{one}}\n{{/" "d}}\n{{one}}{{two}}{{three}}{{two}}{{one}}\n{{/" - "c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n"); + "c}}\n{{one}}{{two}}{{one}}\n{{/b}}\n{{one}}\n{{/a}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -489,7 +618,10 @@ TEST(MustacheSections, DeeplyNestedContexts) { TEST(MustacheSections, List) { Value D = Object{{"list", Array{Object{{"item", 1}}, Object{{"item", 2}}, Object{{"item", 3}}}}}; - Template T("{{#list}}{{item}}{{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}{{item}}{{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -498,7 +630,10 @@ TEST(MustacheSections, List) { TEST(MustacheSections, EmptyList) { Value D = Object{{"list", Array{}}}; - Template T("{{#list}}Yay lists!{{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}Yay lists!{{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -507,8 +642,12 @@ TEST(MustacheSections, EmptyList) { TEST(MustacheSections, Doubled) { Value D = Object{{"bool", true}, {"two", "second"}}; + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); Template T("{{#bool}}\n* first\n{{/bool}}\n* " - "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n"); + "{{two}}\n{{#bool}}\n* third\n{{/bool}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -517,7 +656,10 @@ TEST(MustacheSections, Doubled) { TEST(MustacheSections, NestedTruthy) { Value D = Object{{"bool", true}}; - Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -526,7 +668,10 @@ TEST(MustacheSections, NestedTruthy) { TEST(MustacheSections, NestedFalsey) { Value D = Object{{"bool", false}}; - Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| A {{#bool}}B {{#bool}}C{{/bool}} D{{/bool}} E |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -535,7 +680,10 @@ TEST(MustacheSections, NestedFalsey) { TEST(MustacheSections, ContextMisses) { Value D = Object{}; - Template T("[{{#missing}}Found key 'missing'!{{/missing}}]"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[{{#missing}}Found key 'missing'!{{/missing}}]", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -544,7 +692,10 @@ TEST(MustacheSections, ContextMisses) { TEST(MustacheSections, ImplicitIteratorString) { Value D = Object{{"list", Array{"a", "b", "c", "d", "e"}}}; - Template T("{{#list}}({{.}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{.}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -553,7 +704,10 @@ TEST(MustacheSections, ImplicitIteratorString) { TEST(MustacheSections, ImplicitIteratorInteger) { Value D = Object{{"list", Array{1, 2, 3, 4, 5}}}; - Template T("{{#list}}({{.}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{.}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -562,7 +716,10 @@ TEST(MustacheSections, ImplicitIteratorInteger) { TEST(MustacheSections, ImplicitIteratorArray) { Value D = Object{{"list", Array{Array{1, 2, 3}, Array{"a", "b", "c"}}}}; - Template T("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{#.}}{{.}}{{/.}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -571,7 +728,10 @@ TEST(MustacheSections, ImplicitIteratorArray) { TEST(MustacheSections, ImplicitIteratorHTMLEscaping) { Value D = Object{{"list", Array{"&", "\"", "<", ">"}}}; - Template T("{{#list}}({{.}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{.}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -580,7 +740,10 @@ TEST(MustacheSections, ImplicitIteratorHTMLEscaping) { TEST(MustacheSections, ImplicitIteratorAmpersand) { Value D = Object{{"list", Array{"&", "\"", "<", ">"}}}; - Template T("{{#list}}({{&.}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{&.}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -589,7 +752,10 @@ TEST(MustacheSections, ImplicitIteratorAmpersand) { TEST(MustacheSections, ImplicitIteratorRootLevel) { Value D = Array{Object{{"value", "a"}}, Object{{"value", "b"}}}; - Template T("{{#.}}({{value}}){{/.}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#.}}({{value}}){{/.}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -598,7 +764,10 @@ TEST(MustacheSections, ImplicitIteratorRootLevel) { TEST(MustacheSections, DottedNamesTruthy) { Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}}; - Template T("{{#a.b.c}}Here{{/a.b.c}} == Here"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#a.b.c}}Here{{/a.b.c}} == Here", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -607,7 +776,10 @@ TEST(MustacheSections, DottedNamesTruthy) { TEST(MustacheSections, DottedNamesFalsey) { Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}}; - Template T("{{#a.b.c}}Here{{/a.b.c}} == "); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#a.b.c}}Here{{/a.b.c}} == ", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -615,8 +787,11 @@ TEST(MustacheSections, DottedNamesFalsey) { } TEST(MustacheSections, DottedNamesBrokenChains) { - Value D = Object{{"a", Object{}}}; - Template T("{{#a.b.c}}Here{{/a.b.c}} == "); + Value D = Object{{"a", Object{{}}}}; + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#a.b.c}}Here{{/a.b.c}} == ", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -625,7 +800,10 @@ TEST(MustacheSections, DottedNamesBrokenChains) { TEST(MustacheSections, SurroundingWhitespace) { Value D = Object{{"boolean", true}}; - Template T(" | {{#boolean}}\t|\t{{/boolean}} | \n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" | {{#boolean}}\t|\t{{/boolean}} | \n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -634,7 +812,11 @@ TEST(MustacheSections, SurroundingWhitespace) { TEST(MustacheSections, InternalWhitespace) { Value D = Object{{"boolean", true}}; - Template T(" | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" | {{#boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -643,7 +825,11 @@ TEST(MustacheSections, InternalWhitespace) { TEST(MustacheSections, IndentedInlineSections) { Value D = Object{{"boolean", true}}; - Template T(" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{#boolean}}YES{{/boolean}}\n {{#boolean}}GOOD{{/boolean}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -652,7 +838,10 @@ TEST(MustacheSections, IndentedInlineSections) { TEST(MustacheSections, StandaloneLines) { Value D = Object{{"boolean", true}}; - Template T("| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| This Is\n{{#boolean}}\n|\n{{/boolean}}\n| A Line\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -661,7 +850,10 @@ TEST(MustacheSections, StandaloneLines) { TEST(MustacheSections, IndentedStandaloneLines) { Value D = Object{{"boolean", true}}; - Template T("| This Is\n {{#boolean}}\n|\n {{/boolean}}\n| A Line\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| This Is\n {{#boolean}}\n|\n {{/boolean}}\n| A Line\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -670,7 +862,10 @@ TEST(MustacheSections, IndentedStandaloneLines) { TEST(MustacheSections, StandaloneLineEndings) { Value D = Object{{"boolean", true}}; - Template T("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|\r\n{{#boolean}}\r\n{{/boolean}}\r\n|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -679,7 +874,10 @@ TEST(MustacheSections, StandaloneLineEndings) { TEST(MustacheSections, StandaloneWithoutPreviousLine) { Value D = Object{{"boolean", true}}; - Template T(" {{#boolean}}\n#{{/boolean}}\n/"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{#boolean}}\n#{{/boolean}}\n/", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -688,7 +886,10 @@ TEST(MustacheSections, StandaloneWithoutPreviousLine) { TEST(MustacheSections, StandaloneWithoutNewline) { Value D = Object{{"boolean", true}}; - Template T("#{{#boolean}}\n/\n {{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("#{{#boolean}}\n/\n {{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -697,7 +898,10 @@ TEST(MustacheSections, StandaloneWithoutNewline) { TEST(MustacheSections, Padding) { Value D = Object{{"boolean", true}}; - Template T("|{{# boolean }}={{/ boolean }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{# boolean }}={{/ boolean }}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -706,7 +910,10 @@ TEST(MustacheSections, Padding) { TEST(MustacheInvertedSections, Falsey) { Value D = Object{{"boolean", false}}; - Template T("{{^boolean}}This should be rendered.{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^boolean}}This should be rendered.{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -715,7 +922,10 @@ TEST(MustacheInvertedSections, Falsey) { TEST(MustacheInvertedSections, Truthy) { Value D = Object{{"boolean", true}}; - Template T("{{^boolean}}This should not be rendered.{{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^boolean}}This should not be rendered.{{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -724,7 +934,10 @@ TEST(MustacheInvertedSections, Truthy) { TEST(MustacheInvertedSections, NullIsFalsey) { Value D = Object{{"null", nullptr}}; - Template T("{{^null}}This should be rendered.{{/null}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^null}}This should be rendered.{{/null}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -733,7 +946,10 @@ TEST(MustacheInvertedSections, NullIsFalsey) { TEST(MustacheInvertedSections, Context) { Value D = Object{{"context", Object{{"name", "Joe"}}}}; - Template T("{{^context}}Hi {{name}}.{{/context}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^context}}Hi {{name}}.{{/context}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -743,7 +959,10 @@ TEST(MustacheInvertedSections, Context) { TEST(MustacheInvertedSections, List) { Value D = Object{ {"list", Array{Object{{"n", 1}}, Object{{"n", 2}}, Object{{"n", 3}}}}}; - Template T("{{^list}}{{n}}{{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^list}}{{n}}{{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -752,7 +971,10 @@ TEST(MustacheInvertedSections, List) { TEST(MustacheInvertedSections, EmptyList) { Value D = Object{{"list", Array{}}}; - Template T("{{^list}}Yay lists!{{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^list}}Yay lists!{{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -761,8 +983,12 @@ TEST(MustacheInvertedSections, EmptyList) { TEST(MustacheInvertedSections, Doubled) { Value D = Object{{"bool", false}, {"two", "second"}}; + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); Template T("{{^bool}}\n* first\n{{/bool}}\n* " - "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n"); + "{{two}}\n{{^bool}}\n* third\n{{/bool}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -771,7 +997,10 @@ TEST(MustacheInvertedSections, Doubled) { TEST(MustacheInvertedSections, NestedFalsey) { Value D = Object{{"bool", false}}; - Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -780,7 +1009,10 @@ TEST(MustacheInvertedSections, NestedFalsey) { TEST(MustacheInvertedSections, NestedTruthy) { Value D = Object{{"bool", true}}; - Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| A {{^bool}}B {{^bool}}C{{/bool}} D{{/bool}} E |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -789,7 +1021,10 @@ TEST(MustacheInvertedSections, NestedTruthy) { TEST(MustacheInvertedSections, ContextMisses) { Value D = Object{}; - Template T("[{{^missing}}Cannot find key 'missing'!{{/missing}}]"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[{{^missing}}Cannot find key 'missing'!{{/missing}}]", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -798,7 +1033,10 @@ TEST(MustacheInvertedSections, ContextMisses) { TEST(MustacheInvertedSections, DottedNamesTruthy) { Value D = Object{{"a", Object{{"b", Object{{"c", true}}}}}}; - Template T("{{^a.b.c}}Not Here{{/a.b.c}} == "); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^a.b.c}}Not Here{{/a.b.c}} == ", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -807,7 +1045,10 @@ TEST(MustacheInvertedSections, DottedNamesTruthy) { TEST(MustacheInvertedSections, DottedNamesFalsey) { Value D = Object{{"a", Object{{"b", Object{{"c", false}}}}}}; - Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -816,7 +1057,10 @@ TEST(MustacheInvertedSections, DottedNamesFalsey) { TEST(MustacheInvertedSections, DottedNamesBrokenChains) { Value D = Object{{"a", Object{}}}; - Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{^a.b.c}}Not Here{{/a.b.c}} == Not Here", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -825,7 +1069,10 @@ TEST(MustacheInvertedSections, DottedNamesBrokenChains) { TEST(MustacheInvertedSections, SurroundingWhitespace) { Value D = Object{{"boolean", false}}; - Template T(" | {{^boolean}}\t|\t{{/boolean}} | \n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" | {{^boolean}}\t|\t{{/boolean}} | \n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -834,7 +1081,11 @@ TEST(MustacheInvertedSections, SurroundingWhitespace) { TEST(MustacheInvertedSections, InternalWhitespace) { Value D = Object{{"boolean", false}}; - Template T(" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" | {{^boolean}} {{! Important Whitespace }}\n {{/boolean}} | \n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -843,7 +1094,11 @@ TEST(MustacheInvertedSections, InternalWhitespace) { TEST(MustacheInvertedSections, IndentedInlineSections) { Value D = Object{{"boolean", false}}; - Template T(" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{^boolean}}NO{{/boolean}}\n {{^boolean}}WAY{{/boolean}}\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -852,7 +1107,10 @@ TEST(MustacheInvertedSections, IndentedInlineSections) { TEST(MustacheInvertedSections, StandaloneLines) { Value D = Object{{"boolean", false}}; - Template T("| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| This Is\n{{^boolean}}\n|\n{{/boolean}}\n| A Line\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -861,7 +1119,10 @@ TEST(MustacheInvertedSections, StandaloneLines) { TEST(MustacheInvertedSections, StandaloneIndentedLines) { Value D = Object{{"boolean", false}}; - Template T("| This Is\n {{^boolean}}\n|\n {{/boolean}}\n| A Line\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| This Is\n {{^boolean}}\n|\n {{/boolean}}\n| A Line\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -870,7 +1131,10 @@ TEST(MustacheInvertedSections, StandaloneIndentedLines) { TEST(MustacheInvertedSections, StandaloneLineEndings) { Value D = Object{{"boolean", false}}; - Template T("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|\r\n{{^boolean}}\r\n{{/boolean}}\r\n|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -879,7 +1143,10 @@ TEST(MustacheInvertedSections, StandaloneLineEndings) { TEST(MustacheInvertedSections, StandaloneWithoutPreviousLine) { Value D = Object{{"boolean", false}}; - Template T(" {{^boolean}}\n^{{/boolean}}\n/"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{^boolean}}\n^{{/boolean}}\n/", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -888,7 +1155,10 @@ TEST(MustacheInvertedSections, StandaloneWithoutPreviousLine) { TEST(MustacheInvertedSections, StandaloneWithoutNewline) { Value D = Object{{"boolean", false}}; - Template T("^{{^boolean}}\n/\n {{/boolean}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("^{{^boolean}}\n/\n {{/boolean}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -897,7 +1167,10 @@ TEST(MustacheInvertedSections, StandaloneWithoutNewline) { TEST(MustacheInvertedSections, Padding) { Value D = Object{{"boolean", false}}; - Template T("|{{^ boolean }}={{/ boolean }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{^ boolean }}={{/ boolean }}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -906,7 +1179,10 @@ TEST(MustacheInvertedSections, Padding) { TEST(MustachePartials, BasicBehavior) { Value D = Object{}; - Template T("{{>text}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{>text}}", Ctx); T.registerPartial("text", "from partial"); std::string Out; raw_string_ostream OS(Out); @@ -916,7 +1192,10 @@ TEST(MustachePartials, BasicBehavior) { TEST(MustachePartials, FailedLookup) { Value D = Object{}; - Template T("{{>text}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{>text}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -925,7 +1204,10 @@ TEST(MustachePartials, FailedLookup) { TEST(MustachePartials, Context) { Value D = Object{{"text", "content"}}; - Template T("{{>partial}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{>partial}}", Ctx); T.registerPartial("partial", "*{{text}}*"); std::string Out; raw_string_ostream OS(Out); @@ -937,7 +1219,10 @@ TEST(MustachePartials, Recursion) { Value D = Object{{"content", "X"}, {"nodes", Array{Object{{"content", "Y"}, {"nodes", Array{}}}}}}; - Template T("{{>node}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{>node}}", Ctx); T.registerPartial("node", "{{content}}({{#nodes}}{{>node}}{{/nodes}})"); std::string Out; raw_string_ostream OS(Out); @@ -947,7 +1232,10 @@ TEST(MustachePartials, Recursion) { TEST(MustachePartials, Nested) { Value D = Object{{"a", "hello"}, {"b", "world"}}; - Template T("{{>outer}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{>outer}}", Ctx); T.registerPartial("outer", "*{{a}} {{>inner}}*"); T.registerPartial("inner", "{{b}}!"); std::string Out; @@ -958,7 +1246,10 @@ TEST(MustachePartials, Nested) { TEST(MustachePartials, SurroundingWhitespace) { Value D = Object{}; - Template T("| {{>partial}} |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| {{>partial}} |", Ctx); T.registerPartial("partial", "\t|\t"); std::string Out; raw_string_ostream OS(Out); @@ -968,7 +1259,10 @@ TEST(MustachePartials, SurroundingWhitespace) { TEST(MustachePartials, InlineIndentation) { Value D = Object{{"data", "|"}}; - Template T(" {{data}} {{> partial}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{data}} {{> partial}}\n", Ctx); T.registerPartial("partial", "<\n<"); std::string Out; raw_string_ostream OS(Out); @@ -978,7 +1272,10 @@ TEST(MustachePartials, InlineIndentation) { TEST(MustachePartials, PaddingWhitespace) { Value D = Object{{"boolean", true}}; - Template T("|{{> partial }}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{> partial }}|", Ctx); T.registerPartial("partial", "[]"); std::string Out; raw_string_ostream OS(Out); @@ -987,7 +1284,10 @@ TEST(MustachePartials, PaddingWhitespace) { } TEST(MustachePartials, StandaloneIndentation) { - mustache::Template T("\\\n {{>partial}}\n/\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + mustache::Template T("\\\n {{>partial}}\n/\n", Ctx); T.registerPartial("partial", "|\n{{{content}}}\n|\n"); std::string O; raw_string_ostream OS(O); @@ -998,7 +1298,10 @@ TEST(MustachePartials, StandaloneIndentation) { TEST(MustacheLambdas, BasicInterpolation) { Value D = Object{}; - Template T("Hello, {{lambda}}!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{lambda}}!", Ctx); Lambda L = []() -> llvm::json::Value { return "World"; }; T.registerLambda("lambda", L); std::string Out; @@ -1009,7 +1312,10 @@ TEST(MustacheLambdas, BasicInterpolation) { TEST(MustacheLambdas, InterpolationExpansion) { Value D = Object{{"planet", "World"}}; - Template T("Hello, {{lambda}}!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{lambda}}!", Ctx); Lambda L = []() -> llvm::json::Value { return "{{planet}}"; }; T.registerLambda("lambda", L); std::string Out; @@ -1020,7 +1326,10 @@ TEST(MustacheLambdas, InterpolationExpansion) { TEST(MustacheLambdas, BasicMultipleCalls) { Value D = Object{}; - Template T("{{lambda}} == {{lambda}} == {{lambda}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{lambda}} == {{lambda}} == {{lambda}}", Ctx); int I = 0; Lambda L = [&I]() -> llvm::json::Value { I += 1; @@ -1035,7 +1344,10 @@ TEST(MustacheLambdas, BasicMultipleCalls) { TEST(MustacheLambdas, Escaping) { Value D = Object{}; - Template T("<{{lambda}}{{&lambda}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("<{{lambda}}{{&lambda}}", Ctx); Lambda L = []() -> llvm::json::Value { return ">"; }; T.registerLambda("lambda", L); std::string Out; @@ -1046,7 +1358,10 @@ TEST(MustacheLambdas, Escaping) { TEST(MustacheLambdas, Sections) { Value D = Object{}; - Template T("<{{#lambda}}{{x}}{{/lambda}}>"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("<{{#lambda}}{{x}}{{/lambda}}>", Ctx); SectionLambda L = [](StringRef Text) -> llvm::json::Value { if (Text == "{{x}}") { return "yes"; @@ -1064,7 +1379,10 @@ TEST(MustacheLambdas, SectionExpansion) { Value D = Object{ {"planet", "Earth"}, }; - Template T("<{{#lambda}}-{{/lambda}}>"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("<{{#lambda}}-{{/lambda}}>", Ctx); SectionLambda L = [](StringRef Text) -> llvm::json::Value { SmallString<128> Result; Result += Text; @@ -1081,7 +1399,10 @@ TEST(MustacheLambdas, SectionExpansion) { TEST(MustacheLambdas, SectionsMultipleCalls) { Value D = Object{}; - Template T("{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#lambda}}FILE{{/lambda}} != {{#lambda}}LINE{{/lambda}}", Ctx); SectionLambda L = [](StringRef Text) -> llvm::json::Value { SmallString<128> Result; Result += "__"; @@ -1098,7 +1419,10 @@ TEST(MustacheLambdas, SectionsMultipleCalls) { TEST(MustacheLambdas, InvertedSections) { Value D = Object{{"static", "static"}}; - Template T("<{{^lambda}}{{static}}{{/lambda}}>"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("<{{^lambda}}{{static}}{{/lambda}}>", Ctx); SectionLambda L = [](StringRef Text) -> llvm::json::Value { return false; }; T.registerLambda("lambda", L); std::string Out; @@ -1110,7 +1434,10 @@ TEST(MustacheLambdas, InvertedSections) { TEST(MustacheComments, Inline) { // Comment blocks should be removed from the template. Value D = {}; - Template T("12345{{! Comment Block! }}67890"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("12345{{! Comment Block! }}67890", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1120,7 +1447,10 @@ TEST(MustacheComments, Inline) { TEST(MustacheComments, Multiline) { // Multiline comments should be permitted. Value D = {}; - Template T("12345{{!\n This is a\n multi-line comment...\n}}67890\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("12345{{!\n This is a\n multi-line comment...\n}}67890\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1130,7 +1460,10 @@ TEST(MustacheComments, Multiline) { TEST(MustacheComments, Standalone) { // All standalone comment lines should be removed. Value D = {}; - Template T("Begin.\n{{! Comment Block! }}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n{{! Comment Block! }}\nEnd.\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1140,7 +1473,10 @@ TEST(MustacheComments, Standalone) { TEST(MustacheComments, IndentedStandalone) { // All standalone comment lines should be removed. Value D = {}; - Template T("Begin.\n {{! Indented Comment Block! }}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n {{! Indented Comment Block! }}\nEnd.\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1150,7 +1486,10 @@ TEST(MustacheComments, IndentedStandalone) { TEST(MustacheComments, StandaloneLineEndings) { // "\r\n" should be considered a newline for standalone tags. Value D = {}; - Template T("|\r\n{{! Standalone Comment }}\r\n|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|\r\n{{! Standalone Comment }}\r\n|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1160,7 +1499,10 @@ TEST(MustacheComments, StandaloneLineEndings) { TEST(MustacheComments, StandaloneWithoutPreviousLine) { // Standalone tags should not require a newline to precede them. Value D = {}; - Template T(" {{! I'm Still Standalone }}\n!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{! I'm Still Standalone }}\n!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1170,7 +1512,10 @@ TEST(MustacheComments, StandaloneWithoutPreviousLine) { TEST(MustacheComments, StandaloneWithoutNewline) { // Standalone tags should not require a newline to follow them. Value D = {}; - Template T("!\n {{! I'm Still Standalone }}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("!\n {{! I'm Still Standalone }}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1180,7 +1525,10 @@ TEST(MustacheComments, StandaloneWithoutNewline) { TEST(MustacheComments, MultilineStandalone) { // All standalone comment lines should be removed. Value D = {}; - Template T("Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n{{!\nSomething's going on here...\n}}\nEnd.\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1190,7 +1538,11 @@ TEST(MustacheComments, MultilineStandalone) { TEST(MustacheComments, IndentedMultilineStandalone) { // All standalone comment lines should be removed. Value D = {}; - Template T("Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n {{!\n Something's going on here...\n }}\nEnd.\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1200,7 +1552,10 @@ TEST(MustacheComments, IndentedMultilineStandalone) { TEST(MustacheComments, IndentedInline) { // Inline comments should not strip whitespace. Value D = {}; - Template T(" 12 {{! 34 }}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" 12 {{! 34 }}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1210,7 +1565,10 @@ TEST(MustacheComments, IndentedInline) { TEST(MustacheComments, SurroundingWhitespace) { // Comment removal should preserve surrounding whitespace. Value D = {}; - Template T("12345 {{! Comment Block! }} 67890"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("12345 {{! Comment Block! }} 67890", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1221,7 +1579,10 @@ TEST(MustacheComments, VariableNameCollision) { // Comments must never render, even if a variable with the same name exists. Value D = Object{ {"! comment", 1}, {"! comment ", 2}, {"!comment", 3}, {"comment", 4}}; - Template T("comments never show: >{{! comment }}<"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("comments never show: >{{! comment }}<", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1234,7 +1595,10 @@ TEST(MustacheComments, VariableNameCollision) { // implemented, these assertions should be changed back to EXPECT_EQ. TEST(MustacheTripleMustache, Basic) { Value D = Object{{"subject", "World"}}; - Template T("Hello, {{{subject}}}!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Hello, {{{subject}}}!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1243,7 +1607,10 @@ TEST(MustacheTripleMustache, Basic) { TEST(MustacheTripleMustache, IntegerInterpolation) { Value D = Object{{"mph", 85}}; - Template T("{{{mph}}} miles an hour!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{{mph}}} miles an hour!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1252,7 +1619,10 @@ TEST(MustacheTripleMustache, IntegerInterpolation) { TEST(MustacheTripleMustache, DecimalInterpolation) { Value D = Object{{"power", 1.21}}; - Template T("{{{power}}} jiggawatts!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{{power}}} jiggawatts!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1261,7 +1631,10 @@ TEST(MustacheTripleMustache, DecimalInterpolation) { TEST(MustacheTripleMustache, NullInterpolation) { Value D = Object{{"cannot", nullptr}}; - Template T("I ({{{cannot}}}) be seen!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("I ({{{cannot}}}) be seen!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1270,7 +1643,10 @@ TEST(MustacheTripleMustache, NullInterpolation) { TEST(MustacheTripleMustache, ContextMissInterpolation) { Value D = Object{}; - Template T("I ({{{cannot}}}) be seen!"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("I ({{{cannot}}}) be seen!", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1279,7 +1655,10 @@ TEST(MustacheTripleMustache, ContextMissInterpolation) { TEST(MustacheTripleMustache, DottedNames) { Value D = Object{{"person", Object{{"name", "Joe"}}}}; - Template T("{{{person.name}}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{{person.name}}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1288,7 +1667,10 @@ TEST(MustacheTripleMustache, DottedNames) { TEST(MustacheTripleMustache, ImplicitIterator) { Value D = Object{{"list", Array{"", ""}}}; - Template T("{{#list}}({{{.}}}){{/list}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{#list}}({{{.}}}){{/list}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1297,7 +1679,10 @@ TEST(MustacheTripleMustache, ImplicitIterator) { TEST(MustacheTripleMustache, SurroundingWhitespace) { Value D = Object{{"string", "---"}}; - Template T("| {{{string}}} |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| {{{string}}} |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1306,7 +1691,10 @@ TEST(MustacheTripleMustache, SurroundingWhitespace) { TEST(MustacheTripleMustache, Standalone) { Value D = Object{{"string", "---"}}; - Template T(" {{{string}}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{{string}}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1315,7 +1703,10 @@ TEST(MustacheTripleMustache, Standalone) { TEST(MustacheTripleMustache, WithPadding) { Value D = Object{{"string", "---"}}; - Template T("|{{{ string }}}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{{ string }}}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1324,7 +1715,10 @@ TEST(MustacheTripleMustache, WithPadding) { TEST(MustacheDelimiters, PairBehavior) { Value D = Object{{"text", "Hey!"}}; - Template T("{{=<% %>=}}(<%text%>)"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("{{=<% %>=}}(<%text%>)", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1333,7 +1727,10 @@ TEST(MustacheDelimiters, PairBehavior) { TEST(MustacheDelimiters, SpecialCharacters) { Value D = Object{{"text", "It worked!"}}; - Template T("({{=[ ]=}}[text])"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("({{=[ ]=}}[text])", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1342,9 +1739,12 @@ TEST(MustacheDelimiters, SpecialCharacters) { TEST(MustacheDelimiters, Sections) { Value D = Object{{"section", true}, {"data", "I got interpolated."}}; - auto T = - Template("[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= " - "| | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[\n{{#section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= " + "| | =}}\n|#section|\n {{data}}\n |data|\n|/section|\n]\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1355,9 +1755,12 @@ TEST(MustacheDelimiters, Sections) { TEST(MustacheDelimiters, InvertedSections) { Value D = Object{{"section", false}, {"data", "I got interpolated."}}; - auto T = - Template("[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= " - "| | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[\n{{^section}}\n {{data}}\n |data|\n{{/section}}\n\n{{= " + "| | =}}\n|^section|\n {{data}}\n |data|\n|/section|\n]\n", + Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1368,7 +1771,10 @@ TEST(MustacheDelimiters, InvertedSections) { TEST(MustacheDelimiters, PartialInheritence) { Value D = Object{{"value", "yes"}}; - Template T("[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[ {{>include}} ]\n{{= | | =}}\n[ |>include| ]\n", Ctx); T.registerPartial("include", ".{{value}}."); std::string Out; raw_string_ostream OS(Out); @@ -1378,7 +1784,10 @@ TEST(MustacheDelimiters, PartialInheritence) { TEST(MustacheDelimiters, PostPartialBehavior) { Value D = Object{{"value", "yes"}}; - Template T("[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("[ {{>include}} ]\n[ .{{value}}. .|value|. ]\n", Ctx); T.registerPartial("include", ".{{value}}. {{= | | =}} .|value|."); std::string Out; raw_string_ostream OS(Out); @@ -1388,7 +1797,10 @@ TEST(MustacheDelimiters, PostPartialBehavior) { TEST(MustacheDelimiters, SurroundingWhitespace) { Value D = Object{}; - Template T("| {{=@ @=}} |"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("| {{=@ @=}} |", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1397,7 +1809,10 @@ TEST(MustacheDelimiters, SurroundingWhitespace) { TEST(MustacheDelimiters, OutlyingWhitespaceInline) { Value D = Object{}; - Template T(" | {{=@ @=}}\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" | {{=@ @=}}\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1406,7 +1821,10 @@ TEST(MustacheDelimiters, OutlyingWhitespaceInline) { TEST(MustacheDelimiters, StandaloneTag) { Value D = Object{}; - Template T("Begin.\n{{=@ @=}}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n{{=@ @=}}\nEnd.\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1415,7 +1833,10 @@ TEST(MustacheDelimiters, StandaloneTag) { TEST(MustacheDelimiters, IndentedStandaloneTag) { Value D = Object{}; - Template T("Begin.\n {{=@ @=}}\nEnd.\n"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("Begin.\n {{=@ @=}}\nEnd.\n", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1424,7 +1845,10 @@ TEST(MustacheDelimiters, IndentedStandaloneTag) { TEST(MustacheDelimiters, StandaloneLineEndings) { Value D = Object{}; - Template T("|\r\n{{= @ @ =}}\r\n|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|\r\n{{= @ @ =}}\r\n|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1433,7 +1857,10 @@ TEST(MustacheDelimiters, StandaloneLineEndings) { TEST(MustacheDelimiters, StandaloneWithoutPreviousLine) { Value D = Object{}; - Template T(" {{=@ @=}}\n="); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(" {{=@ @=}}\n=", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1442,7 +1869,10 @@ TEST(MustacheDelimiters, StandaloneWithoutPreviousLine) { TEST(MustacheDelimiters, StandaloneWithoutNewline) { Value D = Object{}; - Template T("=\n {{=@ @=}}"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("=\n {{=@ @=}}", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); @@ -1451,7 +1881,10 @@ TEST(MustacheDelimiters, StandaloneWithoutNewline) { TEST(MustacheDelimiters, PairwithPadding) { Value D = Object{}; - Template T("|{{= @ @ =}}|"); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T("|{{= @ @ =}}|", Ctx); std::string Out; raw_string_ostream OS(Out); T.render(D, OS); diff --git a/llvm/utils/llvm-test-mustache-spec/llvm-test-mustache-spec.cpp b/llvm/utils/llvm-test-mustache-spec/llvm-test-mustache-spec.cpp index 9007eb365a15f..93e2efef17117 100644 --- a/llvm/utils/llvm-test-mustache-spec/llvm-test-mustache-spec.cpp +++ b/llvm/utils/llvm-test-mustache-spec/llvm-test-mustache-spec.cpp @@ -212,7 +212,10 @@ static void runTest(StringRef InputFile) { for (Value V : *TestArray) { auto TestData = ExitOnErr(TestData::createTestData(V.getAsObject(), InputFile)); - Template T(TestData.TemplateStr); + BumpPtrAllocator Allocator; + StringSaver Saver(Allocator); + MustacheContext Ctx(Allocator, Saver); + Template T(TestData.TemplateStr, Ctx); registerPartials(TestData.Partials, T); std::string ActualStr;