[llvm] [clang] [Support] Add VirtualOutputBackends to virtualize the output from tools (PR #68447)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 7 05:54:26 PST 2023


================
@@ -0,0 +1,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
----------------
zmodem wrote:

Should this be guarded by asserts also being enabled?

https://github.com/llvm/llvm-project/pull/68447


More information about the cfe-commits mailing list