diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-18 20:10:56 +0000 |
| commit | 044eb2f6afba375a914ac9d8024f8f5142bb912e (patch) | |
| tree | 1475247dc9f9fe5be155ebd4c9069c75aadf8c20 /unittests/Support | |
| parent | eb70dddbd77e120e5d490bd8fbe7ff3f8fa81c6b (diff) | |
Notes
Diffstat (limited to 'unittests/Support')
27 files changed, 1225 insertions, 434 deletions
diff --git a/unittests/Support/ARMAttributeParser.cpp b/unittests/Support/ARMAttributeParser.cpp index 1df03db6d07f..994011872b96 100644 --- a/unittests/Support/ARMAttributeParser.cpp +++ b/unittests/Support/ARMAttributeParser.cpp @@ -1,6 +1,5 @@ #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" -#include "llvm/Support/LEB128.h" #include "gtest/gtest.h" #include <string> diff --git a/unittests/Support/BinaryStreamTest.cpp b/unittests/Support/BinaryStreamTest.cpp index e257583e4b12..35a010e73c7b 100644 --- a/unittests/Support/BinaryStreamTest.cpp +++ b/unittests/Support/BinaryStreamTest.cpp @@ -17,8 +17,6 @@ #include "gtest/gtest.h" -#include <unordered_map> -#include <utility> using namespace llvm; using namespace llvm::support; @@ -36,7 +34,7 @@ public: Error readBytes(uint32_t Offset, uint32_t Size, ArrayRef<uint8_t> &Buffer) override { - if (auto EC = checkOffset(Offset, Size)) + if (auto EC = checkOffsetForRead(Offset, Size)) return EC; uint32_t S = startIndex(Offset); auto Ref = Data.drop_front(S); @@ -55,7 +53,7 @@ public: Error readLongestContiguousChunk(uint32_t Offset, ArrayRef<uint8_t> &Buffer) override { - if (auto EC = checkOffset(Offset, 1)) + if (auto EC = checkOffsetForRead(Offset, 1)) return EC; uint32_t S = startIndex(Offset); Buffer = Data.drop_front(S); @@ -65,7 +63,7 @@ public: uint32_t getLength() override { return Data.size(); } Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> SrcData) override { - if (auto EC = checkOffset(Offset, SrcData.size())) + if (auto EC = checkOffsetForWrite(Offset, SrcData.size())) return EC; if (SrcData.empty()) return Error::success(); @@ -267,6 +265,56 @@ TEST_F(BinaryStreamTest, StreamRefBounds) { } } +TEST_F(BinaryStreamTest, StreamRefDynamicSize) { + StringRef Strings[] = {"1", "2", "3", "4"}; + AppendingBinaryByteStream Stream(support::little); + + BinaryStreamWriter Writer(Stream); + BinaryStreamReader Reader(Stream); + const uint8_t *Byte; + StringRef Str; + + // When the stream is empty, it should report a 0 length and we should get an + // error trying to read even 1 byte from it. + BinaryStreamRef ConstRef(Stream); + EXPECT_EQ(0U, ConstRef.getLength()); + EXPECT_THAT_ERROR(Reader.readObject(Byte), Failed()); + + // But if we write to it, its size should increase and we should be able to + // read not just a byte, but the string that was written. + EXPECT_THAT_ERROR(Writer.writeCString(Strings[0]), Succeeded()); + EXPECT_EQ(2U, ConstRef.getLength()); + EXPECT_THAT_ERROR(Reader.readObject(Byte), Succeeded()); + + Reader.setOffset(0); + EXPECT_THAT_ERROR(Reader.readCString(Str), Succeeded()); + EXPECT_EQ(Str, Strings[0]); + + // If we drop some bytes from the front, we should still track the length as + // the + // underlying stream grows. + BinaryStreamRef Dropped = ConstRef.drop_front(1); + EXPECT_EQ(1U, Dropped.getLength()); + + EXPECT_THAT_ERROR(Writer.writeCString(Strings[1]), Succeeded()); + EXPECT_EQ(4U, ConstRef.getLength()); + EXPECT_EQ(3U, Dropped.getLength()); + + // If we drop zero bytes from the back, we should continue tracking the + // length. + Dropped = Dropped.drop_back(0); + EXPECT_THAT_ERROR(Writer.writeCString(Strings[2]), Succeeded()); + EXPECT_EQ(6U, ConstRef.getLength()); + EXPECT_EQ(5U, Dropped.getLength()); + + // If we drop non-zero bytes from the back, we should stop tracking the + // length. + Dropped = Dropped.drop_back(1); + EXPECT_THAT_ERROR(Writer.writeCString(Strings[3]), Succeeded()); + EXPECT_EQ(8U, ConstRef.getLength()); + EXPECT_EQ(4U, Dropped.getLength()); +} + TEST_F(BinaryStreamTest, DropOperations) { std::vector<uint8_t> InputData = {1, 2, 3, 4, 5, 4, 3, 2, 1}; auto RefData = makeArrayRef(InputData); @@ -314,7 +362,6 @@ TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { // 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 @@ -346,6 +393,25 @@ TEST_F(BinaryStreamTest, MutableBinaryByteStreamBounds) { } } +TEST_F(BinaryStreamTest, AppendingStream) { + AppendingBinaryByteStream Stream(llvm::support::little); + EXPECT_EQ(0U, Stream.getLength()); + + std::vector<uint8_t> InputData = {'T', 'e', 's', 't', 'T', 'e', 's', 't'}; + auto Test = makeArrayRef(InputData).take_front(4); + // Writing past the end of the stream is an error. + EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Failed()); + + // Writing exactly at the end of the stream is ok. + EXPECT_THAT_ERROR(Stream.writeBytes(0, Test), Succeeded()); + EXPECT_EQ(Test, Stream.data()); + + // And now that the end of the stream is where we couldn't write before, now + // we can write. + EXPECT_THAT_ERROR(Stream.writeBytes(4, Test), Succeeded()); + EXPECT_EQ(MutableArrayRef<uint8_t>(InputData), Stream.data()); +} + // Test that FixedStreamArray works correctly. TEST_F(BinaryStreamTest, FixedStreamArray) { std::vector<uint32_t> Ints = {90823, 12908, 109823, 209823}; @@ -355,7 +421,6 @@ TEST_F(BinaryStreamTest, FixedStreamArray) { 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); @@ -535,7 +600,6 @@ TEST_F(BinaryStreamTest, StreamReaderEnum) { BinaryStreamReader Reader(*Stream.Input); - ArrayRef<MyEnum> Array; FixedStreamArray<MyEnum> FSA; for (size_t I = 0; I < Enums.size(); ++I) { @@ -696,6 +760,23 @@ TEST_F(BinaryStreamTest, StringWriterStrings) { EXPECT_EQ(makeArrayRef(Strings), makeArrayRef(InStrings)); } } + +TEST_F(BinaryStreamTest, StreamWriterAppend) { + StringRef Strings[] = {"First", "Second", "Third", "Fourth"}; + AppendingBinaryByteStream Stream(support::little); + BinaryStreamWriter Writer(Stream); + + for (auto &Str : Strings) { + EXPECT_THAT_ERROR(Writer.writeCString(Str), Succeeded()); + } + + BinaryStreamReader Reader(Stream); + for (auto &Str : Strings) { + StringRef S; + EXPECT_THAT_ERROR(Reader.readCString(S), Succeeded()); + EXPECT_EQ(Str, S); + } +} } namespace { diff --git a/unittests/Support/CMakeLists.txt b/unittests/Support/CMakeLists.txt index 641163e39ed3..299106e0dbf7 100644 --- a/unittests/Support/CMakeLists.txt +++ b/unittests/Support/CMakeLists.txt @@ -42,6 +42,7 @@ add_llvm_unittest(SupportTests ProcessTest.cpp ProgramTest.cpp RegexTest.cpp + ReverseIterationTest.cpp ReplaceFileTest.cpp ScaledNumberTest.cpp SourceMgrTest.cpp @@ -67,12 +68,14 @@ add_llvm_unittest(SupportTests xxhashTest.cpp ) +target_link_libraries(SupportTests PRIVATE LLVMTestingSupport) + # Disable all warning for AlignOfTest.cpp, # as it does things intentionally, and there is no reliable way of # disabling all warnings for all the compilers by using pragmas. set_source_files_properties(AlignOfTest.cpp PROPERTIES COMPILE_FLAGS -w) # ManagedStatic.cpp uses <pthread>. -target_link_libraries(SupportTests LLVMTestingSupport ${LLVM_PTHREAD_LIB}) +target_link_libraries(SupportTests PRIVATE LLVMTestingSupport ${LLVM_PTHREAD_LIB}) add_subdirectory(DynamicLibrary) diff --git a/unittests/Support/Chrono.cpp b/unittests/Support/Chrono.cpp index 1410baf848bb..a6b76c81a9c0 100644 --- a/unittests/Support/Chrono.cpp +++ b/unittests/Support/Chrono.cpp @@ -31,33 +31,35 @@ TEST(Chrono, TimeTConversion) { EXPECT_EQ(TP, toTimePoint(toTimeT(TP))); } -TEST(Chrono, StringConversion) { +TEST(Chrono, TimePointFormat) { + using namespace std::chrono; + struct tm TM {}; + TM.tm_year = 106; + TM.tm_mon = 0; + TM.tm_mday = 2; + TM.tm_hour = 15; + TM.tm_min = 4; + TM.tm_sec = 5; + TM.tm_isdst = -1; + TimePoint<> T = + system_clock::from_time_t(mktime(&TM)) + nanoseconds(123456789); + + // operator<< uses the format YYYY-MM-DD HH:MM:SS.NNNNNNNNN std::string S; raw_string_ostream OS(S); - OS << system_clock::now(); - - // Do a basic sanity check on the output. - // The format we expect is YYYY-MM-DD HH:MM:SS.MMMUUUNNN - StringRef Date, Time; - std::tie(Date, Time) = StringRef(OS.str()).split(' '); - - SmallVector<StringRef, 3> Components; - Date.split(Components, '-'); - ASSERT_EQ(3u, Components.size()); - EXPECT_EQ(4u, Components[0].size()); - EXPECT_EQ(2u, Components[1].size()); - EXPECT_EQ(2u, Components[2].size()); - - StringRef Sec, Nano; - std::tie(Sec, Nano) = Time.split('.'); - - Components.clear(); - Sec.split(Components, ':'); - ASSERT_EQ(3u, Components.size()); - EXPECT_EQ(2u, Components[0].size()); - EXPECT_EQ(2u, Components[1].size()); - EXPECT_EQ(2u, Components[2].size()); - EXPECT_EQ(9u, Nano.size()); + OS << T; + EXPECT_EQ("2006-01-02 15:04:05.123456789", OS.str()); + + // formatv default style matches operator<<. + EXPECT_EQ("2006-01-02 15:04:05.123456789", formatv("{0}", T).str()); + // formatv supports strftime-style format strings. + EXPECT_EQ("15:04:05", formatv("{0:%H:%M:%S}", T).str()); + // formatv supports our strftime extensions for sub-second precision. + EXPECT_EQ("123", formatv("{0:%L}", T).str()); + EXPECT_EQ("123456", formatv("{0:%f}", T).str()); + EXPECT_EQ("123456789", formatv("{0:%N}", T).str()); + // our extensions don't interfere with %% escaping. + EXPECT_EQ("%foo", formatv("{0:%%foo}", T).str()); } // Test that toTimePoint and toTimeT can be called with a arguments with varying diff --git a/unittests/Support/CommandLineTest.cpp b/unittests/Support/CommandLineTest.cpp index 660df11446ac..1fb0213b4d18 100644 --- a/unittests/Support/CommandLineTest.cpp +++ b/unittests/Support/CommandLineTest.cpp @@ -613,4 +613,39 @@ TEST(CommandLineTest, ResponseFiles) { llvm::sys::fs::remove(TestDir); } +TEST(CommandLineTest, SetDefautValue) { + cl::ResetCommandLineParser(); + + StackOption<std::string> Opt1("opt1", cl::init("true")); + StackOption<bool> Opt2("opt2", cl::init(true)); + cl::alias Alias("alias", llvm::cl::aliasopt(Opt2)); + StackOption<int> Opt3("opt3", cl::init(3)); + + const char *args[] = {"prog", "-opt1=false", "-opt2", "-opt3"}; + + EXPECT_TRUE( + cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls())); + + EXPECT_TRUE(Opt1 == "false"); + EXPECT_TRUE(Opt2); + EXPECT_TRUE(Opt3 == 3); + + Opt2 = false; + Opt3 = 1; + + cl::ResetAllOptionOccurrences(); + + for (auto &OM : cl::getRegisteredOptions(*cl::TopLevelSubCommand)) { + cl::Option *O = OM.second; + if (O->ArgStr == "opt2") { + continue; + } + O->setDefault(); + } + + EXPECT_TRUE(Opt1 == "true"); + EXPECT_TRUE(Opt2); + EXPECT_TRUE(Opt3 == 3); +} + } // anonymous namespace diff --git a/unittests/Support/ConvertUTFTest.cpp b/unittests/Support/ConvertUTFTest.cpp index 0af09e98a217..dd6e0df3688f 100644 --- a/unittests/Support/ConvertUTFTest.cpp +++ b/unittests/Support/ConvertUTFTest.cpp @@ -9,10 +9,8 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/Format.h" #include "gtest/gtest.h" #include <string> -#include <utility> #include <vector> using namespace llvm; diff --git a/unittests/Support/DynamicLibrary/CMakeLists.txt b/unittests/Support/DynamicLibrary/CMakeLists.txt index b5844381362e..4f060e4020d1 100644 --- a/unittests/Support/DynamicLibrary/CMakeLists.txt +++ b/unittests/Support/DynamicLibrary/CMakeLists.txt @@ -1,13 +1,15 @@ set(LLVM_LINK_COMPONENTS Support) add_library(DynamicLibraryLib STATIC ExportedFuncs.cxx) +set_target_properties(DynamicLibraryLib PROPERTIES FOLDER "Tests") add_llvm_unittest(DynamicLibraryTests DynamicLibraryTest.cpp) -target_link_libraries(DynamicLibraryTests DynamicLibraryLib) +target_link_libraries(DynamicLibraryTests PRIVATE DynamicLibraryLib) export_executable_symbols(DynamicLibraryTests) function(dynlib_add_module NAME) add_library(${NAME} SHARED PipSqueak.cxx) + set_target_properties(${NAME} PROPERTIES FOLDER "Tests") set_output_directory(${NAME} BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR} @@ -22,5 +24,12 @@ function(dynlib_add_module NAME) add_dependencies(DynamicLibraryTests ${NAME}) endfunction(dynlib_add_module) +# Revert -Wl,-z,nodelete on this test since it relies on the file +# being unloaded. +if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + string(REPLACE "-Wl,-z,nodelete" "" CMAKE_SHARED_LINKER_FLAGS + ${CMAKE_SHARED_LINKER_FLAGS}) +endif() + dynlib_add_module(PipSqueak) dynlib_add_module(SecondLib) diff --git a/unittests/Support/ErrorTest.cpp b/unittests/Support/ErrorTest.cpp index a762cf023f9c..2629e640f79c 100644 --- a/unittests/Support/ErrorTest.cpp +++ b/unittests/Support/ErrorTest.cpp @@ -12,6 +12,8 @@ #include "llvm/ADT/Twine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Testing/Support/Error.h" +#include "gtest/gtest-spi.h" #include "gtest/gtest.h" #include <memory> @@ -386,7 +388,8 @@ TEST(Error, FailureToHandle) { }); }; - EXPECT_DEATH(FailToHandle(), "Program aborted due to an unhandled Error:") + EXPECT_DEATH(FailToHandle(), + "Failure value returned from cantFail wrapped call") << "Unhandled Error in handleAllErrors call did not cause an " "abort()"; } @@ -405,7 +408,7 @@ TEST(Error, FailureFromHandler) { }; EXPECT_DEATH(ReturnErrorFromHandler(), - "Program aborted due to an unhandled Error:") + "Failure value returned from cantFail wrapped call") << " Error returned from handler in handleAllErrors call did not " "cause abort()"; } @@ -482,11 +485,12 @@ TEST(Error, CantFailSuccess) { } // Test that cantFail results in a crash if you pass it a failure value. -#if LLVM_ENABLE_ABI_BREAKING_CHECKS +#if LLVM_ENABLE_ABI_BREAKING_CHECKS && !defined(NDEBUG) TEST(Error, CantFailDeath) { EXPECT_DEATH( - cantFail(make_error<StringError>("foo", inconvertibleErrorCode())), - "Failure value returned from cantFail wrapped call") + cantFail(make_error<StringError>("foo", inconvertibleErrorCode()), + "Cantfail call failed"), + "Cantfail call failed") << "cantFail(Error) did not cause an abort for failure value"; EXPECT_DEATH( @@ -604,6 +608,59 @@ TEST(Error, ExpectedCovariance) { (void)!!A2; } +// Test that handleExpected just returns success values. +TEST(Error, HandleExpectedSuccess) { + auto ValOrErr = + handleExpected(Expected<int>(42), + []() { return Expected<int>(43); }); + EXPECT_TRUE(!!ValOrErr) + << "handleExpected should have returned a success value here"; + EXPECT_EQ(*ValOrErr, 42) + << "handleExpected should have returned the original success value here"; +} + +enum FooStrategy { Aggressive, Conservative }; + +static Expected<int> foo(FooStrategy S) { + if (S == Aggressive) + return make_error<CustomError>(7); + return 42; +} + +// Test that handleExpected invokes the error path if errors are not handled. +TEST(Error, HandleExpectedUnhandledError) { + // foo(Aggressive) should return a CustomError which should pass through as + // there is no handler for CustomError. + auto ValOrErr = + handleExpected( + foo(Aggressive), + []() { return foo(Conservative); }); + + EXPECT_FALSE(!!ValOrErr) + << "handleExpected should have returned an error here"; + auto Err = ValOrErr.takeError(); + EXPECT_TRUE(Err.isA<CustomError>()) + << "handleExpected should have returned the CustomError generated by " + "foo(Aggressive) here"; + consumeError(std::move(Err)); +} + +// Test that handleExpected invokes the fallback path if errors are handled. +TEST(Error, HandleExpectedHandledError) { + // foo(Aggressive) should return a CustomError which should handle triggering + // the fallback path. + auto ValOrErr = + handleExpected( + foo(Aggressive), + []() { return foo(Conservative); }, + [](const CustomError&) { /* do nothing */ }); + + EXPECT_TRUE(!!ValOrErr) + << "handleExpected should have returned a success value here"; + EXPECT_EQ(*ValOrErr, 42) + << "handleExpected returned the wrong success value"; +} + TEST(Error, ErrorCodeConversions) { // Round-trip a success value to check that it converts correctly. EXPECT_EQ(errorToErrorCode(errorCodeToError(std::error_code())), @@ -659,4 +716,53 @@ TEST(Error, ErrorMessage) { 0); } +TEST(Error, ErrorMatchers) { + EXPECT_THAT_ERROR(Error::success(), Succeeded()); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_ERROR(make_error<CustomError>(0), Succeeded()), + "Expected: succeeded\n Actual: failed (CustomError { 0})"); + + EXPECT_THAT_ERROR(make_error<CustomError>(0), Failed()); + EXPECT_NONFATAL_FAILURE(EXPECT_THAT_ERROR(Error::success(), Failed()), + "Expected: failed\n Actual: succeeded"); + + EXPECT_THAT_EXPECTED(Expected<int>(0), Succeeded()); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), + Succeeded()), + "Expected: succeeded\n Actual: failed (CustomError { 0})"); + + EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), Failed()); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(0), Failed()), + "Expected: failed\n Actual: succeeded with value 0"); + + EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(0)); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), + HasValue(0)), + "Expected: succeeded with value (is equal to 0)\n" + " Actual: failed (CustomError { 0})"); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(0)), + "Expected: succeeded with value (is equal to 0)\n" + " Actual: succeeded with value 1, (isn't equal to 0)"); + + EXPECT_THAT_EXPECTED(Expected<int &>(make_error<CustomError>(0)), Failed()); + int a = 1; + EXPECT_THAT_EXPECTED(Expected<int &>(a), Succeeded()); + EXPECT_THAT_EXPECTED(Expected<int &>(a), HasValue(testing::Eq(1))); + + EXPECT_THAT_EXPECTED(Expected<int>(1), HasValue(testing::Gt(0))); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(0), HasValue(testing::Gt(1))), + "Expected: succeeded with value (is > 1)\n" + " Actual: succeeded with value 0, (isn't > 1)"); + EXPECT_NONFATAL_FAILURE( + EXPECT_THAT_EXPECTED(Expected<int>(make_error<CustomError>(0)), + HasValue(testing::Gt(1))), + "Expected: succeeded with value (is > 1)\n" + " Actual: failed (CustomError { 0})"); +} + } // end anon namespace diff --git a/unittests/Support/FileOutputBufferTest.cpp b/unittests/Support/FileOutputBufferTest.cpp index 5f20634d66c2..e7f1fd765bde 100644 --- a/unittests/Support/FileOutputBufferTest.cpp +++ b/unittests/Support/FileOutputBufferTest.cpp @@ -40,18 +40,18 @@ TEST(FileOutputBuffer, Test) { // TEST 1: Verify commit case. SmallString<128> File1(TestDirectory); - File1.append("/file1"); + File1.append("/file1"); { - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(File1, 8192); - ASSERT_NO_ERROR(BufferOrErr.getError()); + ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError())); std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr; // Start buffer with special header. memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20); // Write to end of buffer to verify it is writable. memcpy(Buffer->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20); // Commit buffer. - ASSERT_NO_ERROR(Buffer->commit()); + ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit())); } // Verify file is correct size. @@ -64,9 +64,9 @@ TEST(FileOutputBuffer, Test) { SmallString<128> File2(TestDirectory); File2.append("/file2"); { - ErrorOr<std::unique_ptr<FileOutputBuffer>> Buffer2OrErr = + Expected<std::unique_ptr<FileOutputBuffer>> Buffer2OrErr = FileOutputBuffer::create(File2, 8192); - ASSERT_NO_ERROR(Buffer2OrErr.getError()); + ASSERT_NO_ERROR(errorToErrorCode(Buffer2OrErr.takeError())); std::unique_ptr<FileOutputBuffer> &Buffer2 = *Buffer2OrErr; // Fill buffer with special header. memcpy(Buffer2->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20); @@ -79,17 +79,17 @@ TEST(FileOutputBuffer, Test) { // TEST 3: Verify sizing down case. SmallString<128> File3(TestDirectory); - File3.append("/file3"); + File3.append("/file3"); { - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(File3, 8192000); - ASSERT_NO_ERROR(BufferOrErr.getError()); + ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError())); std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr; // Start buffer with special header. memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20); // Write to end of buffer to verify it is writable. memcpy(Buffer->getBufferEnd() - 20, "AABBCCDDEEFFGGHHIIJJ", 20); - ASSERT_NO_ERROR(Buffer->commit()); + ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit())); } // Verify file is correct size. @@ -100,16 +100,16 @@ TEST(FileOutputBuffer, Test) { // TEST 4: Verify file can be made executable. SmallString<128> File4(TestDirectory); - File4.append("/file4"); + File4.append("/file4"); { - ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr = + Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(File4, 8192, FileOutputBuffer::F_executable); - ASSERT_NO_ERROR(BufferOrErr.getError()); + ASSERT_NO_ERROR(errorToErrorCode(BufferOrErr.takeError())); std::unique_ptr<FileOutputBuffer> &Buffer = *BufferOrErr; // Start buffer with special header. memcpy(Buffer->getBufferStart(), "AABBCCDDEEFFGGHHIIJJ", 20); // Commit buffer. - ASSERT_NO_ERROR(Buffer->commit()); + ASSERT_NO_ERROR(errorToErrorCode(Buffer->commit())); } // Verify file exists and is executable. fs::file_status Status; diff --git a/unittests/Support/FormatVariadicTest.cpp b/unittests/Support/FormatVariadicTest.cpp index bfbe556b31a7..ddecffdeed1d 100644 --- a/unittests/Support/FormatVariadicTest.cpp +++ b/unittests/Support/FormatVariadicTest.cpp @@ -578,3 +578,34 @@ TEST(FormatVariadicTest, FormatAdapter) { // const Format cvar(1); // EXPECT_EQ("Format", formatv("{0}", cvar).str()); } + +TEST(FormatVariadicTest, FormatFormatvObject) { + EXPECT_EQ("Format", formatv("F{0}t", formatv("o{0}a", "rm")).str()); + EXPECT_EQ("[ ! ]", formatv("[{0,+5}]", formatv("{0,-2}", "!")).str()); +} + +namespace { +struct Recorder { + int Copied = 0, Moved = 0; + Recorder() = default; + Recorder(const Recorder &Copy) : Copied(1 + Copy.Copied), Moved(Copy.Moved) {} + Recorder(const Recorder &&Move) + : Copied(Move.Copied), Moved(1 + Move.Moved) {} +}; +} // namespace +namespace llvm { +template <> struct format_provider<Recorder> { + static void format(const Recorder &R, raw_ostream &OS, StringRef style) { + OS << R.Copied << "C " << R.Moved << "M"; + } +}; +} // namespace + +TEST(FormatVariadicTest, CopiesAndMoves) { + Recorder R; + EXPECT_EQ("0C 0M", formatv("{0}", R).str()); + EXPECT_EQ("0C 3M", formatv("{0}", std::move(R)).str()); + EXPECT_EQ("0C 3M", formatv("{0}", Recorder()).str()); + EXPECT_EQ(0, R.Copied); + EXPECT_EQ(0, R.Moved); +} diff --git a/unittests/Support/GlobPatternTest.cpp b/unittests/Support/GlobPatternTest.cpp index 44d77266db1f..d7016ab218d3 100644 --- a/unittests/Support/GlobPatternTest.cpp +++ b/unittests/Support/GlobPatternTest.cpp @@ -67,4 +67,13 @@ TEST_F(GlobPatternTest, Invalid) { EXPECT_FALSE((bool)Pat1); handleAllErrors(Pat1.takeError(), [&](ErrorInfoBase &EIB) {}); } + +TEST_F(GlobPatternTest, ExtSym) { + Expected<GlobPattern> Pat1 = GlobPattern::create("a*\xFF"); + EXPECT_TRUE((bool)Pat1); + EXPECT_TRUE(Pat1->match("axxx\xFF")); + Expected<GlobPattern> Pat2 = GlobPattern::create("[\xFF-\xFF]"); + EXPECT_TRUE((bool)Pat2); + EXPECT_TRUE(Pat2->match("\xFF")); +} } diff --git a/unittests/Support/Host.cpp b/unittests/Support/Host.cpp index 7c018ac50423..736b04c2049c 100644 --- a/unittests/Support/Host.cpp +++ b/unittests/Support/Host.cpp @@ -106,8 +106,17 @@ TEST(getLinuxHostCPUName, AArch64) { "CPU part : 0x201"), "kryo"); EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" + "CPU part : 0x800"), + "cortex-a73"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" + "CPU part : 0x801"), + "cortex-a73"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" "CPU part : 0xc00"), "falkor"); + EXPECT_EQ(sys::detail::getHostCPUNameForARM("CPU implementer : 0x51\n" + "CPU part : 0xc01"), + "saphira"); // MSM8992/4 weirdness StringRef MSM8992ProcCpuInfo = R"( @@ -130,6 +139,37 @@ Hardware : Qualcomm Technologies, Inc MSM8992 EXPECT_EQ(sys::detail::getHostCPUNameForARM(MSM8992ProcCpuInfo), "cortex-a53"); + + // Exynos big.LITTLE weirdness + const std::string ExynosProcCpuInfo = R"( +processor : 0 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 +CPU implementer : 0x41 +CPU architecture: 8 +CPU variant : 0x0 +CPU part : 0xd03 + +processor : 1 +Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 +CPU implementer : 0x53 +CPU architecture: 8 +)"; + + // Verify default for Exynos. + EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo + + "CPU variant : 0xc\n" + "CPU part : 0xafe"), + "exynos-m1"); + // Verify Exynos M1. + EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo + + "CPU variant : 0x1\n" + "CPU part : 0x001"), + "exynos-m1"); + // Verify Exynos M2. + EXPECT_EQ(sys::detail::getHostCPUNameForARM(ExynosProcCpuInfo + + "CPU variant : 0x4\n" + "CPU part : 0x001"), + "exynos-m2"); } #if defined(__APPLE__) @@ -147,8 +187,9 @@ TEST_F(HostTest, getMacOSHostVersion) { const char *SwVersPath = "/usr/bin/sw_vers"; const char *argv[] = {SwVersPath, "-productVersion", nullptr}; StringRef OutputPath = OutputFile.str(); - const StringRef *Redirects[] = {/*STDIN=*/nullptr, /*STDOUT=*/&OutputPath, - /*STDERR=*/nullptr}; + const Optional<StringRef> Redirects[] = {/*STDIN=*/None, + /*STDOUT=*/OutputPath, + /*STDERR=*/None}; int RetCode = ExecuteAndWait(SwVersPath, argv, /*env=*/nullptr, Redirects); ASSERT_EQ(0, RetCode); diff --git a/unittests/Support/LEB128Test.cpp b/unittests/Support/LEB128Test.cpp index 09db6dfdc593..1c9b5dbd2bd9 100644 --- a/unittests/Support/LEB128Test.cpp +++ b/unittests/Support/LEB128Test.cpp @@ -46,16 +46,17 @@ TEST(LEB128Test, EncodeSLEB128) { 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); + EXPECT_SLEB128_EQ("\x80\x00", 0, 2); + EXPECT_SLEB128_EQ("\x80\x80\x00", 0, 3); + EXPECT_SLEB128_EQ("\xff\x80\x00", 0x7f, 3); + EXPECT_SLEB128_EQ("\xff\x80\x80\x00", 0x7f, 4); + EXPECT_SLEB128_EQ("\x80\x81\x00", 0x80, 3); + EXPECT_SLEB128_EQ("\x80\x81\x80\x00", 0x80, 4); + EXPECT_SLEB128_EQ("\xc0\x7f", -0x40, 2); + + EXPECT_SLEB128_EQ("\xc0\xff\x7f", -0x40, 3); + EXPECT_SLEB128_EQ("\x80\xff\x7f", -0x80, 3); + EXPECT_SLEB128_EQ("\x80\xff\xff\x7f", -0x80, 4); #undef EXPECT_SLEB128_EQ } @@ -93,12 +94,12 @@ TEST(LEB128Test, EncodeULEB128) { EXPECT_ULEB128_EQ("\x81\x02", 0x101, 0); // Encode ULEB128 with some extra padding bytes - EXPECT_ULEB128_EQ("\x80\x00", 0, 1); - EXPECT_ULEB128_EQ("\x80\x80\x00", 0, 2); - EXPECT_ULEB128_EQ("\xff\x00", 0x7f, 1); - EXPECT_ULEB128_EQ("\xff\x80\x00", 0x7f, 2); - EXPECT_ULEB128_EQ("\x80\x81\x00", 0x80, 1); - EXPECT_ULEB128_EQ("\x80\x81\x80\x00", 0x80, 2); + EXPECT_ULEB128_EQ("\x80\x00", 0, 2); + EXPECT_ULEB128_EQ("\x80\x80\x00", 0, 3); + EXPECT_ULEB128_EQ("\xff\x00", 0x7f, 2); + EXPECT_ULEB128_EQ("\xff\x80\x00", 0x7f, 3); + EXPECT_ULEB128_EQ("\x80\x81\x00", 0x80, 3); + EXPECT_ULEB128_EQ("\x80\x81\x80\x00", 0x80, 4); #undef EXPECT_ULEB128_EQ } diff --git a/unittests/Support/ManagedStatic.cpp b/unittests/Support/ManagedStatic.cpp index 4e2e93036a83..07e324cdfb65 100644 --- a/unittests/Support/ManagedStatic.cpp +++ b/unittests/Support/ManagedStatic.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/ManagedStatic.h" #include "llvm/Config/config.h" -#include "llvm/Support/Threading.h" #ifdef HAVE_PTHREAD_H #include <pthread.h> #endif diff --git a/unittests/Support/MemoryTest.cpp b/unittests/Support/MemoryTest.cpp index 140219ffd1d6..650be7b6f1dd 100644 --- a/unittests/Support/MemoryTest.cpp +++ b/unittests/Support/MemoryTest.cpp @@ -1,6 +1,6 @@ //===- llvm/unittest/Support/AllocatorTest.cpp - BumpPtrAllocator tests ---===// // -// The LLVM Compiler Infrastructure +// The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. @@ -350,16 +350,16 @@ TEST_P(MappedMemoryTest, UnalignedNear) { // Note that Memory::MF_WRITE is not supported exclusively across // operating systems and architectures and can imply MF_READ|MF_WRITE unsigned MemoryFlags[] = { - Memory::MF_READ, - Memory::MF_WRITE, - Memory::MF_READ|Memory::MF_WRITE, - Memory::MF_EXEC, - Memory::MF_READ|Memory::MF_EXEC, - Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC - }; + Memory::MF_READ, + Memory::MF_WRITE, + Memory::MF_READ|Memory::MF_WRITE, + Memory::MF_EXEC, + Memory::MF_READ|Memory::MF_EXEC, + Memory::MF_READ|Memory::MF_WRITE|Memory::MF_EXEC + }; INSTANTIATE_TEST_CASE_P(AllocationTests, - MappedMemoryTest, - ::testing::ValuesIn(MemoryFlags),); + MappedMemoryTest, + ::testing::ValuesIn(MemoryFlags),); } // anonymous namespace diff --git a/unittests/Support/Path.cpp b/unittests/Support/Path.cpp index 3e474f33ca6d..f624626f5e53 100644 --- a/unittests/Support/Path.cpp +++ b/unittests/Support/Path.cpp @@ -564,6 +564,27 @@ TEST_F(FileSystemTest, RealPath) { ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1")); } +TEST_F(FileSystemTest, TempFileKeepDiscard) { + // We can keep then discard. + auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); + ASSERT_TRUE((bool)TempFileOrError); + fs::TempFile File = std::move(*TempFileOrError); + ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep")); + ASSERT_FALSE((bool)File.discard()); + ASSERT_TRUE(fs::exists(TestDirectory + "/keep")); + ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep")); +} + +TEST_F(FileSystemTest, TempFileDiscardDiscard) { + // We can discard twice. + auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); + ASSERT_TRUE((bool)TempFileOrError); + fs::TempFile File = std::move(*TempFileOrError); + ASSERT_FALSE((bool)File.discard()); + ASSERT_FALSE((bool)File.discard()); + ASSERT_FALSE(fs::exists(TestDirectory + "/keep")); +} + TEST_F(FileSystemTest, TempFiles) { // Create a temp file. int FileDescriptor; @@ -699,6 +720,21 @@ TEST_F(FileSystemTest, CreateDir) { ThisDir = path::parent_path(ThisDir); } + // Also verify that paths with Unix separators are handled correctly. + std::string LongPathWithUnixSeparators(TestDirectory.str()); + // Add at least one subdirectory to TestDirectory, and replace slashes with + // backslashes + do { + LongPathWithUnixSeparators.append("/DirNameWith19Charss"); + } while (LongPathWithUnixSeparators.size() < 260); + std::replace(LongPathWithUnixSeparators.begin(), + LongPathWithUnixSeparators.end(), + '\\', '/'); + ASSERT_NO_ERROR(fs::create_directories(Twine(LongPathWithUnixSeparators))); + // cleanup + ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + + "/DirNameWith19Charss")); + // Similarly for a relative pathname. Need to set the current directory to // TestDirectory so that the one we create ends up in the right place. char PreviousDir[260]; @@ -854,8 +890,8 @@ TEST_F(FileSystemTest, BrokenSymlinkDirectoryIteration) { i != e; i.increment(ec)) { ASSERT_NO_ERROR(ec); - fs::file_status status; - if (i->status(status) == + ErrorOr<fs::basic_file_status> status = i->status(); + if (status.getError() == std::make_error_code(std::errc::no_such_file_or_directory)) { i.no_push(); continue; @@ -1145,96 +1181,6 @@ TEST(Support, ReplacePathPrefix) { EXPECT_EQ(Path, "/foo"); } -TEST_F(FileSystemTest, PathFromFD) { - // Create a temp file. - int FileDescriptor; - SmallString<64> TempPath; - ASSERT_NO_ERROR( - fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); - FileRemover Cleanup(TempPath); - - // Make sure it exists. - ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); - - // Try to get the path from the file descriptor - SmallString<64> ResultPath; - std::error_code ErrorCode = - fs::getPathFromOpenFD(FileDescriptor, ResultPath); - - // If we succeeded, check that the paths are the same (modulo case): - if (!ErrorCode) { - // The paths returned by createTemporaryFile and getPathFromOpenFD - // should reference the same file on disk. - fs::UniqueID D1, D2; - ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); - ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); - ASSERT_EQ(D1, D2); - } - - ::close(FileDescriptor); -} - -TEST_F(FileSystemTest, PathFromFDWin32) { - // Create a temp file. - int FileDescriptor; - SmallString<64> TempPath; - ASSERT_NO_ERROR( - fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); - FileRemover Cleanup(TempPath); - - // Make sure it exists. - ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); - - SmallVector<char, 8> ResultPath; - std::error_code ErrorCode = - fs::getPathFromOpenFD(FileDescriptor, ResultPath); - - if (!ErrorCode) { - // Now that we know how much space is required for the path, create a path - // buffer with exactly enough space (sans null terminator, which should not - // be present), and call getPathFromOpenFD again to ensure that the API - // properly handles exactly-sized buffers. - SmallVector<char, 8> ExactSizedPath(ResultPath.size()); - ErrorCode = fs::getPathFromOpenFD(FileDescriptor, ExactSizedPath); - ResultPath = ExactSizedPath; - } - - if (!ErrorCode) { - fs::UniqueID D1, D2; - ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); - ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); - ASSERT_EQ(D1, D2); - } - ::close(FileDescriptor); -} - -TEST_F(FileSystemTest, PathFromFDUnicode) { - // Create a temp file. - int FileDescriptor; - SmallString<64> TempPath; - - // Test Unicode: "<temp directory>/(pi)r^2<temp rand chars>.aleth.0" - ASSERT_NO_ERROR( - fs::createTemporaryFile("\xCF\x80r\xC2\xB2", - "\xE2\x84\xB5.0", FileDescriptor, TempPath)); - FileRemover Cleanup(TempPath); - - // Make sure it exists. - ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); - - SmallVector<char, 8> ResultPath; - std::error_code ErrorCode = - fs::getPathFromOpenFD(FileDescriptor, ResultPath); - - if (!ErrorCode) { - fs::UniqueID D1, D2; - ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); - ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); - ASSERT_EQ(D1, D2); - } - ::close(FileDescriptor); -} - TEST_F(FileSystemTest, OpenFileForRead) { // Create a temp file. int FileDescriptor; diff --git a/unittests/Support/ProcessTest.cpp b/unittests/Support/ProcessTest.cpp index 298a0a373234..37587bf47996 100644 --- a/unittests/Support/ProcessTest.cpp +++ b/unittests/Support/ProcessTest.cpp @@ -42,10 +42,18 @@ TEST(ProcessTest, None) { Optional<std::string> val( Process::GetEnv("__LLVM_TEST_ENVIRON_NO_SUCH_VAR__")); EXPECT_FALSE(val.hasValue()); -} +} #endif #ifdef LLVM_ON_WIN32 + +TEST(ProcessTest, EmptyVal) { + SetEnvironmentVariableA("__LLVM_TEST_ENVIRON_VAR__", ""); + Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__")); + EXPECT_TRUE(val.hasValue()); + EXPECT_STREQ("", val->c_str()); +} + TEST(ProcessTest, Wchar) { SetEnvironmentVariableW(L"__LLVM_TEST_ENVIRON_VAR__", L"abcdefghijklmnopqrs"); Optional<std::string> val(Process::GetEnv("__LLVM_TEST_ENVIRON_VAR__")); diff --git a/unittests/Support/ProgramTest.cpp b/unittests/Support/ProgramTest.cpp index f658980073da..3c272bb980c5 100644 --- a/unittests/Support/ProgramTest.cpp +++ b/unittests/Support/ProgramTest.cpp @@ -145,11 +145,10 @@ TEST_F(ProgramEnvTest, CreateProcessLongPath) { LongPath.push_back('\\'); // MAX_PATH = 260 LongPath.append(260 - TestDirectory.size(), 'a'); - StringRef LongPathRef(LongPath); std::string Error; bool ExecutionFailed; - const StringRef *Redirects[] = { nullptr, &LongPathRef, nullptr }; + Optional<StringRef> Redirects[] = {None, LongPath.str(), None}; int RC = ExecuteAndWait(MyExe, ArgV, getEnviron(), Redirects, /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &Error, &ExecutionFailed); @@ -192,7 +191,7 @@ TEST_F(ProgramEnvTest, CreateProcessTrailingSlash) { #else StringRef nul("/dev/null"); #endif - const StringRef *redirects[] = { &nul, &nul, nullptr }; + Optional<StringRef> redirects[] = { nul, nul, None }; int rc = ExecuteAndWait(my_exe, argv, getEnviron(), redirects, /*secondsToWait=*/ 10, /*memoryLimit=*/ 0, &error, &ExecutionFailed); @@ -221,8 +220,8 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) { std::string Error; bool ExecutionFailed; - ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0, - &Error, &ExecutionFailed); + ProcessInfo PI1 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error, + &ExecutionFailed); ASSERT_FALSE(ExecutionFailed) << Error; ASSERT_NE(PI1.Pid, ProcessInfo::InvalidPid) << "Invalid process id"; @@ -240,8 +239,8 @@ TEST_F(ProgramEnvTest, TestExecuteNoWait) { EXPECT_EQ(LoopCount, 1u) << "LoopCount should be 1"; - ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), nullptr, 0, - &Error, &ExecutionFailed); + ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error, + &ExecutionFailed); ASSERT_FALSE(ExecutionFailed) << Error; ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id"; @@ -280,7 +279,7 @@ TEST_F(ProgramEnvTest, TestExecuteAndWaitTimeout) { std::string Error; bool ExecutionFailed; int RetCode = - ExecuteAndWait(Executable, argv, getEnviron(), nullptr, /*secondsToWait=*/1, 0, + ExecuteAndWait(Executable, argv, getEnviron(), {}, /*secondsToWait=*/1, 0, &Error, &ExecutionFailed); ASSERT_EQ(-2, RetCode); } @@ -292,8 +291,8 @@ TEST(ProgramTest, TestExecuteNegative) { { std::string Error; bool ExecutionFailed; - int RetCode = ExecuteAndWait(Executable, argv, nullptr, nullptr, 0, 0, - &Error, &ExecutionFailed); + int RetCode = ExecuteAndWait(Executable, argv, nullptr, {}, 0, 0, &Error, + &ExecutionFailed); ASSERT_TRUE(RetCode < 0) << "On error ExecuteAndWait should return 0 or " "positive value indicating the result code"; ASSERT_TRUE(ExecutionFailed); @@ -303,8 +302,8 @@ TEST(ProgramTest, TestExecuteNegative) { { std::string Error; bool ExecutionFailed; - ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, nullptr, 0, - &Error, &ExecutionFailed); + ProcessInfo PI = ExecuteNoWait(Executable, argv, nullptr, {}, 0, &Error, + &ExecutionFailed); ASSERT_EQ(PI.Pid, ProcessInfo::InvalidPid) << "On error ExecuteNoWait should return an invalid ProcessInfo"; ASSERT_TRUE(ExecutionFailed); diff --git a/unittests/Support/RegexTest.cpp b/unittests/Support/RegexTest.cpp index 5e3ce39f0057..7e44a3c0614a 100644 --- a/unittests/Support/RegexTest.cpp +++ b/unittests/Support/RegexTest.cpp @@ -171,4 +171,12 @@ TEST_F(RegexTest, MatchInvalid) { EXPECT_FALSE(r1.match("X")); } +// https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=3727 +TEST_F(RegexTest, OssFuzz3727Regression) { + // Wrap in a StringRef so the NUL byte doesn't terminate the string + Regex r(StringRef("[[[=GS\x00[=][", 10)); + std::string Error; + EXPECT_FALSE(r.isValid(Error)); +} + } diff --git a/unittests/Support/ReplaceFileTest.cpp b/unittests/Support/ReplaceFileTest.cpp index 8b16daf3233c..794f36b1f654 100644 --- a/unittests/Support/ReplaceFileTest.cpp +++ b/unittests/Support/ReplaceFileTest.cpp @@ -52,6 +52,21 @@ class ScopedFD { ~ScopedFD() { Process::SafelyCloseFileDescriptor(FD); } }; +bool FDHasContent(int FD, StringRef Content) { + auto Buffer = MemoryBuffer::getOpenFile(FD, "", -1); + assert(Buffer); + return Buffer.get()->getBuffer() == Content; +} + +bool FileHasContent(StringRef File, StringRef Content) { + int FD = 0; + auto EC = fs::openFileForRead(File, FD); + (void)EC; + assert(!EC); + ScopedFD EventuallyCloseIt(FD); + return FDHasContent(FD, Content); +} + TEST(rename, FileOpenedForReadingCanBeReplaced) { // Create unique temporary directory for this test. SmallString<128> TestDirectory; @@ -79,25 +94,15 @@ TEST(rename, FileOpenedForReadingCanBeReplaced) { // We should still be able to read the old data through the existing // descriptor. - auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1); - ASSERT_TRUE(static_cast<bool>(Buffer)); - EXPECT_EQ(Buffer.get()->getBuffer(), "!!target!!"); + EXPECT_TRUE(FDHasContent(ReadFD, "!!target!!")); // The source file should no longer exist EXPECT_FALSE(fs::exists(SourceFileName)); } - { - // If we obtain a new descriptor for the target file, we should find that it - // contains the content that was in the source file. - int ReadFD = 0; - ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, ReadFD)); - ScopedFD EventuallyCloseIt(ReadFD); - auto Buffer = MemoryBuffer::getOpenFile(ReadFD, TargetFileName, -1); - ASSERT_TRUE(static_cast<bool>(Buffer)); - - EXPECT_EQ(Buffer.get()->getBuffer(), "!!source!!"); - } + // If we obtain a new descriptor for the target file, we should find that it + // contains the content that was in the source file. + EXPECT_TRUE(FileHasContent(TargetFileName, "!!source!!")); // Rename the target file back to the source file name to confirm that rename // still works if the destination does not already exist. @@ -110,4 +115,59 @@ TEST(rename, FileOpenedForReadingCanBeReplaced) { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } +TEST(rename, ExistingTemp) { + // Test that existing .tmpN files don't get deleted by the Windows + // sys::fs::rename implementation. + SmallString<128> TestDirectory; + ASSERT_NO_ERROR( + fs::createUniqueDirectory("ExistingTemp-test", TestDirectory)); + + SmallString<128> SourceFileName(TestDirectory); + path::append(SourceFileName, "source"); + + SmallString<128> TargetFileName(TestDirectory); + path::append(TargetFileName, "target"); + + SmallString<128> TargetTmp0FileName(TestDirectory); + path::append(TargetTmp0FileName, "target.tmp0"); + + SmallString<128> TargetTmp1FileName(TestDirectory); + path::append(TargetTmp1FileName, "target.tmp1"); + + ASSERT_NO_ERROR(CreateFileWithContent(SourceFileName, "!!source!!")); + ASSERT_NO_ERROR(CreateFileWithContent(TargetFileName, "!!target!!")); + ASSERT_NO_ERROR(CreateFileWithContent(TargetTmp0FileName, "!!target.tmp0!!")); + + { + // Use mapped_file_region to make sure that the destination file is mmap'ed. + // This will cause SetInformationByHandle to fail when renaming to the + // destination, and we will follow the code path that tries to give target + // a temporary name. + int TargetFD; + std::error_code EC; + ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, TargetFD)); + ScopedFD X(TargetFD); + sys::fs::mapped_file_region MFR( + TargetFD, sys::fs::mapped_file_region::readonly, 10, 0, EC); + ASSERT_FALSE(EC); + + ASSERT_NO_ERROR(fs::rename(SourceFileName, TargetFileName)); + +#ifdef _WIN32 + // Make sure that target was temporarily renamed to target.tmp1 on Windows. + // This is signified by a permission denied error as opposed to no such file + // or directory when trying to open it. + int Tmp1FD; + EXPECT_EQ(errc::permission_denied, + fs::openFileForRead(TargetTmp1FileName, Tmp1FD)); +#endif + } + + EXPECT_TRUE(FileHasContent(TargetTmp0FileName, "!!target.tmp0!!")); + + ASSERT_NO_ERROR(fs::remove(TargetFileName)); + ASSERT_NO_ERROR(fs::remove(TargetTmp0FileName)); + ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); +} + } // anonymous namespace diff --git a/unittests/Support/ReverseIterationTest.cpp b/unittests/Support/ReverseIterationTest.cpp new file mode 100644 index 000000000000..930bd43d11b2 --- /dev/null +++ b/unittests/Support/ReverseIterationTest.cpp @@ -0,0 +1,110 @@ +//===- llvm/unittest/Support/ReverseIterationTest.cpp ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// Reverse Iteration unit tests. +// +//===---------------------------------------------------------------------===// + +#include "llvm/Support/ReverseIteration.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseMapInfo.h" +#include "gtest/gtest.h" + +using namespace llvm; + +TEST(ReverseIterationTest, DenseMapTest1) { + static_assert(detail::IsPointerLike<int *>::value, + "int * is pointer-like"); + static_assert(detail::IsPointerLike<uintptr_t>::value, + "uintptr_t is pointer-like"); + static_assert(!detail::IsPointerLike<int>::value, + "int is not pointer-like"); + static_assert(detail::IsPointerLike<void *>::value, + "void * is pointer-like"); + struct IncompleteType; + static_assert(detail::IsPointerLike<IncompleteType *>::value, + "incomplete * is pointer-like"); + + // For a DenseMap with non-pointer-like keys, forward iteration equals + // reverse iteration. + DenseMap<int, int> Map; + int Keys[] = { 1, 2, 3, 4 }; + + // Insert keys into the DenseMap. + for (auto Key: Keys) + Map[Key] = 0; + + // Note: This is the observed order of keys in the DenseMap. + // If there is any change in the behavior of the DenseMap, this order + // would need to be adjusted accordingly. + int IterKeys[] = { 2, 4, 1, 3 }; + + // Check that the DenseMap is iterated in the expected order. + for (const auto &Tuple : zip(Map, IterKeys)) + ASSERT_EQ(std::get<0>(Tuple).first, std::get<1>(Tuple)); + + // Check operator++ (post-increment). + int i = 0; + for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i) + ASSERT_EQ(iter->first, IterKeys[i]); +} + +// Define a pointer-like int. +struct PtrLikeInt { int value; }; + +namespace llvm { + +template<> struct DenseMapInfo<PtrLikeInt *> { + static PtrLikeInt *getEmptyKey() { + static PtrLikeInt EmptyKey; + return &EmptyKey; + } + + static PtrLikeInt *getTombstoneKey() { + static PtrLikeInt TombstoneKey; + return &TombstoneKey; + } + + static int getHashValue(const PtrLikeInt *P) { + return P->value; + } + + static bool isEqual(const PtrLikeInt *LHS, const PtrLikeInt *RHS) { + return LHS == RHS; + } +}; + +} // end namespace llvm + +TEST(ReverseIterationTest, DenseMapTest2) { + static_assert(detail::IsPointerLike<PtrLikeInt *>::value, + "PtrLikeInt * is pointer-like"); + + PtrLikeInt a = {4}, b = {8}, c = {12}, d = {16}; + PtrLikeInt *Keys[] = { &a, &b, &c, &d }; + + // Insert keys into the DenseMap. + DenseMap<PtrLikeInt *, int> Map; + for (auto *Key : Keys) + Map[Key] = Key->value; + + // Note: If there is any change in the behavior of the DenseMap, + // the observed order of keys would need to be adjusted accordingly. + if (shouldReverseIterate<PtrLikeInt *>()) + std::reverse(&Keys[0], &Keys[4]); + + // Check that the DenseMap is iterated in the expected order. + for (const auto &Tuple : zip(Map, Keys)) + ASSERT_EQ(std::get<0>(Tuple).second, std::get<1>(Tuple)->value); + + // Check operator++ (post-increment). + int i = 0; + for (auto iter = Map.begin(), end = Map.end(); iter != end; iter++, ++i) + ASSERT_EQ(iter->second, Keys[i]->value); +} diff --git a/unittests/Support/SourceMgrTest.cpp b/unittests/Support/SourceMgrTest.cpp index 79c2d7278f12..2a84a89912ad 100644 --- a/unittests/Support/SourceMgrTest.cpp +++ b/unittests/Support/SourceMgrTest.cpp @@ -67,6 +67,16 @@ TEST_F(SourceMgrTest, BasicWarning) { Output); } +TEST_F(SourceMgrTest, BasicRemark) { + setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); + printMessage(getLoc(4), SourceMgr::DK_Remark, "message", None, None); + + EXPECT_EQ("file.in:1:5: remark: message\n" + "aaa bbb\n" + " ^\n", + Output); +} + TEST_F(SourceMgrTest, BasicNote) { setMainBuffer("aaa bbb\nccc ddd\n", "file.in"); printMessage(getLoc(4), SourceMgr::DK_Note, "message", None, None); diff --git a/unittests/Support/SpecialCaseListTest.cpp b/unittests/Support/SpecialCaseListTest.cpp index 130848845e45..060703e102fc 100644 --- a/unittests/Support/SpecialCaseListTest.cpp +++ b/unittests/Support/SpecialCaseListTest.cpp @@ -51,47 +51,102 @@ TEST_F(SpecialCaseListTest, Basic) { "src:bye\n" "src:hi=category\n" "src:z*=category\n"); - EXPECT_TRUE(SCL->inSection("src", "hello")); - EXPECT_TRUE(SCL->inSection("src", "bye")); - EXPECT_TRUE(SCL->inSection("src", "hi", "category")); - EXPECT_TRUE(SCL->inSection("src", "zzzz", "category")); - EXPECT_FALSE(SCL->inSection("src", "hi")); - EXPECT_FALSE(SCL->inSection("fun", "hello")); - EXPECT_FALSE(SCL->inSection("src", "hello", "category")); + EXPECT_TRUE(SCL->inSection("", "src", "hello")); + EXPECT_TRUE(SCL->inSection("", "src", "bye")); + EXPECT_TRUE(SCL->inSection("", "src", "hi", "category")); + EXPECT_TRUE(SCL->inSection("", "src", "zzzz", "category")); + EXPECT_FALSE(SCL->inSection("", "src", "hi")); + EXPECT_FALSE(SCL->inSection("", "fun", "hello")); + EXPECT_FALSE(SCL->inSection("", "src", "hello", "category")); + + EXPECT_EQ(3u, SCL->inSectionBlame("", "src", "hello")); + EXPECT_EQ(4u, SCL->inSectionBlame("", "src", "bye")); + EXPECT_EQ(5u, SCL->inSectionBlame("", "src", "hi", "category")); + EXPECT_EQ(6u, SCL->inSectionBlame("", "src", "zzzz", "category")); + EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hi")); + EXPECT_EQ(0u, SCL->inSectionBlame("", "fun", "hello")); + EXPECT_EQ(0u, SCL->inSectionBlame("", "src", "hello", "category")); +} + +TEST_F(SpecialCaseListTest, CorrectErrorLineNumberWithBlankLine) { + std::string Error; + EXPECT_EQ(nullptr, makeSpecialCaseList("# This is a comment.\n" + "\n" + "[not valid\n", + Error)); + EXPECT_TRUE( + ((StringRef)Error).startswith("malformed section header on line 3:")); + + EXPECT_EQ(nullptr, makeSpecialCaseList("\n\n\n" + "[not valid\n", + Error)); + EXPECT_TRUE( + ((StringRef)Error).startswith("malformed section header on line 4:")); +} + +TEST_F(SpecialCaseListTest, SectionRegexErrorHandling) { + std::string Error; + EXPECT_EQ(makeSpecialCaseList("[address", Error), nullptr); + EXPECT_TRUE(((StringRef)Error).startswith("malformed section header ")); + + EXPECT_EQ(makeSpecialCaseList("[[]", Error), nullptr); + EXPECT_TRUE(((StringRef)Error).startswith("malformed regex for section [: ")); + + EXPECT_EQ(makeSpecialCaseList("src:=", Error), nullptr); + EXPECT_TRUE(((StringRef)Error).endswith("Supplied regexp was blank")); +} + +TEST_F(SpecialCaseListTest, Section) { + std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:global\n" + "[sect1|sect2]\n" + "src:test1\n" + "[sect3*]\n" + "src:test2\n"); + EXPECT_TRUE(SCL->inSection("arbitrary", "src", "global")); + EXPECT_TRUE(SCL->inSection("", "src", "global")); + EXPECT_TRUE(SCL->inSection("sect1", "src", "test1")); + EXPECT_FALSE(SCL->inSection("sect1-arbitrary", "src", "test1")); + EXPECT_FALSE(SCL->inSection("sect", "src", "test1")); + EXPECT_FALSE(SCL->inSection("sect1", "src", "test2")); + EXPECT_TRUE(SCL->inSection("sect2", "src", "test1")); + EXPECT_TRUE(SCL->inSection("sect3", "src", "test2")); + EXPECT_TRUE(SCL->inSection("sect3-arbitrary", "src", "test2")); + EXPECT_FALSE(SCL->inSection("", "src", "test1")); + EXPECT_FALSE(SCL->inSection("", "src", "test2")); } TEST_F(SpecialCaseListTest, GlobalInit) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("global:foo=init\n"); - EXPECT_FALSE(SCL->inSection("global", "foo")); - EXPECT_FALSE(SCL->inSection("global", "bar")); - EXPECT_TRUE(SCL->inSection("global", "foo", "init")); - EXPECT_FALSE(SCL->inSection("global", "bar", "init")); + EXPECT_FALSE(SCL->inSection("", "global", "foo")); + EXPECT_FALSE(SCL->inSection("", "global", "bar")); + EXPECT_TRUE(SCL->inSection("", "global", "foo", "init")); + EXPECT_FALSE(SCL->inSection("", "global", "bar", "init")); SCL = makeSpecialCaseList("type:t2=init\n"); - EXPECT_FALSE(SCL->inSection("type", "t1")); - EXPECT_FALSE(SCL->inSection("type", "t2")); - EXPECT_FALSE(SCL->inSection("type", "t1", "init")); - EXPECT_TRUE(SCL->inSection("type", "t2", "init")); + EXPECT_FALSE(SCL->inSection("", "type", "t1")); + EXPECT_FALSE(SCL->inSection("", "type", "t2")); + EXPECT_FALSE(SCL->inSection("", "type", "t1", "init")); + EXPECT_TRUE(SCL->inSection("", "type", "t2", "init")); SCL = makeSpecialCaseList("src:hello=init\n"); - EXPECT_FALSE(SCL->inSection("src", "hello")); - EXPECT_FALSE(SCL->inSection("src", "bye")); - EXPECT_TRUE(SCL->inSection("src", "hello", "init")); - EXPECT_FALSE(SCL->inSection("src", "bye", "init")); + EXPECT_FALSE(SCL->inSection("", "src", "hello")); + EXPECT_FALSE(SCL->inSection("", "src", "bye")); + EXPECT_TRUE(SCL->inSection("", "src", "hello", "init")); + EXPECT_FALSE(SCL->inSection("", "src", "bye", "init")); } TEST_F(SpecialCaseListTest, Substring) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:hello\n" "fun:foo\n" "global:bar\n"); - EXPECT_FALSE(SCL->inSection("src", "othello")); - EXPECT_FALSE(SCL->inSection("fun", "tomfoolery")); - EXPECT_FALSE(SCL->inSection("global", "bartender")); + EXPECT_FALSE(SCL->inSection("", "src", "othello")); + EXPECT_FALSE(SCL->inSection("", "fun", "tomfoolery")); + EXPECT_FALSE(SCL->inSection("", "global", "bartender")); SCL = makeSpecialCaseList("fun:*foo*\n"); - EXPECT_TRUE(SCL->inSection("fun", "tomfoolery")); - EXPECT_TRUE(SCL->inSection("fun", "foobar")); + EXPECT_TRUE(SCL->inSection("", "fun", "tomfoolery")); + EXPECT_TRUE(SCL->inSection("", "fun", "foobar")); } TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) { @@ -113,7 +168,7 @@ TEST_F(SpecialCaseListTest, InvalidSpecialCaseList) { TEST_F(SpecialCaseListTest, EmptySpecialCaseList) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList(""); - EXPECT_FALSE(SCL->inSection("foo", "bar")); + EXPECT_FALSE(SCL->inSection("", "foo", "bar")); } TEST_F(SpecialCaseListTest, MultipleBlacklists) { @@ -124,12 +179,12 @@ TEST_F(SpecialCaseListTest, MultipleBlacklists) { Files.push_back(makeSpecialCaseListFile("src:baz\n" "src:*fog*\n")); auto SCL = SpecialCaseList::createOrDie(Files); - EXPECT_TRUE(SCL->inSection("src", "bar")); - EXPECT_TRUE(SCL->inSection("src", "baz")); - EXPECT_FALSE(SCL->inSection("src", "ban")); - EXPECT_TRUE(SCL->inSection("src", "ban", "init")); - EXPECT_TRUE(SCL->inSection("src", "tomfoolery")); - EXPECT_TRUE(SCL->inSection("src", "tomfoglery")); + EXPECT_TRUE(SCL->inSection("", "src", "bar")); + EXPECT_TRUE(SCL->inSection("", "src", "baz")); + EXPECT_FALSE(SCL->inSection("", "src", "ban")); + EXPECT_TRUE(SCL->inSection("", "src", "ban", "init")); + EXPECT_TRUE(SCL->inSection("", "src", "tomfoolery")); + EXPECT_TRUE(SCL->inSection("", "src", "tomfoglery")); for (auto &Path : Files) sys::fs::remove(Path); } @@ -137,35 +192,35 @@ TEST_F(SpecialCaseListTest, MultipleBlacklists) { TEST_F(SpecialCaseListTest, NoTrigramsInRules) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:b.r\n" "fun:za*az\n"); - EXPECT_TRUE(SCL->inSection("fun", "bar")); - EXPECT_FALSE(SCL->inSection("fun", "baz")); - EXPECT_TRUE(SCL->inSection("fun", "zakaz")); - EXPECT_FALSE(SCL->inSection("fun", "zaraza")); + EXPECT_TRUE(SCL->inSection("", "fun", "bar")); + EXPECT_FALSE(SCL->inSection("", "fun", "baz")); + EXPECT_TRUE(SCL->inSection("", "fun", "zakaz")); + EXPECT_FALSE(SCL->inSection("", "fun", "zaraza")); } TEST_F(SpecialCaseListTest, NoTrigramsInARule) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*\n" "fun:za*az\n"); - EXPECT_TRUE(SCL->inSection("fun", "abara")); - EXPECT_FALSE(SCL->inSection("fun", "bor")); - EXPECT_TRUE(SCL->inSection("fun", "zakaz")); - EXPECT_FALSE(SCL->inSection("fun", "zaraza")); + EXPECT_TRUE(SCL->inSection("", "fun", "abara")); + EXPECT_FALSE(SCL->inSection("", "fun", "bor")); + EXPECT_TRUE(SCL->inSection("", "fun", "zakaz")); + EXPECT_FALSE(SCL->inSection("", "fun", "zaraza")); } TEST_F(SpecialCaseListTest, RepetitiveRule) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("fun:*bar*bar*bar*bar*\n" "fun:bar*\n"); - EXPECT_TRUE(SCL->inSection("fun", "bara")); - EXPECT_FALSE(SCL->inSection("fun", "abara")); - EXPECT_TRUE(SCL->inSection("fun", "barbarbarbar")); - EXPECT_TRUE(SCL->inSection("fun", "abarbarbarbar")); - EXPECT_FALSE(SCL->inSection("fun", "abarbarbar")); + EXPECT_TRUE(SCL->inSection("", "fun", "bara")); + EXPECT_FALSE(SCL->inSection("", "fun", "abara")); + EXPECT_TRUE(SCL->inSection("", "fun", "barbarbarbar")); + EXPECT_TRUE(SCL->inSection("", "fun", "abarbarbarbar")); + EXPECT_FALSE(SCL->inSection("", "fun", "abarbarbar")); } TEST_F(SpecialCaseListTest, SpecialSymbolRule) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n"); - EXPECT_TRUE(SCL->inSection("src", "c++abi")); - EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi")); + EXPECT_TRUE(SCL->inSection("", "src", "c++abi")); + EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi")); } TEST_F(SpecialCaseListTest, PopularTrigram) { @@ -173,20 +228,20 @@ TEST_F(SpecialCaseListTest, PopularTrigram) { "fun:*aaaaa*\n" "fun:*aaaa*\n" "fun:*aaa*\n"); - EXPECT_TRUE(SCL->inSection("fun", "aaa")); - EXPECT_TRUE(SCL->inSection("fun", "aaaa")); - EXPECT_TRUE(SCL->inSection("fun", "aaaabbbaaa")); + EXPECT_TRUE(SCL->inSection("", "fun", "aaa")); + EXPECT_TRUE(SCL->inSection("", "fun", "aaaa")); + EXPECT_TRUE(SCL->inSection("", "fun", "aaaabbbaaa")); } TEST_F(SpecialCaseListTest, EscapedSymbols) { std::unique_ptr<SpecialCaseList> SCL = makeSpecialCaseList("src:*c\\+\\+abi*\n" "src:*hello\\\\world*\n"); - EXPECT_TRUE(SCL->inSection("src", "dir/c++abi")); - EXPECT_FALSE(SCL->inSection("src", "dir/c\\+\\+abi")); - EXPECT_FALSE(SCL->inSection("src", "c\\+\\+abi")); - EXPECT_TRUE(SCL->inSection("src", "C:\\hello\\world")); - EXPECT_TRUE(SCL->inSection("src", "hello\\world")); - EXPECT_FALSE(SCL->inSection("src", "hello\\\\world")); + EXPECT_TRUE(SCL->inSection("", "src", "dir/c++abi")); + EXPECT_FALSE(SCL->inSection("", "src", "dir/c\\+\\+abi")); + EXPECT_FALSE(SCL->inSection("", "src", "c\\+\\+abi")); + EXPECT_TRUE(SCL->inSection("", "src", "C:\\hello\\world")); + EXPECT_TRUE(SCL->inSection("", "src", "hello\\world")); + EXPECT_FALSE(SCL->inSection("", "src", "hello\\\\world")); } } diff --git a/unittests/Support/TarWriterTest.cpp b/unittests/Support/TarWriterTest.cpp index 927c8ed9be14..901dd906ca78 100644 --- a/unittests/Support/TarWriterTest.cpp +++ b/unittests/Support/TarWriterTest.cpp @@ -11,6 +11,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "gtest/gtest.h" +#include <vector> using namespace llvm; namespace { @@ -37,7 +38,7 @@ struct UstarHeader { class TarWriterTest : public ::testing::Test {}; -static UstarHeader create(StringRef Base, StringRef Filename) { +static std::vector<uint8_t> createTar(StringRef Base, StringRef Filename) { // Create a temporary file. SmallString<128> Path; std::error_code EC = @@ -55,12 +56,25 @@ static UstarHeader create(StringRef Base, StringRef Filename) { ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getFile(Path); EXPECT_TRUE((bool)MBOrErr); std::unique_ptr<MemoryBuffer> MB = std::move(*MBOrErr); + std::vector<uint8_t> Buf((const uint8_t *)MB->getBufferStart(), + (const uint8_t *)MB->getBufferEnd()); + + // Windows does not allow us to remove a mmap'ed files, so + // unmap first and then remove the temporary file. + MB = nullptr; sys::fs::remove(Path); - return *reinterpret_cast<const UstarHeader *>(MB->getBufferStart()); + + return Buf; +} + +static UstarHeader createUstar(StringRef Base, StringRef Filename) { + std::vector<uint8_t> Buf = createTar(Base, Filename); + EXPECT_TRUE(Buf.size() >= sizeof(UstarHeader)); + return *reinterpret_cast<const UstarHeader *>(Buf.data()); } TEST_F(TarWriterTest, Basics) { - UstarHeader Hdr = create("base", "file"); + UstarHeader Hdr = createUstar("base", "file"); EXPECT_EQ("ustar", StringRef(Hdr.Magic)); EXPECT_EQ("00", StringRef(Hdr.Version, 2)); EXPECT_EQ("base/file", StringRef(Hdr.Name)); @@ -68,21 +82,98 @@ TEST_F(TarWriterTest, Basics) { } TEST_F(TarWriterTest, LongFilename) { - UstarHeader Hdr1 = create( - "012345678", std::string(99, 'x') + "/" + std::string(44, 'x') + "/foo"); - EXPECT_EQ("foo", StringRef(Hdr1.Name)); - EXPECT_EQ("012345678/" + std::string(99, 'x') + "/" + std::string(44, 'x'), - StringRef(Hdr1.Prefix)); - - UstarHeader Hdr2 = create( - "012345678", std::string(99, 'x') + "/" + std::string(45, 'x') + "/foo"); - EXPECT_EQ("foo", StringRef(Hdr2.Name)); - EXPECT_EQ("012345678/" + std::string(99, 'x') + "/" + std::string(45, 'x'), - StringRef(Hdr2.Prefix)); - - UstarHeader Hdr3 = create( - "012345678", std::string(99, 'x') + "/" + std::string(46, 'x') + "/foo"); - EXPECT_EQ(std::string(46, 'x') + "/foo", StringRef(Hdr3.Name)); - EXPECT_EQ("012345678/" + std::string(99, 'x'), StringRef(Hdr3.Prefix)); + std::string x154(154, 'x'); + std::string x155(155, 'x'); + std::string y99(99, 'y'); + std::string y100(100, 'y'); + + UstarHeader Hdr1 = createUstar("", x154 + "/" + y99); + EXPECT_EQ("/" + x154, StringRef(Hdr1.Prefix)); + EXPECT_EQ(y99, StringRef(Hdr1.Name)); + + UstarHeader Hdr2 = createUstar("", x155 + "/" + y99); + EXPECT_EQ("", StringRef(Hdr2.Prefix)); + EXPECT_EQ("", StringRef(Hdr2.Name)); + + UstarHeader Hdr3 = createUstar("", x154 + "/" + y100); + EXPECT_EQ("", StringRef(Hdr3.Prefix)); + EXPECT_EQ("", StringRef(Hdr3.Name)); + + UstarHeader Hdr4 = createUstar("", x155 + "/" + y100); + EXPECT_EQ("", StringRef(Hdr4.Prefix)); + EXPECT_EQ("", StringRef(Hdr4.Name)); + + std::string yz = "yyyyyyyyyyyyyyyyyyyy/zzzzzzzzzzzzzzzzzzzz"; + UstarHeader Hdr5 = createUstar("", x154 + "/" + yz); + EXPECT_EQ("/" + x154, StringRef(Hdr5.Prefix)); + EXPECT_EQ(yz, StringRef(Hdr5.Name)); +} + +TEST_F(TarWriterTest, Pax) { + std::vector<uint8_t> Buf = createTar("", std::string(200, 'x')); + EXPECT_TRUE(Buf.size() >= 1024); + + auto *Hdr = reinterpret_cast<const UstarHeader *>(Buf.data()); + EXPECT_EQ("", StringRef(Hdr->Prefix)); + EXPECT_EQ("", StringRef(Hdr->Name)); + + StringRef Pax = StringRef((char *)(Buf.data() + 512), 512); + EXPECT_TRUE(Pax.startswith("211 path=/" + std::string(200, 'x'))); +} + +TEST_F(TarWriterTest, SingleFile) { + SmallString<128> Path; + std::error_code EC = + sys::fs::createTemporaryFile("TarWriterTest", "tar", Path); + EXPECT_FALSE((bool)EC); + + Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, ""); + EXPECT_TRUE((bool)TarOrErr); + std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); + Tar->append("FooPath", "foo"); + Tar.reset(); + + uint64_t TarSize; + EC = sys::fs::file_size(Path, TarSize); + EXPECT_FALSE((bool)EC); + EXPECT_EQ(TarSize, 2048ULL); +} + +TEST_F(TarWriterTest, NoDuplicate) { + SmallString<128> Path; + std::error_code EC = + sys::fs::createTemporaryFile("TarWriterTest", "tar", Path); + EXPECT_FALSE((bool)EC); + + Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, ""); + EXPECT_TRUE((bool)TarOrErr); + std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); + Tar->append("FooPath", "foo"); + Tar->append("BarPath", "bar"); + Tar.reset(); + + uint64_t TarSize; + EC = sys::fs::file_size(Path, TarSize); + EXPECT_FALSE((bool)EC); + EXPECT_EQ(TarSize, 3072ULL); } + +TEST_F(TarWriterTest, Duplicate) { + SmallString<128> Path; + std::error_code EC = + sys::fs::createTemporaryFile("TarWriterTest", "tar", Path); + EXPECT_FALSE((bool)EC); + + Expected<std::unique_ptr<TarWriter>> TarOrErr = TarWriter::create(Path, ""); + EXPECT_TRUE((bool)TarOrErr); + std::unique_ptr<TarWriter> Tar = std::move(*TarOrErr); + Tar->append("FooPath", "foo"); + Tar->append("FooPath", "bar"); + Tar.reset(); + + uint64_t TarSize; + EC = sys::fs::file_size(Path, TarSize); + EXPECT_FALSE((bool)EC); + EXPECT_EQ(TarSize, 2048ULL); } +} // namespace diff --git a/unittests/Support/TargetParserTest.cpp b/unittests/Support/TargetParserTest.cpp index b9b725f934b3..dcef40345f05 100644 --- a/unittests/Support/TargetParserTest.cpp +++ b/unittests/Support/TargetParserTest.cpp @@ -25,25 +25,25 @@ const char *ARMArch[] = { "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"}; + "armv8.1-a", "armv8.1a", "armv8.2-a", "armv8.2a", "armv8.3-a", + "armv8.3a", "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, StringRef CPUAttr) { - unsigned ArchKind = ARM::parseCPUArch(CPUName); - bool pass = ARM::getArchName(ArchKind).equals(ExpectedArch); - unsigned FPUKind = ARM::getDefaultFPU(CPUName, ArchKind); + ARM::ArchKind AK = ARM::parseCPUArch(CPUName); + bool pass = ARM::getArchName(AK).equals(ExpectedArch); + unsigned FPUKind = ARM::getDefaultFPU(CPUName, AK); pass &= ARM::getFPUName(FPUKind).equals(ExpectedFPU); - unsigned ExtKind = ARM::getDefaultExtensions(CPUName, ArchKind); + unsigned ExtKind = ARM::getDefaultExtensions(CPUName, AK); if (ExtKind > 1 && (ExtKind & ARM::AEK_NONE)) pass &= ((ExtKind ^ ARM::AEK_NONE) == ExpectedFlags); else pass &= (ExtKind == ExpectedFlags); - pass &= ARM::getCPUAttr(ArchKind).equals(CPUAttr); + pass &= ARM::getCPUAttr(AK).equals(CPUAttr); return pass; } @@ -218,6 +218,12 @@ TEST(TargetParserTest, testARMCPU) { ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "8-A")); + EXPECT_TRUE(testARMCPU("cortex-a55", "armv8.2-a", "crypto-neon-fp-armv8", + ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP | + ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_FP16 | + ARM::AEK_RAS | ARM::AEK_DOTPROD, + "8.2-A")); EXPECT_TRUE(testARMCPU("cortex-a57", "armv8-a", "crypto-neon-fp-armv8", ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | @@ -233,6 +239,12 @@ TEST(TargetParserTest, testARMCPU) { ARM::AEK_VIRT | ARM::AEK_HWDIVARM | ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP, "8-A")); + EXPECT_TRUE(testARMCPU("cortex-a75", "armv8.2-a", "crypto-neon-fp-armv8", + ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP | + ARM::AEK_VIRT | ARM::AEK_HWDIVARM | + ARM::AEK_HWDIVTHUMB | ARM::AEK_DSP | ARM::AEK_FP16 | + ARM::AEK_RAS | ARM::AEK_DOTPROD, + "8.2-A")); EXPECT_TRUE(testARMCPU("cyclone", "armv8-a", "crypto-neon-fp-armv8", ARM::AEK_CRC | ARM::AEK_SEC | ARM::AEK_MP | ARM::AEK_VIRT | ARM::AEK_HWDIVARM | @@ -268,11 +280,11 @@ TEST(TargetParserTest, testARMCPU) { bool testARMArch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch, unsigned ArchAttr) { - unsigned ArchKind = ARM::parseArch(Arch); - return (ArchKind != ARM::AK_INVALID) & + ARM::ArchKind AK = ARM::parseArch(Arch); + return (AK!= ARM::ArchKind::INVALID) & ARM::getDefaultCPU(Arch).equals(DefaultCPU) & - ARM::getSubArch(ArchKind).equals(SubArch) & - (ARM::getArchAttr(ArchKind) == ArchAttr); + ARM::getSubArch(AK).equals(SubArch) & + (ARM::getArchAttr(AK) == ArchAttr); } TEST(TargetParserTest, testARMArch) { @@ -343,6 +355,9 @@ TEST(TargetParserTest, testARMArch) { testARMArch("armv8.2-a", "generic", "v8.2a", ARMBuildAttrs::CPUArch::v8_A)); EXPECT_TRUE( + testARMArch("armv8.3-a", "generic", "v8.3a", + ARMBuildAttrs::CPUArch::v8_A)); + EXPECT_TRUE( testARMArch("armv8-r", "cortex-r52", "v8r", ARMBuildAttrs::CPUArch::v8_R)); EXPECT_TRUE( @@ -368,94 +383,118 @@ TEST(TargetParserTest, testARMArch) { ARMBuildAttrs::CPUArch::v7)); } -bool testARMExtension(StringRef CPUName, unsigned ArchKind, StringRef ArchExt) { +bool testARMExtension(StringRef CPUName,ARM::ArchKind ArchKind, StringRef ArchExt) { return ARM::getDefaultExtensions(CPUName, ArchKind) & ARM::parseArchExt(ArchExt); } TEST(TargetParserTest, testARMExtension) { - EXPECT_FALSE(testARMExtension("arm2", 0, "thumb")); - EXPECT_FALSE(testARMExtension("arm3", 0, "thumb")); - EXPECT_FALSE(testARMExtension("arm6", 0, "thumb")); - EXPECT_FALSE(testARMExtension("arm7m", 0, "thumb")); - EXPECT_FALSE(testARMExtension("strongarm", 0, "dsp")); - EXPECT_FALSE(testARMExtension("arm7tdmi", 0, "dsp")); - EXPECT_FALSE(testARMExtension("arm10tdmi", 0, "simd")); - EXPECT_FALSE(testARMExtension("arm1022e", 0, "simd")); - EXPECT_FALSE(testARMExtension("arm926ej-s", 0, "simd")); - EXPECT_FALSE(testARMExtension("arm1136jf-s", 0, "crypto")); - EXPECT_FALSE(testARMExtension("arm1176j-s", 0, "crypto")); - EXPECT_FALSE(testARMExtension("arm1156t2-s", 0, "crypto")); - EXPECT_FALSE(testARMExtension("arm1176jzf-s", 0, "crypto")); - EXPECT_FALSE(testARMExtension("cortex-m0", 0, "crypto")); - EXPECT_FALSE(testARMExtension("cortex-a8", 0, "crypto")); - EXPECT_FALSE(testARMExtension("cortex-r4", 0, "crypto")); - EXPECT_FALSE(testARMExtension("cortex-m3", 0, "crypto")); - EXPECT_FALSE(testARMExtension("cortex-a53", 0, "ras")); - EXPECT_FALSE(testARMExtension("cortex-r52", 0, "ras")); - EXPECT_FALSE(testARMExtension("iwmmxt", 0, "crc")); - EXPECT_FALSE(testARMExtension("xscale", 0, "crc")); - EXPECT_FALSE(testARMExtension("swift", 0, "crc")); - - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV2, "thumb")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV2A, "thumb")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV3, "thumb")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV3M, "thumb")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV4, "dsp")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV4T, "dsp")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5T, "simd")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5TE, "simd")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV5TEJ, "simd")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6K, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6T2, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6KZ, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV6M, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7A, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7R, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7M, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7EM, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8A, "ras")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8_1A, "ras")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8_2A, "spe")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8R, "ras")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8MBaseline, "crc")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV8MMainline, "crc")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_IWMMXT, "crc")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_IWMMXT2, "crc")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_XSCALE, "crc")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7S, "crypto")); - EXPECT_FALSE(testARMExtension("generic", ARM::AK_ARMV7K, "crypto")); + EXPECT_FALSE(testARMExtension("arm2", ARM::ArchKind::INVALID, "thumb")); + EXPECT_FALSE(testARMExtension("arm3", ARM::ArchKind::INVALID, "thumb")); + EXPECT_FALSE(testARMExtension("arm6", ARM::ArchKind::INVALID, "thumb")); + EXPECT_FALSE(testARMExtension("arm7m", ARM::ArchKind::INVALID, "thumb")); + EXPECT_FALSE(testARMExtension("strongarm", ARM::ArchKind::INVALID, "dsp")); + EXPECT_FALSE(testARMExtension("arm7tdmi", ARM::ArchKind::INVALID, "dsp")); + EXPECT_FALSE(testARMExtension("arm10tdmi", + ARM::ArchKind::INVALID, "simd")); + EXPECT_FALSE(testARMExtension("arm1022e", ARM::ArchKind::INVALID, "simd")); + EXPECT_FALSE(testARMExtension("arm926ej-s", + ARM::ArchKind::INVALID, "simd")); + EXPECT_FALSE(testARMExtension("arm1136jf-s", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("arm1176j-s", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("arm1156t2-s", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("arm1176jzf-s", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("cortex-m0", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("cortex-a8", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("cortex-r4", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("cortex-m3", + ARM::ArchKind::INVALID, "crypto")); + EXPECT_FALSE(testARMExtension("cortex-a53", + ARM::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testARMExtension("cortex-r52", + ARM::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testARMExtension("iwmmxt", ARM::ArchKind::INVALID, "crc")); + EXPECT_FALSE(testARMExtension("xscale", ARM::ArchKind::INVALID, "crc")); + EXPECT_FALSE(testARMExtension("swift", ARM::ArchKind::INVALID, "crc")); + + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV2, "thumb")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV2A, "thumb")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV3, "thumb")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV3M, "thumb")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV4, "dsp")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV4T, "dsp")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5T, "simd")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5TE, "simd")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV5TEJ, "simd")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6K, "crypto")); + EXPECT_FALSE(testARMExtension("generic", + ARM::ArchKind::ARMV6T2, "crypto")); + EXPECT_FALSE(testARMExtension("generic", + ARM::ArchKind::ARMV6KZ, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV6M, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7A, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7R, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7M, "crypto")); + EXPECT_FALSE(testARMExtension("generic", + ARM::ArchKind::ARMV7EM, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8A, "ras")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_1A, "ras")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8_2A, "spe")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV8R, "ras")); + EXPECT_FALSE(testARMExtension("generic", + ARM::ArchKind::ARMV8MBaseline, "crc")); + EXPECT_FALSE(testARMExtension("generic", + ARM::ArchKind::ARMV8MMainline, "crc")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::IWMMXT, "crc")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::IWMMXT2, "crc")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::XSCALE, "crc")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7S, "crypto")); + EXPECT_FALSE(testARMExtension("generic", ARM::ArchKind::ARMV7K, "crypto")); } TEST(TargetParserTest, ARMFPUVersion) { - for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0); + for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0); FK <= ARM::FPUKind::FK_LAST; FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1)) - if (FK == ARM::FK_LAST) - EXPECT_EQ(0U, ARM::getFPUVersion(FK)); + if (FK == ARM::FK_LAST || ARM::getFPUName(FK) == "invalid" || + ARM::getFPUName(FK) == "none" || ARM::getFPUName(FK) == "softvfp") + EXPECT_EQ(ARM::FPUVersion::NONE, ARM::getFPUVersion(FK)); else - EXPECT_LE(0U, ARM::getFPUVersion(FK)); + EXPECT_NE(ARM::FPUVersion::NONE, ARM::getFPUVersion(FK)); } TEST(TargetParserTest, ARMFPUNeonSupportLevel) { for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0); FK <= ARM::FPUKind::FK_LAST; FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1)) - if (FK == ARM::FK_LAST) - EXPECT_EQ(0U, ARM::getFPUNeonSupportLevel(FK)); + if (FK == ARM::FK_LAST || + ARM::getFPUName(FK).find("neon") == std::string::npos) + EXPECT_EQ(ARM::NeonSupportLevel::None, + ARM::getFPUNeonSupportLevel(FK)); else - EXPECT_LE(0U, ARM::getFPUNeonSupportLevel(FK)); + EXPECT_NE(ARM::NeonSupportLevel::None, + ARM::getFPUNeonSupportLevel(FK)); } TEST(TargetParserTest, ARMFPURestriction) { for (ARM::FPUKind FK = static_cast<ARM::FPUKind>(0); FK <= ARM::FPUKind::FK_LAST; - FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1)) - if (FK == ARM::FK_LAST) - EXPECT_EQ(0U, ARM::getFPURestriction(FK)); + FK = static_cast<ARM::FPUKind>(static_cast<unsigned>(FK) + 1)) { + if (FK == ARM::FK_LAST || + (ARM::getFPUName(FK).find("d16") == std::string::npos && + ARM::getFPUName(FK).find("vfpv3xd") == std::string::npos)) + EXPECT_EQ(ARM::FPURestriction::None, ARM::getFPURestriction(FK)); else - EXPECT_LE(0U, ARM::getFPURestriction(FK)); + EXPECT_NE(ARM::FPURestriction::None, ARM::getFPURestriction(FK)); + } } TEST(TargetParserTest, ARMExtensionFeatures) { @@ -491,6 +530,7 @@ TEST(TargetParserTest, ARMArchExtFeature) { {"virt", "novirt", nullptr, nullptr}, {"fp16", "nofp16", "+fullfp16", "-fullfp16"}, {"ras", "noras", "+ras", "-ras"}, + {"dotprod", "nodotprod", "+dotprod", "-dotprod"}, {"os", "noos", nullptr, nullptr}, {"iwmmxt", "noiwmmxt", nullptr, nullptr}, {"iwmmxt2", "noiwmmxt2", nullptr, nullptr}, @@ -517,7 +557,7 @@ TEST(TargetParserTest, ARMparseArchEndianAndISA) { "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"}; + "v8.1-a", "v8.1a", "v8.2-a", "v8.2a", "v8.3-a", "v8.3a", "v8-r"}; for (unsigned i = 0; i < array_lengthof(Arch); i++) { std::string arm_1 = "armeb" + (std::string)(Arch[i]); @@ -527,57 +567,60 @@ TEST(TargetParserTest, ARMparseArchEndianAndISA) { std::string thumb_2 = "thumb" + (std::string)(Arch[i]) + "eb"; std::string thumb_3 = "thumb" + (std::string)(Arch[i]); - EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(arm_1)); - EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(arm_2)); - EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian(arm_3)); + EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(arm_1)); + EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(arm_2)); + EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian(arm_3)); - EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_1)); - EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_2)); - EXPECT_EQ(ARM::IK_ARM, ARM::parseArchISA(arm_3)); + EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_1)); + EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_2)); + EXPECT_EQ(ARM::ISAKind::ARM, ARM::parseArchISA(arm_3)); if (i >= 4) { - EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(thumb_1)); - EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian(thumb_2)); - EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian(thumb_3)); + EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(thumb_1)); + EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian(thumb_2)); + EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian(thumb_3)); - EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_1)); - EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_2)); - EXPECT_EQ(ARM::IK_THUMB, ARM::parseArchISA(thumb_3)); + EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_1)); + EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_2)); + EXPECT_EQ(ARM::ISAKind::THUMB, ARM::parseArchISA(thumb_3)); } } - EXPECT_EQ(ARM::EK_LITTLE, ARM::parseArchEndian("aarch64")); - EXPECT_EQ(ARM::EK_BIG, ARM::parseArchEndian("aarch64_be")); + EXPECT_EQ(ARM::EndianKind::LITTLE, ARM::parseArchEndian("aarch64")); + EXPECT_EQ(ARM::EndianKind::BIG, ARM::parseArchEndian("aarch64_be")); - EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("aarch64")); - EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("aarch64_be")); - EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("arm64")); - EXPECT_EQ(ARM::IK_AARCH64, ARM::parseArchISA("arm64_be")); + EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("aarch64")); + EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("aarch64_be")); + EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("arm64")); + EXPECT_EQ(ARM::ISAKind::AARCH64, ARM::parseArchISA("arm64_be")); } TEST(TargetParserTest, ARMparseArchProfile) { for (unsigned i = 0; i < array_lengthof(ARMArch); i++) { switch (ARM::parseArch(ARMArch[i])) { - case ARM::AK_ARMV6M: - case ARM::AK_ARMV7M: - case ARM::AK_ARMV7EM: - case ARM::AK_ARMV8MMainline: - case ARM::AK_ARMV8MBaseline: - EXPECT_EQ(ARM::PK_M, ARM::parseArchProfile(ARMArch[i])); - continue; - case ARM::AK_ARMV7R: - case ARM::AK_ARMV8R: - 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: - case ARM::AK_ARMV8_2A: - EXPECT_EQ(ARM::PK_A, ARM::parseArchProfile(ARMArch[i])); - continue; + case ARM::ArchKind::ARMV6M: + case ARM::ArchKind::ARMV7M: + case ARM::ArchKind::ARMV7EM: + case ARM::ArchKind::ARMV8MMainline: + case ARM::ArchKind::ARMV8MBaseline: + EXPECT_EQ(ARM::ProfileKind::M, ARM::parseArchProfile(ARMArch[i])); + break; + case ARM::ArchKind::ARMV7R: + case ARM::ArchKind::ARMV8R: + EXPECT_EQ(ARM::ProfileKind::R, ARM::parseArchProfile(ARMArch[i])); + break; + case ARM::ArchKind::ARMV7A: + case ARM::ArchKind::ARMV7VE: + case ARM::ArchKind::ARMV7K: + case ARM::ArchKind::ARMV8A: + case ARM::ArchKind::ARMV8_1A: + case ARM::ArchKind::ARMV8_2A: + case ARM::ArchKind::ARMV8_3A: + EXPECT_EQ(ARM::ProfileKind::A, ARM::parseArchProfile(ARMArch[i])); + break; + default: + EXPECT_EQ(ARM::ProfileKind::INVALID, ARM::parseArchProfile(ARMArch[i])); + break; } - EXPECT_EQ(ARM::PK_INVALID, ARM::parseArchProfile(ARMArch[i])); } } @@ -592,18 +635,18 @@ TEST(TargetParserTest, ARMparseArchVersion) { bool testAArch64CPU(StringRef CPUName, StringRef ExpectedArch, StringRef ExpectedFPU, unsigned ExpectedFlags, StringRef CPUAttr) { - unsigned ArchKind = AArch64::parseCPUArch(CPUName); - bool pass = AArch64::getArchName(ArchKind).equals(ExpectedArch); - unsigned FPUKind = AArch64::getDefaultFPU(CPUName, ArchKind); + AArch64::ArchKind AK = AArch64::parseCPUArch(CPUName); + bool pass = AArch64::getArchName(AK).equals(ExpectedArch); + unsigned FPUKind = AArch64::getDefaultFPU(CPUName, AK); pass &= AArch64::getFPUName(FPUKind).equals(ExpectedFPU); - unsigned ExtKind = AArch64::getDefaultExtensions(CPUName, ArchKind); + unsigned ExtKind = AArch64::getDefaultExtensions(CPUName, AK); if (ExtKind > 1 && (ExtKind & AArch64::AEK_NONE)) pass &= ((ExtKind ^ AArch64::AEK_NONE) == ExpectedFlags); else pass &= (ExtKind == ExpectedFlags); - pass &= AArch64::getCPUAttr(ArchKind).equals(CPUAttr); + pass &= AArch64::getCPUAttr(AK).equals(CPUAttr); return pass; } @@ -625,6 +668,12 @@ TEST(TargetParserTest, testAArch64CPU) { AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD, "8-A")); EXPECT_TRUE(testAArch64CPU( + "cortex-a55", "armv8.2-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | + AArch64::AEK_RCPC, "8.2-A")); + EXPECT_TRUE(testAArch64CPU( "cortex-a57", "armv8-a", "crypto-neon-fp-armv8", AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD, "8-A")); @@ -637,6 +686,12 @@ TEST(TargetParserTest, testAArch64CPU) { AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD, "8-A")); EXPECT_TRUE(testAArch64CPU( + "cortex-a75", "armv8.2-a", "crypto-neon-fp-armv8", + AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | + AArch64::AEK_SIMD | AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_FP16 | AArch64::AEK_DOTPROD | + AArch64::AEK_RCPC, "8.2-A")); + EXPECT_TRUE(testAArch64CPU( "cyclone", "armv8-a", "crypto-neon-fp-armv8", AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD, "8-A")); EXPECT_TRUE(testAArch64CPU( @@ -654,7 +709,7 @@ TEST(TargetParserTest, testAArch64CPU) { EXPECT_TRUE(testAArch64CPU( "falkor", "armv8-a", "crypto-neon-fp-armv8", AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | - AArch64::AEK_SIMD, "8-A")); + AArch64::AEK_SIMD | AArch64::AEK_RDM, "8-A")); EXPECT_TRUE(testAArch64CPU( "kryo", "armv8-a", "crypto-neon-fp-armv8", AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | @@ -662,7 +717,7 @@ TEST(TargetParserTest, testAArch64CPU) { EXPECT_TRUE(testAArch64CPU( "thunderx2t99", "armv8.1-a", "crypto-neon-fp-armv8", AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_LSE | - AArch64::AEK_FP | AArch64::AEK_SIMD, "8.1-A")); + AArch64::AEK_RDM | AArch64::AEK_FP | 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 | @@ -687,11 +742,11 @@ TEST(TargetParserTest, testAArch64CPU) { bool testAArch64Arch(StringRef Arch, StringRef DefaultCPU, StringRef SubArch, unsigned ArchAttr) { - unsigned ArchKind = AArch64::parseArch(Arch); - return (ArchKind != static_cast<unsigned>(AArch64::ArchKind::AK_INVALID)) & + AArch64::ArchKind AK = AArch64::parseArch(Arch); + return (AK != AArch64::ArchKind::INVALID) & AArch64::getDefaultCPU(Arch).equals(DefaultCPU) & - AArch64::getSubArch(ArchKind).equals(SubArch) & - (AArch64::getArchAttr(ArchKind) == ArchAttr); + AArch64::getSubArch(AK).equals(SubArch) & + (AArch64::getArchAttr(AK) == ArchAttr); } TEST(TargetParserTest, testAArch64Arch) { @@ -701,35 +756,74 @@ TEST(TargetParserTest, testAArch64Arch) { ARMBuildAttrs::CPUArch::v8_A)); EXPECT_TRUE(testAArch64Arch("armv8.2-a", "generic", "v8.2a", ARMBuildAttrs::CPUArch::v8_A)); + EXPECT_TRUE(testAArch64Arch("armv8.3-a", "generic", "v8.3a", + ARMBuildAttrs::CPUArch::v8_A)); } -bool testAArch64Extension(StringRef CPUName, unsigned ArchKind, +bool testAArch64Extension(StringRef CPUName, AArch64::ArchKind AK, StringRef ArchExt) { - return AArch64::getDefaultExtensions(CPUName, ArchKind) & + return AArch64::getDefaultExtensions(CPUName, AK) & AArch64::parseArchExt(ArchExt); } TEST(TargetParserTest, testAArch64Extension) { - EXPECT_FALSE(testAArch64Extension("cortex-a35", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("cortex-a53", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("cortex-a57", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("cortex-a72", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("cortex-a73", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("cyclone", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("exynos-m1", 0, "ras")); - EXPECT_FALSE(testAArch64Extension("kryo", 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("cortex-a35", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("cortex-a53", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_TRUE(testAArch64Extension("cortex-a55", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("cortex-a57", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("cortex-a72", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("cortex-a73", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_TRUE(testAArch64Extension("cortex-a75", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("cyclone", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("exynos-m1", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("exynos-m2", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("exynos-m3", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_TRUE(testAArch64Extension("falkor", + AArch64::ArchKind::INVALID, "rdm")); + EXPECT_FALSE(testAArch64Extension("kryo", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "crc")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "lse")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "rdm")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "rcpc")); + EXPECT_TRUE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "profile")); + EXPECT_FALSE(testAArch64Extension("saphira", + AArch64::ArchKind::INVALID, "fullfp16")); + EXPECT_FALSE(testAArch64Extension("thunderx2t99", + AArch64::ArchKind::INVALID, "ras")); + EXPECT_FALSE(testAArch64Extension("thunderx", + AArch64::ArchKind::INVALID, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt81", + AArch64::ArchKind::INVALID, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt83", + AArch64::ArchKind::INVALID, "lse")); + EXPECT_FALSE(testAArch64Extension("thunderxt88", + AArch64::ArchKind::INVALID, "lse")); EXPECT_FALSE(testAArch64Extension( - "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8A), "ras")); + "generic", AArch64::ArchKind::ARMV8A, "ras")); EXPECT_FALSE(testAArch64Extension( - "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_1A), "ras")); + "generic", AArch64::ArchKind::ARMV8_1A, "ras")); EXPECT_FALSE(testAArch64Extension( - "generic", static_cast<unsigned>(AArch64::ArchKind::AK_ARMV8_2A), "spe")); + "generic", AArch64::ArchKind::ARMV8_2A, "spe")); } TEST(TargetParserTest, AArch64ExtensionFeatures) { @@ -737,7 +831,9 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { unsigned Extensions = AArch64::AEK_CRC | AArch64::AEK_CRYPTO | AArch64::AEK_FP | AArch64::AEK_SIMD | AArch64::AEK_FP16 | AArch64::AEK_PROFILE | - AArch64::AEK_RAS | AArch64::AEK_SVE; + AArch64::AEK_RAS | AArch64::AEK_LSE | + AArch64::AEK_RDM | AArch64::AEK_SVE | + AArch64::AEK_DOTPROD | AArch64::AEK_RCPC; for (unsigned i = 0; i <= Extensions; i++) EXPECT_TRUE(i == 0 ? !AArch64::getExtensionFeatures(i, Features) @@ -746,11 +842,14 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { TEST(TargetParserTest, AArch64ArchFeatures) { std::vector<StringRef> Features; - - for (unsigned AK = 0; AK < static_cast<unsigned>(AArch64::ArchKind::AK_LAST); - AK++) - EXPECT_TRUE((AK == static_cast<unsigned>(AArch64::ArchKind::AK_INVALID) || - AK == static_cast<unsigned>(AArch64::ArchKind::AK_LAST)) + AArch64::ArchKind ArchKinds[] = { +#define AARCH64_ARCH(NAME, ID, CPU_ATTR, SUB_ARCH, ARCH_ATTR, ARCH_FPU, ARCH_BASE_EXT) \ + AArch64::ArchKind::ID, +#include "llvm/Support/AArch64TargetParser.def" + }; + + for (auto AK : ArchKinds) + EXPECT_TRUE((AK == AArch64::ArchKind::INVALID) ? !AArch64::getArchFeatures(AK, Features) : AArch64::getArchFeatures(AK, Features)); } @@ -763,7 +862,11 @@ TEST(TargetParserTest, AArch64ArchExtFeature) { {"fp16", "nofp16", "+fullfp16", "-fullfp16"}, {"profile", "noprofile", "+spe", "-spe"}, {"ras", "noras", "+ras", "-ras"}, - {"sve", "nosve", "+sve", "-sve"}}; + {"lse", "nolse", "+lse", "-lse"}, + {"rdm", "nordm", "+rdm", "-rdm"}, + {"sve", "nosve", "+sve", "-sve"}, + {"dotprod", "nodotprod", "+dotprod", "-dotprod"}, + {"rcpc", "norcpc", "+rcpc", "-rcpc" }}; for (unsigned i = 0; i < array_lengthof(ArchExt); i++) { EXPECT_EQ(StringRef(ArchExt[i][2]), diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 120773a0c8dd..9caff85a5963 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -860,7 +860,7 @@ namespace yaml { return "malformed by"; } } - static bool mustQuote(StringRef) { return true; } + static QuotingType mustQuote(StringRef) { return QuotingType::Single; } }; } } @@ -1064,7 +1064,7 @@ namespace yaml { return StringRef(); } - static bool mustQuote(StringRef) { return false; } + static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; template <> struct ScalarTraits<MyString> { @@ -1075,7 +1075,9 @@ namespace yaml { static StringRef input(StringRef S, void *Ctx, MyString &V) { return Impl::input(S, Ctx, V.value); } - static bool mustQuote(StringRef S) { return Impl::mustQuote(S); } + static QuotingType mustQuote(StringRef S) { + return Impl::mustQuote(S); + } }; } } @@ -2232,7 +2234,7 @@ struct ScalarTraits<FlowSeq> { return ""; } - static bool mustQuote(StringRef S) { return false; } + static QuotingType mustQuote(StringRef S) { return QuotingType::None; } }; } } @@ -2455,3 +2457,87 @@ TEST(YAMLIO, InvalidInput) { yin >> Data; EXPECT_TRUE((bool)yin.error()); } + +TEST(YAMLIO, TestEscapedSingleQuote) { + std::string Id = "@abc@"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'@abc@'", out); +} + +TEST(YAMLIO, TestEscapedNoQuote) { + std::string Id = "abc/"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("abc/", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteNonPrintable) { + std::string Id = "\01@abc@"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("\"\\x01@abc@\"", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteInsideSingleQuote) { + std::string Id = "abc\"fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'abc\"fdf'", out); +} + +TEST(YAMLIO, TestEscapedDoubleQuoteInsideDoubleQuote) { + std::string Id = "\01bc\"fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("\"\\x01bc\\\"fdf\"", out); +} + +TEST(YAMLIO, TestEscapedSingleQuoteInsideSingleQuote) { + std::string Id = "abc'fdf"; + + std::string out; + llvm::raw_string_ostream ostr(out); + Output xout(ostr, nullptr, 0); + + llvm::yaml::EmptyContext Ctx; + yamlize(xout, Id, true, Ctx); + + ostr.flush(); + EXPECT_EQ("'abc''fdf'", out); +} diff --git a/unittests/Support/YAMLParserTest.cpp b/unittests/Support/YAMLParserTest.cpp index d411a286830b..7962f3ca1ad1 100644 --- a/unittests/Support/YAMLParserTest.cpp +++ b/unittests/Support/YAMLParserTest.cpp @@ -180,6 +180,7 @@ TEST(YAMLParser, HandlesEndOfFileGracefully) { } TEST(YAMLParser, HandlesNullValuesInKeyValueNodesGracefully) { + ExpectParseError("KeyValueNode with null key", "? \"\n:"); ExpectParseError("KeyValueNode with null value", "test: '"); } |
