| //===- BitstreamWriterTest.cpp - Tests for BitstreamWriter ----------------===// | 
 | // | 
 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
 | // See https://llvm.org/LICENSE.txt for license information. | 
 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/Bitstream/BitstreamWriter.h" | 
 | #include "llvm/ADT/STLExtras.h" | 
 | #include "llvm/ADT/SmallString.h" | 
 | #include "llvm/Bitstream/BitCodeEnums.h" | 
 | #include "llvm/Bitstream/BitstreamReader.h" | 
 | #include "llvm/Support/Error.h" | 
 | #include "llvm/Support/MemoryBuffer.h" | 
 | #include "llvm/Testing/Support/SupportHelpers.h" | 
 | #include "gmock/gmock.h" | 
 | #include "gtest/gtest.h" | 
 |  | 
 | using namespace llvm; | 
 |  | 
 | namespace { | 
 |  | 
 | TEST(BitstreamWriterTest, emitBlob) { | 
 |   SmallString<64> Buffer; | 
 |   BitstreamWriter W(Buffer); | 
 |   W.emitBlob("str", /* ShouldEmitSize */ false); | 
 |   EXPECT_EQ(StringRef("str\0", 4), Buffer); | 
 | } | 
 |  | 
 | TEST(BitstreamWriterTest, emitBlobWithSize) { | 
 |   SmallString<64> Buffer; | 
 |   { | 
 |     BitstreamWriter W(Buffer); | 
 |     W.emitBlob("str"); | 
 |   } | 
 |   SmallString<64> Expected; | 
 |   { | 
 |     BitstreamWriter W(Expected); | 
 |     W.EmitVBR(3, 6); | 
 |     W.FlushToWord(); | 
 |     W.Emit('s', 8); | 
 |     W.Emit('t', 8); | 
 |     W.Emit('r', 8); | 
 |     W.Emit(0, 8); | 
 |   } | 
 |   EXPECT_EQ(Expected.str(), Buffer); | 
 | } | 
 |  | 
 | TEST(BitstreamWriterTest, emitBlobEmpty) { | 
 |   SmallString<64> Buffer; | 
 |   BitstreamWriter W(Buffer); | 
 |   W.emitBlob("", /* ShouldEmitSize */ false); | 
 |   EXPECT_EQ(StringRef(""), Buffer); | 
 | } | 
 |  | 
 | TEST(BitstreamWriterTest, emitBlob4ByteAligned) { | 
 |   SmallString<64> Buffer; | 
 |   BitstreamWriter W(Buffer); | 
 |   W.emitBlob("str0", /* ShouldEmitSize */ false); | 
 |   EXPECT_EQ(StringRef("str0"), Buffer); | 
 | } | 
 |  | 
 | class BitstreamWriterFlushTest : public ::testing::TestWithParam<int> { | 
 | protected: | 
 |   // Any value after bitc::FIRST_APPLICATION_BLOCKID is good, but let's pick a | 
 |   // distinctive one. | 
 |   const unsigned BlkID = bitc::FIRST_APPLICATION_BLOCKID + 17; | 
 |  | 
 |   void write(StringRef TestFilePath, int FlushThreshold, | 
 |              llvm::function_ref<void(BitstreamWriter &)> Action) { | 
 |     std::error_code EC; | 
 |     raw_fd_stream Out(TestFilePath, EC); | 
 |     ASSERT_FALSE(EC); | 
 |     BitstreamWriter W(Out, FlushThreshold); | 
 |     Action(W); | 
 |   } | 
 | }; | 
 |  | 
 | TEST_P(BitstreamWriterFlushTest, simpleExample) { | 
 |   llvm::unittest::TempFile TestFile("bitstream", "", "", | 
 |                                     /*Unique*/ true); | 
 |   write(TestFile.path(), GetParam(), | 
 |         [&](BitstreamWriter &W) { W.EmitVBR(42, 2); }); | 
 |  | 
 |   ErrorOr<std::unique_ptr<MemoryBuffer>> MB = | 
 |       MemoryBuffer::getFile(TestFile.path()); | 
 |   ASSERT_TRUE(!!MB); | 
 |   ASSERT_NE(*MB, nullptr); | 
 |   BitstreamCursor Cursor((*MB)->getBuffer()); | 
 |   auto V = Cursor.ReadVBR(2); | 
 |   EXPECT_TRUE(!!V); | 
 |   EXPECT_EQ(*V, 42U); | 
 | } | 
 |  | 
 | TEST_P(BitstreamWriterFlushTest, subBlock) { | 
 |   llvm::unittest::TempFile TestFile("bitstream", "", "", | 
 |                                     /*Unique*/ true); | 
 |   write(TestFile.path(), GetParam(), [&](BitstreamWriter &W) { | 
 |     W.EnterSubblock(BlkID, 2); | 
 |     W.EmitVBR(42, 2); | 
 |     W.ExitBlock(); | 
 |   }); | 
 |   ErrorOr<std::unique_ptr<MemoryBuffer>> MB = | 
 |       MemoryBuffer::getFile(TestFile.path()); | 
 |   ASSERT_TRUE(!!MB); | 
 |   ASSERT_NE(*MB, nullptr); | 
 |   BitstreamCursor Cursor((*MB)->getBuffer()); | 
 |   auto Blk = Cursor.advance(BitstreamCursor::AF_DontAutoprocessAbbrevs); | 
 |   ASSERT_TRUE(!!Blk); | 
 |   EXPECT_EQ(Blk->Kind, BitstreamEntry::SubBlock); | 
 |   EXPECT_EQ(Blk->ID, BlkID); | 
 |   EXPECT_FALSE(Cursor.EnterSubBlock(BlkID)); | 
 |   auto V = Cursor.ReadVBR(2); | 
 |   EXPECT_TRUE(!!V); | 
 |   EXPECT_EQ(*V, 42U); | 
 |   // ReadBlockEnd() returns false if it actually read the block end. | 
 |   EXPECT_FALSE(Cursor.ReadBlockEnd()); | 
 |   EXPECT_TRUE(Cursor.AtEndOfStream()); | 
 | } | 
 |  | 
 | TEST_P(BitstreamWriterFlushTest, blobRawRead) { | 
 |   llvm::unittest::TempFile TestFile("bitstream", "", "", | 
 |                                     /*Unique*/ true); | 
 |   write(TestFile.path(), GetParam(), [&](BitstreamWriter &W) { | 
 |     W.emitBlob("str", /* ShouldEmitSize */ false); | 
 |   }); | 
 |  | 
 |   ErrorOr<std::unique_ptr<MemoryBuffer>> MB = | 
 |       MemoryBuffer::getFile(TestFile.path()); | 
 |   ASSERT_TRUE(!!MB); | 
 |   ASSERT_NE(*MB, nullptr); | 
 |   EXPECT_EQ(StringRef("str\0", 4), (*MB)->getBuffer()); | 
 | } | 
 |  | 
 | INSTANTIATE_TEST_SUITE_P(BitstreamWriterFlushCases, BitstreamWriterFlushTest, | 
 |                          ::testing::Values(0, 1 /*MB*/)); | 
 | } // end namespace |