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,581 @@ +//===- 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: + std::string StreamBuffer; + raw_string_ostream OS; + ScopedPrinter Writer; + + ScopedPrinterTest() : OS(StreamBuffer), Writer(OS) {} + + using PrintFunc = function_ref; + + void verifyScopedPrinter(StringRef Expected, PrintFunc Func) { + Func(Writer); + EXPECT_EQ(Expected.str(), OS.str()); + } +}; + +TEST_F(ScopedPrinterTest, Indent) { + auto PrintFunc = [](ScopedPrinter &W) { + W.printString("|"); + W.indent(); + W.printString("|"); + W.indent(2); + W.printString("|"); + W.flush(); + }; + + 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("|"); + W.flush(); + }; + + const char *ExpectedOut = R"( | + | +| +| +)"; + verifyScopedPrinter(ExpectedOut, PrintFunc); +} + +TEST_F(ScopedPrinterTest, ResetIndent) { + auto PrintFunc = [](ScopedPrinter &W) { + W.indent(4); + W.printString("|"); + W.resetIndent(); + W.printString("|"); + W.flush(); + }; + + 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("|"); + W.flush(); + }; + + 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, makeArrayRef(EnumList)); + W.printEnum("DoesNotExist", OtherEnum.Value, makeArrayRef(EnumList)); + }; + + const char *ExpectedOut = R"(Exists: Name2 (0x2) +DoesNotExist: 0x5 +)"; + verifyScopedPrinter(ExpectedOut, 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, 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); + }; + + 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) +] +)"; + verifyScopedPrinter(ExpectedOut, PrintFunc); +} + +TEST_F(ScopedPrinterTest, PrintNumber) { + 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); + }; + + const char *ExpectedOut = 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(ExpectedOut, 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 +)"; + verifyScopedPrinter(ExpectedOut, 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", makeArrayRef(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] +)"; + verifyScopedPrinter(ExpectedOut, 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) +)"; + verifyScopedPrinter(ExpectedOut, 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] +)"; + verifyScopedPrinter(ExpectedOut, 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 +)"; + verifyScopedPrinter(ExpectedOut, 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 +] +)"; + verifyScopedPrinter(ExpectedOut, 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 |..| +) +)"; + verifyScopedPrinter(ExpectedOut, PrintFunc); +} + +TEST_F(ScopedPrinterTest, PrintObject) { + auto PrintFunc = [](ScopedPrinter &W) { W.printObject("Object", "Value"); }; + + const char *ExpectedOut = R"(Object: Value +)"; + verifyScopedPrinter(ExpectedOut, 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 [ + ] +] +)"; + verifyScopedPrinter(ExpectedOut, PrintFunc); +}