|
8 | 8 | // Official repository: https://github.com/cppalliance/mrdox
|
9 | 9 | //
|
10 | 10 |
|
11 |
| -#include <mrdox/Corpus.hpp> |
12 |
| -#include <mrdox/Reporter.hpp> |
13 |
| -#include <mrdox/Generator.hpp> |
| 11 | +#include "Tester.hpp" |
14 | 12 | #include <clang/Tooling/AllTUsExecution.h>
|
15 |
| -#include <clang/Tooling/CompilationDatabase.h> |
16 |
| -#include <clang/Tooling/StandaloneExecution.h> |
17 |
| -#include <llvm/ADT/SmallString.h> |
18 |
| -#include <llvm/ADT/Twine.h> |
19 |
| -#include <llvm/Support/Program.h> |
20 | 13 | #include <llvm/Support/Signals.h>
|
21 |
| -#include <llvm/Support/ThreadPool.h> |
22 |
| -#include <string_view> |
23 |
| -#include <vector> |
24 |
| - |
25 |
| -// Each test comes as a pair of files. |
26 |
| -// A .cpp file containing valid declarations, |
27 |
| -// and a .xml file containing the expected output |
28 |
| -// of the XML generator, which must match exactly. |
29 | 14 |
|
30 | 15 | namespace clang {
|
31 | 16 | namespace mrdox {
|
32 | 17 |
|
33 |
| -//------------------------------------------------ |
34 |
| - |
35 |
| -/** Compilation database for a single .cpp file. |
36 |
| -*/ |
37 |
| -class SingleFile |
38 |
| - : public tooling::CompilationDatabase |
39 |
| -{ |
40 |
| - std::vector<tooling::CompileCommand> cc_; |
41 |
| - |
42 |
| -public: |
43 |
| - SingleFile( |
44 |
| - llvm::StringRef dir, |
45 |
| - llvm::StringRef file, |
46 |
| - llvm::StringRef output) |
47 |
| - { |
48 |
| - std::vector<std::string> cmds; |
49 |
| - cmds.emplace_back("clang"); |
50 |
| - cmds.emplace_back(file); |
51 |
| - cc_.emplace_back( |
52 |
| - dir, |
53 |
| - file, |
54 |
| - std::move(cmds), |
55 |
| - output); |
56 |
| - cc_.back().Heuristic = "unit test"; |
57 |
| - } |
58 |
| - |
59 |
| - std::vector<tooling::CompileCommand> |
60 |
| - getCompileCommands( |
61 |
| - llvm::StringRef FilePath) const override |
62 |
| - { |
63 |
| - if(! FilePath.equals(cc_.front().Filename)) |
64 |
| - return {}; |
65 |
| - return { cc_.front() }; |
66 |
| - } |
67 |
| - |
68 |
| - std::vector<std::string> |
69 |
| - getAllFiles() const override |
70 |
| - { |
71 |
| - return { cc_.front().Filename }; |
72 |
| - } |
73 |
| - |
74 |
| - std::vector<tooling::CompileCommand> |
75 |
| - getAllCompileCommands() const override |
76 |
| - { |
77 |
| - return { cc_.front() }; |
78 |
| - } |
79 |
| -}; |
80 |
| - |
81 |
| -//------------------------------------------------ |
82 |
| - |
83 |
| -struct Tester |
84 |
| -{ |
85 |
| - Config const& config_; |
86 |
| - std::unique_ptr<Generator> xmlGen; |
87 |
| - std::unique_ptr<Generator> adocGen; |
88 |
| - Reporter& R_; |
89 |
| - |
90 |
| - explicit |
91 |
| - Tester( |
92 |
| - Config const& config, |
93 |
| - Reporter &R) |
94 |
| - : config_(config) |
95 |
| - , xmlGen(makeXMLGenerator()) |
96 |
| - , adocGen(makeAsciidocGenerator()) |
97 |
| - , R_(R) |
98 |
| - { |
99 |
| - } |
100 |
| - |
101 |
| - bool |
102 |
| - testDirectory( |
103 |
| - llvm::SmallString<340> dirPath, |
104 |
| - llvm::ThreadPool& threadPool) |
105 |
| - { |
106 |
| - namespace fs = llvm::sys::fs; |
107 |
| - namespace path = llvm::sys::path; |
108 |
| - |
109 |
| - std::error_code ec; |
110 |
| - llvm::SmallString<32> outputPath; |
111 |
| - path::remove_dots(dirPath, true); |
112 |
| - fs::directory_iterator const end{}; |
113 |
| - |
114 |
| - fs::directory_iterator iter(dirPath, ec, false); |
115 |
| - if(ec) |
116 |
| - { |
117 |
| - R_.failed("visitDirectory", ec); |
118 |
| - return false; |
119 |
| - } |
120 |
| - |
121 |
| - while(iter != end) |
122 |
| - { |
123 |
| - if(iter->type() == fs::file_type::directory_file) |
124 |
| - { |
125 |
| - if(! testDirectory(llvm::StringRef(iter->path()), threadPool)) |
126 |
| - return false; |
127 |
| - } |
128 |
| - else if( |
129 |
| - iter->type() == fs::file_type::regular_file && |
130 |
| - path::extension(iter->path()).equals_insensitive(".cpp")) |
131 |
| - { |
132 |
| - outputPath = iter->path(); |
133 |
| - path::replace_extension(outputPath, "xml"); |
134 |
| - threadPool.async([this, |
135 |
| - dirPath, |
136 |
| - inputPath = llvm::SmallString<0>(iter->path()), |
137 |
| - outputPath = llvm::SmallString<340>(outputPath)]() mutable |
138 |
| - { |
139 |
| - SingleFile db(dirPath, inputPath, outputPath); |
140 |
| - tooling::StandaloneToolExecutor ex(db, { std::string(inputPath) }); |
141 |
| - auto corpus = Corpus::build(ex, config_, R_); |
142 |
| - if(corpus) |
143 |
| - performTest(*corpus, inputPath, outputPath); |
144 |
| - }); |
145 |
| - } |
146 |
| - else |
147 |
| - { |
148 |
| - // we don't handle this type |
149 |
| - } |
150 |
| - iter.increment(ec); |
151 |
| - if(ec) |
152 |
| - { |
153 |
| - R_.failed("fs::directory_iterator::increment", ec); |
154 |
| - return false; |
155 |
| - } |
156 |
| - } |
157 |
| - return true; |
158 |
| - } |
159 |
| - |
160 |
| - void |
161 |
| - performTest( |
162 |
| - Corpus& corpus, |
163 |
| - llvm::StringRef inputPath, |
164 |
| - llvm::SmallVectorImpl<char>& outputPathStr) |
165 |
| - { |
166 |
| - namespace fs = llvm::sys::fs; |
167 |
| - namespace path = llvm::sys::path; |
168 |
| - |
169 |
| - llvm::StringRef outputPath; |
170 |
| - outputPath = { outputPathStr.data(), outputPathStr.size() }; |
171 |
| - |
172 |
| - std::string xmlString; |
173 |
| - if(! xmlGen->buildString(xmlString, corpus, config_, R_)) |
174 |
| - { |
175 |
| - R_.testFailed(); |
176 |
| - return; |
177 |
| - } |
178 |
| - std::error_code ec; |
179 |
| - fs::file_status stat; |
180 |
| - ec = fs::status(outputPathStr, stat, false); |
181 |
| - if(ec == std::errc::no_such_file_or_directory) |
182 |
| - { |
183 |
| - // create the xml file and write to it |
184 |
| - llvm::raw_fd_ostream os(outputPath, ec, llvm::sys::fs::OF_None); |
185 |
| - if(! ec) |
186 |
| - { |
187 |
| - os << xmlString; |
188 |
| - } |
189 |
| - else |
190 |
| - { |
191 |
| - llvm::errs() << |
192 |
| - "Writing \"" << outputPath << "\" failed: " << |
193 |
| - ec.message() << "\n"; |
194 |
| - R_.testFailed(); |
195 |
| - } |
196 |
| - } |
197 |
| - else if(ec) |
198 |
| - { |
199 |
| - R_.failed("fs::status", ec); |
200 |
| - return; |
201 |
| - } |
202 |
| - if(stat.type() != fs::file_type::regular_file) |
203 |
| - { |
204 |
| - R_.failed("'%s' is not a regular file", outputPath); |
205 |
| - return; |
206 |
| - } |
207 |
| - auto bufferResult = llvm::MemoryBuffer::getFile(outputPath, false); |
208 |
| - if(! bufferResult) |
209 |
| - { |
210 |
| - R_.failed("MemoryBuffer::getFile", bufferResult); |
211 |
| - return; |
212 |
| - } |
213 |
| - std::string_view got(bufferResult->get()->getBuffer()); |
214 |
| - if(xmlString != bufferResult->get()->getBuffer()) |
215 |
| - { |
216 |
| - R_.errs( |
217 |
| - "File: \"", inputPath, "\" failed.\n", |
218 |
| - "Expected:\n", |
219 |
| - bufferResult->get()->getBuffer(), "\n", |
220 |
| - "Got:\n", xmlString, "\n"); |
221 |
| - R_.testFailed(); |
222 |
| - } |
223 |
| - |
224 |
| - if(adocGen) |
225 |
| - { |
226 |
| - path::replace_extension(outputPathStr, adocGen->extension()); |
227 |
| - outputPath = { outputPathStr.data(), outputPathStr.size() }; |
228 |
| - adocGen->buildOne(outputPath, corpus, config_, R_); |
229 |
| - } |
230 |
| - } |
231 |
| -}; |
232 |
| - |
233 |
| -//------------------------------------------------ |
234 |
| - |
235 | 18 | void
|
236 | 19 | testMain(
|
237 | 20 | int argc, const char* const* argv,
|
@@ -263,7 +46,8 @@ testMain(
|
263 | 46 | llvm::ThreadPool threadPool(
|
264 | 47 | llvm::hardware_concurrency(
|
265 | 48 | tooling::ExecutorConcurrency));
|
266 |
| - if(! tester.testDirectory(llvm::StringRef(argv[i]), threadPool)) |
| 49 | + if(! tester.checkDirRecursively( |
| 50 | + llvm::StringRef(argv[i]), threadPool)) |
267 | 51 | break;
|
268 | 52 | threadPool.wait();
|
269 | 53 | }
|
|
0 commit comments