Index: llvm/unittests/Support/CMakeLists.txt =================================================================== --- llvm/unittests/Support/CMakeLists.txt +++ llvm/unittests/Support/CMakeLists.txt @@ -68,6 +68,7 @@ ReplaceFileTest.cpp RISCVAttributeParserTest.cpp ScaledNumberTest.cpp + ScopedPrinterTest.cpp SHA256.cpp SourceMgrTest.cpp SpecialCaseListTest.cpp Index: llvm/unittests/Support/ScopedPrinterTest.cpp =================================================================== --- /dev/null +++ llvm/unittests/Support/ScopedPrinterTest.cpp @@ -0,0 +1,629 @@ +//===- 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 "gtest/gtest.h" +#include + +using namespace llvm; + +class ScopedPrinterTest : public ::testing::Test { +protected: + using PrintFunc = + function_ref; + + void verifyScopedPrinter(StringRef Expected, PrintFunc Func) { + std::string StreamBuffer; + raw_string_ostream OS(StreamBuffer); + ScopedPrinter Writer(OS); + EXPECT_EQ(Expected.str(), Func(OS, Writer)); + } +}; + +TEST_F(ScopedPrinterTest, Indent) { + auto IndentFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.printString("|"); + W.indent(); + W.printString("|"); + W.indent(2); + W.printString("|"); + W.flush(); + return OS.str(); + }; + + const char *IndentOut = R"(| + | + | +)"; + verifyScopedPrinter(IndentOut, IndentFunc); +} + +TEST_F(ScopedPrinterTest, Unindent) { + auto UnindentFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.indent(3); + W.printString("|"); + W.unindent(2); + W.printString("|"); + W.unindent(); + W.printString("|"); + W.unindent(); + W.printString("|"); + W.flush(); + return OS.str(); + }; + + const char *UnindentOut = R"( | + | +| +| +)"; + verifyScopedPrinter(UnindentOut, UnindentFunc); +} + +TEST_F(ScopedPrinterTest, ResetIndent) { + auto ResetIndentFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.indent(4); + W.printString("|"); + W.resetIndent(); + W.printString("|"); + W.flush(); + return OS.str(); + }; + + const char *ResetIndentOut = R"( | +| +)"; + verifyScopedPrinter(ResetIndentOut, ResetIndentFunc); +} + +TEST_F(ScopedPrinterTest, PrintIndent) { + auto ResetIndentFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.printIndent(); + W.printString("|"); + W.indent(); + W.printIndent(); + W.printString("|"); + W.flush(); + return OS.str(); + }; + + const char *ResetIndentOut = R"(| + | +)"; + verifyScopedPrinter(ResetIndentOut, ResetIndentFunc); +} + +TEST_F(ScopedPrinterTest, GetIndentLevel) { + std::string StreamBuffer; + raw_string_ostream OS(StreamBuffer); + ScopedPrinter W(OS); + EXPECT_EQ(W.getIndentLevel(), 0); + W.indent(); + EXPECT_EQ(W.getIndentLevel(), 1); + W.indent(); + EXPECT_EQ(W.getIndentLevel(), 2); + W.unindent(); + EXPECT_EQ(W.getIndentLevel(), 1); + W.indent(); + W.resetIndent(); + EXPECT_EQ(W.getIndentLevel(), 0); + W.unindent(); + EXPECT_EQ(W.getIndentLevel(), 0); + W.indent(); + EXPECT_EQ(W.getIndentLevel(), 1); +} + +TEST_F(ScopedPrinterTest, SetPrefix) { + auto SetPrefixFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.setPrefix("Prefix1"); + W.indent(); + W.printIndent(); + W.printString("|"); + W.unindent(); + W.printIndent(); + W.printString("|"); + W.setPrefix("Prefix2"); + W.printIndent(); + W.printString("|"); + return OS.str(); + }; + + const char *SetPrefixOut = R"(Prefix1 Prefix1 | +Prefix1Prefix1| +Prefix2Prefix2| +)"; + verifyScopedPrinter(SetPrefixOut, SetPrefixFunc); +} + +TEST_F(ScopedPrinterTest, PrintEnum) { + auto EnumFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + const EnumEntry EnumList[] = {{"Name1", "AltName1", 1}, + {"Name2", "AltName2", 2}, + {"Name3", "AltName3", 3}, + {"Name4", "AltName4", 2}}; + EnumEntry OtherEnum{"Name5", "AltName5", 5}; + { + DictScope D(W); + W.printEnum("Exists", EnumList[1].Value, makeArrayRef(EnumList)); + W.printEnum("DoesNotExist", OtherEnum.Value, makeArrayRef(EnumList)); + } + return OS.str(); + }; + + const char *Out = R"({ + Exists: Name2 (0x2) + DoesNotExist: 0x5 +} +)"; + verifyScopedPrinter(Out, EnumFunc); +} + +TEST_F(ScopedPrinterTest, PrintFlag) { + auto FlagFunc = [](raw_string_ostream &OS, 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}}; + { + DictScope D(W); + W.printFlags("ZeroFlag", 0, makeArrayRef(SingleBitFlags)); + W.printFlags("NoFlag", 1 << 3, makeArrayRef(SingleBitFlags)); + W.printFlags("Flag1", SingleBitFlags[1].Value, + makeArrayRef(SingleBitFlags)); + W.printFlags("Flag1&3", (1 << 2) + 1, makeArrayRef(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, + makeArrayRef(UnsortedFlags)); + + uint16_t NoBitMask = 0; + uint16_t FirstByteMask = 0xFu; + uint16_t SecondByteMask = 0xF0u; + uint16_t ThirdByteMask = 0xF00u; + W.printFlags("NoBitMask", 0xFFFu, makeArrayRef(EnumFlags), NoBitMask); + W.printFlags("FirstByteMask", 0x3u, makeArrayRef(EnumFlags), + FirstByteMask); + W.printFlags("SecondByteMask", 0x30u, makeArrayRef(EnumFlags), + SecondByteMask); + W.printFlags("ValueOutsideMask", 0x1u, makeArrayRef(EnumFlags), + SecondByteMask); + W.printFlags("FirstSecondByteMask", 0xFFu, makeArrayRef(EnumFlags), + FirstByteMask, SecondByteMask); + W.printFlags("FirstSecondThirdByteMask", 0x333u, makeArrayRef(EnumFlags), + FirstByteMask, SecondByteMask, ThirdByteMask); + } + return OS.str(); + }; + + const char *Out = 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) + ] +} +)"; + verifyScopedPrinter(Out, FlagFunc); +} + +TEST_F(ScopedPrinterTest, PrintNumber) { + auto NumberFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(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); + } + return OS.str(); + }; + + const char *Out = 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) +} +)"; + verifyScopedPrinter(Out, NumberFunc); +} + +TEST_F(ScopedPrinterTest, PrintBoolean) { + auto BooleanFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printBoolean("True", true); + W.printBoolean("False", false); + } + return OS.str(); + }; + + const char *Out = R"({ + True: Yes + False: No +} +)"; + verifyScopedPrinter(Out, BooleanFunc); +} + +TEST_F(ScopedPrinterTest, PrintVersion) { + auto VersionFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printVersion("Version", "123", "456", "789"); + } + return OS.str(); + }; + const char *Out = R"({ + Version: 123.456.789 +} +)"; + verifyScopedPrinter(Out, VersionFunc); +} + +TEST_F(ScopedPrinterTest, PrintList) { + auto ListFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + const std::vector EmptyList; + const int NumberList[] = {1, 2, 3}; + const std::string StringList[] = {"foo", "bar", "baz"}; + DictScope D(W); + W.printList("EmptyList", EmptyList); + W.printList("NumberList", NumberList); + W.printList("StringList", StringList); + } + return OS.str(); + }; + + const char *Out = R"({ + EmptyList: [] + NumberList: [1, 2, 3] + StringList: [foo, bar, baz] +} +)"; + verifyScopedPrinter(Out, ListFunc); +} + +TEST_F(ScopedPrinterTest, PrintListPrinter) { + auto ListPrinterFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + const std::string StringList[] = {"a", "ab", "abc"}; + W.printList("StringSizeList", StringList, + [](raw_ostream &OS, StringRef Item) { OS << Item.size(); }); + return OS.str(); + }; + + const char *Out = R"(StringSizeList: [1, 2, 3] +)"; + verifyScopedPrinter(Out, ListPrinterFunc); +} + +TEST_F(ScopedPrinterTest, PrintHex) { + auto HexFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printHex("HexNumber", 0x10); + W.printHex("HexLabel", "Name", 0x10); + } + return OS.str(); + }; + + const char *Out = R"({ + HexNumber: 0x10 + HexLabel: Name (0x10) +} +)"; + verifyScopedPrinter(Out, HexFunc); +} + +TEST_F(ScopedPrinterTest, PrintHexList) { + auto HexListFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + const uint64_t HexList[] = {0x1, 0x10, 0x100}; + W.printHexList("HexList", HexList); + } + return OS.str(); + }; + const char *Out = R"({ + HexList: [0x1, 0x10, 0x100] +} +)"; + verifyScopedPrinter(Out, HexListFunc); +} + +TEST_F(ScopedPrinterTest, PrintSymbolOffset) { + auto SymbolOffsetFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printSymbolOffset("SymbolOffset", "SymbolName", 0x10); + W.printSymbolOffset("NoSymbolOffset", "SymbolName", 0); + } + return OS.str(); + }; + const char *Out = R"({ + SymbolOffset: SymbolName+0x10 + NoSymbolOffset: SymbolName+0x0 +} +)"; + verifyScopedPrinter(Out, SymbolOffsetFunc); +} + +TEST_F(ScopedPrinterTest, PrintString) { + auto StringFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(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); + } + return OS.str(); + }; + + const char *Out = R"({ + StringRef: Value + String: Value + CharArray: Value + StringList [ + Value + ] +} +)"; + verifyScopedPrinter(Out, StringFunc); +} + +TEST_F(ScopedPrinterTest, PrintBinary) { + auto BinaryFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(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); + } + return OS.str(); + }; + + const char *Out = 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 |..| + ) +} +)"; + verifyScopedPrinter(Out, BinaryFunc); +} + +TEST_F(ScopedPrinterTest, PrintObject) { + auto ObjectFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printObject("Object", "Value"); + } + return OS.str(); + }; + + const char *Out = R"({ + Object: Value +} +)"; + verifyScopedPrinter(Out, ObjectFunc); +} + +TEST_F(ScopedPrinterTest, StartLine) { + auto StartLineFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.startLine() << "|"; + W.indent(2); + W.startLine() << "|"; + W.unindent(); + W.startLine() << "|"; + return OS.str(); + }; + + const char *Out = "| | |"; + verifyScopedPrinter(Out, StartLineFunc); +} + +TEST_F(ScopedPrinterTest, GetOStream) { + auto GetOStreamFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.getOStream() << "Test"; + return OS.str(); + }; + + const char *Out = "Test"; + verifyScopedPrinter(Out, GetOStreamFunc); +} + +TEST_F(ScopedPrinterTest, PrintScope) { + auto ScopeFunc = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(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"); } + } + } + return OS.str(); + }; + + const char *Out = R"({ + Object { + ObjectInObject { + } + ListInObject [ + ] + } + List [ + ObjectInList { + } + ListInList [ + ] + ] +} +)"; + verifyScopedPrinter(Out, ScopeFunc); +}