summaryrefslogtreecommitdiff
path: root/unittests
diff options
context:
space:
mode:
Diffstat (limited to 'unittests')
-rw-r--r--unittests/ADT/ValueMapTest.cpp291
-rw-r--r--unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp77
-rw-r--r--unittests/ExecutionEngine/JIT/JITTest.cpp4
-rw-r--r--unittests/Support/raw_ostream_test.cpp16
4 files changed, 348 insertions, 40 deletions
diff --git a/unittests/ADT/ValueMapTest.cpp b/unittests/ADT/ValueMapTest.cpp
new file mode 100644
index 000000000000..9de340c3f355
--- /dev/null
+++ b/unittests/ADT/ValueMapTest.cpp
@@ -0,0 +1,291 @@
+//===- llvm/unittest/ADT/ValueMapTest.cpp - ValueMap unit tests -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ValueMap.h"
+
+#include "llvm/Instructions.h"
+#include "llvm/ADT/OwningPtr.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+// Test fixture
+template<typename T>
+class ValueMapTest : public testing::Test {
+protected:
+ Constant *ConstantV;
+ OwningPtr<BitCastInst> BitcastV;
+ OwningPtr<BinaryOperator> AddV;
+
+ ValueMapTest() :
+ ConstantV(ConstantInt::get(Type::getInt32Ty(getGlobalContext()), 0)),
+ BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(getGlobalContext()))),
+ AddV(BinaryOperator::CreateAdd(ConstantV, ConstantV)) {
+ }
+};
+
+// Run everything on Value*, a subtype to make sure that casting works as
+// expected, and a const subtype to make sure we cast const correctly.
+typedef ::testing::Types<Value, Instruction, const Instruction> KeyTypes;
+TYPED_TEST_CASE(ValueMapTest, KeyTypes);
+
+TYPED_TEST(ValueMapTest, Null) {
+ ValueMap<TypeParam*, int> VM1;
+ VM1[NULL] = 7;
+ EXPECT_EQ(7, VM1.lookup(NULL));
+}
+
+TYPED_TEST(ValueMapTest, FollowsValue) {
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 7;
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(7, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ this->AddV.reset();
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(0U, VM.size());
+}
+
+TYPED_TEST(ValueMapTest, OperationsWork) {
+ ValueMap<TypeParam*, int> VM;
+ ValueMap<TypeParam*, int> VM2(16);
+ typename ValueMapConfig<TypeParam*>::ExtraData Data;
+ ValueMap<TypeParam*, int> VM3(Data, 16);
+ EXPECT_TRUE(VM.empty());
+
+ VM[this->BitcastV.get()] = 7;
+
+ // Find:
+ typename ValueMap<TypeParam*, int>::iterator I =
+ VM.find(this->BitcastV.get());
+ ASSERT_TRUE(I != VM.end());
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ EXPECT_EQ(7, I->second);
+ EXPECT_TRUE(VM.find(this->AddV.get()) == VM.end());
+
+ // Const find:
+ const ValueMap<TypeParam*, int> &CVM = VM;
+ typename ValueMap<TypeParam*, int>::const_iterator CI =
+ CVM.find(this->BitcastV.get());
+ ASSERT_TRUE(CI != CVM.end());
+ EXPECT_EQ(this->BitcastV.get(), CI->first);
+ EXPECT_EQ(7, CI->second);
+ EXPECT_TRUE(CVM.find(this->AddV.get()) == CVM.end());
+
+ // Insert:
+ std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult1 =
+ VM.insert(std::make_pair(this->AddV.get(), 3));
+ EXPECT_EQ(this->AddV.get(), InsertResult1.first->first);
+ EXPECT_EQ(3, InsertResult1.first->second);
+ EXPECT_TRUE(InsertResult1.second);
+ EXPECT_EQ(true, VM.count(this->AddV.get()));
+ std::pair<typename ValueMap<TypeParam*, int>::iterator, bool> InsertResult2 =
+ VM.insert(std::make_pair(this->AddV.get(), 5));
+ EXPECT_EQ(this->AddV.get(), InsertResult2.first->first);
+ EXPECT_EQ(3, InsertResult2.first->second);
+ EXPECT_FALSE(InsertResult2.second);
+
+ // Erase:
+ VM.erase(InsertResult2.first);
+ EXPECT_EQ(false, VM.count(this->AddV.get()));
+ EXPECT_EQ(true, VM.count(this->BitcastV.get()));
+ VM.erase(this->BitcastV.get());
+ EXPECT_EQ(false, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(0U, VM.size());
+
+ // Range insert:
+ SmallVector<std::pair<Instruction*, int>, 2> Elems;
+ Elems.push_back(std::make_pair(this->AddV.get(), 1));
+ Elems.push_back(std::make_pair(this->BitcastV.get(), 2));
+ VM.insert(Elems.begin(), Elems.end());
+ EXPECT_EQ(1, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(2, VM.lookup(this->BitcastV.get()));
+}
+
+template<typename ExpectedType, typename VarType>
+void CompileAssertHasType(VarType) {
+ typedef char assert[is_same<ExpectedType, VarType>::value ? 1 : -1];
+}
+
+TYPED_TEST(ValueMapTest, Iteration) {
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 2;
+ VM[this->AddV.get()] = 3;
+ size_t size = 0;
+ for (typename ValueMap<TypeParam*, int>::iterator I = VM.begin(), E = VM.end();
+ I != E; ++I) {
+ ++size;
+ std::pair<TypeParam*, int> value = *I;
+ CompileAssertHasType<TypeParam*>(I->first);
+ if (I->second == 2) {
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ I->second = 5;
+ } else if (I->second == 3) {
+ EXPECT_EQ(this->AddV.get(), I->first);
+ I->second = 6;
+ } else {
+ ADD_FAILURE() << "Iterated through an extra value.";
+ }
+ }
+ EXPECT_EQ(2U, size);
+ EXPECT_EQ(5, VM[this->BitcastV.get()]);
+ EXPECT_EQ(6, VM[this->AddV.get()]);
+
+ size = 0;
+ // Cast to const ValueMap to avoid a bug in DenseMap's iterators.
+ const ValueMap<TypeParam*, int>& CVM = VM;
+ for (typename ValueMap<TypeParam*, int>::const_iterator I = CVM.begin(),
+ E = CVM.end(); I != E; ++I) {
+ ++size;
+ std::pair<TypeParam*, int> value = *I;
+ CompileAssertHasType<TypeParam*>(I->first);
+ if (I->second == 5) {
+ EXPECT_EQ(this->BitcastV.get(), I->first);
+ } else if (I->second == 6) {
+ EXPECT_EQ(this->AddV.get(), I->first);
+ } else {
+ ADD_FAILURE() << "Iterated through an extra value.";
+ }
+ }
+ EXPECT_EQ(2U, size);
+}
+
+TYPED_TEST(ValueMapTest, DefaultCollisionBehavior) {
+ // By default, we overwrite the old value with the replaced value.
+ ValueMap<TypeParam*, int> VM;
+ VM[this->BitcastV.get()] = 7;
+ VM[this->AddV.get()] = 9;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(0, VM.count(this->BitcastV.get()));
+ EXPECT_EQ(9, VM.lookup(this->AddV.get()));
+}
+
+TYPED_TEST(ValueMapTest, ConfiguredCollisionBehavior) {
+ // TODO: Implement this when someone needs it.
+}
+
+template<typename KeyT>
+struct LockMutex : ValueMapConfig<KeyT> {
+ struct ExtraData {
+ sys::Mutex *M;
+ bool *CalledRAUW;
+ bool *CalledDeleted;
+ };
+ static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) {
+ *Data.CalledRAUW = true;
+ EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked.";
+ }
+ static void onDeleted(const ExtraData &Data, KeyT Old) {
+ *Data.CalledDeleted = true;
+ EXPECT_FALSE(Data.M->tryacquire()) << "Mutex should already be locked.";
+ }
+ static sys::Mutex *getMutex(const ExtraData &Data) { return Data.M; }
+};
+TYPED_TEST(ValueMapTest, LocksMutex) {
+ sys::Mutex M(false); // Not recursive.
+ bool CalledRAUW = false, CalledDeleted = false;
+ typename LockMutex<TypeParam*>::ExtraData Data =
+ {&M, &CalledRAUW, &CalledDeleted};
+ ValueMap<TypeParam*, int, LockMutex<TypeParam*> > VM(Data);
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ this->AddV.reset();
+ EXPECT_TRUE(CalledRAUW);
+ EXPECT_TRUE(CalledDeleted);
+}
+
+template<typename KeyT>
+struct NoFollow : ValueMapConfig<KeyT> {
+ enum { FollowRAUW = false };
+};
+
+TYPED_TEST(ValueMapTest, NoFollowRAUW) {
+ ValueMap<TypeParam*, int, NoFollow<TypeParam*> > VM;
+ VM[this->BitcastV.get()] = 7;
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.count(this->AddV.get()));
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ this->AddV.reset();
+ EXPECT_EQ(7, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ this->BitcastV.reset();
+ EXPECT_EQ(0, VM.lookup(this->BitcastV.get()));
+ EXPECT_EQ(0, VM.lookup(this->AddV.get()));
+ EXPECT_EQ(0U, VM.size());
+}
+
+template<typename KeyT>
+struct CountOps : ValueMapConfig<KeyT> {
+ struct ExtraData {
+ int *Deletions;
+ int *RAUWs;
+ };
+
+ static void onRAUW(const ExtraData &Data, KeyT Old, KeyT New) {
+ ++*Data.RAUWs;
+ }
+ static void onDeleted(const ExtraData &Data, KeyT Old) {
+ ++*Data.Deletions;
+ }
+};
+
+TYPED_TEST(ValueMapTest, CallsConfig) {
+ int Deletions = 0, RAUWs = 0;
+ typename CountOps<TypeParam*>::ExtraData Data = {&Deletions, &RAUWs};
+ ValueMap<TypeParam*, int, CountOps<TypeParam*> > VM(Data);
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_EQ(0, Deletions);
+ EXPECT_EQ(1, RAUWs);
+ this->AddV.reset();
+ EXPECT_EQ(1, Deletions);
+ EXPECT_EQ(1, RAUWs);
+ this->BitcastV.reset();
+ EXPECT_EQ(1, Deletions);
+ EXPECT_EQ(1, RAUWs);
+}
+
+template<typename KeyT>
+struct ModifyingConfig : ValueMapConfig<KeyT> {
+ // We'll put a pointer here back to the ValueMap this key is in, so
+ // that we can modify it (and clobber *this) before the ValueMap
+ // tries to do the same modification. In previous versions of
+ // ValueMap, that exploded.
+ typedef ValueMap<KeyT, int, ModifyingConfig<KeyT> > **ExtraData;
+
+ static void onRAUW(ExtraData Map, KeyT Old, KeyT New) {
+ (*Map)->erase(Old);
+ }
+ static void onDeleted(ExtraData Map, KeyT Old) {
+ (*Map)->erase(Old);
+ }
+};
+TYPED_TEST(ValueMapTest, SurvivesModificationByConfig) {
+ ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > *MapAddress;
+ ValueMap<TypeParam*, int, ModifyingConfig<TypeParam*> > VM(&MapAddress);
+ MapAddress = &VM;
+ // Now the ModifyingConfig can modify the Map inside a callback.
+ VM[this->BitcastV.get()] = 7;
+ this->BitcastV->replaceAllUsesWith(this->AddV.get());
+ EXPECT_FALSE(VM.count(this->BitcastV.get()));
+ EXPECT_FALSE(VM.count(this->AddV.get()));
+ VM[this->AddV.get()] = 7;
+ this->AddV.reset();
+ EXPECT_FALSE(VM.count(this->AddV.get()));
+}
+
+}
diff --git a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
index 89a4be70be20..f0c491fba5b3 100644
--- a/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
+++ b/unittests/ExecutionEngine/JIT/JITMemoryManagerTest.cpp
@@ -32,37 +32,36 @@ TEST(JITMemoryManagerTest, NoAllocations) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
uintptr_t size;
- uint8_t *start;
std::string Error;
// Allocate the functions.
OwningPtr<Function> F1(makeFakeFunction());
size = 1024;
- start = MemMgr->startFunctionBody(F1.get(), size);
- memset(start, 0xFF, 1024);
- MemMgr->endFunctionBody(F1.get(), start, start + 1024);
+ uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
+ memset(FunctionBody1, 0xFF, 1024);
+ MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F2(makeFakeFunction());
size = 1024;
- start = MemMgr->startFunctionBody(F2.get(), size);
- memset(start, 0xFF, 1024);
- MemMgr->endFunctionBody(F2.get(), start, start + 1024);
+ uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
+ memset(FunctionBody2, 0xFF, 1024);
+ MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F3(makeFakeFunction());
size = 1024;
- start = MemMgr->startFunctionBody(F3.get(), size);
- memset(start, 0xFF, 1024);
- MemMgr->endFunctionBody(F3.get(), start, start + 1024);
+ uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
+ memset(FunctionBody3, 0xFF, 1024);
+ MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + 1024);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Deallocate them out of order, in case that matters.
- MemMgr->deallocateMemForFunction(F2.get());
+ MemMgr->deallocateFunctionBody(FunctionBody2);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F1.get());
+ MemMgr->deallocateFunctionBody(FunctionBody1);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F3.get());
+ MemMgr->deallocateFunctionBody(FunctionBody3);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
}
@@ -72,7 +71,6 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
OwningPtr<JITMemoryManager> MemMgr(
JITMemoryManager::CreateDefaultMemManager());
uintptr_t size;
- uint8_t *start;
std::string Error;
// Big functions are a little less than the largest block size.
@@ -83,26 +81,26 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
// Allocate big functions
OwningPtr<Function> F1(makeFakeFunction());
size = bigFuncSize;
- start = MemMgr->startFunctionBody(F1.get(), size);
+ uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
ASSERT_LE(bigFuncSize, size);
- memset(start, 0xFF, bigFuncSize);
- MemMgr->endFunctionBody(F1.get(), start, start + bigFuncSize);
+ memset(FunctionBody1, 0xFF, bigFuncSize);
+ MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F2(makeFakeFunction());
size = bigFuncSize;
- start = MemMgr->startFunctionBody(F2.get(), size);
+ uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
ASSERT_LE(bigFuncSize, size);
- memset(start, 0xFF, bigFuncSize);
- MemMgr->endFunctionBody(F2.get(), start, start + bigFuncSize);
+ memset(FunctionBody2, 0xFF, bigFuncSize);
+ MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F3(makeFakeFunction());
size = bigFuncSize;
- start = MemMgr->startFunctionBody(F3.get(), size);
+ uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
ASSERT_LE(bigFuncSize, size);
- memset(start, 0xFF, bigFuncSize);
- MemMgr->endFunctionBody(F3.get(), start, start + bigFuncSize);
+ memset(FunctionBody3, 0xFF, bigFuncSize);
+ MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + bigFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Check that each large function took it's own slab.
@@ -111,43 +109,46 @@ TEST(JITMemoryManagerTest, TestCodeAllocation) {
// Allocate small functions
OwningPtr<Function> F4(makeFakeFunction());
size = smallFuncSize;
- start = MemMgr->startFunctionBody(F4.get(), size);
+ uint8_t *FunctionBody4 = MemMgr->startFunctionBody(F4.get(), size);
ASSERT_LE(smallFuncSize, size);
- memset(start, 0xFF, smallFuncSize);
- MemMgr->endFunctionBody(F4.get(), start, start + smallFuncSize);
+ memset(FunctionBody4, 0xFF, smallFuncSize);
+ MemMgr->endFunctionBody(F4.get(), FunctionBody4,
+ FunctionBody4 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F5(makeFakeFunction());
size = smallFuncSize;
- start = MemMgr->startFunctionBody(F5.get(), size);
+ uint8_t *FunctionBody5 = MemMgr->startFunctionBody(F5.get(), size);
ASSERT_LE(smallFuncSize, size);
- memset(start, 0xFF, smallFuncSize);
- MemMgr->endFunctionBody(F5.get(), start, start + smallFuncSize);
+ memset(FunctionBody5, 0xFF, smallFuncSize);
+ MemMgr->endFunctionBody(F5.get(), FunctionBody5,
+ FunctionBody5 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
OwningPtr<Function> F6(makeFakeFunction());
size = smallFuncSize;
- start = MemMgr->startFunctionBody(F6.get(), size);
+ uint8_t *FunctionBody6 = MemMgr->startFunctionBody(F6.get(), size);
ASSERT_LE(smallFuncSize, size);
- memset(start, 0xFF, smallFuncSize);
- MemMgr->endFunctionBody(F6.get(), start, start + smallFuncSize);
+ memset(FunctionBody6, 0xFF, smallFuncSize);
+ MemMgr->endFunctionBody(F6.get(), FunctionBody6,
+ FunctionBody6 + smallFuncSize);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
// Check that the small functions didn't allocate any new slabs.
EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
// Deallocate them out of order, in case that matters.
- MemMgr->deallocateMemForFunction(F2.get());
+ MemMgr->deallocateFunctionBody(FunctionBody2);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F1.get());
+ MemMgr->deallocateFunctionBody(FunctionBody1);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F4.get());
+ MemMgr->deallocateFunctionBody(FunctionBody4);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F3.get());
+ MemMgr->deallocateFunctionBody(FunctionBody3);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F5.get());
+ MemMgr->deallocateFunctionBody(FunctionBody5);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
- MemMgr->deallocateMemForFunction(F6.get());
+ MemMgr->deallocateFunctionBody(FunctionBody6);
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
}
diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp
index d7aaea7134fc..8f9b65ab0bad 100644
--- a/unittests/ExecutionEngine/JIT/JITTest.cpp
+++ b/unittests/ExecutionEngine/JIT/JITTest.cpp
@@ -166,7 +166,7 @@ TEST_F(JITTest, FarCallToKnownFunction) {
EXPECT_EQ(8, TestFunctionPtr());
}
-#if !defined(__arm__) && !defined(__ppc__)
+#if !defined(__arm__) && !defined(__powerpc__) && !defined(__ppc__)
// Test a function C which calls A and B which call each other.
TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
TheJIT->DisableLazyCompilation();
@@ -221,7 +221,6 @@ TEST_F(JITTest, NonLazyCompilationStillNeedsStubs) {
F1Ptr();
}
-#endif
// Regression test for PR5162. This used to trigger an AssertingVH inside the
// JIT's Function to stub mapping.
@@ -263,6 +262,7 @@ TEST_F(JITTest, NonLazyLeaksNoStubs) {
EXPECT_EQ(Func2->getNumUses(), 0u);
Func2->eraseFromParent();
}
+#endif
// This code is copied from JITEventListenerTest, but it only runs once for all
// the tests in this directory. Everything seems fine, but that's strange
diff --git a/unittests/Support/raw_ostream_test.cpp b/unittests/Support/raw_ostream_test.cpp
index bd2e95cbb531..2b797b43666b 100644
--- a/unittests/Support/raw_ostream_test.cpp
+++ b/unittests/Support/raw_ostream_test.cpp
@@ -127,4 +127,20 @@ TEST(raw_ostreamTest, TinyBuffer) {
EXPECT_EQ("hello1world", OS.str());
}
+TEST(raw_ostreamTest, WriteEscaped) {
+ std::string Str;
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("hi");
+ EXPECT_EQ("hi", Str);
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("\\\t\n\"");
+ EXPECT_EQ("\\\\\\t\\n\\\"", Str);
+
+ Str = "";
+ raw_string_ostream(Str).write_escaped("\1\10\200");
+ EXPECT_EQ("\\001\\010\\200", Str);
+}
+
}