Skip to content

Commit e60f2cb

Browse files
[libc] add tests to WrapperGen
This adds an initial test that can serve as a basis for other tests on wrappergen. Reviewed By: sivachandra Differential Revision: https://reviews.llvm.org/D92137
1 parent 9cf4f49 commit e60f2cb

File tree

5 files changed

+296
-0
lines changed

5 files changed

+296
-0
lines changed

libc/test/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
add_subdirectory(FPUtil)
22
add_subdirectory(CPP)
3+
add_subdirectory(tools)

libc/test/utils/tools/CMakeLists.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
add_custom_target(libc-tool-util-tests)
2+
3+
function(add_libc_tool_unittest target_name)
4+
5+
cmake_parse_arguments(
6+
"LIBC_TOOL_UNITTEST"
7+
"" # No optional arguments
8+
"" # Single value arguments
9+
"SRCS;DEPENDS;ARGS" # Multi-value arguments
10+
${ARGN}
11+
)
12+
13+
add_executable(${target_name}
14+
EXCLUDE_FROM_ALL
15+
${LIBC_TOOL_UNITTEST_SRCS}
16+
)
17+
target_link_libraries(${target_name}
18+
PRIVATE
19+
gtest_main
20+
gtest
21+
${LIBC_TOOL_UNITTEST_DEPENDS}
22+
)
23+
24+
add_custom_command(
25+
TARGET ${target_name}
26+
POST_BUILD
27+
COMMAND $<TARGET_FILE:${target_name}>
28+
${LIBC_TOOL_UNITTEST_ARGS}
29+
)
30+
add_dependencies(libc-tool-util-tests ${target_name})
31+
32+
target_compile_options(${target_name} PUBLIC -fno-rtti)
33+
target_link_libraries(${target_name} PRIVATE LLVMSupport)
34+
endfunction()
35+
36+
add_subdirectory(WrapperGen)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
add_libc_tool_unittest( wrappergen_test
2+
SRCS
3+
wrappergen_test.cpp
4+
ARGS
5+
--path=${LIBC_SOURCE_DIR}
6+
--tool=${CMAKE_BINARY_DIR}/bin/libc-wrappergen
7+
--api=${LIBC_SOURCE_DIR}/test/utils/tools/WrapperGen/testapi.td
8+
)
9+
10+
add_dependencies(wrappergen_test libc-wrappergen)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include "spec/spec.td"
2+
include "spec/stdc.td"
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
//===-- Unittests for WrapperGen ------------------------------------------===//
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-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/ADT/SmallString.h"
10+
#include "llvm/ADT/StringRef.h"
11+
#include "llvm/ADT/Twine.h"
12+
#include "llvm/Support/CommandLine.h"
13+
#include "llvm/Support/Error.h"
14+
#include "llvm/Support/FileSystem.h"
15+
#include "llvm/Support/MemoryBuffer.h"
16+
#include "llvm/Support/Program.h"
17+
#include "llvm/Support/raw_ostream.h"
18+
#include "gmock/gmock.h"
19+
#include "gtest/gtest.h"
20+
#include <unistd.h>
21+
22+
llvm::cl::opt<std::string>
23+
LibcPath("path", llvm::cl::desc("Path to the top level libc directory."),
24+
llvm::cl::value_desc("<path to libc>"), llvm::cl::Required);
25+
llvm::cl::opt<std::string>
26+
ToolPath("tool", llvm::cl::desc("Path to the tool executable."),
27+
llvm::cl::value_desc("<path to tool>"), llvm::cl::Required);
28+
llvm::cl::opt<std::string>
29+
APIPath("api",
30+
llvm::cl::desc("Path to the api tablegen file used by the tests."),
31+
llvm::cl::value_desc("<path to testapi.td>"), llvm::cl::Required);
32+
33+
class WrapperGenTest : public ::testing::Test {
34+
public:
35+
std::string IncludeArg;
36+
std::string APIArg;
37+
llvm::StringRef ProgPath;
38+
llvm::Expected<llvm::sys::fs::TempFile> STDOutFile =
39+
llvm::sys::fs::TempFile::create("wrappergen-stdout-%%-%%-%%-%%.txt");
40+
llvm::Expected<llvm::sys::fs::TempFile> STDErrFile =
41+
llvm::sys::fs::TempFile::create("wrappergen-stderr-%%-%%-%%-%%.txt");
42+
43+
protected:
44+
void SetUp() override {
45+
IncludeArg = "-I=";
46+
IncludeArg.append(LibcPath);
47+
APIArg = APIPath;
48+
ProgPath = llvm::StringRef(ToolPath);
49+
50+
if (!STDOutFile) {
51+
llvm::errs() << "Error: " << llvm::toString(STDOutFile.takeError())
52+
<< "\n";
53+
llvm::report_fatal_error(
54+
"Temporary file failed to initialize for libc-wrappergen tests.");
55+
}
56+
if (!STDErrFile) {
57+
llvm::errs() << "Error: " << llvm::toString(STDErrFile.takeError())
58+
<< "\n";
59+
llvm::report_fatal_error(
60+
"Temporary file failed to initialize for libc-wrappergen tests.");
61+
}
62+
}
63+
void TearDown() override {
64+
llvm::consumeError(STDOutFile.get().discard());
65+
llvm::consumeError(STDErrFile.get().discard());
66+
}
67+
};
68+
69+
TEST_F(WrapperGenTest, RunWrapperGenAndGetNoErrors) {
70+
llvm::Optional<llvm::StringRef> Redirects[] = {
71+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
72+
llvm::StringRef(STDErrFile.get().TmpName)};
73+
74+
llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg),
75+
llvm::StringRef(APIArg), "--name", "strlen"};
76+
77+
int ExitCode =
78+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
79+
80+
EXPECT_EQ(ExitCode, 0);
81+
82+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
83+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
84+
ASSERT_EQ(STDErrOutput, "");
85+
}
86+
87+
TEST_F(WrapperGenTest, RunWrapperGenOnStrlen) {
88+
llvm::Optional<llvm::StringRef> Redirects[] = {
89+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
90+
llvm::StringRef(STDErrFile.get().TmpName)};
91+
92+
llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg),
93+
llvm::StringRef(APIArg), "--name", "strlen"};
94+
95+
int ExitCode =
96+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
97+
98+
EXPECT_EQ(ExitCode, 0);
99+
100+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
101+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
102+
103+
ASSERT_EQ(STDErrOutput, "");
104+
105+
auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName);
106+
std::string STDOutOutput = STDOutOrError.get()->getBuffer().str();
107+
108+
ASSERT_EQ(STDOutOutput, "#include \"src/string/strlen.h\"\n"
109+
"extern \"C\" size_t strlen(const char * __arg0) {\n"
110+
" return __llvm_libc::strlen(__arg0);\n"
111+
"}\n");
112+
// TODO:(michaelrj) Figure out how to make this output comparison
113+
// less brittle. Currently it's just comparing the output of the program
114+
// to an exact string, this means that even a small formatting change
115+
// would break this test.
116+
}
117+
118+
TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithAliasee) {
119+
llvm::Optional<llvm::StringRef> Redirects[] = {
120+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
121+
llvm::StringRef(STDErrFile.get().TmpName)};
122+
123+
llvm::StringRef ArgV[] = {ProgPath,
124+
llvm::StringRef(IncludeArg),
125+
llvm::StringRef(APIArg),
126+
"--aliasee",
127+
"STRLEN_ALIAS",
128+
"--name",
129+
"strlen"};
130+
131+
int ExitCode =
132+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
133+
134+
EXPECT_EQ(ExitCode, 0);
135+
136+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
137+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
138+
139+
ASSERT_EQ(STDErrOutput, "");
140+
141+
auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName);
142+
std::string STDOutOutput = STDOutOrError.get()->getBuffer().str();
143+
144+
ASSERT_EQ(STDOutOutput, "extern \"C\" size_t strlen(const char * __arg0) "
145+
"__attribute__((alias(\"STRLEN_ALIAS\")));\n");
146+
// TODO:(michaelrj) Figure out how to make this output comparison
147+
// less brittle. Currently it's just comparing the output of the program
148+
// to an exact string, this means that even a small formatting change
149+
// would break this test.
150+
}
151+
152+
/////////////////////////////////////////////////////////////////////
153+
// BAD INPUT TESTS
154+
// all of the tests after this point are testing inputs that should
155+
// return errors
156+
/////////////////////////////////////////////////////////////////////
157+
158+
TEST_F(WrapperGenTest,
159+
RunWrapperGenOnStrlenWithAliaseeAndAliaseeFileWhichIsError) {
160+
llvm::Optional<llvm::StringRef> Redirects[] = {
161+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
162+
llvm::StringRef(STDErrFile.get().TmpName)};
163+
164+
llvm::StringRef ArgV[] = {ProgPath,
165+
llvm::StringRef(IncludeArg),
166+
llvm::StringRef(APIArg),
167+
"--aliasee",
168+
"STRLEN_ALIAS",
169+
"--aliasee-file",
170+
"STRLEN_ALIAS_FILE",
171+
"--name",
172+
"strlen"};
173+
174+
int ExitCode =
175+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
176+
177+
EXPECT_EQ(ExitCode, 1);
178+
179+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
180+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
181+
182+
ASSERT_EQ(STDErrOutput, "error: The options 'aliasee' and 'aliasee-file' "
183+
"cannot be specified simultaniously.\n");
184+
185+
auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName);
186+
std::string STDOutOutput = STDOutOrError.get()->getBuffer().str();
187+
188+
ASSERT_EQ(STDOutOutput, "");
189+
}
190+
191+
TEST_F(WrapperGenTest, RunWrapperGenOnBadFuncName) {
192+
llvm::Optional<llvm::StringRef> Redirects[] = {
193+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
194+
llvm::StringRef(STDErrFile.get().TmpName)};
195+
196+
llvm::StringRef BadFuncName = "FAKE_TEST_FUNC";
197+
198+
llvm::StringRef ArgV[] = {ProgPath, llvm::StringRef(IncludeArg),
199+
llvm::StringRef(APIArg), "--name", BadFuncName};
200+
201+
int ExitCode =
202+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
203+
204+
EXPECT_EQ(ExitCode, 1);
205+
206+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
207+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
208+
209+
ASSERT_EQ(STDErrOutput, ("error: Function '" + BadFuncName +
210+
"' not found in any standard spec.\n")
211+
.str());
212+
213+
auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName);
214+
std::string STDOutOutput = STDOutOrError.get()->getBuffer().str();
215+
216+
ASSERT_EQ(STDOutOutput, "");
217+
}
218+
219+
TEST_F(WrapperGenTest, RunWrapperGenOnStrlenWithBadAliaseeFile) {
220+
llvm::Optional<llvm::StringRef> Redirects[] = {
221+
llvm::None, llvm::StringRef(STDOutFile.get().TmpName),
222+
llvm::StringRef(STDErrFile.get().TmpName)};
223+
224+
llvm::StringRef BadAliaseeFileName = "FILE_THAT_DOESNT_EXIST.txt";
225+
226+
llvm::StringRef ArgV[] = {
227+
ProgPath, llvm::StringRef(IncludeArg), llvm::StringRef(APIArg),
228+
"--aliasee-file", BadAliaseeFileName, "--name",
229+
"strlen"};
230+
231+
int ExitCode =
232+
llvm::sys::ExecuteAndWait(ProgPath, ArgV, llvm::None, Redirects);
233+
234+
EXPECT_EQ(ExitCode, 1);
235+
236+
auto STDErrOrError = llvm::MemoryBuffer::getFile(STDErrFile.get().TmpName);
237+
std::string STDErrOutput = STDErrOrError.get()->getBuffer().str();
238+
239+
ASSERT_EQ(STDErrOutput, ("error: Unable to read the aliasee file " +
240+
BadAliaseeFileName + "\n")
241+
.str());
242+
243+
auto STDOutOrError = llvm::MemoryBuffer::getFile(STDOutFile.get().TmpName);
244+
std::string STDOutOutput = STDOutOrError.get()->getBuffer().str();
245+
246+
ASSERT_EQ(STDOutOutput, "");
247+
}

0 commit comments

Comments
 (0)