Index: llvm/include/llvm/Support/ScopedPrinter.h =================================================================== --- llvm/include/llvm/Support/ScopedPrinter.h +++ llvm/include/llvm/Support/ScopedPrinter.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include @@ -92,7 +93,20 @@ class ScopedPrinter { public: - ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + enum class ScopedPrinterKind { + Base, + JSON, + }; + + ScopedPrinter(raw_ostream &OS, + ScopedPrinterKind Kind = ScopedPrinterKind::Base) + : OS(OS), IndentLevel(0), Kind(Kind) {} + + ScopedPrinterKind getKind() const { return Kind; } + + static bool classof(const ScopedPrinter *SP) { + return SP->getKind() == ScopedPrinterKind::Base; + } virtual ~ScopedPrinter() {} @@ -479,6 +493,7 @@ raw_ostream &OS; int IndentLevel; StringRef Prefix; + ScopedPrinterKind Kind; }; template <> @@ -488,30 +503,329 @@ startLine() << Label << ": " << hex(Value) << "\n"; } +struct DelimitedScope; + +class JSONScopedPrinter : public ScopedPrinter { +private: + enum class Scope { + Array, + Object, + }; + + enum class ScopeKind { + NoAttribute, + Attribute, + NestedAttribute, + }; + + struct ScopeContext { + Scope Context; + ScopeKind Kind; + ScopeContext(Scope Context, ScopeKind Kind = ScopeKind::NoAttribute) + : Context(Context), Kind(Kind) {} + }; + + SmallVector ScopeHistory; + json::OStream JOS; + std::unique_ptr OuterScope; + +public: + JSONScopedPrinter(raw_ostream &OS, bool PrettyPrint = false, + std::unique_ptr &&OuterScope = + std::unique_ptr{}); + + static bool classof(const ScopedPrinter *SP) { + return SP->getKind() == ScopedPrinter::ScopedPrinterKind::JSON; + } + + void printNumber(StringRef Label, uint64_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint16_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint8_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int64_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int16_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int8_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, const APSInt &Value) override { + JOS.attributeBegin(Label); + printAPSInt(Value); + JOS.attributeEnd(); + } + + void printBoolean(StringRef Label, bool Value) override { + JOS.attribute(Label, Value); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + printListImpl(Label, List); + } + + void printList(StringRef Label, const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const APSInt &Item : List) { + printAPSInt(Item); + } + }); + } + + void printString(StringRef Value) override { JOS.value(Value); } + + void printString(StringRef Label, StringRef Value) override { + JOS.attribute(Label, Value); + } + + void objectBegin() override { + scopedBegin({Scope::Object, ScopeKind::NoAttribute}); + } + + void objectBegin(StringRef Label) override { + scopedBegin(Label, Scope::Object); + } + + void objectEnd() override { scopedEnd(); } + + void arrayBegin() override { + scopedBegin({Scope::Array, ScopeKind::NoAttribute}); + } + + void arrayBegin(StringRef Label) override { + scopedBegin(Label, Scope::Array); + } + + void arrayEnd() override { scopedEnd(); } + +private: + // Output HexNumbers as decimals so that they're easier to parse. + uint64_t hexNumberToInt(HexNumber Hex) { return Hex.Value; } + + void printAPSInt(const APSInt &Value) { + JOS.rawValueBegin() << Value; + JOS.rawValueEnd(); + } + + void printFlagsImpl(StringRef Label, HexNumber Value, + ArrayRef Flags) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("RawFlags", hexNumberToInt(Value)); + JOS.attributeArray("Flags", [&]() { + for (const FlagEntry &Flag : Flags) { + JOS.objectBegin(); + JOS.attribute("Name", Flag.Name); + JOS.attribute("Value", Flag.Value); + JOS.objectEnd(); + } + }); + }); + } + + void printFlagsImpl(StringRef Label, HexNumber Value, + ArrayRef Flags) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("RawFlags", hexNumberToInt(Value)); + JOS.attributeArray("Flags", [&]() { + for (const HexNumber &Flag : Flags) { + JOS.value(Flag.Value); + } + }); + }); + } + + template void printListImpl(StringRef Label, const T &List) { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) + JOS.value(Item); + }); + } + + void printHexListImpl(StringRef Label, + const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const HexNumber &Item : List) { + JOS.value(hexNumberToInt(Item)); + } + }); + } + + void printHexImpl(StringRef Label, HexNumber Value) override { + JOS.attribute(Label, hexNumberToInt(Value)); + } + + void printHexImpl(StringRef Label, StringRef Str, HexNumber Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("Value", Str); + JOS.attribute("RawValue", hexNumberToInt(Value)); + }); + } + + void printSymbolOffsetImpl(StringRef Label, StringRef Symbol, + HexNumber Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("SymName", Symbol); + JOS.attribute("Offset", hexNumberToInt(Value)); + }); + } + + void printNumberImpl(StringRef Label, StringRef Str, + StringRef Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("Value", Str); + JOS.attributeBegin("RawValue"); + JOS.rawValueBegin() << Value; + JOS.rawValueEnd(); + JOS.attributeEnd(); + }); + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, + bool Block, uint32_t StartOffset = 0) override { + JOS.attributeObject(Label, [&]() { + if (!Str.empty()) + JOS.attribute("Value", Str); + JOS.attribute("Offset", StartOffset); + JOS.attributeArray("Bytes", [&]() { + for (uint8_t Val : Value) + JOS.value(Val); + }); + }); + } + + void scopedBegin(ScopeContext ScopeCtx) { + if (ScopeCtx.Context == Scope::Object) + JOS.objectBegin(); + else if (ScopeCtx.Context == Scope::Array) + JOS.arrayBegin(); + ScopeHistory.push_back(ScopeCtx); + } + + void scopedBegin(StringRef Label, Scope Ctx) { + ScopeKind Kind = ScopeKind::Attribute; + if (ScopeHistory.empty() || ScopeHistory.back().Context != Scope::Object) { + JOS.objectBegin(); + Kind = ScopeKind::NestedAttribute; + } + JOS.attributeBegin(Label); + scopedBegin({Ctx, Kind}); + } + + void scopedEnd() { + ScopeContext ScopeCtx = ScopeHistory.back(); + if (ScopeCtx.Context == Scope::Object) + JOS.objectEnd(); + else if (ScopeCtx.Context == Scope::Array) + JOS.arrayEnd(); + if (ScopeCtx.Kind == ScopeKind::Attribute || + ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.attributeEnd(); + if (ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.objectEnd(); + ScopeHistory.pop_back(); + } +}; + struct DelimitedScope { - DelimitedScope(ScopedPrinter &W) : W(W) {} + DelimitedScope(ScopedPrinter &W) : W(&W) {} + DelimitedScope() : W(nullptr) {} virtual ~DelimitedScope(){}; - ScopedPrinter &W; + virtual void setPrinter(ScopedPrinter &W) = 0; + ScopedPrinter *W; }; struct DictScope : DelimitedScope { + explicit DictScope() : DelimitedScope() {} explicit DictScope(ScopedPrinter &W) : DelimitedScope(W) { W.objectBegin(); } DictScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) { W.objectBegin(N); } - ~DictScope() { W.objectEnd(); } + void setPrinter(ScopedPrinter &W) override { + this->W = &W; + W.objectBegin(); + } + + ~DictScope() { + if (W) + W->objectEnd(); + } }; struct ListScope : DelimitedScope { + explicit ListScope() : DelimitedScope() {} explicit ListScope(ScopedPrinter &W) : DelimitedScope(W) { W.arrayBegin(); } ListScope(ScopedPrinter &W, StringRef N) : DelimitedScope(W) { W.arrayBegin(N); } - ~ListScope() { W.arrayEnd(); } + void setPrinter(ScopedPrinter &W) override { + this->W = &W; + W.arrayBegin(); + } + + ~ListScope() { + if (W) + W->arrayEnd(); + } }; } // namespace llvm Index: llvm/lib/Support/ScopedPrinter.cpp =================================================================== --- llvm/lib/Support/ScopedPrinter.cpp +++ llvm/lib/Support/ScopedPrinter.cpp @@ -43,4 +43,14 @@ } } +JSONScopedPrinter::JSONScopedPrinter( + raw_ostream &OS, bool PrettyPrint, + std::unique_ptr &&OuterScope) + : ScopedPrinter(OS, ScopedPrinter::ScopedPrinterKind::JSON), + JOS(OS, /*Indent=*/PrettyPrint ? 2 : 0), + OuterScope(std::move(OuterScope)) { + if (this->OuterScope) + this->OuterScope->setPrinter(*this); +} + } // namespace llvm Index: llvm/tools/llvm-readobj/ARMEHABIPrinter.h =================================================================== --- llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -512,7 +512,7 @@ void PrinterContext::PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const { ListScope OCC(SW, "Opcodes"); - OpcodeDecoder(OCC.W).Decode(Entry, Offset, Length); + OpcodeDecoder(SW).Decode(Entry, Offset, Length); } template Index: llvm/unittests/Support/ScopedPrinterTest.cpp =================================================================== --- llvm/unittests/Support/ScopedPrinterTest.cpp +++ llvm/unittests/Support/ScopedPrinterTest.cpp @@ -13,13 +13,63 @@ 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, OS.str()); + StreamBuffer.clear(); + PrintFunc(NoPrettyPrintWriter); + EXPECT_EQ(NoPrettyPrintOut, OS.str()); +} + +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"})", OS.str()); + StreamBuffer.clear(); + { + JSONScopedPrinter ListScopeWriter(OS, /*PrettyPrint=*/false, + std::make_unique()); + ListScopeWriter.printString("ListScope"); + } + EXPECT_EQ(R"(["ListScope"])", OS.str()); + StreamBuffer.clear(); + { + JSONScopedPrinter NoScopeWriter(OS, /*PrettyPrint=*/false); + NoScopeWriter.printString("NoScope"); + } + EXPECT_EQ(R"("NoScope")", OS.str()); +} + class ScopedPrinterTest : public ::testing::Test { protected: std::string StreamBuffer; raw_string_ostream OS; ScopedPrinter Writer; + JSONScopedPrinter JSONWriter; - ScopedPrinterTest() : OS(StreamBuffer), Writer(OS) {} + bool HasPrintedToJSON; + + ScopedPrinterTest() + : OS(StreamBuffer), Writer(OS), JSONWriter(OS, /*PrettyPrint=*/true), + HasPrintedToJSON(false) {} using PrintFunc = function_ref; @@ -27,9 +77,45 @@ Func(Writer); Writer.flush(); EXPECT_EQ(Expected.str(), OS.str()); + StreamBuffer.clear(); + } + + void verifyJSONScopedPrinter(StringRef Expected, PrintFunc Func) { + { + DictScope D(JSONWriter); + Func(JSONWriter); + } + JSONWriter.flush(); + EXPECT_EQ(Expected.str(), OS.str()); + 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("|"); @@ -147,7 +233,15 @@ const char *ExpectedOut = R"(Exists: Name2 (0x2) DoesNotExist: 0x5 )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "Exists": { + "Value": "Name2", + "RawValue": 2 + }, + "DoesNotExist": 5 +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintFlag) { @@ -251,7 +345,169 @@ ThirdByte3 (0x300) ] )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "ZeroFlag": { + "RawFlags": 0, + "Flags": [] + }, + "NoFlag": { + "RawFlags": 8, + "Flags": [] + }, + "Flag1": { + "RawFlags": 1, + "Flags": [ + { + "Name": "Name1", + "Value": 1 + } + ] + }, + "Flag1&3": { + "RawFlags": 5, + "Flags": [ + { + "Name": "Name1", + "Value": 1 + }, + { + "Name": "Name3", + "Value": 4 + } + ] + }, + "ZeroFlagRaw": { + "RawFlags": 0, + "Flags": [] + }, + "NoFlagRaw": { + "RawFlags": 8, + "Flags": [ + 8 + ] + }, + "Flag1Raw": { + "RawFlags": 1, + "Flags": [ + 1 + ] + }, + "Flag1&3Raw": { + "RawFlags": 5, + "Flags": [ + 1, + 4 + ] + }, + "FlagSorted": { + "RawFlags": 7, + "Flags": [ + { + "Name": "A", + "Value": 4 + }, + { + "Name": "B", + "Value": 2 + }, + { + "Name": "C", + "Value": 1 + } + ] + }, + "NoBitMask": { + "RawFlags": 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": { + "RawFlags": 3, + "Flags": [ + { + "Name": "FirstByte3", + "Value": 3 + } + ] + }, + "SecondByteMask": { + "RawFlags": 48, + "Flags": [ + { + "Name": "SecondByte3", + "Value": 48 + } + ] + }, + "ValueOutsideMask": { + "RawFlags": 1, + "Flags": [ + { + "Name": "FirstByte1", + "Value": 1 + } + ] + }, + "FirstSecondByteMask": { + "RawFlags": 255, + "Flags": [] + }, + "FirstSecondThirdByteMask": { + "RawFlags": 819, + "Flags": [ + { + "Name": "FirstByte3", + "Value": 3 + }, + { + "Name": "SecondByte3", + "Value": 48 + }, + { + "Name": "ThirdByte3", + "Value": 768 + } + ] + } +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintNumber) { @@ -321,7 +577,31 @@ apsint: 9999999999999999999999 label: value (0) )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = 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": "value", + "RawValue": 0 + } +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintBoolean) { @@ -333,7 +613,12 @@ const char *ExpectedOut = R"(True: Yes False: No )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "True": true, + "False": false +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintVersion) { @@ -402,7 +687,56 @@ int8List: [127, -128] APSIntList: [9999999999999999999999, -9999999999999999999999] )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + 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) { @@ -426,7 +760,15 @@ const char *ExpectedOut = R"(HexNumber: 0x10 HexLabel: Name (0x10) )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "HexNumber": 16, + "HexLabel": { + "Value": "Name", + "RawValue": 16 + } +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintHexList) { @@ -436,7 +778,15 @@ }; const char *ExpectedOut = R"(HexList: [0x1, 0x10, 0x100] )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "HexList": [ + 1, + 16, + 256 + ] +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintSymbolOffset) { @@ -447,7 +797,18 @@ const char *ExpectedOut = R"(SymbolOffset: SymbolName+0x10 NoSymbolOffset: SymbolName+0x0 )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "SymbolOffset": { + "SymName": "SymbolName", + "Offset": 16 + }, + "NoSymbolOffset": { + "SymName": "SymbolName", + "Offset": 0 + } +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintString) { @@ -469,7 +830,16 @@ Value ] )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "StringRef": "Value", + "String": "Value", + "CharArray": "Value", + "StringList": [ + "Value" + ] +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, PrintBinary) { @@ -516,7 +886,157 @@ 0000: FFFF |..| ) )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + 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) { @@ -524,7 +1044,11 @@ const char *ExpectedOut = R"(Object: Value )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "Object": "Value" +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); } TEST_F(ScopedPrinterTest, StartLine) { @@ -574,5 +1098,20 @@ ] ] )"; - verifyScopedPrinter(ExpectedOut, PrintFunc); + + const char *JSONExpectedOut = R"({ + "Object": { + "ObjectInObject": {}, + "ListInObject": [] + }, + "List": [ + { + "ObjectInList": {} + }, + { + "ListInList": [] + } + ] +})"; + verifyAll(ExpectedOut, JSONExpectedOut, PrintFunc); }