1 //===- unittests/libclang/TestUtils.h -------------------------------------===//
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-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_CLANG_TEST_TESTUTILS_H
10 #define LLVM_CLANG_TEST_TESTUTILS_H
12 #include "clang-c/Index.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/Path.h"
17 #include "gtest/gtest.h"
24 class LibclangParseTest
: public ::testing::Test
{
25 typedef std::unique_ptr
<std::string
> fixed_addr_string
;
26 std::map
<fixed_addr_string
, fixed_addr_string
> UnsavedFileContents
;
28 // std::greater<> to remove files before their parent dirs in TearDown().
29 std::set
<std::string
, std::greater
<>> FilesAndDirsToRemove
;
31 bool RemoveTestDirRecursivelyDuringTeardown
= false;
33 CXTranslationUnit ClangTU
;
35 std::vector
<CXUnsavedFile
> UnsavedFiles
;
37 void SetUp() override
{
38 llvm::SmallString
<256> Dir
;
39 ASSERT_FALSE(llvm::sys::fs::createUniqueDirectory("libclang-test", Dir
));
40 TestDir
= std::string(Dir
.str());
41 TUFlags
= CXTranslationUnit_DetailedPreprocessingRecord
|
42 clang_defaultEditingTranslationUnitOptions();
46 void TearDown() override
{
47 clang_disposeTranslationUnit(ClangTU
);
48 clang_disposeIndex(Index
);
50 namespace fs
= llvm::sys::fs
;
51 for (const std::string
&Path
: FilesAndDirsToRemove
)
52 EXPECT_FALSE(fs::remove(Path
, /*IgnoreNonExisting=*/false));
53 if (RemoveTestDirRecursivelyDuringTeardown
)
54 EXPECT_FALSE(fs::remove_directories(TestDir
, /*IgnoreErrors=*/false));
56 EXPECT_FALSE(fs::remove(TestDir
, /*IgnoreNonExisting=*/false));
58 void WriteFile(std::string
&Filename
, const std::string
&Contents
) {
59 if (!llvm::sys::path::is_absolute(Filename
)) {
60 llvm::SmallString
<256> Path(TestDir
);
61 namespace path
= llvm::sys::path
;
62 for (auto FileI
= path::begin(Filename
), FileEnd
= path::end(Filename
);
63 FileI
!= FileEnd
; ++FileI
) {
64 ASSERT_NE(*FileI
, ".");
65 path::append(Path
, *FileI
);
66 FilesAndDirsToRemove
.emplace(Path
.str());
68 Filename
= std::string(Path
.str());
70 llvm::sys::fs::create_directories(llvm::sys::path::parent_path(Filename
));
71 std::ofstream
OS(Filename
);
75 void MapUnsavedFile(std::string Filename
, const std::string
&Contents
) {
76 if (!llvm::sys::path::is_absolute(Filename
)) {
77 llvm::SmallString
<256> Path(TestDir
);
78 llvm::sys::path::append(Path
, Filename
);
79 Filename
= std::string(Path
.str());
81 auto it
= UnsavedFileContents
.insert(std::make_pair(
82 fixed_addr_string(new std::string(Filename
)),
83 fixed_addr_string(new std::string(Contents
))));
84 UnsavedFiles
.push_back({
85 it
.first
->first
->c_str(), // filename
86 it
.first
->second
->c_str(), // contents
87 it
.first
->second
->size() // length
91 void Traverse(const CXCursor
&cursor
, const F
&TraversalFunctor
) {
92 std::reference_wrapper
<const F
> FunctorRef
= std::cref(TraversalFunctor
);
93 clang_visitChildren(cursor
,
94 &TraverseStateless
<std::reference_wrapper
<const F
>>,
98 template <typename F
> void Traverse(const F
&TraversalFunctor
) {
99 Traverse(clang_getTranslationUnitCursor(ClangTU
), TraversalFunctor
);
102 static std::string
fromCXString(CXString cx_string
) {
103 std::string string
{clang_getCString(cx_string
)};
104 clang_disposeString(cx_string
);
109 virtual void CreateIndex() { Index
= clang_createIndex(0, 0); }
112 template<typename TState
>
113 static CXChildVisitResult
TraverseStateless(CXCursor cx
, CXCursor parent
,
115 TState
*State
= static_cast<TState
*>(data
);
116 return State
->get()(cx
, parent
);
120 #endif // LLVM_CLANG_TEST_TESTUTILS_H