diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-04-16 16:01:22 +0000 |
commit | 71d5a2540a98c81f5bcaeb48805e0e2881f530ef (patch) | |
tree | 5343938942df402b49ec7300a1c25a2d4ccd5821 /unittests/Support | |
parent | 31bbf64f3a4974a2d6c8b3b27ad2f519caf74057 (diff) |
Diffstat (limited to 'unittests/Support')
-rw-r--r-- | unittests/Support/ARMAttributeParser.cpp | 385 | ||||
-rw-r--r-- | unittests/Support/AllocatorTest.cpp | 6 | ||||
-rw-r--r-- | unittests/Support/BinaryStreamTest.cpp | 711 | ||||
-rw-r--r-- | unittests/Support/CMakeLists.txt | 5 | ||||
-rw-r--r-- | unittests/Support/CachePruningTest.cpp | 71 | ||||
-rw-r--r-- | unittests/Support/Casting.cpp | 75 | ||||
-rw-r--r-- | unittests/Support/Chrono.cpp | 31 | ||||
-rw-r--r-- | unittests/Support/CommandLineTest.cpp | 76 | ||||
-rw-r--r-- | unittests/Support/CompressionTest.cpp | 17 | ||||
-rw-r--r-- | unittests/Support/ErrorTest.cpp | 28 | ||||
-rw-r--r-- | unittests/Support/FormatVariadicTest.cpp | 2 | ||||
-rw-r--r-- | unittests/Support/Host.cpp | 92 | ||||
-rw-r--r-- | unittests/Support/LEB128Test.cpp | 47 | ||||
-rw-r--r-- | unittests/Support/MD5Test.cpp | 4 | ||||
-rw-r--r-- | unittests/Support/Path.cpp | 570 | ||||
-rw-r--r-- | unittests/Support/ProgramTest.cpp | 1 | ||||
-rw-r--r-- | unittests/Support/TargetParserTest.cpp | 73 | ||||
-rw-r--r-- | unittests/Support/ThreadPool.cpp | 4 | ||||
-rw-r--r-- | unittests/Support/TrailingObjectsTest.cpp | 21 | ||||
-rw-r--r-- | unittests/Support/YAMLIOTest.cpp | 16 | ||||
-rw-r--r-- | unittests/Support/raw_ostream_test.cpp | 8 |
21 files changed, 2072 insertions, 171 deletions
diff --git a/unittests/Support/ARMAttributeParser.cpp b/unittests/Support/ARMAttributeParser.cpp new file mode 100644 index 000000000000..c2df6537ff63 --- /dev/null +++ b/unittests/Support/ARMAttributeParser.cpp @@ -0,0 +1,385 @@ +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/LEB128.h" +#include "gtest/gtest.h" +#include <string> + +using namespace llvm; + +struct AttributeSection { + unsigned Tag; + unsigned Value; + + AttributeSection(unsigned tag, unsigned value) : Tag(tag), Value(value) { } + + void write(raw_ostream &OS) { + OS.flush(); + // length = length + "aeabi\0" + TagFile + ByteSize + Tag + Value; + // length = 17 bytes + + OS << 'A' << (uint8_t)17 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0; + OS << "aeabi" << '\0'; + OS << (uint8_t)1 << (uint8_t)7 << (uint8_t)0 << (uint8_t)0 << (uint8_t)0; + OS << (uint8_t)Tag << (uint8_t)Value; + + } +}; + +bool testBuildAttr(unsigned Tag, unsigned Value, + unsigned ExpectedTag, unsigned ExpectedValue) { + std::string buffer; + raw_string_ostream OS(buffer); + AttributeSection Section(Tag, Value); + Section.write(OS); + ArrayRef<uint8_t> Bytes( + reinterpret_cast<const uint8_t*>(OS.str().c_str()), OS.str().size()); + + ARMAttributeParser Parser; + Parser.Parse(Bytes, true); + + return (Parser.hasAttribute(ExpectedTag) && + Parser.getAttributeValue(ExpectedTag) == ExpectedValue); +} + +bool testTagString(unsigned Tag, const char *name) { + return ARMBuildAttrs::AttrTypeAsString(Tag).str() == name; +} + +TEST(CPUArchBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(6, "Tag_CPU_arch")); + + EXPECT_TRUE(testBuildAttr(6, 0, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::Pre_v4)); + EXPECT_TRUE(testBuildAttr(6, 1, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v4)); + EXPECT_TRUE(testBuildAttr(6, 2, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v4T)); + EXPECT_TRUE(testBuildAttr(6, 3, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5T)); + EXPECT_TRUE(testBuildAttr(6, 4, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5TE)); + EXPECT_TRUE(testBuildAttr(6, 5, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v5TEJ)); + EXPECT_TRUE(testBuildAttr(6, 6, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6)); + EXPECT_TRUE(testBuildAttr(6, 7, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6KZ)); + EXPECT_TRUE(testBuildAttr(6, 8, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6T2)); + EXPECT_TRUE(testBuildAttr(6, 9, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6K)); + EXPECT_TRUE(testBuildAttr(6, 10, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v7)); + EXPECT_TRUE(testBuildAttr(6, 11, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6_M)); + EXPECT_TRUE(testBuildAttr(6, 12, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v6S_M)); + EXPECT_TRUE(testBuildAttr(6, 13, ARMBuildAttrs::CPU_arch, + ARMBuildAttrs::v7E_M)); +} + +TEST(CPUArchProfileBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(7, "Tag_CPU_arch_profile")); + EXPECT_TRUE(testBuildAttr(7, 'A', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::ApplicationProfile)); + EXPECT_TRUE(testBuildAttr(7, 'R', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::RealTimeProfile)); + EXPECT_TRUE(testBuildAttr(7, 'M', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::MicroControllerProfile)); + EXPECT_TRUE(testBuildAttr(7, 'S', ARMBuildAttrs::CPU_arch_profile, + ARMBuildAttrs::SystemProfile)); +} + +TEST(ARMISABuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(8, "Tag_ARM_ISA_use")); + EXPECT_TRUE(testBuildAttr(8, 0, ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(8, 1, ARMBuildAttrs::ARM_ISA_use, + ARMBuildAttrs::Allowed)); +} + +TEST(ThumbISABuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(9, "Tag_THUMB_ISA_use")); + EXPECT_TRUE(testBuildAttr(9, 0, ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(9, 1, ARMBuildAttrs::THUMB_ISA_use, + ARMBuildAttrs::Allowed)); +} + +TEST(FPArchBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(10, "Tag_FP_arch")); + EXPECT_TRUE(testBuildAttr(10, 0, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(10, 1, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::Allowed)); + EXPECT_TRUE(testBuildAttr(10, 2, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv2)); + EXPECT_TRUE(testBuildAttr(10, 3, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv3A)); + EXPECT_TRUE(testBuildAttr(10, 4, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv3B)); + EXPECT_TRUE(testBuildAttr(10, 5, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv4A)); + EXPECT_TRUE(testBuildAttr(10, 6, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPv4B)); + EXPECT_TRUE(testBuildAttr(10, 7, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPARMv8A)); + EXPECT_TRUE(testBuildAttr(10, 8, ARMBuildAttrs::FP_arch, + ARMBuildAttrs::AllowFPARMv8B)); +} + +TEST(WMMXBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(11, "Tag_WMMX_arch")); + EXPECT_TRUE(testBuildAttr(11, 0, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(11, 1, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::AllowWMMXv1)); + EXPECT_TRUE(testBuildAttr(11, 2, ARMBuildAttrs::WMMX_arch, + ARMBuildAttrs::AllowWMMXv2)); +} + +TEST(SIMDBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(12, "Tag_Advanced_SIMD_arch")); + EXPECT_TRUE(testBuildAttr(12, 0, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(12, 1, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeon)); + EXPECT_TRUE(testBuildAttr(12, 2, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeon2)); + EXPECT_TRUE(testBuildAttr(12, 3, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeonARMv8)); + EXPECT_TRUE(testBuildAttr(12, 4, ARMBuildAttrs::Advanced_SIMD_arch, + ARMBuildAttrs::AllowNeonARMv8_1a)); +} + +TEST(FPHPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(36, "Tag_FP_HP_extension")); + EXPECT_TRUE(testBuildAttr(36, 0, ARMBuildAttrs::FP_HP_extension, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(36, 1, ARMBuildAttrs::FP_HP_extension, + ARMBuildAttrs::AllowHPFP)); +} + +TEST(CPUAlignBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(34, "Tag_CPU_unaligned_access")); + EXPECT_TRUE(testBuildAttr(34, 0, ARMBuildAttrs::CPU_unaligned_access, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(34, 1, ARMBuildAttrs::CPU_unaligned_access, + ARMBuildAttrs::Allowed)); +} + +TEST(T2EEBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(66, "Tag_T2EE_use")); + EXPECT_TRUE(testBuildAttr(66, 0, ARMBuildAttrs::T2EE_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(66, 1, ARMBuildAttrs::T2EE_use, + ARMBuildAttrs::Allowed)); +} + +TEST(VirtualizationBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(68, "Tag_Virtualization_use")); + EXPECT_TRUE(testBuildAttr(68, 0, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(68, 1, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowTZ)); + EXPECT_TRUE(testBuildAttr(68, 2, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowVirtualization)); + EXPECT_TRUE(testBuildAttr(68, 3, ARMBuildAttrs::Virtualization_use, + ARMBuildAttrs::AllowTZVirtualization)); +} + +TEST(MPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(42, "Tag_MPextension_use")); + EXPECT_TRUE(testBuildAttr(42, 0, ARMBuildAttrs::MPextension_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(42, 1, ARMBuildAttrs::MPextension_use, + ARMBuildAttrs::AllowMP)); +} + +TEST(DivBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(44, "Tag_DIV_use")); + EXPECT_TRUE(testBuildAttr(44, 0, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::AllowDIVIfExists)); + EXPECT_TRUE(testBuildAttr(44, 1, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::DisallowDIV)); + EXPECT_TRUE(testBuildAttr(44, 2, ARMBuildAttrs::DIV_use, + ARMBuildAttrs::AllowDIVExt)); +} + +TEST(PCS_ConfigBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(13, "Tag_PCS_config")); + EXPECT_TRUE(testBuildAttr(13, 0, ARMBuildAttrs::PCS_config, 0)); + EXPECT_TRUE(testBuildAttr(13, 1, ARMBuildAttrs::PCS_config, 1)); + EXPECT_TRUE(testBuildAttr(13, 2, ARMBuildAttrs::PCS_config, 2)); + EXPECT_TRUE(testBuildAttr(13, 3, ARMBuildAttrs::PCS_config, 3)); + EXPECT_TRUE(testBuildAttr(13, 4, ARMBuildAttrs::PCS_config, 4)); + EXPECT_TRUE(testBuildAttr(13, 5, ARMBuildAttrs::PCS_config, 5)); + EXPECT_TRUE(testBuildAttr(13, 6, ARMBuildAttrs::PCS_config, 6)); + EXPECT_TRUE(testBuildAttr(13, 7, ARMBuildAttrs::PCS_config, 7)); +} + +TEST(PCS_R9BuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(14, "Tag_ABI_PCS_R9_use")); + EXPECT_TRUE(testBuildAttr(14, 0, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsGPR)); + EXPECT_TRUE(testBuildAttr(14, 1, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsSB)); + EXPECT_TRUE(testBuildAttr(14, 2, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9IsTLSPointer)); + EXPECT_TRUE(testBuildAttr(14, 3, ARMBuildAttrs::ABI_PCS_R9_use, + ARMBuildAttrs::R9Reserved)); +} + +TEST(PCS_RWBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(15, "Tag_ABI_PCS_RW_data")); + EXPECT_TRUE(testBuildAttr(15, 0, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(15, 1, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWPCRel)); + EXPECT_TRUE(testBuildAttr(15, 2, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWSBRel)); + EXPECT_TRUE(testBuildAttr(15, 3, ARMBuildAttrs::ABI_PCS_RW_data, + ARMBuildAttrs::AddressRWNone)); +} + +TEST(PCS_ROBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(16, "Tag_ABI_PCS_RO_data")); + EXPECT_TRUE(testBuildAttr(16, 0, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(16, 1, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::AddressROPCRel)); + EXPECT_TRUE(testBuildAttr(16, 2, ARMBuildAttrs::ABI_PCS_RO_data, + ARMBuildAttrs::AddressRONone)); +} + +TEST(PCS_GOTBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(17, "Tag_ABI_PCS_GOT_use")); + EXPECT_TRUE(testBuildAttr(17, 0, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(17, 1, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::AddressDirect)); + EXPECT_TRUE(testBuildAttr(17, 2, ARMBuildAttrs::ABI_PCS_GOT_use, + ARMBuildAttrs::AddressGOT)); +} + +TEST(PCS_WCharBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(18, "Tag_ABI_PCS_wchar_t")); + EXPECT_TRUE(testBuildAttr(18, 0, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharProhibited)); + EXPECT_TRUE(testBuildAttr(18, 2, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharWidth2Bytes)); + EXPECT_TRUE(testBuildAttr(18, 4, ARMBuildAttrs::ABI_PCS_wchar_t, + ARMBuildAttrs::WCharWidth4Bytes)); +} + +TEST(EnumSizeBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(26, "Tag_ABI_enum_size")); + EXPECT_TRUE(testBuildAttr(26, 0, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::EnumProhibited)); + EXPECT_TRUE(testBuildAttr(26, 1, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::EnumSmallest)); + EXPECT_TRUE(testBuildAttr(26, 2, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::Enum32Bit)); + EXPECT_TRUE(testBuildAttr(26, 3, ARMBuildAttrs::ABI_enum_size, + ARMBuildAttrs::Enum32BitABI)); +} + +TEST(AlignNeededBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(24, "Tag_ABI_align_needed")); + EXPECT_TRUE(testBuildAttr(24, 0, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(24, 1, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Align8Byte)); + EXPECT_TRUE(testBuildAttr(24, 2, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::Align4Byte)); + EXPECT_TRUE(testBuildAttr(24, 3, ARMBuildAttrs::ABI_align_needed, + ARMBuildAttrs::AlignReserved)); +} + +TEST(AlignPreservedBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(25, "Tag_ABI_align_preserved")); + EXPECT_TRUE(testBuildAttr(25, 0, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignNotPreserved)); + EXPECT_TRUE(testBuildAttr(25, 1, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignPreserve8Byte)); + EXPECT_TRUE(testBuildAttr(25, 2, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignPreserveAll)); + EXPECT_TRUE(testBuildAttr(25, 3, ARMBuildAttrs::ABI_align_preserved, + ARMBuildAttrs::AlignReserved)); +} + +TEST(FPRoundingBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(19, "Tag_ABI_FP_rounding")); + EXPECT_TRUE(testBuildAttr(19, 0, ARMBuildAttrs::ABI_FP_rounding, 0)); + EXPECT_TRUE(testBuildAttr(19, 1, ARMBuildAttrs::ABI_FP_rounding, 1)); +} + +TEST(FPDenormalBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(20, "Tag_ABI_FP_denormal")); + EXPECT_TRUE(testBuildAttr(20, 0, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::PositiveZero)); + EXPECT_TRUE(testBuildAttr(20, 1, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::IEEEDenormals)); + EXPECT_TRUE(testBuildAttr(20, 2, ARMBuildAttrs::ABI_FP_denormal, + ARMBuildAttrs::PreserveFPSign)); +} + +TEST(FPExceptionsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(21, "Tag_ABI_FP_exceptions")); + EXPECT_TRUE(testBuildAttr(21, 0, ARMBuildAttrs::ABI_FP_exceptions, 0)); + EXPECT_TRUE(testBuildAttr(21, 1, ARMBuildAttrs::ABI_FP_exceptions, 1)); +} + +TEST(FPUserExceptionsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(22, "Tag_ABI_FP_user_exceptions")); + EXPECT_TRUE(testBuildAttr(22, 0, ARMBuildAttrs::ABI_FP_user_exceptions, 0)); + EXPECT_TRUE(testBuildAttr(22, 1, ARMBuildAttrs::ABI_FP_user_exceptions, 1)); +} + +TEST(FPNumberModelBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(23, "Tag_ABI_FP_number_model")); + EXPECT_TRUE(testBuildAttr(23, 0, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(23, 1, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowIEEENormal)); + EXPECT_TRUE(testBuildAttr(23, 2, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowRTABI)); + EXPECT_TRUE(testBuildAttr(23, 3, ARMBuildAttrs::ABI_FP_number_model, + ARMBuildAttrs::AllowIEEE754)); +} + +TEST(FP16BuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(38, "Tag_ABI_FP_16bit_format")); + EXPECT_TRUE(testBuildAttr(38, 0, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::Not_Allowed)); + EXPECT_TRUE(testBuildAttr(38, 1, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::FP16FormatIEEE)); + EXPECT_TRUE(testBuildAttr(38, 2, ARMBuildAttrs::ABI_FP_16bit_format, + ARMBuildAttrs::FP16VFP3)); +} + +TEST(HardFPBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(27, "Tag_ABI_HardFP_use")); + EXPECT_TRUE(testBuildAttr(27, 0, ARMBuildAttrs::ABI_HardFP_use, + ARMBuildAttrs::HardFPImplied)); + EXPECT_TRUE(testBuildAttr(27, 1, ARMBuildAttrs::ABI_HardFP_use, + ARMBuildAttrs::HardFPSinglePrecision)); + EXPECT_TRUE(testBuildAttr(27, 2, ARMBuildAttrs::ABI_HardFP_use, 2)); +} + +TEST(VFPArgsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(28, "Tag_ABI_VFP_args")); + EXPECT_TRUE(testBuildAttr(28, 0, ARMBuildAttrs::ABI_VFP_args, + ARMBuildAttrs::BaseAAPCS)); + EXPECT_TRUE(testBuildAttr(28, 1, ARMBuildAttrs::ABI_VFP_args, + ARMBuildAttrs::HardFPAAPCS)); + EXPECT_TRUE(testBuildAttr(28, 2, ARMBuildAttrs::ABI_VFP_args, 2)); + EXPECT_TRUE(testBuildAttr(28, 3, ARMBuildAttrs::ABI_VFP_args, 3)); +} + +TEST(WMMXArgsBuildAttr, testBuildAttr) { + EXPECT_TRUE(testTagString(29, "Tag_ABI_WMMX_args")); + EXPECT_TRUE(testBuildAttr(29, 0, ARMBuildAttrs::ABI_WMMX_args, 0)); + EXPECT_TRUE(testBuildAttr(29, 1, ARMBuildAttrs::ABI_WMMX_args, 1)); + EXPECT_TRUE(testBuildAttr(29, 2, ARMBuildAttrs::ABI_WMMX_args, 2)); +} diff --git a/unittests/Support/AllocatorTest.cpp b/unittests/Support/AllocatorTest.cpp index 4b544641e9bf..4897c47eb28b 100644 --- a/unittests/Support/AllocatorTest.cpp +++ b/unittests/Support/AllocatorTest.cpp @@ -17,9 +17,9 @@ namespace { TEST(AllocatorTest, Basics) { BumpPtrAllocator Alloc; - int *a = (int*)Alloc.Allocate(sizeof(int), 1); - int *b = (int*)Alloc.Allocate(sizeof(int) * 10, 1); - int *c = (int*)Alloc.Allocate(sizeof(int), 1); + int *a = (int*)Alloc.Allocate(sizeof(int), alignof(int)); + int *b = (int*)Alloc.Allocate(sizeof(int) * 10, alignof(int)); + int *c = (int*)Alloc.Allocate(sizeof(int), alignof(int)); *a = 1; b[0] = 2; b[9] = 2; diff --git a/unittests/Support/BinaryStreamTest.cpp b/unittests/Support/BinaryStreamTest.cpp new file mode 100644 index 000000000000..1e646a6cf900 --- /dev/null +++ b/unittests/Support/BinaryStreamTest.cpp @@ -0,0 +1,711 @@ +//===- llvm/unittest/Support/BinaryStreamTest.cpp -------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryItemStream.h" +#include "llvm/Support/BinaryStreamArray.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/BinaryStreamRef.h" +#include "llvm/Support/BinaryStreamWriter.h" +#include "gtest/gtest.h" + +#include <unordered_map> + +using namespace llvm; +using namespace llvm::support; + +#define EXPECT_NO_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_FALSE(static_cast<bool>(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +#define ASSERT_NO_ERROR(Err) \ + { \ + auto E = Err; \ + ASSERT_FALSE(static_cast<bool>(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +#define EXPECT_ERROR(Err) \ + { \ + auto E = Err; \ + EXPECT_TRUE(static_cast<bool>(E)); \ + if (E) \ + consumeError(std::move(E)); \ + } + +namespace { + +class BrokenStream : public WritableBinaryStream { +public: + BrokenStream(MutableArrayRef<uint8_t> Data, endianness Endian, + uint32_t Align) + : Data(Data), PartitionIndex(alignDown(Data.size() / 2, Align)), + Endian(Endian) {} + + endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffset(Offset, Size)) + return EC; + uint32_t S = startIndex(Offset); + auto Ref = Data.drop_front(S); + if (Ref.size() >= Size) { + Buffer = Ref.take_front(Size); + return Error::success(); + } + + uint32_t BytesLeft = Size - Ref.size(); + uint8_t *Ptr = Allocator.Allocate<uint8_t>(Size); + ::memcpy(Ptr, Ref.data(), Ref.size()); + ::memcpy(Ptr + Ref.size(), Data.data(), BytesLeft); + Buffer = makeArrayRef<uint8_t>(Ptr, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffset(Offset, 1)) + return EC; + uint32_t S = startIndex(Offset); + Buffer = Data.drop_front(S); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override { + if (auto EC = checkOffset(Offset, SrcData.size())) + return EC; + if (SrcData.empty()) + return Error::success(); + + uint32_t S = startIndex(Offset); + MutableArrayRef<uint8_t> Ref(Data); + Ref = Ref.drop_front(S); + if (Ref.size() >= SrcData.size()) { + ::memcpy(Ref.data(), SrcData.data(), SrcData.size()); + return Error::success(); + } + + uint32_t BytesLeft = SrcData.size() - Ref.size(); + ::memcpy(Ref.data(), SrcData.data(), Ref.size()); + ::memcpy(&Data[0], SrcData.data() + Ref.size(), BytesLeft); + return Error::success(); + } + Error commit() override { return Error::success(); } + +private: + uint32_t startIndex(uint32_t Offset) const { + return (Offset + PartitionIndex) % Data.size(); + } + + uint32_t endIndex(uint32_t Offset, uint32_t Size) const { + return (startIndex(Offset) + Size - 1) % Data.size(); + } + + // Buffer is organized like this: + // ------------------------------------------------- + // | N/2 | N/2+1 | ... | N-1 | 0 | 1 | ... | N-2-1 | + // ------------------------------------------------- + // So reads from the beginning actually come from the middle. + MutableArrayRef<uint8_t> Data; + uint32_t PartitionIndex = 0; + endianness Endian; + BumpPtrAllocator Allocator; +}; + +constexpr endianness Endians[] = {big, little, native}; +constexpr uint32_t NumEndians = llvm::array_lengthof(Endians); +constexpr uint32_t NumStreams = 2 * NumEndians; + +class BinaryStreamTest : public testing::Test { + +public: + BinaryStreamTest() {} + + void SetUp() override { + Streams.clear(); + Streams.resize(NumStreams); + for (uint32_t I = 0; I < NumStreams; ++I) + Streams[I].IsContiguous = (I % 2 == 0); + + InputData.clear(); + OutputData.clear(); + } + +protected: + struct StreamPair { + bool IsContiguous; + std::unique_ptr<BinaryStream> Input; + std::unique_ptr<WritableBinaryStream> Output; + }; + + void initializeInput(ArrayRef<uint8_t> Input, uint32_t Align) { + InputData = Input; + + BrokenInputData.resize(InputData.size()); + if (!Input.empty()) { + uint32_t PartitionIndex = alignDown(InputData.size() / 2, Align); + uint32_t RightBytes = InputData.size() - PartitionIndex; + uint32_t LeftBytes = PartitionIndex; + if (RightBytes > 0) + ::memcpy(&BrokenInputData[PartitionIndex], Input.data(), RightBytes); + if (LeftBytes > 0) + ::memcpy(&BrokenInputData[0], Input.data() + RightBytes, LeftBytes); + } + + for (uint32_t I = 0; I < NumEndians; ++I) { + auto InByteStream = + llvm::make_unique<BinaryByteStream>(InputData, Endians[I]); + auto InBrokenStream = llvm::make_unique<BrokenStream>( + BrokenInputData, Endians[I], Align); + + Streams[I * 2].Input = std::move(InByteStream); + Streams[I * 2 + 1].Input = std::move(InBrokenStream); + } + } + + void initializeOutput(uint32_t Size, uint32_t Align) { + OutputData.resize(Size); + BrokenOutputData.resize(Size); + + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Output = + llvm::make_unique<MutableBinaryByteStream>(OutputData, Endians[I]); + Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>( + BrokenOutputData, Endians[I], Align); + } + } + + void initializeOutputFromInput(uint32_t Align) { + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Output = + llvm::make_unique<MutableBinaryByteStream>(InputData, Endians[I]); + Streams[I * 2 + 1].Output = llvm::make_unique<BrokenStream>( + BrokenInputData, Endians[I], Align); + } + } + + void initializeInputFromOutput(uint32_t Align) { + for (uint32_t I = 0; I < NumEndians; ++I) { + Streams[I * 2].Input = + llvm::make_unique<BinaryByteStream>(OutputData, Endians[I]); + Streams[I * 2 + 1].Input = llvm::make_unique<BrokenStream>( + BrokenOutputData, Endians[I], Align); + } + } + + std::vector<uint8_t> InputData; + std::vector<uint8_t> BrokenInputData; + + std::vector<uint8_t> OutputData; + std::vector<uint8_t> BrokenOutputData; + + std::vector<StreamPair> Streams; +}; + +// Tests that a we can read from a BinaryByteStream without a StreamReader. +TEST_F(BinaryStreamTest, BinaryByteStreamBounds) { + std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; + initializeInput(InputData, 1); + + for (auto &Stream : Streams) { + ArrayRef<uint8_t> Buffer; + + // 1. If the read fits it should work. + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + ASSERT_NO_ERROR(Stream.Input->readBytes(2, 1, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); + ASSERT_NO_ERROR(Stream.Input->readBytes(0, 4, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(0, 4), Buffer); + + // 2. Reading past the bounds of the input should fail. + EXPECT_ERROR(Stream.Input->readBytes(4, 2, Buffer)); + } +} + +TEST_F(BinaryStreamTest, StreamRefBounds) { + std::vector<uint8_t> InputData = {1, 2, 3, 4, 5}; + initializeInput(InputData, 1); + + for (const auto &Stream : Streams) { + ArrayRef<uint8_t> Buffer; + BinaryStreamRef Ref(*Stream.Input); + + // Read 1 byte from offset 2 should work + ASSERT_EQ(InputData.size(), Ref.getLength()); + ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).slice(2, 1), Buffer); + + // Reading everything from offset 2 on. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(2), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading 6 bytes from offset 0 is too big. + EXPECT_ERROR(Ref.readBytes(0, 6, Buffer)); + EXPECT_ERROR(Ref.readLongestContiguousChunk(6, Buffer)); + + // Reading 1 byte from offset 2 after dropping 1 byte is the same as reading + // 1 byte from offset 3. + Ref = Ref.drop_front(1); + ASSERT_NO_ERROR(Ref.readBytes(2, 1, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(3, 1), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading everything from offset 2 on after dropping 1 byte. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + if (Stream.IsContiguous) + EXPECT_EQ(makeArrayRef(InputData).slice(3), Buffer); + else + EXPECT_FALSE(Buffer.empty()); + + // Reading 2 bytes from offset 2 after dropping 2 bytes is the same as + // reading 2 bytes from offset 4, and should fail. + Ref = Ref.drop_front(1); + EXPECT_ERROR(Ref.readBytes(2, 2, Buffer)); + + // But if we read the longest contiguous chunk instead, we should still + // get the 1 byte at the end. + ASSERT_NO_ERROR(Ref.readLongestContiguousChunk(2, Buffer)); + EXPECT_EQ(makeArrayRef(InputData).take_back(), Buffer); + } +} + +// Test that we can write to a BinaryStream without a StreamWriter. +TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { + std::vector<uint8_t> InputData = {'T', 'e', 's', 't', '\0'}; + initializeInput(InputData, 1); + initializeOutput(InputData.size(), 1); + + // For every combination of input stream and output stream. + for (auto &Stream : Streams) { + MutableArrayRef<uint8_t> Buffer; + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + + // 1. Try two reads that are supposed to work. One from offset 0, and one + // from the middle. + uint32_t Offsets[] = {0, 3}; + for (auto Offset : Offsets) { + uint32_t ExpectedSize = Stream.Input->getLength() - Offset; + + // Read everything from Offset until the end of the input data. + ArrayRef<uint8_t> Data; + ASSERT_NO_ERROR(Stream.Input->readBytes(Offset, ExpectedSize, Data)); + ASSERT_EQ(ExpectedSize, Data.size()); + + // Then write it to the destination. + ASSERT_NO_ERROR(Stream.Output->writeBytes(0, Data)); + + // Then we read back what we wrote, it should match the corresponding + // slice of the original input data. + ArrayRef<uint8_t> Data2; + ASSERT_NO_ERROR(Stream.Output->readBytes(Offset, ExpectedSize, Data2)); + EXPECT_EQ(makeArrayRef(InputData).drop_front(Offset), Data2); + } + + std::vector<uint8_t> BigData = {0, 1, 2, 3, 4}; + // 2. If the write is too big, it should fail. + EXPECT_ERROR(Stream.Output->writeBytes(3, BigData)); + } +} + +// Test that FixedStreamArray works correctly. +TEST_F(BinaryStreamTest, FixedStreamArray) { + std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823}; + ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(Ints.data()), + Ints.size() * sizeof(uint32_t)); + + initializeInput(IntBytes, alignof(uint32_t)); + + for (auto &Stream : Streams) { + MutableArrayRef<uint8_t> Buffer; + ASSERT_EQ(InputData.size(), Stream.Input->getLength()); + + FixedStreamArray<uint32_t> Array(*Stream.Input); + auto Iter = Array.begin(); + ASSERT_EQ(Ints[0], *Iter++); + ASSERT_EQ(Ints[1], *Iter++); + ASSERT_EQ(Ints[2], *Iter++); + ASSERT_EQ(Ints[3], *Iter++); + ASSERT_EQ(Array.end(), Iter); + } +} + +// Test that VarStreamArray works correctly. +TEST_F(BinaryStreamTest, VarStreamArray) { + StringLiteral Strings("1. Test2. Longer Test3. Really Long Test4. Super " + "Extra Longest Test Of All"); + ArrayRef<uint8_t> StringBytes( + reinterpret_cast<const uint8_t *>(Strings.data()), Strings.size()); + initializeInput(StringBytes, 1); + + struct StringExtractor { + public: + Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { + if (Index == 0) + Len = strlen("1. Test"); + else if (Index == 1) + Len = strlen("2. Longer Test"); + else if (Index == 2) + Len = strlen("3. Really Long Test"); + else + Len = strlen("4. Super Extra Longest Test Of All"); + ArrayRef<uint8_t> Bytes; + if (auto EC = Stream.readBytes(0, Len, Bytes)) + return EC; + Item = + StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size()); + ++Index; + return Error::success(); + } + + private: + uint32_t Index = 0; + }; + + for (auto &Stream : Streams) { + VarStreamArray<StringRef, StringExtractor> Array(*Stream.Input); + auto Iter = Array.begin(); + ASSERT_EQ("1. Test", *Iter++); + ASSERT_EQ("2. Longer Test", *Iter++); + ASSERT_EQ("3. Really Long Test", *Iter++); + ASSERT_EQ("4. Super Extra Longest Test Of All", *Iter++); + ASSERT_EQ(Array.end(), Iter); + } +} + +TEST_F(BinaryStreamTest, StreamReaderBounds) { + std::vector<uint8_t> Bytes; + + initializeInput(Bytes, 1); + for (auto &Stream : Streams) { + StringRef S; + BinaryStreamReader Reader(*Stream.Input); + EXPECT_EQ(0U, Reader.bytesRemaining()); + EXPECT_ERROR(Reader.readFixedString(S, 1)); + } + + Bytes.resize(5); + initializeInput(Bytes, 1); + for (auto &Stream : Streams) { + StringRef S; + BinaryStreamReader Reader(*Stream.Input); + EXPECT_EQ(Bytes.size(), Reader.bytesRemaining()); + EXPECT_NO_ERROR(Reader.readFixedString(S, 5)); + EXPECT_ERROR(Reader.readFixedString(S, 6)); + } +} + +TEST_F(BinaryStreamTest, StreamReaderIntegers) { + support::ulittle64_t Little{908234}; + support::ubig32_t Big{28907823}; + short NS = 2897; + int NI = -89723; + unsigned long NUL = 902309023UL; + constexpr uint32_t Size = + sizeof(Little) + sizeof(Big) + sizeof(NS) + sizeof(NI) + sizeof(NUL); + + initializeOutput(Size, alignof(support::ulittle64_t)); + initializeInputFromOutput(alignof(support::ulittle64_t)); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + ASSERT_NO_ERROR(Writer.writeObject(Little)); + ASSERT_NO_ERROR(Writer.writeObject(Big)); + ASSERT_NO_ERROR(Writer.writeInteger(NS)); + ASSERT_NO_ERROR(Writer.writeInteger(NI)); + ASSERT_NO_ERROR(Writer.writeInteger(NUL)); + + const support::ulittle64_t *Little2; + const support::ubig32_t *Big2; + short NS2; + int NI2; + unsigned long NUL2; + + // 1. Reading fields individually. + BinaryStreamReader Reader(*Stream.Input); + ASSERT_NO_ERROR(Reader.readObject(Little2)); + ASSERT_NO_ERROR(Reader.readObject(Big2)); + ASSERT_NO_ERROR(Reader.readInteger(NS2)); + ASSERT_NO_ERROR(Reader.readInteger(NI2)); + ASSERT_NO_ERROR(Reader.readInteger(NUL2)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ(Little, *Little2); + EXPECT_EQ(Big, *Big2); + EXPECT_EQ(NS, NS2); + EXPECT_EQ(NI, NI2); + EXPECT_EQ(NUL, NUL2); + } +} + +TEST_F(BinaryStreamTest, StreamReaderIntegerArray) { + // 1. Arrays of integers + std::vector<int> Ints = {1, 2, 3, 4, 5}; + ArrayRef<uint8_t> IntBytes(reinterpret_cast<uint8_t *>(&Ints[0]), + Ints.size() * sizeof(int)); + + initializeInput(IntBytes, alignof(int)); + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + ArrayRef<int> IntsRef; + ASSERT_NO_ERROR(Reader.readArray(IntsRef, Ints.size())); + ASSERT_EQ(0U, Reader.bytesRemaining()); + EXPECT_EQ(makeArrayRef(Ints), IntsRef); + + Reader.setOffset(0); + FixedStreamArray<int> FixedIntsRef; + ASSERT_NO_ERROR(Reader.readArray(FixedIntsRef, Ints.size())); + ASSERT_EQ(0U, Reader.bytesRemaining()); + ASSERT_EQ(Ints, std::vector<int>(FixedIntsRef.begin(), FixedIntsRef.end())); + } +} + +TEST_F(BinaryStreamTest, StreamReaderEnum) { + enum class MyEnum : int64_t { Foo = -10, Bar = 0, Baz = 10 }; + + std::vector<MyEnum> Enums = {MyEnum::Bar, MyEnum::Baz, MyEnum::Foo}; + + initializeOutput(Enums.size() * sizeof(MyEnum), alignof(MyEnum)); + initializeInputFromOutput(alignof(MyEnum)); + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + for (auto Value : Enums) + ASSERT_NO_ERROR(Writer.writeEnum(Value)); + + BinaryStreamReader Reader(*Stream.Input); + + ArrayRef<MyEnum> Array; + FixedStreamArray<MyEnum> FSA; + + for (size_t I = 0; I < Enums.size(); ++I) { + MyEnum Value; + ASSERT_NO_ERROR(Reader.readEnum(Value)); + EXPECT_EQ(Enums[I], Value); + } + ASSERT_EQ(0U, Reader.bytesRemaining()); + } +} + +TEST_F(BinaryStreamTest, StreamReaderObject) { + struct Foo { + int X; + double Y; + char Z; + + bool operator==(const Foo &Other) const { + return X == Other.X && Y == Other.Y && Z == Other.Z; + } + }; + + std::vector<Foo> Foos; + Foos.push_back({-42, 42.42, 42}); + Foos.push_back({100, 3.1415, static_cast<char>(-89)}); + Foos.push_back({200, 2.718, static_cast<char>(-12) }); + + const uint8_t *Bytes = reinterpret_cast<const uint8_t *>(&Foos[0]); + + initializeInput(makeArrayRef(Bytes, 3 * sizeof(Foo)), alignof(Foo)); + + for (auto &Stream : Streams) { + // 1. Reading object pointers. + BinaryStreamReader Reader(*Stream.Input); + const Foo *FPtrOut = nullptr; + const Foo *GPtrOut = nullptr; + const Foo *HPtrOut = nullptr; + ASSERT_NO_ERROR(Reader.readObject(FPtrOut)); + ASSERT_NO_ERROR(Reader.readObject(GPtrOut)); + ASSERT_NO_ERROR(Reader.readObject(HPtrOut)); + EXPECT_EQ(0U, Reader.bytesRemaining()); + EXPECT_EQ(Foos[0], *FPtrOut); + EXPECT_EQ(Foos[1], *GPtrOut); + EXPECT_EQ(Foos[2], *HPtrOut); + } +} + +TEST_F(BinaryStreamTest, StreamReaderStrings) { + std::vector<uint8_t> Bytes = {'O', 'n', 'e', '\0', 'T', 'w', 'o', + '\0', 'T', 'h', 'r', 'e', 'e', '\0', + 'F', 'o', 'u', 'r', '\0'}; + initializeInput(Bytes, 1); + + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + + StringRef S1; + StringRef S2; + StringRef S3; + StringRef S4; + ASSERT_NO_ERROR(Reader.readCString(S1)); + ASSERT_NO_ERROR(Reader.readCString(S2)); + ASSERT_NO_ERROR(Reader.readCString(S3)); + ASSERT_NO_ERROR(Reader.readCString(S4)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ("One", S1); + EXPECT_EQ("Two", S2); + EXPECT_EQ("Three", S3); + EXPECT_EQ("Four", S4); + + S1 = S2 = S3 = S4 = ""; + Reader.setOffset(0); + ASSERT_NO_ERROR(Reader.readFixedString(S1, 3)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S2, 3)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S3, 5)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_NO_ERROR(Reader.readFixedString(S4, 4)); + ASSERT_NO_ERROR(Reader.skip(1)); + ASSERT_EQ(0U, Reader.bytesRemaining()); + + EXPECT_EQ("One", S1); + EXPECT_EQ("Two", S2); + EXPECT_EQ("Three", S3); + EXPECT_EQ("Four", S4); + } +} + +TEST_F(BinaryStreamTest, StreamWriterBounds) { + initializeOutput(5, 1); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + + // 1. Can write a string that exactly fills the buffer. + EXPECT_EQ(5U, Writer.bytesRemaining()); + EXPECT_NO_ERROR(Writer.writeFixedString("abcde")); + EXPECT_EQ(0U, Writer.bytesRemaining()); + + // 2. Can write an empty string even when you're full + EXPECT_NO_ERROR(Writer.writeFixedString("")); + EXPECT_ERROR(Writer.writeFixedString("a")); + + // 3. Can't write a string that is one character too long. + Writer.setOffset(0); + EXPECT_ERROR(Writer.writeFixedString("abcdef")); + } +} + +TEST_F(BinaryStreamTest, StreamWriterIntegerArrays) { + // 3. Arrays of integers + std::vector<int> SourceInts = {1, 2, 3, 4, 5}; + ArrayRef<uint8_t> SourceBytes(reinterpret_cast<uint8_t *>(&SourceInts[0]), + SourceInts.size() * sizeof(int)); + + initializeInput(SourceBytes, alignof(int)); + initializeOutputFromInput(alignof(int)); + + for (auto &Stream : Streams) { + BinaryStreamReader Reader(*Stream.Input); + BinaryStreamWriter Writer(*Stream.Output); + ArrayRef<int> Ints; + ArrayRef<int> Ints2; + // First read them, then write them, then read them back. + ASSERT_NO_ERROR(Reader.readArray(Ints, SourceInts.size())); + ASSERT_NO_ERROR(Writer.writeArray(Ints)); + + BinaryStreamReader ReaderBacker(*Stream.Output); + ASSERT_NO_ERROR(ReaderBacker.readArray(Ints2, SourceInts.size())); + + EXPECT_EQ(makeArrayRef(SourceInts), Ints2); + } +} + +TEST_F(BinaryStreamTest, StringWriterStrings) { + StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; + + size_t Length = 0; + for (auto S : Strings) + Length += S.size() + 1; + initializeOutput(Length, 1); + initializeInputFromOutput(1); + + for (auto &Stream : Streams) { + BinaryStreamWriter Writer(*Stream.Output); + for (auto S : Strings) + ASSERT_NO_ERROR(Writer.writeCString(S)); + std::vector<StringRef> InStrings; + BinaryStreamReader Reader(*Stream.Input); + while (!Reader.empty()) { + StringRef S; + ASSERT_NO_ERROR(Reader.readCString(S)); + InStrings.push_back(S); + } + EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); + } +} +} + +namespace { +struct BinaryItemStreamObject { + explicit BinaryItemStreamObject(ArrayRef<uint8_t> Bytes) : Bytes(Bytes) {} + + ArrayRef<uint8_t> Bytes; +}; +} + +namespace llvm { +template <> struct BinaryItemTraits<BinaryItemStreamObject> { + static size_t length(const BinaryItemStreamObject &Item) { + return Item.Bytes.size(); + } + + static ArrayRef<uint8_t> bytes(const BinaryItemStreamObject &Item) { + return Item.Bytes; + } +}; +} + +namespace { + +TEST_F(BinaryStreamTest, BinaryItemStream) { + std::vector<BinaryItemStreamObject> Objects; + + struct Foo { + int X; + double Y; + }; + std::vector<Foo> Foos = {{1, 1.0}, {2, 2.0}, {3, 3.0}}; + BumpPtrAllocator Allocator; + for (const auto &F : Foos) { + uint8_t *Ptr = static_cast<uint8_t *>(Allocator.Allocate(sizeof(Foo), + alignof(Foo))); + MutableArrayRef<uint8_t> Buffer(Ptr, sizeof(Foo)); + MutableBinaryByteStream Stream(Buffer, llvm::support::big); + BinaryStreamWriter Writer(Stream); + ASSERT_NO_ERROR(Writer.writeObject(F)); + Objects.push_back(BinaryItemStreamObject(Buffer)); + } + + BinaryItemStream<BinaryItemStreamObject> ItemStream(big); + ItemStream.setItems(Objects); + BinaryStreamReader Reader(ItemStream); + + for (const auto &F : Foos) { + const Foo *F2; + ASSERT_NO_ERROR(Reader.readObject(F2)); + + EXPECT_EQ(F.X, F2->X); + EXPECT_DOUBLE_EQ(F.Y, F2->Y); + } +} + +} // end anonymous namespace diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index 6068de5514c7..a7be18b6a3c5 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -5,9 +5,12 @@ set(LLVM_LINK_COMPONENTS add_llvm_unittest(SupportTests AlignOfTest.cpp AllocatorTest.cpp + ARMAttributeParser.cpp ArrayRecyclerTest.cpp + BinaryStreamTest.cpp BlockFrequencyTest.cpp BranchProbabilityTest.cpp + CachePruningTest.cpp Casting.cpp Chrono.cpp CommandLineTest.cpp @@ -63,4 +66,4 @@ add_llvm_unittest(SupportTests ) # ManagedStatic.cpp uses <pthread>. -target_link_libraries(SupportTests ${PTHREAD_LIB}) +target_link_libraries(SupportTests ${LLVM_PTHREAD_LIB}) diff --git a/unittests/Support/CachePruningTest.cpp b/unittests/Support/CachePruningTest.cpp new file mode 100644 index 000000000000..04ac0d09b493 --- /dev/null +++ b/unittests/Support/CachePruningTest.cpp @@ -0,0 +1,71 @@ +//===- CachePruningTest.cpp -----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/CachePruning.h" +#include "llvm/Support/Error.h" +#include "gtest/gtest.h" + +using namespace llvm; + +TEST(CachePruningPolicyParser, Empty) { + auto P = parseCachePruningPolicy(""); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::seconds(1200), P->Interval); + EXPECT_EQ(std::chrono::hours(7 * 24), P->Expiration); + EXPECT_EQ(75u, P->PercentageOfAvailableSpace); +} + +TEST(CachePruningPolicyParser, Interval) { + auto P = parseCachePruningPolicy("prune_interval=1s"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::seconds(1), P->Interval); + P = parseCachePruningPolicy("prune_interval=2m"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::minutes(2), P->Interval); + P = parseCachePruningPolicy("prune_interval=3h"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::hours(3), P->Interval); +} + +TEST(CachePruningPolicyParser, Expiration) { + auto P = parseCachePruningPolicy("prune_after=1s"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::seconds(1), P->Expiration); +} + +TEST(CachePruningPolicyParser, PercentageOfAvailableSpace) { + auto P = parseCachePruningPolicy("cache_size=100%"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(100u, P->PercentageOfAvailableSpace); +} + +TEST(CachePruningPolicyParser, Multiple) { + auto P = parseCachePruningPolicy("prune_after=1s:cache_size=50%"); + ASSERT_TRUE(bool(P)); + EXPECT_EQ(std::chrono::seconds(1200), P->Interval); + EXPECT_EQ(std::chrono::seconds(1), P->Expiration); + EXPECT_EQ(50u, P->PercentageOfAvailableSpace); +} + +TEST(CachePruningPolicyParser, Errors) { + EXPECT_EQ("Duration must not be empty", + toString(parseCachePruningPolicy("prune_interval=").takeError())); + EXPECT_EQ("'foo' not an integer", + toString(parseCachePruningPolicy("prune_interval=foos").takeError())); + EXPECT_EQ("'24x' must end with one of 's', 'm' or 'h'", + toString(parseCachePruningPolicy("prune_interval=24x").takeError())); + EXPECT_EQ("'foo' must be a percentage", + toString(parseCachePruningPolicy("cache_size=foo").takeError())); + EXPECT_EQ("'foo' not an integer", + toString(parseCachePruningPolicy("cache_size=foo%").takeError())); + EXPECT_EQ("'101' must be between 0 and 100", + toString(parseCachePruningPolicy("cache_size=101%").takeError())); + EXPECT_EQ("Unknown key: 'foo'", + toString(parseCachePruningPolicy("foo=bar").takeError())); +} diff --git a/unittests/Support/Casting.cpp b/unittests/Support/Casting.cpp index e6c35fc21eb7..9a818f6bdebd 100644 --- a/unittests/Support/Casting.cpp +++ b/unittests/Support/Casting.cpp @@ -40,6 +40,14 @@ struct foo { }*/ }; +struct base { + virtual ~base() {} +}; + +struct derived : public base { + static bool classof(const base *B) { return true; } +}; + template <> struct isa_impl<foo, bar> { static inline bool doit(const bar &Val) { dbgs() << "Classof: " << &Val << "\n"; @@ -47,6 +55,10 @@ template <> struct isa_impl<foo, bar> { } }; +template <typename T> struct isa_impl<foo, T> { + static inline bool doit(const T &Val) { return false; } +}; + foo *bar::baz() { return cast<foo>(this); } @@ -123,6 +135,13 @@ TEST(CastingTest, cast) { // EXPECT_EQ(F7, null_foo); foo *F8 = B1.baz(); EXPECT_NE(F8, null_foo); + + std::unique_ptr<const bar> BP(B2); + auto FP = cast<foo>(std::move(BP)); + static_assert(std::is_same<std::unique_ptr<const foo>, decltype(FP)>::value, + "Incorrect deduced return type!"); + EXPECT_NE(FP.get(), null_foo); + FP.release(); } TEST(CastingTest, cast_or_null) { @@ -136,6 +155,10 @@ TEST(CastingTest, cast_or_null) { EXPECT_EQ(F14, null_foo); foo *F15 = B1.caz(); EXPECT_NE(F15, null_foo); + + std::unique_ptr<const bar> BP(fub()); + auto FP = cast_or_null<foo>(std::move(BP)); + EXPECT_EQ(FP.get(), null_foo); } TEST(CastingTest, dyn_cast) { @@ -165,6 +188,58 @@ TEST(CastingTest, dyn_cast_or_null) { EXPECT_NE(F5, null_foo); } +std::unique_ptr<derived> newd() { return llvm::make_unique<derived>(); } +std::unique_ptr<base> newb() { return llvm::make_unique<derived>(); } + +TEST(CastingTest, unique_dyn_cast) { + derived *OrigD = nullptr; + auto D = llvm::make_unique<derived>(); + OrigD = D.get(); + + // Converting from D to itself is valid, it should return a new unique_ptr + // and the old one should become nullptr. + auto NewD = unique_dyn_cast<derived>(D); + ASSERT_EQ(OrigD, NewD.get()); + ASSERT_EQ(nullptr, D); + + // Converting from D to B is valid, B should have a value and D should be + // nullptr. + auto B = unique_dyn_cast<base>(NewD); + ASSERT_EQ(OrigD, B.get()); + ASSERT_EQ(nullptr, NewD); + + // Converting from B to itself is valid, it should return a new unique_ptr + // and the old one should become nullptr. + auto NewB = unique_dyn_cast<base>(B); + ASSERT_EQ(OrigD, NewB.get()); + ASSERT_EQ(nullptr, B); + + // Converting from B to D is valid, D should have a value and B should be + // nullptr; + D = unique_dyn_cast<derived>(NewB); + ASSERT_EQ(OrigD, D.get()); + ASSERT_EQ(nullptr, NewB); + + // Converting between unrelated types should fail. The original value should + // remain unchanged and it should return nullptr. + auto F = unique_dyn_cast<foo>(D); + ASSERT_EQ(nullptr, F); + ASSERT_EQ(OrigD, D.get()); + + // All of the above should also hold for temporaries. + auto D2 = unique_dyn_cast<derived>(newd()); + EXPECT_NE(nullptr, D2); + + auto B2 = unique_dyn_cast<derived>(newb()); + EXPECT_NE(nullptr, B2); + + auto B3 = unique_dyn_cast<base>(newb()); + EXPECT_NE(nullptr, B3); + + auto F2 = unique_dyn_cast<foo>(newb()); + EXPECT_EQ(nullptr, F2); +} + // These lines are errors... //foo *F20 = cast<foo>(B2); // Yields const foo* //foo &F21 = cast<foo>(B3); // Yields const foo& diff --git a/unittests/Support/Chrono.cpp b/unittests/Support/Chrono.cpp index 3d5787807563..1410baf848bb 100644 --- a/unittests/Support/Chrono.cpp +++ b/unittests/Support/Chrono.cpp @@ -9,6 +9,7 @@ #include "llvm/Support/Chrono.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Support/FormatVariadic.h" #include "gtest/gtest.h" using namespace llvm; @@ -76,4 +77,34 @@ TEST(Chrono, ImplicitConversions) { EXPECT_EQ(TimeT, toTimeT(Nano)); } +TEST(Chrono, DurationFormat) { + EXPECT_EQ("1 h", formatv("{0}", hours(1)).str()); + EXPECT_EQ("1 m", formatv("{0}", minutes(1)).str()); + EXPECT_EQ("1 s", formatv("{0}", seconds(1)).str()); + EXPECT_EQ("1 ms", formatv("{0}", milliseconds(1)).str()); + EXPECT_EQ("1 us", formatv("{0}", microseconds(1)).str()); + EXPECT_EQ("1 ns", formatv("{0}", nanoseconds(1)).str()); + + EXPECT_EQ("1 s", formatv("{0:+}", seconds(1)).str()); + EXPECT_EQ("1", formatv("{0:-}", seconds(1)).str()); + + EXPECT_EQ("1000 ms", formatv("{0:ms}", seconds(1)).str()); + EXPECT_EQ("1000000 us", formatv("{0:us}", seconds(1)).str()); + EXPECT_EQ("1000", formatv("{0:ms-}", seconds(1)).str()); + + EXPECT_EQ("1,000 ms", formatv("{0:+n}", milliseconds(1000)).str()); + EXPECT_EQ("0x3e8", formatv("{0:-x}", milliseconds(1000)).str()); + EXPECT_EQ("010", formatv("{0:-3}", milliseconds(10)).str()); + EXPECT_EQ("10,000", formatv("{0:ms-n}", seconds(10)).str()); + + EXPECT_EQ("1.00 s", formatv("{0}", duration<float>(1)).str()); + EXPECT_EQ("0.123 s", formatv("{0:+3}", duration<float>(0.123f)).str()); + EXPECT_EQ("1.230e-01 s", formatv("{0:+e3}", duration<float>(0.123f)).str()); + + typedef duration<float, std::ratio<60 * 60 * 24 * 14, 1000000>> + microfortnights; + EXPECT_EQ("1.00", formatv("{0:-}", microfortnights(1)).str()); + EXPECT_EQ("1209.60 ms", formatv("{0:ms}", microfortnights(1)).str()); +} + } // anonymous namespace diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index 945eb1d4e1cf..33573c4e6960 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -303,7 +303,8 @@ TEST(CommandLineTest, SetValueInSubcategories) { EXPECT_FALSE(SC1Opt); EXPECT_FALSE(SC2Opt); const char *args[] = {"prog", "-top-level"}; - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); EXPECT_TRUE(TopLevelOpt); EXPECT_FALSE(SC1Opt); EXPECT_FALSE(SC2Opt); @@ -315,7 +316,8 @@ TEST(CommandLineTest, SetValueInSubcategories) { EXPECT_FALSE(SC1Opt); EXPECT_FALSE(SC2Opt); const char *args2[] = {"prog", "sc1", "-sc1"}; - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); EXPECT_FALSE(TopLevelOpt); EXPECT_TRUE(SC1Opt); EXPECT_FALSE(SC2Opt); @@ -327,7 +329,8 @@ TEST(CommandLineTest, SetValueInSubcategories) { EXPECT_FALSE(SC1Opt); EXPECT_FALSE(SC2Opt); const char *args3[] = {"prog", "sc2", "-sc2"}; - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(3, args3, StringRef(), &llvm::nulls())); EXPECT_FALSE(TopLevelOpt); EXPECT_FALSE(SC1Opt); EXPECT_TRUE(SC2Opt); @@ -342,8 +345,13 @@ TEST(CommandLineTest, LookupFailsInWrongSubCommand) { StackOption<bool> SC1Opt("sc1", cl::sub(SC1), cl::init(false)); StackOption<bool> SC2Opt("sc2", cl::sub(SC2), cl::init(false)); + std::string Errs; + raw_string_ostream OS(Errs); + const char *args[] = {"prog", "sc1", "-sc2"}; - EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true)); + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); + OS.flush(); + EXPECT_FALSE(Errs.empty()); } TEST(CommandLineTest, AddToAllSubCommands) { @@ -358,23 +366,30 @@ TEST(CommandLineTest, AddToAllSubCommands) { const char *args2[] = {"prog", "sc1", "-everywhere"}; const char *args3[] = {"prog", "sc2", "-everywhere"}; + std::string Errs; + raw_string_ostream OS(Errs); + EXPECT_FALSE(AllOpt); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), &OS)); EXPECT_TRUE(AllOpt); AllOpt = false; cl::ResetAllOptionOccurrences(); EXPECT_FALSE(AllOpt); - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), &OS)); EXPECT_TRUE(AllOpt); AllOpt = false; cl::ResetAllOptionOccurrences(); EXPECT_FALSE(AllOpt); - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args3, StringRef(), &OS)); EXPECT_TRUE(AllOpt); + + // Since all parsing succeeded, the error message should be empty. + OS.flush(); + EXPECT_TRUE(Errs.empty()); } TEST(CommandLineTest, ReparseCommandLineOptions) { @@ -386,14 +401,16 @@ TEST(CommandLineTest, ReparseCommandLineOptions) { const char *args[] = {"prog", "-top-level"}; EXPECT_FALSE(TopLevelOpt); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); EXPECT_TRUE(TopLevelOpt); TopLevelOpt = false; cl::ResetAllOptionOccurrences(); EXPECT_FALSE(TopLevelOpt); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); EXPECT_TRUE(TopLevelOpt); } @@ -406,14 +423,21 @@ TEST(CommandLineTest, RemoveFromRegularSubCommand) { const char *args[] = {"prog", "sc", "-remove-option"}; + std::string Errs; + raw_string_ostream OS(Errs); + EXPECT_FALSE(RemoveOption); - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), true)); + EXPECT_TRUE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); EXPECT_TRUE(RemoveOption); + OS.flush(); + EXPECT_TRUE(Errs.empty()); RemoveOption.removeArgument(); cl::ResetAllOptionOccurrences(); - EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), true)); + EXPECT_FALSE(cl::ParseCommandLineOptions(3, args, StringRef(), &OS)); + OS.flush(); + EXPECT_FALSE(Errs.empty()); } TEST(CommandLineTest, RemoveFromTopLevelSubCommand) { @@ -427,13 +451,15 @@ TEST(CommandLineTest, RemoveFromTopLevelSubCommand) { const char *args[] = {"prog", "-top-level-remove"}; EXPECT_FALSE(TopLevelRemove); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); EXPECT_TRUE(TopLevelRemove); TopLevelRemove.removeArgument(); cl::ResetAllOptionOccurrences(); - EXPECT_FALSE(cl::ParseCommandLineOptions(2, args, StringRef(), true)); + EXPECT_FALSE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); } TEST(CommandLineTest, RemoveFromAllSubCommands) { @@ -452,32 +478,38 @@ TEST(CommandLineTest, RemoveFromAllSubCommands) { // It should work for all subcommands including the top-level. EXPECT_FALSE(RemoveOption); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); EXPECT_TRUE(RemoveOption); RemoveOption = false; cl::ResetAllOptionOccurrences(); EXPECT_FALSE(RemoveOption); - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args1, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); EXPECT_TRUE(RemoveOption); RemoveOption = false; cl::ResetAllOptionOccurrences(); EXPECT_FALSE(RemoveOption); - EXPECT_TRUE(cl::ParseCommandLineOptions(3, args2, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); EXPECT_TRUE(RemoveOption); RemoveOption.removeArgument(); // It should not work for any subcommands including the top-level. cl::ResetAllOptionOccurrences(); - EXPECT_FALSE(cl::ParseCommandLineOptions(2, args0, StringRef(), true)); + EXPECT_FALSE( + cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); cl::ResetAllOptionOccurrences(); - EXPECT_FALSE(cl::ParseCommandLineOptions(3, args1, StringRef(), true)); + EXPECT_FALSE( + cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls())); cl::ResetAllOptionOccurrences(); - EXPECT_FALSE(cl::ParseCommandLineOptions(3, args2, StringRef(), true)); + EXPECT_FALSE( + cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls())); } TEST(CommandLineTest, GetRegisteredSubcommands) { @@ -491,7 +523,8 @@ TEST(CommandLineTest, GetRegisteredSubcommands) { const char *args0[] = {"prog", "sc1"}; const char *args1[] = {"prog", "sc2"}; - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args0, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args0, StringRef(), &llvm::nulls())); EXPECT_FALSE(Opt1); EXPECT_FALSE(Opt2); for (auto *S : cl::getRegisteredSubcommands()) { @@ -500,7 +533,8 @@ TEST(CommandLineTest, GetRegisteredSubcommands) { } cl::ResetAllOptionOccurrences(); - EXPECT_TRUE(cl::ParseCommandLineOptions(2, args1, StringRef(), true)); + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls())); EXPECT_FALSE(Opt1); EXPECT_FALSE(Opt2); for (auto *S : cl::getRegisteredSubcommands()) { diff --git a/unittests/Support/CompressionTest.cpp b/unittests/Support/CompressionTest.cpp index 36b84d85f22b..18a6175460d3 100644 --- a/unittests/Support/CompressionTest.cpp +++ b/unittests/Support/CompressionTest.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Compression.h" +#include "llvm/Support/Error.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Config/config.h" @@ -26,15 +27,21 @@ namespace { void TestZlibCompression(StringRef Input, zlib::CompressionLevel Level) { SmallString<32> Compressed; SmallString<32> Uncompressed; - EXPECT_EQ(zlib::StatusOK, zlib::compress(Input, Compressed, Level)); + + Error E = zlib::compress(Input, Compressed, Level); + EXPECT_FALSE(E); + consumeError(std::move(E)); + // Check that uncompressed buffer is the same as original. - EXPECT_EQ(zlib::StatusOK, - zlib::uncompress(Compressed, Uncompressed, Input.size())); + E = zlib::uncompress(Compressed, Uncompressed, Input.size()); + EXPECT_FALSE(E); + consumeError(std::move(E)); + EXPECT_EQ(Input, Uncompressed); if (Input.size() > 0) { // Uncompression fails if expected length is too short. - EXPECT_EQ(zlib::StatusBufferTooShort, - zlib::uncompress(Compressed, Uncompressed, Input.size() - 1)); + E = zlib::uncompress(Compressed, Uncompressed, Input.size() - 1); + EXPECT_EQ("zlib error: Z_BUF_ERROR", llvm::toString(std::move(E))); } } diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp index 29a173a058b6..382346cd231a 100644 --- a/unittests/Support/ErrorTest.cpp +++ b/unittests/Support/ErrorTest.cpp @@ -469,6 +469,34 @@ TEST(Error, ExitOnError) { << "exitOnError returned an unexpected error result"; } +// Test that the ExitOnError utility works as expected. +TEST(Error, CantFailSuccess) { + cantFail(Error::success()); + + int X = cantFail(Expected<int>(42)); + EXPECT_EQ(X, 42) << "Expected value modified by cantFail"; +} + +// Test that cantFail results in a crash if you pass it a failure value. +#if LLVM_ENABLE_ABI_BREAKING_CHECKS +TEST(Error, CantFailDeath) { + EXPECT_DEATH( + cantFail(make_error<StringError>("foo", inconvertibleErrorCode())), + "Failure value returned from cantFail wrapped call") + << "cantFail(Error) did not cause an abort for failure value"; + + EXPECT_DEATH( + { + auto IEC = inconvertibleErrorCode(); + int X = cantFail(Expected<int>(make_error<StringError>("foo", IEC))); + (void)X; + }, + "Failure value returned from cantFail wrapped call") + << "cantFail(Expected<int>) did not cause an abort for failure value"; +} +#endif + + // Test Checked Expected<T> in success mode. TEST(Error, CheckedExpectedInSuccessMode) { Expected<int> A = 7; diff --git a/unittests/Support/FormatVariadicTest.cpp b/unittests/Support/FormatVariadicTest.cpp index 9307c6d8e09b..b0c843870afc 100644 --- a/unittests/Support/FormatVariadicTest.cpp +++ b/unittests/Support/FormatVariadicTest.cpp @@ -324,11 +324,13 @@ TEST(FormatVariadicTest, StringFormatting) { const char FooArray[] = "FooArray"; const char *FooPtr = "FooPtr"; llvm::StringRef FooRef("FooRef"); + constexpr StringLiteral FooLiteral("FooLiteral"); std::string FooString("FooString"); // 1. Test that we can print various types of strings. EXPECT_EQ(FooArray, formatv("{0}", FooArray).str()); EXPECT_EQ(FooPtr, formatv("{0}", FooPtr).str()); EXPECT_EQ(FooRef, formatv("{0}", FooRef).str()); + EXPECT_EQ(FooLiteral, formatv("{0}", FooLiteral).str()); EXPECT_EQ(FooString, formatv("{0}", FooString).str()); // 2. Test that the precision specifier prints the correct number of diff --git a/unittests/Support/Host.cpp b/unittests/Support/Host.cpp index 934a60495427..fd53697793c7 100644 --- a/unittests/Support/Host.cpp +++ b/unittests/Support/Host.cpp @@ -17,25 +17,17 @@ using namespace llvm; class HostTest : public testing::Test { Triple Host; - SmallVector<std::pair<Triple::ArchType, Triple::OSType>, 4> SupportedArchAndOSs; protected: bool isSupportedArchAndOS() { - if (is_contained(SupportedArchAndOSs, std::make_pair(Host.getArch(), Host.getOS()))) - return true; - - return false; - } - - HostTest() { - Host.setTriple(Triple::normalize(sys::getProcessTriple())); - // Initially this is only testing detection of the number of // physical cores, which is currently only supported/tested for // x86_64 Linux and Darwin. - SupportedArchAndOSs.push_back(std::make_pair(Triple::x86_64, Triple::Linux)); - SupportedArchAndOSs.push_back(std::make_pair(Triple::x86_64, Triple::Darwin)); + return (Host.getArch() == Triple::x86_64 && + (Host.isOSDarwin() || Host.getOS() == Triple::Linux)); } + + HostTest() : Host(Triple::normalize(sys::getProcessTriple())) {} }; TEST_F(HostTest, NumPhysicalCores) { @@ -46,3 +38,79 @@ TEST_F(HostTest, NumPhysicalCores) { else ASSERT_EQ(Num, -1); } + +TEST(getLinuxHostCPUName, ARM) { + StringRef CortexA9ProcCpuinfo = R"( +processor : 0 +model name : ARMv7 Processor rev 10 (v7l) +BogoMIPS : 1393.66 +Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x2 +CPU part : 0xc09 +CPU revision : 10 + +processor : 1 +model name : ARMv7 Processor rev 10 (v7l) +BogoMIPS : 1393.66 +Features : half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpd32 +CPU implementer : 0x41 +CPU architecture: 7 +CPU variant : 0x2 +CPU part : 0xc09 +CPU revision : 10 + +Hardware : Generic OMAP4 (Flattened Device Tree) +Revision : 0000 +Serial : 0000000000000000 +)"; + + EXPECT_EQ(sys::detail::getHostCPUNameForARM(CortexA9ProcCpuinfo), + "cortex-a9"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n" + "CPU part : 0xc0f"), + "cortex-a15"); + // Verify that both CPU implementer and CPU part are checked: + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n" + "CPU part : 0xc0f"), + "generic"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" + "CPU part : 0x06f"), + "krait"); +} + +TEST(getLinuxHostCPUName, AArch64) { + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x41\n" + "CPU part : 0xd03"), + "cortex-a53"); + // Verify that both CPU implementer and CPU part are checked: + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x40\n" + "CPU part : 0xd03"), + "generic"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" + "CPU part : 0x201"), + "kryo"); + + // MSM8992/4 weirdness + StringRef MSM8992ProcCpuInfo = R"( +Processor : AArch64 Processor rev 3 (aarch64) +processor : 0 +processor : 1 +processor : 2 +processor : 3 +processor : 4 +processor : 5 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0xd03 +CPU revision : 3 + +Hardware : Qualcomm Technologies, Inc MSM8992 +)"; + + EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo), + "cortex-a53"); +} diff --git a/unittests/Support/LEB128Test.cpp b/unittests/Support/LEB128Test.cpp index 76b63e5a8381..061936df1d19 100644 --- a/unittests/Support/LEB128Test.cpp +++ b/unittests/Support/LEB128Test.cpp @@ -17,26 +17,45 @@ using namespace llvm; namespace { TEST(LEB128Test, EncodeSLEB128) { -#define EXPECT_SLEB128_EQ(EXPECTED, VALUE) \ +#define EXPECT_SLEB128_EQ(EXPECTED, VALUE, PAD) \ do { \ - /* encodeSLEB128(uint64_t, raw_ostream &) */ \ std::string Expected(EXPECTED, sizeof(EXPECTED) - 1); \ - std::string Actual; \ - raw_string_ostream Stream(Actual); \ - encodeSLEB128(VALUE, Stream); \ + \ + /* encodeSLEB128(uint64_t, raw_ostream &, unsigned) */ \ + std::string Actual1; \ + raw_string_ostream Stream(Actual1); \ + encodeSLEB128(VALUE, Stream, PAD); \ Stream.flush(); \ - EXPECT_EQ(Expected, Actual); \ + EXPECT_EQ(Expected, Actual1); \ + \ + /* encodeSLEB128(uint64_t, uint8_t *, unsigned) */ \ + uint8_t Buffer[32]; \ + unsigned Size = encodeSLEB128(VALUE, Buffer, PAD); \ + std::string Actual2(reinterpret_cast<const char *>(Buffer), Size); \ + EXPECT_EQ(Expected, Actual2); \ } while (0) // Encode SLEB128 - EXPECT_SLEB128_EQ("\x00", 0); - EXPECT_SLEB128_EQ("\x01", 1); - EXPECT_SLEB128_EQ("\x7f", -1); - EXPECT_SLEB128_EQ("\x3f", 63); - EXPECT_SLEB128_EQ("\x41", -63); - EXPECT_SLEB128_EQ("\x40", -64); - EXPECT_SLEB128_EQ("\xbf\x7f", -65); - EXPECT_SLEB128_EQ("\xc0\x00", 64); + EXPECT_SLEB128_EQ("\x00", 0, 0); + EXPECT_SLEB128_EQ("\x01", 1, 0); + EXPECT_SLEB128_EQ("\x7f", -1, 0); + EXPECT_SLEB128_EQ("\x3f", 63, 0); + EXPECT_SLEB128_EQ("\x41", -63, 0); + EXPECT_SLEB128_EQ("\x40", -64, 0); + EXPECT_SLEB128_EQ("\xbf\x7f", -65, 0); + EXPECT_SLEB128_EQ("\xc0\x00", 64, 0); + + // Encode SLEB128 with some extra padding bytes + EXPECT_SLEB128_EQ("\x80\x00", 0, 1); + EXPECT_SLEB128_EQ("\x80\x80\x00", 0, 2); + EXPECT_SLEB128_EQ("\xff\x80\x00", 0x7f, 1); + EXPECT_SLEB128_EQ("\xff\x80\x80\x00", 0x7f, 2); + EXPECT_SLEB128_EQ("\x80\x81\x00", 0x80, 1); + EXPECT_SLEB128_EQ("\x80\x81\x80\x00", 0x80, 2); + EXPECT_SLEB128_EQ("\xc0\x7f", -0x40, 1); + EXPECT_SLEB128_EQ("\xc0\xff\x7f", -0x40, 2); + EXPECT_SLEB128_EQ("\x80\xff\x7f", -0x80, 1); + EXPECT_SLEB128_EQ("\x80\xff\xff\x7f", -0x80, 2); #undef EXPECT_SLEB128_EQ } diff --git a/unittests/Support/MD5Test.cpp b/unittests/Support/MD5Test.cpp index 4d790254503e..fa9372fde33f 100644 --- a/unittests/Support/MD5Test.cpp +++ b/unittests/Support/MD5Test.cpp @@ -63,8 +63,10 @@ TEST(MD5HashTest, MD5) { std::array<uint8_t, 16> Vec = MD5::hash(Input); MD5::MD5Result MD5Res; SmallString<32> Res; - memcpy(MD5Res, Vec.data(), Vec.size()); + memcpy(MD5Res.Bytes.data(), Vec.data(), Vec.size()); MD5::stringifyResult(MD5Res, Res); EXPECT_EQ(Res, "c3fcd3d76192e4007dfb496cca67e13b"); + EXPECT_EQ(0x3be167ca6c49fb7dULL, MD5Res.high()); + EXPECT_EQ(0x00e49261d7d3fcc3ULL, MD5Res.low()); } } diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 30eaa8b278ab..86ad57f3f3ff 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -8,12 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Path.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Triple.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "gtest/gtest.h" @@ -25,6 +28,7 @@ #endif #ifdef LLVM_ON_UNIX +#include <pwd.h> #include <sys/stat.h> #endif @@ -50,6 +54,9 @@ TEST(is_separator, Works) { EXPECT_FALSE(path::is_separator('-')); EXPECT_FALSE(path::is_separator(' ')); + EXPECT_TRUE(path::is_separator('\\', path::Style::windows)); + EXPECT_FALSE(path::is_separator('\\', path::Style::posix)); + #ifdef LLVM_ON_WIN32 EXPECT_TRUE(path::is_separator('\\')); #else @@ -249,7 +256,6 @@ TEST(Support, AbsolutePathDotIterator) { } } -#ifdef LLVM_ON_WIN32 TEST(Support, AbsolutePathIteratorWin32) { SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); typedef SmallVector<StringRef, 4> PathComponents; @@ -262,8 +268,9 @@ TEST(Support, AbsolutePathIteratorWin32) { // when iterating. ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\"); - for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; - ++I) { + for (path::const_iterator I = path::begin(Path, path::Style::windows), + E = path::end(Path); + I != E; ++I) { ActualPathComponents.push_back(*I); } @@ -273,34 +280,29 @@ TEST(Support, AbsolutePathIteratorWin32) { EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); } } -#endif // LLVM_ON_WIN32 TEST(Support, AbsolutePathIteratorEnd) { // Trailing slashes are converted to '.' unless they are part of the root path. - SmallVector<StringRef, 4> Paths; - Paths.push_back("/foo/"); - Paths.push_back("/foo//"); - Paths.push_back("//net//"); -#ifdef LLVM_ON_WIN32 - Paths.push_back("c:\\\\"); -#endif - - for (StringRef Path : Paths) { - StringRef LastComponent = *path::rbegin(Path); + SmallVector<std::pair<StringRef, path::Style>, 4> Paths; + Paths.emplace_back("/foo/", path::Style::native); + Paths.emplace_back("/foo//", path::Style::native); + Paths.emplace_back("//net//", path::Style::native); + Paths.emplace_back("c:\\\\", path::Style::windows); + + for (auto &Path : Paths) { + StringRef LastComponent = *path::rbegin(Path.first, Path.second); EXPECT_EQ(".", LastComponent); } - SmallVector<StringRef, 3> RootPaths; - RootPaths.push_back("/"); - RootPaths.push_back("//net/"); -#ifdef LLVM_ON_WIN32 - RootPaths.push_back("c:\\"); -#endif + SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths; + RootPaths.emplace_back("/", path::Style::native); + RootPaths.emplace_back("//net/", path::Style::native); + RootPaths.emplace_back("c:\\", path::Style::windows); - for (StringRef Path : RootPaths) { - StringRef LastComponent = *path::rbegin(Path); + for (auto &Path : RootPaths) { + StringRef LastComponent = *path::rbegin(Path.first, Path.second); EXPECT_EQ(1u, LastComponent.size()); - EXPECT_TRUE(path::is_separator(LastComponent[0])); + EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second)); } } @@ -327,6 +329,36 @@ TEST(Support, HomeDirectory) { } } +#ifdef LLVM_ON_UNIX +TEST(Support, HomeDirectoryWithNoEnv) { + std::string OriginalStorage; + char const *OriginalEnv = ::getenv("HOME"); + if (OriginalEnv) { + // We're going to unset it, so make a copy and save a pointer to the copy + // so that we can reset it at the end of the test. + OriginalStorage = OriginalEnv; + OriginalEnv = OriginalStorage.c_str(); + } + + // Don't run the test if we have nothing to compare against. + struct passwd *pw = getpwuid(getuid()); + if (!pw || !pw->pw_dir) return; + + ::unsetenv("HOME"); + EXPECT_EQ(nullptr, ::getenv("HOME")); + std::string PwDir = pw->pw_dir; + + SmallString<128> HomeDir; + auto status = path::home_directory(HomeDir); + EXPECT_TRUE(status); + EXPECT_EQ(PwDir, HomeDir); + + // Now put the environment back to its original state (meaning that if it was + // unset before, we don't reset it). + if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1); +} +#endif + TEST(Support, UserCacheDirectory) { SmallString<13> CacheDir; SmallString<20> CacheDir2; @@ -496,6 +528,41 @@ TEST_F(FileSystemTest, Unique) { ASSERT_NO_ERROR(fs::remove(TempPath)); } +TEST_F(FileSystemTest, RealPath) { + ASSERT_NO_ERROR( + fs::create_directories(Twine(TestDirectory) + "/test1/test2/test3")); + ASSERT_TRUE(fs::exists(Twine(TestDirectory) + "/test1/test2/test3")); + + SmallString<64> RealBase; + SmallString<64> Expected; + SmallString<64> Actual; + + // TestDirectory itself might be under a symlink or have been specified with + // a different case than the existing temp directory. In such cases real_path + // on the concatenated path will differ in the TestDirectory portion from + // how we specified it. Make sure to compare against the real_path of the + // TestDirectory, and not just the value of TestDirectory. + ASSERT_NO_ERROR(fs::real_path(TestDirectory, RealBase)); + path::native(Twine(RealBase) + "/test1/test2", Expected); + + ASSERT_NO_ERROR(fs::real_path( + Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual)); + + EXPECT_EQ(Expected, Actual); + + SmallString<64> HomeDir; + bool Result = llvm::sys::path::home_directory(HomeDir); + if (Result) { + ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected)); + ASSERT_NO_ERROR(fs::real_path("~", Actual, true)); + EXPECT_EQ(Expected, Actual); + ASSERT_NO_ERROR(fs::real_path("~/", Actual, true)); + EXPECT_EQ(Expected, Actual); + } + + ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1")); +} + TEST_F(FileSystemTest, TempFiles) { // Create a temp file. int FileDescriptor; @@ -740,6 +807,118 @@ TEST_F(FileSystemTest, DirectoryIteration) { ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/reclevel")); } +#ifdef LLVM_ON_UNIX +TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) { + // Create a known hierarchy to recurse over. + ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + "/symlink")); + ASSERT_NO_ERROR( + fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/a")); + ASSERT_NO_ERROR( + fs::create_directories(Twine(TestDirectory) + "/symlink/b/bb")); + ASSERT_NO_ERROR( + fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/ba")); + ASSERT_NO_ERROR( + fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/b/bc")); + ASSERT_NO_ERROR( + fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/c")); + ASSERT_NO_ERROR( + fs::create_directories(Twine(TestDirectory) + "/symlink/d/dd/ddd")); + ASSERT_NO_ERROR(fs::create_link(Twine(TestDirectory) + "/symlink/d/dd", + Twine(TestDirectory) + "/symlink/d/da")); + ASSERT_NO_ERROR( + fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e")); + + typedef std::vector<std::string> v_t; + v_t visited; + + // The directory iterator doesn't stat the file, so we should be able to + // iterate over the whole directory. + std::error_code ec; + for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e; + i != e; i.increment(ec)) { + ASSERT_NO_ERROR(ec); + visited.push_back(path::filename(i->path())); + } + std::sort(visited.begin(), visited.end()); + v_t expected = {"a", "b", "c", "d", "e"}; + ASSERT_TRUE(visited.size() == expected.size()); + ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + visited.clear(); + + // The recursive directory iterator has to stat the file, so we need to skip + // the broken symlinks. + for (fs::recursive_directory_iterator + i(Twine(TestDirectory) + "/symlink", ec), + e; + i != e; i.increment(ec)) { + ASSERT_NO_ERROR(ec); + + fs::file_status status; + if (i->status(status) == + std::make_error_code(std::errc::no_such_file_or_directory)) { + i.no_push(); + continue; + } + + visited.push_back(path::filename(i->path())); + } + std::sort(visited.begin(), visited.end()); + expected = {"b", "bb", "d", "da", "dd", "ddd", "ddd"}; + ASSERT_TRUE(visited.size() == expected.size()); + ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + visited.clear(); + + // This recursive directory iterator doesn't follow symlinks, so we don't need + // to skip them. + for (fs::recursive_directory_iterator + i(Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), + e; + i != e; i.increment(ec)) { + ASSERT_NO_ERROR(ec); + visited.push_back(path::filename(i->path())); + } + std::sort(visited.begin(), visited.end()); + expected = {"a", "b", "ba", "bb", "bc", "c", "d", "da", "dd", "ddd", "e"}; + ASSERT_TRUE(visited.size() == expected.size()); + ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); + + ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink")); +} +#endif + +TEST_F(FileSystemTest, Remove) { + SmallString<64> BaseDir; + SmallString<64> Paths[4]; + int fds[4]; + ASSERT_NO_ERROR(fs::createUniqueDirectory("fs_remove", BaseDir)); + + ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/baz")); + ASSERT_NO_ERROR(fs::create_directories(Twine(BaseDir) + "/foo/bar/buzz")); + ASSERT_NO_ERROR(fs::createUniqueFile( + Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[0], Paths[0])); + ASSERT_NO_ERROR(fs::createUniqueFile( + Twine(BaseDir) + "/foo/bar/baz/%%%%%%.tmp", fds[1], Paths[1])); + ASSERT_NO_ERROR(fs::createUniqueFile( + Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[2], Paths[2])); + ASSERT_NO_ERROR(fs::createUniqueFile( + Twine(BaseDir) + "/foo/bar/buzz/%%%%%%.tmp", fds[3], Paths[3])); + + for (int fd : fds) + ::close(fd); + + EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/baz")); + EXPECT_TRUE(fs::exists(Twine(BaseDir) + "/foo/bar/buzz")); + EXPECT_TRUE(fs::exists(Paths[0])); + EXPECT_TRUE(fs::exists(Paths[1])); + EXPECT_TRUE(fs::exists(Paths[2])); + EXPECT_TRUE(fs::exists(Paths[3])); + + ASSERT_NO_ERROR(fs::remove_directories("D:/footest")); + + ASSERT_NO_ERROR(fs::remove_directories(BaseDir)); + ASSERT_FALSE(fs::exists(BaseDir)); +} + const char archive[] = "!<arch>\x0A"; const char bitcode[] = "\xde\xc0\x17\x0b"; const char coff_object[] = "\x00\x00......"; @@ -863,6 +1042,20 @@ TEST_F(FileSystemTest, Resize) { ASSERT_NO_ERROR(fs::remove(TempPath)); } +TEST_F(FileSystemTest, MD5) { + int FD; + SmallString<64> TempPath; + ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath)); + StringRef Data("abcdefghijklmnopqrstuvwxyz"); + write(FD, Data.data(), Data.size()); + lseek(FD, 0, SEEK_SET); + auto Hash = fs::md5_contents(FD); + ::close(FD); + ASSERT_NO_ERROR(Hash.getError()); + + EXPECT_STREQ("c3fcd3d76192e4007dfb496cca67e13b", Hash->digest().c_str()); +} + TEST_F(FileSystemTest, FileMapping) { // Create a temp file. int FileDescriptor; @@ -906,40 +1099,50 @@ TEST_F(FileSystemTest, FileMapping) { } TEST(Support, NormalizePath) { + using TestTuple = std::tuple<const char *, const char *, const char *>; + std::vector<TestTuple> Tests; + Tests.emplace_back("a", "a", "a"); + Tests.emplace_back("a/b", "a\\b", "a/b"); + Tests.emplace_back("a\\b", "a\\b", "a/b"); + Tests.emplace_back("a\\\\b", "a\\\\b", "a\\\\b"); + Tests.emplace_back("\\a", "\\a", "/a"); + Tests.emplace_back("a\\", "a\\", "a/"); + + for (auto &T : Tests) { + SmallString<64> Win(std::get<0>(T)); + SmallString<64> Posix(Win); + path::native(Win, path::Style::windows); + path::native(Posix, path::Style::posix); + EXPECT_EQ(std::get<1>(T), Win); + EXPECT_EQ(std::get<2>(T), Posix); + } + #if defined(LLVM_ON_WIN32) -#define EXPECT_PATH_IS(path__, windows__, not_windows__) \ - EXPECT_EQ(path__, windows__); -#else -#define EXPECT_PATH_IS(path__, windows__, not_windows__) \ - EXPECT_EQ(path__, not_windows__); + SmallString<64> PathHome; + path::home_directory(PathHome); + + const char *Path7a = "~/aaa"; + SmallString<64> Path7(Path7a); + path::native(Path7); + EXPECT_TRUE(Path7.endswith("\\aaa")); + EXPECT_TRUE(Path7.startswith(PathHome)); + EXPECT_EQ(Path7.size(), PathHome.size() + strlen(Path7a + 1)); + + const char *Path8a = "~"; + SmallString<64> Path8(Path8a); + path::native(Path8); + EXPECT_EQ(Path8, PathHome); + + const char *Path9a = "~aaa"; + SmallString<64> Path9(Path9a); + path::native(Path9); + EXPECT_EQ(Path9, "~aaa"); + + const char *Path10a = "aaa/~/b"; + SmallString<64> Path10(Path10a); + path::native(Path10); + EXPECT_EQ(Path10, "aaa\\~\\b"); #endif - - SmallString<64> Path1("a"); - SmallString<64> Path2("a/b"); - SmallString<64> Path3("a\\b"); - SmallString<64> Path4("a\\\\b"); - SmallString<64> Path5("\\a"); - SmallString<64> Path6("a\\"); - - path::native(Path1); - EXPECT_PATH_IS(Path1, "a", "a"); - - path::native(Path2); - EXPECT_PATH_IS(Path2, "a\\b", "a/b"); - - path::native(Path3); - EXPECT_PATH_IS(Path3, "a\\b", "a/b"); - - path::native(Path4); - EXPECT_PATH_IS(Path4, "a\\\\b", "a\\\\b"); - - path::native(Path5); - EXPECT_PATH_IS(Path5, "\\a", "/a"); - - path::native(Path6); - EXPECT_PATH_IS(Path6, "a\\", "a/"); - -#undef EXPECT_PATH_IS } TEST(Support, RemoveLeadingDotSlash) { @@ -952,43 +1155,48 @@ TEST(Support, RemoveLeadingDotSlash) { EXPECT_EQ(Path2, ""); } -static std::string remove_dots(StringRef path, - bool remove_dot_dot) { +static std::string remove_dots(StringRef path, bool remove_dot_dot, + path::Style style) { SmallString<256> buffer(path); - path::remove_dots(buffer, remove_dot_dot); + path::remove_dots(buffer, remove_dot_dot, style); return buffer.str(); } TEST(Support, RemoveDots) { -#if defined(LLVM_ON_WIN32) - EXPECT_EQ("foolz\\wat", remove_dots(".\\.\\\\foolz\\wat", false)); - EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false)); - - EXPECT_EQ("a\\..\\b\\c", remove_dots(".\\a\\..\\b\\c", false)); - EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true)); - EXPECT_EQ("c", remove_dots(".\\.\\c", true)); - EXPECT_EQ("..\\a\\c", remove_dots("..\\a\\b\\..\\c", true)); - EXPECT_EQ("..\\..\\a\\c", remove_dots("..\\..\\a\\b\\..\\c", true)); + EXPECT_EQ("foolz\\wat", + remove_dots(".\\.\\\\foolz\\wat", false, path::Style::windows)); + EXPECT_EQ("", remove_dots(".\\\\\\\\\\", false, path::Style::windows)); + + EXPECT_EQ("a\\..\\b\\c", + remove_dots(".\\a\\..\\b\\c", false, path::Style::windows)); + EXPECT_EQ("b\\c", remove_dots(".\\a\\..\\b\\c", true, path::Style::windows)); + EXPECT_EQ("c", remove_dots(".\\.\\c", true, path::Style::windows)); + EXPECT_EQ("..\\a\\c", + remove_dots("..\\a\\b\\..\\c", true, path::Style::windows)); + EXPECT_EQ("..\\..\\a\\c", + remove_dots("..\\..\\a\\b\\..\\c", true, path::Style::windows)); SmallString<64> Path1(".\\.\\c"); - EXPECT_TRUE(path::remove_dots(Path1, true)); - EXPECT_EQ("c", Path1); -#else - EXPECT_EQ("foolz/wat", remove_dots("././/foolz/wat", false)); - EXPECT_EQ("", remove_dots("./////", false)); - - EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false)); - EXPECT_EQ("b/c", remove_dots("./a/../b/c", true)); - EXPECT_EQ("c", remove_dots("././c", true)); - EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true)); - EXPECT_EQ("../../a/c", remove_dots("../../a/b/../c", true)); - EXPECT_EQ("/a/c", remove_dots("/../../a/c", true)); - EXPECT_EQ("/a/c", remove_dots("/../a/b//../././/c", true)); - - SmallString<64> Path1("././c"); - EXPECT_TRUE(path::remove_dots(Path1, true)); + EXPECT_TRUE(path::remove_dots(Path1, true, path::Style::windows)); EXPECT_EQ("c", Path1); -#endif + + EXPECT_EQ("foolz/wat", + remove_dots("././/foolz/wat", false, path::Style::posix)); + EXPECT_EQ("", remove_dots("./////", false, path::Style::posix)); + + EXPECT_EQ("a/../b/c", remove_dots("./a/../b/c", false, path::Style::posix)); + EXPECT_EQ("b/c", remove_dots("./a/../b/c", true, path::Style::posix)); + EXPECT_EQ("c", remove_dots("././c", true, path::Style::posix)); + EXPECT_EQ("../a/c", remove_dots("../a/b/../c", true, path::Style::posix)); + EXPECT_EQ("../../a/c", + remove_dots("../../a/b/../c", true, path::Style::posix)); + EXPECT_EQ("/a/c", remove_dots("/../../a/c", true, path::Style::posix)); + EXPECT_EQ("/a/c", + remove_dots("/../a/b//../././/c", true, path::Style::posix)); + + SmallString<64> Path2("././c"); + EXPECT_TRUE(path::remove_dots(Path2, true, path::Style::posix)); + EXPECT_EQ("c", Path2); } TEST(Support, ReplacePathPrefix) { @@ -1135,4 +1343,198 @@ TEST_F(FileSystemTest, OpenFileForRead) { ::close(FileDescriptor); } + +TEST_F(FileSystemTest, set_current_path) { + SmallString<128> path; + + ASSERT_NO_ERROR(fs::current_path(path)); + ASSERT_NE(TestDirectory, path); + + struct RestorePath { + SmallString<128> path; + RestorePath(const SmallString<128> &path) : path(path) {} + ~RestorePath() { fs::set_current_path(path); } + } restore_path(path); + + ASSERT_NO_ERROR(fs::set_current_path(TestDirectory)); + + ASSERT_NO_ERROR(fs::current_path(path)); + + fs::UniqueID D1, D2; + ASSERT_NO_ERROR(fs::getUniqueID(TestDirectory, D1)); + ASSERT_NO_ERROR(fs::getUniqueID(path, D2)); + ASSERT_EQ(D1, D2) << "D1: " << TestDirectory << "\nD2: " << path; +} + +TEST_F(FileSystemTest, permissions) { + int FD; + SmallString<64> TempPath; + ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath)); + FileRemover Cleanup(TempPath); + + // Make sure it exists. + ASSERT_TRUE(fs::exists(Twine(TempPath))); + + auto CheckPermissions = [&](fs::perms Expected) { + ErrorOr<fs::perms> Actual = fs::getPermissions(TempPath); + return Actual && *Actual == Expected; + }; + + std::error_code NoError; + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe)); + +#if defined(LLVM_ON_WIN32) + fs::perms ReadOnly = fs::all_read | fs::all_exe; + EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe | + fs::set_gid_on_exe | + fs::sticky_bit), + NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, ReadOnly | fs::set_uid_on_exe | + fs::set_gid_on_exe | + fs::sticky_bit), + NoError); + EXPECT_TRUE(CheckPermissions(ReadOnly)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_all)); +#else + EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError); + EXPECT_TRUE(CheckPermissions(fs::no_perms)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError); + EXPECT_TRUE(CheckPermissions(fs::owner_read)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::owner_write)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::owner_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::owner_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_read), NoError); + EXPECT_TRUE(CheckPermissions(fs::group_read)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::group_write)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::group_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::group_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::group_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_read), NoError); + EXPECT_TRUE(CheckPermissions(fs::others_read)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::others_write)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::others_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::others_all), NoError); + EXPECT_TRUE(CheckPermissions(fs::others_all)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_read)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_write), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_write)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError); + EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError); + EXPECT_TRUE(CheckPermissions(fs::sticky_bit)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe | + fs::set_gid_on_exe | + fs::sticky_bit), + NoError); + EXPECT_TRUE(CheckPermissions(fs::set_uid_on_exe | fs::set_gid_on_exe | + fs::sticky_bit)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::set_uid_on_exe | + fs::set_gid_on_exe | + fs::sticky_bit), + NoError); + EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe | + fs::set_gid_on_exe | fs::sticky_bit)); + + EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError); + EXPECT_TRUE(CheckPermissions(fs::all_perms)); +#endif +} + } // anonymous namespace diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index 886ead8305bc..3926ceb92b3e 100644 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -87,6 +87,7 @@ protected: EXPECT_TRUE(convStatus); return EnvStorage.back().c_str(); #else + (void)this; return Var; #endif }; diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp index a3d806f76fb5..f0bfe7dbde96 100644 --- a/unittests/Support/TargetParserTest.cpp +++ b/unittests/Support/TargetParserTest.cpp @@ -17,17 +17,17 @@ using namespace llvm; namespace { const char *ARMArch[] = { - "armv2", "armv2a", "armv3", "armv3m", "armv4", - "armv4t", "armv5", "armv5t", "armv5e", "armv5te", - "armv5tej", "armv6", "armv6j", "armv6k", "armv6hl", - "armv6t2", "armv6kz", "armv6z", "armv6zk", "armv6-m", - "armv6m", "armv6sm", "armv6s-m", "armv7-a", "armv7", - "armv7a", "armv7hl", "armv7l", "armv7-r", "armv7r", - "armv7-m", "armv7m", "armv7k", "armv7s", "armv7e-m", - "armv7em", "armv8-a", "armv8", "armv8a", "armv8.1-a", - "armv8.1a", "armv8.2-a", "armv8.2a", "armv8-r", "armv8r", - "armv8-m.base", "armv8m.base", "armv8-m.main", "armv8m.main", "iwmmxt", - "iwmmxt2", "xscale"}; + "armv2", "armv2a", "armv3", "armv3m", "armv4", + "armv4t", "armv5", "armv5t", "armv5e", "armv5te", + "armv5tej", "armv6", "armv6j", "armv6k", "armv6hl", + "armv6t2", "armv6kz", "armv6z", "armv6zk", "armv6-m", + "armv6m", "armv6sm", "armv6s-m", "armv7-a", "armv7", + "armv7a", "armv7ve", "armv7hl", "armv7l", "armv7-r", + "armv7r", "armv7-m", "armv7m", "armv7k", "armv7s", + "armv7e-m", "armv7em", "armv8-a", "armv8", "armv8a", + "armv8.1-a", "armv8.1a", "armv8.2-a", "armv8.2a", "armv8-r", + "armv8r", "armv8-m.base", "armv8m.base", "armv8-m.main", "armv8m.main", + "iwmmxt", "iwmmxt2", "xscale"}; bool testARMCPU(StringRef CPUName, StringRef ExpectedArch, StringRef ExpectedFPU, unsigned ExpectedFlags, @@ -246,6 +246,10 @@ TEST(TargetParserTest, testARMCPU) { ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIV | ARM::AEK_DSP, "8-A")); + EXPECT_TRUE(testARMCPU("cortex-m23", "armv8-m.base", "none", + ARM::AEK_HWDIV, "8-M.Baseline")); + EXPECT_TRUE(testARMCPU("cortex-m33", "armv8-m.main", "fpv5-sp-d16", + ARM::AEK_HWDIV | ARM::AEK_DSP, "8-M.Mainline")); EXPECT_TRUE(testARMCPU("iwmmxt", "iwmmxt", "none", ARM::AEK_NONE, "iwmmxt")); EXPECT_TRUE(testARMCPU("xscale", "xscale", "none", @@ -311,6 +315,9 @@ TEST(TargetParserTest, testARMArch) { testARMArch("armv7-a", "cortex-a8", "v7", ARMBuildAttrs::CPUArch::v7)); EXPECT_TRUE( + testARMArch("armv7ve", "generic", "v7ve", + ARMBuildAttrs::CPUArch::v7)); + EXPECT_TRUE( testARMArch("armv7-r", "cortex-r4", "v7r", ARMBuildAttrs::CPUArch::v7)); EXPECT_TRUE( @@ -498,12 +505,12 @@ TEST(TargetParserTest, ARMparseHWDiv) { TEST(TargetParserTest, ARMparseArchEndianAndISA) { const char *Arch[] = { - "v2", "v2a", "v3", "v3m", "v4", "v4t", "v5", "v5t", - "v5e", "v5te", "v5tej", "v6", "v6j", "v6k", "v6hl", "v6t2", - "v6kz", "v6z", "v6zk", "v6-m", "v6m", "v6sm", "v6s-m", "v7-a", - "v7", "v7a", "v7hl", "v7l", "v7-r", "v7r", "v7-m", "v7m", - "v7k", "v7s", "v7e-m", "v7em", "v8-a", "v8", "v8a", "v8.1-a", - "v8.1a", "v8.2-a", "v8.2a", "v8-r"}; + "v2", "v2a", "v3", "v3m", "v4", "v4t", "v5", "v5t", + "v5e", "v5te", "v5tej", "v6", "v6j", "v6k", "v6hl", "v6t2", + "v6kz", "v6z", "v6zk", "v6-m", "v6m", "v6sm", "v6s-m", "v7-a", + "v7", "v7a", "v7ve", "v7hl", "v7l", "v7-r", "v7r", "v7-m", + "v7m", "v7k", "v7s", "v7e-m", "v7em", "v8-a", "v8", "v8a", + "v8.1-a", "v8.1a", "v8.2-a", "v8.2a", "v8-r"}; for (unsigned i = 0; i < array_lengthof(Arch); i++) { std::string arm_1 = "armeb" + (std::string)(Arch[i]); @@ -555,6 +562,7 @@ TEST(TargetParserTest, ARMparseArchProfile) { EXPECT_EQ(ARM::PK_R, ARM::parseArchProfile(ARMArch[i])); continue; case ARM::AK_ARMV7A: + case ARM::AK_ARMV7VE: case ARM::AK_ARMV7K: case ARM::AK_ARMV8A: case ARM::AK_ARMV8_1A: @@ -635,8 +643,29 @@ TEST(TargetParserTest, testAArch64CPU) { "kryo", "armv8-a", "crypto-neon-fp-armv8", AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8-A")); EXPECT_TRUE(testAArch64CPU( - "vulcan", "armv8.1-a", "crypto-neon-fp-armv8", - AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD, "8.1-A")); + "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_LSE | + AArch64::AEK_SIMD, "8.1-A")); + EXPECT_TRUE(testAArch64CPU( + "thunderx", "armv8-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD | + AArch64::AEK_FP | AArch64::AEK_PROFILE, + "8-A")); + EXPECT_TRUE(testAArch64CPU( + "thunderxt81", "armv8-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD | + AArch64::AEK_FP | AArch64::AEK_PROFILE, + "8-A")); + EXPECT_TRUE(testAArch64CPU( + "thunderxt83", "armv8-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD | + AArch64::AEK_FP | AArch64::AEK_PROFILE, + "8-A")); + EXPECT_TRUE(testAArch64CPU( + "thunderxt88", "armv8-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_SIMD | + AArch64::AEK_FP | AArch64::AEK_PROFILE, + "8-A")); } bool testAArch64Arch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch, @@ -672,7 +701,11 @@ TEST(TargetParserTest, testAArch64Extension) { EXPECT_FALSE(testAArch64Extension("cyclone", 0, "ras")); EXPECT_FALSE(testAArch64Extension("exynos-m1", 0, "ras")); EXPECT_FALSE(testAArch64Extension("kryo", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("vulcan", 0, "ras")); + EXPECT_FALSE(testAArch64Extension("thunderx2t99", 0, "ras")); + EXPECT_FALSE(testAArch64Extension("thunderx", 0, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt81", 0, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt83", 0, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt88", 0, "lse")); EXPECT_FALSE(testAArch64Extension( "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8A), "ras")); diff --git a/unittests/Support/ThreadPool.cpp b/unittests/Support/ThreadPool.cpp index 8e03aacfb1e0..0da33ad50c07 100644 --- a/unittests/Support/ThreadPool.cpp +++ b/unittests/Support/ThreadPool.cpp @@ -90,7 +90,7 @@ TEST_F(ThreadPoolTest, AsyncBarrier) { ThreadPool Pool; for (size_t i = 0; i < 5; ++i) { - Pool.async([this, &checked_in, i] { + Pool.async([this, &checked_in] { waitForMainThread(); ++checked_in; }); @@ -154,7 +154,7 @@ TEST_F(ThreadPoolTest, PoolDestruction) { { ThreadPool Pool; for (size_t i = 0; i < 5; ++i) { - Pool.async([this, &checked_in, i] { + Pool.async([this, &checked_in] { waitForMainThread(); ++checked_in; }); diff --git a/unittests/Support/TrailingObjectsTest.cpp b/unittests/Support/TrailingObjectsTest.cpp index cb5c47d1b25b..23acc54d2376 100644 --- a/unittests/Support/TrailingObjectsTest.cpp +++ b/unittests/Support/TrailingObjectsTest.cpp @@ -236,3 +236,24 @@ TEST(TrailingObjects, Realignment) { reinterpret_cast<char *>(C + 1) + 1, alignof(long)))); } } + +// Test the use of TrailingObjects with a template class. This +// previously failed to compile due to a bug in MSVC's member access +// control/lookup handling for OverloadToken. +template <typename Derived> +class Class5Tmpl : private llvm::TrailingObjects<Derived, float, int> { + using TrailingObjects = typename llvm::TrailingObjects<Derived, float>; + friend TrailingObjects; + + size_t numTrailingObjects( + typename TrailingObjects::template OverloadToken<float>) const { + return 1; + } + + size_t numTrailingObjects( + typename TrailingObjects::template OverloadToken<int>) const { + return 2; + } +}; + +class Class5 : public Class5Tmpl<Class5> {}; diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index dc7c5d47cba9..5a0280c8ca5b 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -1740,7 +1740,7 @@ TEST(YAMLIO, TestFlagsReadError) { // // Test error handling reading built-in uint8_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(uint8_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint8_t) TEST(YAMLIO, TestReadBuiltInTypesUint8Error) { std::vector<uint8_t> seq; Input yin("---\n" @@ -1759,7 +1759,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint8Error) { // // Test error handling reading built-in uint16_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(uint16_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint16_t) TEST(YAMLIO, TestReadBuiltInTypesUint16Error) { std::vector<uint16_t> seq; Input yin("---\n" @@ -1778,7 +1778,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint16Error) { // // Test error handling reading built-in uint32_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(uint32_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint32_t) TEST(YAMLIO, TestReadBuiltInTypesUint32Error) { std::vector<uint32_t> seq; Input yin("---\n" @@ -1797,7 +1797,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint32Error) { // // Test error handling reading built-in uint64_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(uint64_t) TEST(YAMLIO, TestReadBuiltInTypesUint64Error) { std::vector<uint64_t> seq; Input yin("---\n" @@ -1816,7 +1816,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint64Error) { // // Test error handling reading built-in int8_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(int8_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int8_t) TEST(YAMLIO, TestReadBuiltInTypesint8OverError) { std::vector<int8_t> seq; Input yin("---\n" @@ -1854,7 +1854,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) { // // Test error handling reading built-in int16_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(int16_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int16_t) TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) { std::vector<int16_t> seq; Input yin("---\n" @@ -1893,7 +1893,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint16OverError) { // // Test error handling reading built-in int32_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(int32_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int32_t) TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) { std::vector<int32_t> seq; Input yin("---\n" @@ -1931,7 +1931,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint32OverError) { // // Test error handling reading built-in int64_t type // -LLVM_YAML_IS_SEQUENCE_VECTOR(int64_t) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(int64_t) TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) { std::vector<int64_t> seq; Input yin("---\n" diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp index f87d2f60d169..777e555949ee 100644 --- a/unittests/Support/raw_ostream_test.cpp +++ b/unittests/Support/raw_ostream_test.cpp @@ -9,6 +9,7 @@ #include "gtest/gtest.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -330,4 +331,11 @@ TEST(raw_ostreamTest, FormattedHexBytes) { "0007: 68 69 6a 6b 6c |hijkl|", format_bytes_with_ascii_str(B.take_front(12), 0, 7, 1)); } + +TEST(raw_fd_ostreamTest, multiple_raw_fd_ostream_to_stdout) { + std::error_code EC; + + { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); } + { raw_fd_ostream("-", EC, sys::fs::OpenFlags::F_None); } +} } |