1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
//===- raw_ostream_proxy_test.cpp - Tests for raw ostream proxies ---------===//
//
// 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/ADT/SmallString.h"
#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/raw_ostream_proxy.h"
#include "gtest/gtest.h"
using namespace llvm;
namespace {
/// Naive version of raw_svector_ostream that is buffered (by default) and
/// doesn't support pwrite.
class BufferedNoPwriteSmallVectorStream : public raw_ostream {
public:
// Choose a strange buffer size to ensure it doesn't collide with the default
// on \a raw_ostream.
constexpr static const size_t PreferredBufferSize = 63;
size_t preferred_buffer_size() const override { return PreferredBufferSize; }
uint64_t current_pos() const override { return Vector.size(); }
void write_impl(const char *Ptr, size_t Size) override {
Vector.append(Ptr, Ptr + Size);
}
bool is_displayed() const override { return IsDisplayed; }
explicit BufferedNoPwriteSmallVectorStream(SmallVectorImpl<char> &Vector)
: Vector(Vector) {}
~BufferedNoPwriteSmallVectorStream() override { flush(); }
SmallVectorImpl<char> &Vector;
bool IsDisplayed = false;
};
constexpr const size_t BufferedNoPwriteSmallVectorStream::PreferredBufferSize;
TEST(raw_ostream_proxyTest, write) {
// Besides confirming that "write" works, this test confirms that the proxy
// takes on the buffer from the stream it's proxying, such that writes to the
// proxy are flushed to the underlying stream as if no proxy were present.
SmallString<128> Dest;
{
// Confirm that BufferedNoPwriteSmallVectorStream is buffered by default,
// and that setting up a proxy effectively transfers a buffer of the same
// size to the proxy.
BufferedNoPwriteSmallVectorStream DestOS(Dest);
EXPECT_EQ(BufferedNoPwriteSmallVectorStream::PreferredBufferSize,
DestOS.GetBufferSize());
raw_ostream_proxy ProxyOS(DestOS);
EXPECT_EQ(0u, DestOS.GetBufferSize());
EXPECT_EQ(BufferedNoPwriteSmallVectorStream::PreferredBufferSize,
ProxyOS.GetBufferSize());
// Flushing should send through to Dest.
ProxyOS << "abcd";
EXPECT_EQ("", Dest);
ProxyOS.flush();
EXPECT_EQ("abcd", Dest);
// Buffer should still work.
ProxyOS << "e";
EXPECT_EQ("abcd", Dest);
}
// Destructing ProxyOS should flush (and not crash).
EXPECT_EQ("abcde", Dest);
{
// Set up another stream, this time unbuffered.
BufferedNoPwriteSmallVectorStream DestOS(Dest);
DestOS.SetUnbuffered();
EXPECT_EQ(0u, DestOS.GetBufferSize());
raw_ostream_proxy ProxyOS(DestOS);
EXPECT_EQ(0u, DestOS.GetBufferSize());
EXPECT_EQ(0u, ProxyOS.GetBufferSize());
// Flushing should not be required.
ProxyOS << "f";
EXPECT_EQ("abcdef", Dest);
}
EXPECT_EQ("abcdef", Dest);
}
TEST(raw_ostream_proxyTest, pwrite) {
// This test confirms that the proxy takes on the buffer from the stream it's
// proxying, such that writes to the proxy are flushed to the underlying
// stream as if no proxy were present.
SmallString<128> Dest;
raw_svector_ostream DestOS(Dest);
raw_pwrite_stream_proxy ProxyOS(DestOS);
EXPECT_EQ(0u, ProxyOS.GetBufferSize());
// Get some initial data.
ProxyOS << "abcd";
EXPECT_EQ("abcd", Dest);
// Confirm that pwrite works.
ProxyOS.pwrite("BC", 2, 1);
EXPECT_EQ("aBCd", Dest);
}
TEST(raw_ostream_proxyTest, pwriteWithBuffer) {
// This test confirms that when a buffer is configured, pwrite still works.
SmallString<128> Dest;
raw_svector_ostream DestOS(Dest);
DestOS.SetBufferSize(256);
EXPECT_EQ(256u, DestOS.GetBufferSize());
// Confirm that the proxy steals the buffer.
raw_pwrite_stream_proxy ProxyOS(DestOS);
EXPECT_EQ(0u, DestOS.GetBufferSize());
EXPECT_EQ(256u, ProxyOS.GetBufferSize());
// Check that the buffer is working.
ProxyOS << "abcd";
EXPECT_EQ("", Dest);
// Confirm that pwrite flushes.
ProxyOS.pwrite("BC", 2, 1);
EXPECT_EQ("aBCd", Dest);
}
class ProxyWithReset : public raw_ostream_proxy_adaptor<> {
public:
ProxyWithReset(raw_ostream &OS) : raw_ostream_proxy_adaptor<>(OS) {}
// Allow this to be called outside the class.
using raw_ostream_proxy_adaptor<>::hasProxiedOS;
using raw_ostream_proxy_adaptor<>::getProxiedOS;
using raw_ostream_proxy_adaptor<>::resetProxiedOS;
};
TEST(raw_ostream_proxyTest, resetProxiedOS) {
// Confirm that base classes can drop the proxied OS before destruction and
// get consistent crashes.
SmallString<128> Dest;
BufferedNoPwriteSmallVectorStream DestOS(Dest);
ProxyWithReset ProxyOS(DestOS);
EXPECT_TRUE(ProxyOS.hasProxiedOS());
EXPECT_EQ(&DestOS, &ProxyOS.getProxiedOS());
// Write some data.
ProxyOS << "abcd";
EXPECT_EQ("", Dest);
// Reset the underlying stream.
ProxyOS.resetProxiedOS();
EXPECT_EQ("abcd", Dest);
EXPECT_EQ(0u, ProxyOS.GetBufferSize());
EXPECT_FALSE(ProxyOS.hasProxiedOS());
#if GTEST_HAS_DEATH_TEST && !defined(NDEBUG)
EXPECT_DEATH(ProxyOS << "e", "use after reset");
EXPECT_DEATH(ProxyOS.getProxiedOS(), "use after reset");
#endif
}
TEST(raw_ostream_proxyTest, ColorMode) {
{
SmallString<128> Dest;
BufferedNoPwriteSmallVectorStream DestOS(Dest);
raw_ostream_proxy ProxyOS(DestOS);
ProxyOS.enable_colors(true);
WithColor(ProxyOS, HighlightColor::Error, ColorMode::Disable) << "test";
EXPECT_EQ("", Dest);
ProxyOS.flush();
EXPECT_EQ("test", Dest);
}
{
SmallString<128> Dest;
BufferedNoPwriteSmallVectorStream DestOS(Dest);
raw_ostream_proxy ProxyOS(DestOS);
ProxyOS.enable_colors(true);
WithColor(ProxyOS, HighlightColor::Error, ColorMode::Auto) << "test";
EXPECT_EQ("", Dest);
ProxyOS.flush();
EXPECT_EQ("test", Dest);
}
#ifdef LLVM_ON_UNIX
{
SmallString<128> Dest;
BufferedNoPwriteSmallVectorStream DestOS(Dest);
raw_ostream_proxy ProxyOS(DestOS);
ProxyOS.enable_colors(true);
WithColor(ProxyOS, HighlightColor::Error, ColorMode::Enable) << "test";
EXPECT_EQ("", Dest);
ProxyOS.flush();
EXPECT_EQ("\x1B[0;1;31mtest\x1B[0m", Dest);
}
{
SmallString<128> Dest;
BufferedNoPwriteSmallVectorStream DestOS(Dest);
DestOS.IsDisplayed = true;
raw_ostream_proxy ProxyOS(DestOS);
ProxyOS.enable_colors(true);
WithColor(ProxyOS, HighlightColor::Error, ColorMode::Auto) << "test";
EXPECT_EQ("", Dest);
ProxyOS.flush();
EXPECT_EQ("\x1B[0;1;31mtest\x1B[0m", Dest);
}
#endif
}
} // end namespace
|