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