//===- llvm/unittest/Support/ScopedPrinterTest.cpp - ScopedPrinter tests --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/Support/ScopedPrinter.h" #include "llvm/ADT/APSInt.h" #include "llvm/Support/Format.h" #include "gtest/gtest.h" #include #include using namespace llvm; TEST(JSONScopedPrinterTest, PrettyPrintCtor) { auto PrintFunc = [](ScopedPrinter &W) { DictScope D(W); W.printString("Key", "Value"); }; std::string StreamBuffer; raw_string_ostream OS(StreamBuffer); JSONScopedPrinter PrettyPrintWriter(OS, /*PrettyPrint=*/true); JSONScopedPrinter NoPrettyPrintWriter(OS, /*PrettyPrint=*/false); const char *PrettyPrintOut = R"({ "Key": "Value" })"; const char *NoPrettyPrintOut = R"({"Key":"Value"})"; PrintFunc(PrettyPrintWriter); EXPECT_EQ(PrettyPrintOut, StreamBuffer); StreamBuffer.clear(); PrintFunc(NoPrettyPrintWriter); EXPECT_EQ(NoPrettyPrintOut, StreamBuffer); } TEST(JSONScopedPrinterTest, DelimitedScopeCtor) { std::string StreamBuffer; raw_string_ostream OS(StreamBuffer); { JSONScopedPrinter DictScopeWriter(OS, /*PrettyPrint=*/false, std::make_unique()); DictScopeWriter.printString("Label", "DictScope"); } EXPECT_EQ(R"({"Label":"DictScope"})", StreamBuffer); StreamBuffer.clear(); { JSONScopedPrinter ListScopeWriter(OS, /*PrettyPrint=*/false, std::make_unique()); ListScopeWriter.printString("ListScope"); } EXPECT_EQ(R"(["ListScope"])", StreamBuffer); StreamBuffer.clear(); { JSONScopedPrinter NoScopeWriter(OS, /*PrettyPrint=*/false); NoScopeWriter.printString("NoScope"); } EXPECT_EQ(R"("NoScope")", StreamBuffer); } class ScopedPrinterTest : public ::testing::Test { protected: std::string StreamBuffer; raw_string_ostream OS; ScopedPrinter Writer; JSONScopedPrinter JSONWriter; bool HasPrintedToJSON; ScopedPrinterTest() : OS(StreamBuffer), Writer(OS), JSONWriter(OS, /*PrettyPrint=*/true), HasPrintedToJSON(false) {} using PrintFunc = function_ref; void verifyScopedPrinter(StringRef Expected, PrintFunc Func) { Func(Writer); Writer.flush(); EXPECT_EQ(Expected.str(), StreamBuffer); StreamBuffer.clear(); } void verifyJSONScopedPrinter(StringRef Expected, PrintFunc Func) { { DictScope D(JSONWriter); Func(JSONWriter); } JSONWriter.flush(); EXPECT_EQ(Expected.str(), StreamBuffer); StreamBuffer.clear(); HasPrintedToJSON = true; } void verifyAll(StringRef ExpectedOut, StringRef JSONExpectedOut, PrintFunc Func) { verifyScopedPrinter(ExpectedOut, Func); verifyJSONScopedPrinter(JSONExpectedOut, Func); } void TearDown() { // JSONScopedPrinter fails an assert if nothing's been printed. if (!HasPrintedToJSON) JSONWriter.printString(""); } }; TEST_F(ScopedPrinterTest, GetKind) { EXPECT_EQ(ScopedPrinter::ScopedPrinterKind::Base, Writer.getKind()); EXPECT_EQ(ScopedPrinter::ScopedPrinterKind::JSON, JSONWriter.getKind()); } TEST_F(ScopedPrinterTest, ClassOf) { EXPECT_TRUE(ScopedPrinter::classof(&Writer)); EXPECT_TRUE(JSONScopedPrinter::classof(&JSONWriter)); EXPECT_FALSE(ScopedPrinter::classof(&JSONWriter)); EXPECT_FALSE(JSONScopedPrinter::classof(&Writer)); } TEST_F(ScopedPrinterTest, Indent) { auto PrintFunc = [](ScopedPrinter &W) { W.printString("|"); W.indent(); W.printString("|"); W.indent(2); W.printString("|"); }; const char *ExpectedOut = R"(| | | )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, Unindent) { auto PrintFunc = [](ScopedPrinter &W) { W.indent(3); W.printString("|"); W.unindent(2); W.printString("|"); W.unindent(); W.printString("|"); W.unindent(); W.printString("|"); }; const char *ExpectedOut = R"( | | | | )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, ResetIndent) { auto PrintFunc = [](ScopedPrinter &W) { W.indent(4); W.printString("|"); W.resetIndent(); W.printString("|"); }; const char *ExpectedOut = R"( | | )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintIndent) { auto PrintFunc = [](ScopedPrinter &W) { W.printIndent(); W.printString("|"); W.indent(); W.printIndent(); W.printString("|"); }; const char *ExpectedOut = R"(| | )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, GetIndentLevel) { EXPECT_EQ(Writer.getIndentLevel(), 0); Writer.indent(); EXPECT_EQ(Writer.getIndentLevel(), 1); Writer.indent(); EXPECT_EQ(Writer.getIndentLevel(), 2); Writer.unindent(); EXPECT_EQ(Writer.getIndentLevel(), 1); Writer.indent(); Writer.resetIndent(); EXPECT_EQ(Writer.getIndentLevel(), 0); Writer.unindent(); EXPECT_EQ(Writer.getIndentLevel(), 0); Writer.indent(); EXPECT_EQ(Writer.getIndentLevel(), 1); } TEST_F(ScopedPrinterTest, SetPrefix) { auto PrintFunc = [](ScopedPrinter &W) { W.setPrefix("Prefix1"); W.indent(); W.printIndent(); W.printString("|"); W.unindent(); W.printIndent(); W.printString("|"); W.setPrefix("Prefix2"); W.printIndent(); W.printString("|"); }; const char *ExpectedOut = R"(Prefix1 Prefix1 | Prefix1Prefix1| Prefix2Prefix2| )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintEnum) { auto PrintFunc = [](ScopedPrinter &W) { const EnumEntry EnumList[] = {{"Name1", "AltName1", 1}, {"Name2", "AltName2", 2}, {"Name3", "AltName3", 3}, {"Name4", "AltName4", 2}}; EnumEntry OtherEnum{"Name5", "AltName5", 5}; W.printEnum("Exists", EnumList[1].Value, ArrayRef(EnumList)); W.printEnum("DoesNotExist", OtherEnum.Value, ArrayRef(EnumList)); }; const char *ExpectedOut = R"(Exists: Name2 (0x2) DoesNotExist: 0x5 )"; const char *JSONExpectedOut = R"({ "Exists": { "Name": "Name2", "Value": 2 }, "DoesNotExist": 5 })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintFlag) { auto PrintFunc = [](ScopedPrinter &W) { const EnumEntry SingleBitFlags[] = { {"Name0", "AltName0", 0}, {"Name1", "AltName1", 1}, {"Name2", "AltName2", 1 << 1}, {"Name3", "AltName3", 1 << 2}}; const EnumEntry UnsortedFlags[] = { {"C", "c", 1}, {"B", "b", 1 << 1}, {"A", "a", 1 << 2}}; const EnumEntry EnumFlags[] = { {"FirstByte1", "First1", 0x1u}, {"FirstByte2", "First2", 0x2u}, {"FirstByte3", "First3", 0x3u}, {"SecondByte1", "Second1", 0x10u}, {"SecondByte2", "Second2", 0x20u}, {"SecondByte3", "Second3", 0x30u}, {"ThirdByte1", "Third1", 0x100u}, {"ThirdByte2", "Third2", 0x200u}, {"ThirdByte3", "Third3", 0x300u}}; W.printFlags("ZeroFlag", 0, ArrayRef(SingleBitFlags)); W.printFlags("NoFlag", 1 << 3, ArrayRef(SingleBitFlags)); W.printFlags("Flag1", SingleBitFlags[1].Value, ArrayRef(SingleBitFlags)); W.printFlags("Flag1&3", (1 << 2) + 1, ArrayRef(SingleBitFlags)); W.printFlags("ZeroFlagRaw", 0); W.printFlags("NoFlagRaw", 1 << 3); W.printFlags("Flag1Raw", SingleBitFlags[1].Value); W.printFlags("Flag1&3Raw", (1 << 2) + 1); W.printFlags("FlagSorted", (1 << 2) + (1 << 1) + 1, ArrayRef(UnsortedFlags)); uint16_t NoBitMask = 0; uint16_t FirstByteMask = 0xFu; uint16_t SecondByteMask = 0xF0u; uint16_t ThirdByteMask = 0xF00u; W.printFlags("NoBitMask", 0xFFFu, ArrayRef(EnumFlags), NoBitMask); W.printFlags("FirstByteMask", 0x3u, ArrayRef(EnumFlags), FirstByteMask); W.printFlags("SecondByteMask", 0x30u, ArrayRef(EnumFlags), SecondByteMask); W.printFlags("ValueOutsideMask", 0x1u, ArrayRef(EnumFlags), SecondByteMask); W.printFlags("FirstSecondByteMask", 0xFFu, ArrayRef(EnumFlags), FirstByteMask, SecondByteMask); W.printFlags("FirstSecondThirdByteMask", 0x333u, ArrayRef(EnumFlags), FirstByteMask, SecondByteMask, ThirdByteMask); }; const char *ExpectedOut = R"(ZeroFlag [ (0x0) ] NoFlag [ (0x8) ] Flag1 [ (0x1) Name1 (0x1) ] Flag1&3 [ (0x5) Name1 (0x1) Name3 (0x4) ] ZeroFlagRaw [ (0x0) ] NoFlagRaw [ (0x8) 0x8 ] Flag1Raw [ (0x1) 0x1 ] Flag1&3Raw [ (0x5) 0x1 0x4 ] FlagSorted [ (0x7) A (0x4) B (0x2) C (0x1) ] NoBitMask [ (0xFFF) FirstByte1 (0x1) FirstByte2 (0x2) FirstByte3 (0x3) SecondByte1 (0x10) SecondByte2 (0x20) SecondByte3 (0x30) ThirdByte1 (0x100) ThirdByte2 (0x200) ThirdByte3 (0x300) ] FirstByteMask [ (0x3) FirstByte3 (0x3) ] SecondByteMask [ (0x30) SecondByte3 (0x30) ] ValueOutsideMask [ (0x1) FirstByte1 (0x1) ] FirstSecondByteMask [ (0xFF) ] FirstSecondThirdByteMask [ (0x333) FirstByte3 (0x3) SecondByte3 (0x30) ThirdByte3 (0x300) ] )"; const char *JSONExpectedOut = R"({ "ZeroFlag": { "Value": 0, "Flags": [] }, "NoFlag": { "Value": 8, "Flags": [] }, "Flag1": { "Value": 1, "Flags": [ { "Name": "Name1", "Value": 1 } ] }, "Flag1&3": { "Value": 5, "Flags": [ { "Name": "Name1", "Value": 1 }, { "Name": "Name3", "Value": 4 } ] }, "ZeroFlagRaw": { "Value": 0, "Flags": [] }, "NoFlagRaw": { "Value": 8, "Flags": [ 8 ] }, "Flag1Raw": { "Value": 1, "Flags": [ 1 ] }, "Flag1&3Raw": { "Value": 5, "Flags": [ 1, 4 ] }, "FlagSorted": { "Value": 7, "Flags": [ { "Name": "A", "Value": 4 }, { "Name": "B", "Value": 2 }, { "Name": "C", "Value": 1 } ] }, "NoBitMask": { "Value": 4095, "Flags": [ { "Name": "FirstByte1", "Value": 1 }, { "Name": "FirstByte2", "Value": 2 }, { "Name": "FirstByte3", "Value": 3 }, { "Name": "SecondByte1", "Value": 16 }, { "Name": "SecondByte2", "Value": 32 }, { "Name": "SecondByte3", "Value": 48 }, { "Name": "ThirdByte1", "Value": 256 }, { "Name": "ThirdByte2", "Value": 512 }, { "Name": "ThirdByte3", "Value": 768 } ] }, "FirstByteMask": { "Value": 3, "Flags": [ { "Name": "FirstByte3", "Value": 3 } ] }, "SecondByteMask": { "Value": 48, "Flags": [ { "Name": "SecondByte3", "Value": 48 } ] }, "ValueOutsideMask": { "Value": 1, "Flags": [ { "Name": "FirstByte1", "Value": 1 } ] }, "FirstSecondByteMask": { "Value": 255, "Flags": [] }, "FirstSecondThirdByteMask": { "Value": 819, "Flags": [ { "Name": "FirstByte3", "Value": 3 }, { "Name": "SecondByte3", "Value": 48 }, { "Name": "ThirdByte3", "Value": 768 } ] } })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } // Format floats using the same format string as PrintNumber, so we can check // the output on all platforms. template , bool> = true> std::string formatFloatString(T Val) { std::string Ret; raw_string_ostream OS(Ret); OS << format("%5.1f", Val); return Ret; } // Format floats using the same format string used in JSON, so we can check the // output on all platforms. template , bool> = true> std::string formatJsonFloatString(T Val) { std::string Ret; raw_string_ostream OS(Ret); OS << format("%.*g", std::numeric_limits::max_digits10, Val); return Ret; } TEST_F(ScopedPrinterTest, PrintNumber) { constexpr float MaxFloat = std::numeric_limits::max(); constexpr float MinFloat = std::numeric_limits::min(); constexpr float InfFloat = std::numeric_limits::infinity(); const float NaNFloat = std::nanf("1"); constexpr double MaxDouble = std::numeric_limits::max(); constexpr double MinDouble = std::numeric_limits::min(); constexpr double InfDouble = std::numeric_limits::infinity(); const double NaNDouble = std::nan("1"); auto PrintFunc = [&](ScopedPrinter &W) { uint64_t Unsigned64Max = std::numeric_limits::max(); uint64_t Unsigned64Min = std::numeric_limits::min(); W.printNumber("uint64_t-max", Unsigned64Max); W.printNumber("uint64_t-min", Unsigned64Min); uint32_t Unsigned32Max = std::numeric_limits::max(); uint32_t Unsigned32Min = std::numeric_limits::min(); W.printNumber("uint32_t-max", Unsigned32Max); W.printNumber("uint32_t-min", Unsigned32Min); uint16_t Unsigned16Max = std::numeric_limits::max(); uint16_t Unsigned16Min = std::numeric_limits::min(); W.printNumber("uint16_t-max", Unsigned16Max); W.printNumber("uint16_t-min", Unsigned16Min); uint8_t Unsigned8Max = std::numeric_limits::max(); uint8_t Unsigned8Min = std::numeric_limits::min(); W.printNumber("uint8_t-max", Unsigned8Max); W.printNumber("uint8_t-min", Unsigned8Min); int64_t Signed64Max = std::numeric_limits::max(); int64_t Signed64Min = std::numeric_limits::min(); W.printNumber("int64_t-max", Signed64Max); W.printNumber("int64_t-min", Signed64Min); int32_t Signed32Max = std::numeric_limits::max(); int32_t Signed32Min = std::numeric_limits::min(); W.printNumber("int32_t-max", Signed32Max); W.printNumber("int32_t-min", Signed32Min); int16_t Signed16Max = std::numeric_limits::max(); int16_t Signed16Min = std::numeric_limits::min(); W.printNumber("int16_t-max", Signed16Max); W.printNumber("int16_t-min", Signed16Min); int8_t Signed8Max = std::numeric_limits::max(); int8_t Signed8Min = std::numeric_limits::min(); W.printNumber("int8_t-max", Signed8Max); W.printNumber("int8_t-min", Signed8Min); APSInt LargeNum("9999999999999999999999"); W.printNumber("apsint", LargeNum); W.printNumber("label", "value", 0); W.printNumber("float-max", MaxFloat); W.printNumber("float-min", MinFloat); W.printNumber("float-inf", InfFloat); W.printNumber("float-nan", NaNFloat); W.printNumber("float-42.0", 42.0f); W.printNumber("float-42.5625", 42.5625f); W.printNumber("double-max", MaxDouble); W.printNumber("double-min", MinDouble); W.printNumber("double-inf", InfDouble); W.printNumber("double-nan", NaNDouble); W.printNumber("double-42.0", 42.0); W.printNumber("double-42.5625", 42.5625); }; std::string ExpectedOut = Twine( R"(uint64_t-max: 18446744073709551615 uint64_t-min: 0 uint32_t-max: 4294967295 uint32_t-min: 0 uint16_t-max: 65535 uint16_t-min: 0 uint8_t-max: 255 uint8_t-min: 0 int64_t-max: 9223372036854775807 int64_t-min: -9223372036854775808 int32_t-max: 2147483647 int32_t-min: -2147483648 int16_t-max: 32767 int16_t-min: -32768 int8_t-max: 127 int8_t-min: -128 apsint: 9999999999999999999999 label: value (0) float-max: )" + formatFloatString(MaxFloat) + R"( float-min: 0.0 float-inf: )" + formatFloatString(InfFloat) + R"( float-nan: )" + formatFloatString(NaNFloat) + R"( float-42.0: 42.0 float-42.5625: 42.6 double-max: )" + formatFloatString(MaxDouble) + R"( double-min: 0.0 double-inf: )" + formatFloatString(InfDouble) + R"( double-nan: )" + formatFloatString(NaNDouble) + R"( double-42.0: 42.0 double-42.5625: 42.6 )") .str(); std::string JSONExpectedOut = Twine(R"({ "uint64_t-max": 18446744073709551615, "uint64_t-min": 0, "uint32_t-max": 4294967295, "uint32_t-min": 0, "uint16_t-max": 65535, "uint16_t-min": 0, "uint8_t-max": 255, "uint8_t-min": 0, "int64_t-max": 9223372036854775807, "int64_t-min": -9223372036854775808, "int32_t-max": 2147483647, "int32_t-min": -2147483648, "int16_t-max": 32767, "int16_t-min": -32768, "int8_t-max": 127, "int8_t-min": -128, "apsint": 9999999999999999999999, "label": { "Name": "value", "Value": 0 }, "float-max": 3.4028234663852886e+38, "float-min": 1.1754943508222875e-38, "float-inf": )" + formatJsonFloatString(InfFloat) + R"(, "float-nan": )" + formatJsonFloatString(NaNFloat) + R"(, "float-42.0": 42, "float-42.5625": 42.5625, "double-max": 1.7976931348623157e+308, "double-min": 2.2250738585072014e-308, "double-inf": )" + formatJsonFloatString(InfDouble) + R"(, "double-nan": )" + formatJsonFloatString(NaNDouble) + R"(, "double-42.0": 42, "double-42.5625": 42.5625 })") .str(); verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintBoolean) { auto PrintFunc = [](ScopedPrinter &W) { W.printBoolean("True", true); W.printBoolean("False", false); }; const char *ExpectedOut = R"(True: Yes False: No )"; const char *JSONExpectedOut = R"({ "True": true, "False": false })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintVersion) { auto PrintFunc = [](ScopedPrinter &W) { W.printVersion("Version", "123", "456", "789"); }; const char *ExpectedOut = R"(Version: 123.456.789 )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintList) { auto PrintFunc = [](ScopedPrinter &W) { const std::vector EmptyList; const std::vector StringList = {"foo", "bar", "baz"}; const bool BoolList[] = {true, false}; const std::vector Unsigned64List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Unsigned32List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Unsigned16List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Unsigned8List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Signed64List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Signed32List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Signed16List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector Signed8List = { std::numeric_limits::max(), std::numeric_limits::min()}; const std::vector APSIntList = {APSInt("9999999999999999999999"), APSInt("-9999999999999999999999")}; W.printList("EmptyList", EmptyList); W.printList("StringList", StringList); W.printList("BoolList", ArrayRef(BoolList)); W.printList("uint64List", Unsigned64List); W.printList("uint32List", Unsigned32List); W.printList("uint16List", Unsigned16List); W.printList("uint8List", Unsigned8List); W.printList("int64List", Signed64List); W.printList("int32List", Signed32List); W.printList("int16List", Signed16List); W.printList("int8List", Signed8List); W.printList("APSIntList", APSIntList); }; const char *ExpectedOut = R"(EmptyList: [] StringList: [foo, bar, baz] BoolList: [1, 0] uint64List: [18446744073709551615, 0] uint32List: [4294967295, 0] uint16List: [65535, 0] uint8List: [255, 0] int64List: [9223372036854775807, -9223372036854775808] int32List: [2147483647, -2147483648] int16List: [32767, -32768] int8List: [127, -128] APSIntList: [9999999999999999999999, -9999999999999999999999] )"; const char *JSONExpectedOut = R"({ "EmptyList": [], "StringList": [ "foo", "bar", "baz" ], "BoolList": [ true, false ], "uint64List": [ 18446744073709551615, 0 ], "uint32List": [ 4294967295, 0 ], "uint16List": [ 65535, 0 ], "uint8List": [ 255, 0 ], "int64List": [ 9223372036854775807, -9223372036854775808 ], "int32List": [ 2147483647, -2147483648 ], "int16List": [ 32767, -32768 ], "int8List": [ 127, -128 ], "APSIntList": [ 9999999999999999999999, -9999999999999999999999 ] })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintListPrinter) { auto PrintFunc = [](ScopedPrinter &W) { const std::string StringList[] = {"a", "ab", "abc"}; W.printList("StringSizeList", StringList, [](raw_ostream &OS, StringRef Item) { OS << Item.size(); }); }; const char *ExpectedOut = R"(StringSizeList: [1, 2, 3] )"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintHex) { auto PrintFunc = [](ScopedPrinter &W) { W.printHex("HexNumber", 0x10); W.printHex("HexLabel", "Name", 0x10); }; const char *ExpectedOut = R"(HexNumber: 0x10 HexLabel: Name (0x10) )"; const char *JSONExpectedOut = R"({ "HexNumber": 16, "HexLabel": { "Name": "Name", "Value": 16 } })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintHexList) { auto PrintFunc = [](ScopedPrinter &W) { const uint64_t HexList[] = {0x1, 0x10, 0x100}; W.printHexList("HexList", HexList); }; const char *ExpectedOut = R"(HexList: [0x1, 0x10, 0x100] )"; const char *JSONExpectedOut = R"({ "HexList": [ 1, 16, 256 ] })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintSymbolOffset) { auto PrintFunc = [](ScopedPrinter &W) { W.printSymbolOffset("SymbolOffset", "SymbolName", 0x10); W.printSymbolOffset("NoSymbolOffset", "SymbolName", 0); }; const char *ExpectedOut = R"(SymbolOffset: SymbolName+0x10 NoSymbolOffset: SymbolName+0x0 )"; const char *JSONExpectedOut = R"({ "SymbolOffset": { "SymName": "SymbolName", "Offset": 16 }, "NoSymbolOffset": { "SymName": "SymbolName", "Offset": 0 } })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintString) { auto PrintFunc = [](ScopedPrinter &W) { const StringRef StringRefValue("Value"); const std::string StringValue = "Value"; const char *CharArrayValue = "Value"; W.printString("StringRef", StringRefValue); W.printString("String", StringValue); W.printString("CharArray", CharArrayValue); ListScope L(W, "StringList"); W.printString(StringRefValue); }; const char *ExpectedOut = R"(StringRef: Value String: Value CharArray: Value StringList [ Value ] )"; const char *JSONExpectedOut = R"({ "StringRef": "Value", "String": "Value", "CharArray": "Value", "StringList": [ "Value" ] })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintBinary) { auto PrintFunc = [](ScopedPrinter &W) { std::vector IntArray = {70, 111, 111, 66, 97, 114}; std::vector CharArray = {'F', 'o', 'o', 'B', 'a', 'r'}; std::vector InvalidChars = {255, 255}; W.printBinary("Binary1", "FooBar", IntArray); W.printBinary("Binary2", "FooBar", CharArray); W.printBinary("Binary3", IntArray); W.printBinary("Binary4", CharArray); W.printBinary("Binary5", StringRef("FooBar")); W.printBinary("Binary6", StringRef("Multiple Line FooBar")); W.printBinaryBlock("Binary7", IntArray, 20); W.printBinaryBlock("Binary8", IntArray); W.printBinaryBlock("Binary9", "FooBar"); W.printBinaryBlock("Binary10", "Multiple Line FooBar"); W.printBinaryBlock("Binary11", InvalidChars); }; const char *ExpectedOut = R"(Binary1: FooBar (46 6F 6F 42 61 72) Binary2: FooBar (46 6F 6F 42 61 72) Binary3: (46 6F 6F 42 61 72) Binary4: (46 6F 6F 42 61 72) Binary5: (46 6F 6F 42 61 72) Binary6 ( 0000: 4D756C74 69706C65 204C696E 6520466F |Multiple Line Fo| 0010: 6F426172 |oBar| ) Binary7 ( 0014: 466F6F42 6172 |FooBar| ) Binary8 ( 0000: 466F6F42 6172 |FooBar| ) Binary9 ( 0000: 466F6F42 6172 |FooBar| ) Binary10 ( 0000: 4D756C74 69706C65 204C696E 6520466F |Multiple Line Fo| 0010: 6F426172 |oBar| ) Binary11 ( 0000: FFFF |..| ) )"; const char *JSONExpectedOut = R"({ "Binary1": { "Value": "FooBar", "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary2": { "Value": "FooBar", "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary3": { "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary4": { "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary5": { "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary6": { "Offset": 0, "Bytes": [ 77, 117, 108, 116, 105, 112, 108, 101, 32, 76, 105, 110, 101, 32, 70, 111, 111, 66, 97, 114 ] }, "Binary7": { "Offset": 20, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary8": { "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary9": { "Offset": 0, "Bytes": [ 70, 111, 111, 66, 97, 114 ] }, "Binary10": { "Offset": 0, "Bytes": [ 77, 117, 108, 116, 105, 112, 108, 101, 32, 76, 105, 110, 101, 32, 70, 111, 111, 66, 97, 114 ] }, "Binary11": { "Offset": 0, "Bytes": [ 255, 255 ] } })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintObject) { auto PrintFunc = [](ScopedPrinter &W) { W.printObject("Object", "Value"); }; const char *ExpectedOut = R"(Object: Value )"; const char *JSONExpectedOut = R"({ "Object": "Value" })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, StartLine) { auto PrintFunc = [](ScopedPrinter &W) { W.startLine() << "|"; W.indent(2); W.startLine() << "|"; W.unindent(); W.startLine() << "|"; }; const char *ExpectedOut = "| | |"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, GetOStream) { auto PrintFunc = [](ScopedPrinter &W) { W.getOStream() << "Test"; }; const char *ExpectedOut = "Test"; verifyScopedPrinter(ExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintScope) { auto PrintFunc = [](ScopedPrinter &W) { { DictScope O(W, "Object"); { DictScope OO(W, "ObjectInObject"); } { ListScope LO(W, "ListInObject"); } } { ListScope L(W, "List"); { DictScope OL(W, "ObjectInList"); } { ListScope LL(W, "ListInList"); } } }; const char *ExpectedOut = R"(Object { ObjectInObject { } ListInObject [ ] } List [ ObjectInList { } ListInList [ ] ] )"; const char *JSONExpectedOut = R"({ "Object": { "ObjectInObject": {}, "ListInObject": [] }, "List": [ { "ObjectInList": {} }, { "ListInList": [] } ] })"; verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); }