diff --git a/llvm/unittests/Support/CMakeLists.txt b/llvm/unittests/Support/CMakeLists.txt --- a/llvm/unittests/Support/CMakeLists.txt +++ b/llvm/unittests/Support/CMakeLists.txt @@ -68,6 +68,7 @@ ReplaceFileTest.cpp RISCVAttributeParserTest.cpp ScaledNumberTest.cpp + ScopedPrinterTest.cpp SHA256.cpp SourceMgrTest.cpp SpecialCaseListTest.cpp diff --git a/llvm/unittests/Support/ScopedPrinterTest.cpp b/llvm/unittests/Support/ScopedPrinterTest.cpp new file mode 100644 --- /dev/null +++ b/llvm/unittests/Support/ScopedPrinterTest.cpp @@ -0,0 +1,383 @@ +//===- 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 PrintFcn = + function_ref; + + void verifyScopedPrinter(StringRef Expected, PrintFcn Fcn) { + std::string StreamBuffer; + raw_string_ostream OS(StreamBuffer); + ScopedPrinter Writer(OS); + EXPECT_EQ(Expected.str(), Fcn(OS, Writer)); + } +}; + +TEST_F(ScopedPrinterTest, PrintIndent) { + auto IndentFcn = [](raw_string_ostream &OS, ScopedPrinter &W) { + W.indent(); + W.printString("|"); + W.indent(); + W.printString("|"); + W.unindent(); + W.printString("|"); + W.flush(); + return OS.str(); + }; + + const char *Out = R"( | + | + | +)"; + verifyScopedPrinter(Out, IndentFcn); +} + +TEST_F(ScopedPrinterTest, PrintNumber) { + auto NumberOutput = [](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, NumberOutput); +} + +TEST_F(ScopedPrinterTest, PrintEnum) { + auto EnumOutput = [](raw_string_ostream &OS, ScopedPrinter &W) { + const EnumEntry EnumList[] = {{"Name1", "AltName1", 1}, + {"Name2", "AltName2", 2}, + {"Name3", "AltName3", 3}}; + EnumEntry OtherEnum{"Name4", "AltName4", 4}; + { + DictScope D(W); + W.printEnum("Exists", EnumList[0].Value, makeArrayRef(EnumList)); + W.printEnum("DoesNotExist", OtherEnum.Value, makeArrayRef(EnumList)); + } + return OS.str(); + }; + + const char *Out = R"({ + Exists: Name1 (0x1) + DoesNotExist: 0x4 +} +)"; + verifyScopedPrinter(Out, EnumOutput); +} + +TEST_F(ScopedPrinterTest, PrintFlag) { + auto FlagOutput = [](raw_string_ostream &OS, ScopedPrinter &W) { + const EnumEntry FlagList[] = {{"Name1", "AltName1", 1}, + {"Name2", "AltName2", 1 << 1}, + {"Name3", "AltName3", 1 << 2}}; + { + DictScope D(W); + W.printFlags("NoFlag", 1 << 3, makeArrayRef(FlagList)); + W.printFlags("Flag1", FlagList[0].Value, makeArrayRef(FlagList)); + W.printFlags("Flag1&3", (1 << 2) + 1, makeArrayRef(FlagList)); + W.printFlags("NoFlagRaw", 1 << 3); + W.printFlags("Flag1Raw", FlagList[0].Value); + W.printFlags("Flag1&3Raw", (1 << 2) + 1); + } + return OS.str(); + }; + + const char *Out = R"({ + NoFlag [ (0x8) + ] + Flag1 [ (0x1) + Name1 (0x1) + ] + Flag1&3 [ (0x5) + Name1 (0x1) + Name3 (0x4) + ] + NoFlagRaw [ (0x8) + 0x8 + ] + Flag1Raw [ (0x1) + 0x1 + ] + Flag1&3Raw [ (0x5) + 0x1 + 0x4 + ] +} +)"; + verifyScopedPrinter(Out, FlagOutput); +} + +TEST_F(ScopedPrinterTest, PrintBoolean) { + auto BooleanOutput = [](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, BooleanOutput); +} + +TEST_F(ScopedPrinterTest, PrintVersion) { + auto VersionOutput = [](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, VersionOutput); +} + +TEST_F(ScopedPrinterTest, PrintList) { + auto ListOutput = [](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, ListOutput); +} + +TEST_F(ScopedPrinterTest, PrintHex) { + auto HexOutput = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + const uint64_t HexList[] = {0x1, 0x10, 0x100}; + W.printHexList("HexList", HexList); + W.printHex("HexNumber", 0x10); + W.printHex("HexLabel", "Name", 0x10); + W.printSymbolOffset("SymbolOffset", "SymbolName", 0x10); + } + return OS.str(); + }; + + const char *Out = R"({ + HexList: [0x1, 0x10, 0x100] + HexNumber: 0x10 + HexLabel: Name (0x10) + SymbolOffset: SymbolName+0x10 +} +)"; + verifyScopedPrinter(Out, HexOutput); +} + +TEST_F(ScopedPrinterTest, PrintString) { + auto StringOutput = [](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); + W.printString(StringRefValue); + } + return OS.str(); + }; + + const char *Out = R"({ + StringRef: Value + String: Value + CharArray: Value + StringList [ + Value + Value + ] +} +)"; + verifyScopedPrinter(Out, StringOutput); +} + +TEST_F(ScopedPrinterTest, PrintBinary) { + auto BinaryOutput = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + const uint8_t IntArray[] = {70, 111, 111, 66, 97, 114}; + const char CharArray[] = {'F', 'o', 'o', 'B', 'a', 'r'}; + W.printBinary("Binary1", "FooBar", makeArrayRef(IntArray)); + W.printBinary("Binary2", "FooBar", makeArrayRef(CharArray)); + W.printBinary("Binary3", makeArrayRef(IntArray)); + W.printBinary("Binary4", makeArrayRef(CharArray)); + W.printBinaryBlock("Binary5", makeArrayRef(IntArray), 20); + W.printBinaryBlock("Binary6", makeArrayRef(IntArray)); + W.printBinaryBlock("Binary7", "FooBar"); + } + 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 ( + 0014: 466F6F42 6172 |FooBar| + ) + Binary6 ( + 0000: 466F6F42 6172 |FooBar| + ) + Binary7 ( + 0000: 466F6F42 6172 |FooBar| + ) +} +)"; + verifyScopedPrinter(Out, BinaryOutput); +} + +TEST_F(ScopedPrinterTest, PrintObject) { + auto ObjectOutput = [](raw_string_ostream &OS, ScopedPrinter &W) { + { + DictScope D(W); + W.printObject("Object", "Value"); + } + return OS.str(); + }; + + const char *Out = R"({ + Object: Value +} +)"; + verifyScopedPrinter(Out, ObjectOutput); +} + +TEST_F(ScopedPrinterTest, PrintScope) { + auto ScopeOutput = [](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, ScopeOutput); +}