authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-19 16:59:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-19 16:59:20-04:00
log1ff73a8e69a09b3bc993cffb755cc2ca98c7040b
treee01062057af7af8e7b144666b106f110b8e2fc1c
parentd12f1f5b4954d893111c05420060354537a1485c

convert parseh tests to zig build system


5 files changed, 451 insertions(+), 494 deletions(-)

CMakeLists.txt+1-16
...@@ -63,14 +63,6 @@ set(ZIG_SOURCES...@@ -63,14 +63,6 @@ set(ZIG_SOURCES
63 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"63 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
64)64)
6565
66set(TEST_SOURCES
67 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
68 "${CMAKE_SOURCE_DIR}/src/util.cpp"
69 "${CMAKE_SOURCE_DIR}/src/os.cpp"
70 "${CMAKE_SOURCE_DIR}/src/error.cpp"
71 "${CMAKE_SOURCE_DIR}/test/run_tests.cpp"
72)
73
74set(C_HEADERS66set(C_HEADERS
75 "${CMAKE_SOURCE_DIR}/c_headers/Intrin.h"67 "${CMAKE_SOURCE_DIR}/c_headers/Intrin.h"
76 "${CMAKE_SOURCE_DIR}/c_headers/__stddef_max_align_t.h"68 "${CMAKE_SOURCE_DIR}/c_headers/__stddef_max_align_t.h"
...@@ -248,19 +240,12 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${Z...@@ -248,19 +240,12 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${Z
248install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")240install(FILES "${CMAKE_SOURCE_DIR}/std/special/zigrt.zig" DESTINATION "${ZIG_STD_DEST}/special")
249install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")241install(FILES "${CMAKE_SOURCE_DIR}/std/target.zig" DESTINATION "${ZIG_STD_DEST}")
250242
251add_executable(run_tests ${TEST_SOURCES})
252target_link_libraries(run_tests)
253set_target_properties(run_tests PROPERTIES
254 COMPILE_FLAGS ${EXE_CFLAGS}
255 LINK_FLAGS ${EXE_LDFLAGS}
256)
257
258if (ZIG_TEST_COVERAGE)243if (ZIG_TEST_COVERAGE)
259 add_custom_target(coverage244 add_custom_target(coverage
260 DEPENDS run_tests245 DEPENDS run_tests
261 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}246 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
262 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1247 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1
263 COMMAND ./run_tests248 COMMAND ./zig build --build-file ../build.zig test
264 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1249 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1
265 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1250 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1
266 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1251 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1
build.zig+1
...@@ -44,4 +44,5 @@ pub fn build(b: &Builder) {...@@ -44,4 +44,5 @@ pub fn build(b: &Builder) {
44 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));44 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
45 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));45 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
46 test_step.dependOn(tests.addDebugSafetyTests(b, test_filter));46 test_step.dependOn(tests.addDebugSafetyTests(b, test_filter));
47 test_step.dependOn(tests.addParseHTests(b, test_filter));
47}48}
test/parseh.zig created+243
...@@ -0,0 +1,243 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.ParseHContext) {
4 cases.addAllowWarnings("simple data types",
5 \\#include <stdint.h>
6 \\int foo(char a, unsigned char b, signed char c);
7 \\int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
8 \\void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
9 \\void baz(int8_t a, int16_t b, int32_t c, int64_t d);
10 ,
11 \\pub extern fn foo(a: u8, b: u8, c: i8) -> c_int;
12 ,
13 \\pub extern fn bar(a: u8, b: u16, c: u32, d: u64);
14 ,
15 \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64);
16 );
17
18 cases.add("noreturn attribute",
19 \\void foo(void) __attribute__((noreturn));
20 ,
21 \\pub extern fn foo() -> noreturn;
22 );
23
24 cases.add("enums",
25 \\enum Foo {
26 \\ FooA,
27 \\ FooB,
28 \\ Foo1,
29 \\};
30 ,
31 \\pub const enum_Foo = extern enum {
32 \\ A,
33 \\ B,
34 \\ @"1",
35 \\};
36 ,
37 \\pub const FooA = 0;
38 ,
39 \\pub const FooB = 1;
40 ,
41 \\pub const Foo1 = 2;
42 ,
43 \\pub const Foo = enum_Foo
44 );
45
46 cases.add("restrict -> noalias",
47 \\void foo(void *restrict bar, void *restrict);
48 ,
49 \\pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);
50 );
51
52 cases.add("simple struct",
53 \\struct Foo {
54 \\ int x;
55 \\ char *y;
56 \\};
57 ,
58 \\const struct_Foo = extern struct {
59 \\ x: c_int,
60 \\ y: ?&u8,
61 \\};
62 ,
63 \\pub const Foo = struct_Foo;
64 );
65
66 cases.add("qualified struct and enum",
67 \\struct Foo {
68 \\ int x;
69 \\ int y;
70 \\};
71 \\enum Bar {
72 \\ BarA,
73 \\ BarB,
74 \\};
75 \\void func(struct Foo *a, enum Bar **b);
76 ,
77 \\pub const struct_Foo = extern struct {
78 \\ x: c_int,
79 \\ y: c_int,
80 \\};
81 ,
82 \\pub const enum_Bar = extern enum {
83 \\ A,
84 \\ B,
85 \\};
86 ,
87 \\pub const BarA = 0;
88 ,
89 \\pub const BarB = 1;
90 ,
91 \\pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);
92 ,
93 \\pub const Foo = struct_Foo;
94 ,
95 \\pub const Bar = enum_Bar;
96 );
97
98 cases.add("constant size array",
99 \\void func(int array[20]);
100 ,
101 \\pub extern fn func(array: ?&c_int);
102 );
103
104 cases.add("self referential struct with function pointer",
105 \\struct Foo {
106 \\ void (*derp)(struct Foo *foo);
107 \\};
108 ,
109 \\pub const struct_Foo = extern struct {
110 \\ derp: ?extern fn(?&struct_Foo),
111 \\};
112 ,
113 \\pub const Foo = struct_Foo;
114 );
115
116 cases.add("struct prototype used in func",
117 \\struct Foo;
118 \\struct Foo *some_func(struct Foo *foo, int x);
119 ,
120 \\pub const struct_Foo = @OpaqueType();
121 ,
122 \\pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;
123 ,
124 \\pub const Foo = struct_Foo;
125 );
126
127 cases.add("#define a char literal",
128 \\#define A_CHAR 'a'
129 ,
130 \\pub const A_CHAR = 97;
131 );
132
133 cases.add("#define an unsigned integer literal",
134 \\#define CHANNEL_COUNT 24
135 ,
136 \\pub const CHANNEL_COUNT = 24;
137 );
138
139 cases.add("#define referencing another #define",
140 \\#define THING2 THING1
141 \\#define THING1 1234
142 ,
143 \\pub const THING1 = 1234;
144 ,
145 \\pub const THING2 = THING1;
146 );
147
148 cases.add("variables",
149 \\extern int extern_var;
150 \\static const int int_var = 13;
151 ,
152 \\pub extern var extern_var: c_int;
153 ,
154 \\pub const int_var: c_int = 13;
155 );
156
157 cases.add("circular struct definitions",
158 \\struct Bar;
159 \\
160 \\struct Foo {
161 \\ struct Bar *next;
162 \\};
163 \\
164 \\struct Bar {
165 \\ struct Foo *next;
166 \\};
167 ,
168 \\pub const struct_Bar = extern struct {
169 \\ next: ?&struct_Foo,
170 \\};
171 ,
172 \\pub const struct_Foo = extern struct {
173 \\ next: ?&struct_Bar,
174 \\};
175 );
176
177 cases.add("typedef void",
178 \\typedef void Foo;
179 \\Foo fun(Foo *a);
180 ,
181 \\pub const Foo = c_void;
182 ,
183 \\pub extern fn fun(a: ?&c_void);
184 );
185
186 cases.add("generate inline func for #define global extern fn",
187 \\extern void (*fn_ptr)(void);
188 \\#define foo fn_ptr
189 \\
190 \\extern char (*fn_ptr2)(int, float);
191 \\#define bar fn_ptr2
192 ,
193 \\pub extern var fn_ptr: ?extern fn();
194 ,
195 \\pub fn foo();
196 ,
197 \\pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;
198 ,
199 \\pub fn bar(arg0: c_int, arg1: f32) -> u8;
200 );
201
202 cases.add("#define string",
203 \\#define foo "a string"
204 ,
205 \\pub const foo: &const u8 = &(c str lit);
206 );
207
208 cases.add("__cdecl doesn't mess up function pointers",
209 \\void foo(void (__cdecl *fn_ptr)(void));
210 ,
211 \\pub extern fn foo(fn_ptr: ?extern fn());
212 );
213
214 cases.add("comment after integer literal",
215 \\#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
216 ,
217 \\pub const SDL_INIT_VIDEO = 32;
218 );
219
220 cases.add("zig keywords in C code",
221 \\struct comptime {
222 \\ int defer;
223 \\};
224 ,
225 \\pub const struct_comptime = extern struct {
226 \\ @"defer": c_int,
227 \\};
228 ,
229 \\pub const @"comptime" = struct_comptime;
230 );
231
232 cases.add("macro defines string literal with octal",
233 \\#define FOO "aoeu\023 derp"
234 \\#define FOO2 "aoeu\0234 derp"
235 \\#define FOO_CHAR '\077'
236 ,
237 \\pub const FOO: &const u8 = &(c str lit);
238 ,
239 \\pub const FOO2: &const u8 = &(c str lit);
240 ,
241 \\pub const FOO_CHAR = 63;
242 );
243}
test/run_tests.cpp deleted-472
...@@ -1,472 +0,0 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "list.hpp"
9#include "buffer.hpp"
10#include "os.hpp"
11#include "error.hpp"
12#include "config.h"
13
14#include <stdio.h>
15#include <stdarg.h>
16
17enum TestSpecial {
18 TestSpecialNone,
19 TestSpecialLinkStep,
20};
21
22struct TestSourceFile {
23 const char *relative_path;
24 const char *source_code;
25};
26
27enum AllowWarnings {
28 AllowWarningsNo,
29 AllowWarningsYes,
30};
31
32struct TestCase {
33 const char *case_name;
34 const char *output;
35 ZigList<TestSourceFile> source_files;
36 ZigList<const char *> compile_errors;
37 ZigList<const char *> compiler_args;
38 ZigList<const char *> linker_args;
39 ZigList<const char *> program_args;
40 bool is_parseh;
41 TestSpecial special;
42 bool is_release_mode;
43 AllowWarnings allow_warnings;
44};
45
46static ZigList<TestCase*> test_cases = {0};
47static const char *tmp_source_path = ".tmp_source.zig";
48static const char *tmp_h_path = ".tmp_header.h";
49
50#if defined(_WIN32)
51static const char *tmp_exe_path = "./.tmp_exe.exe";
52static const char *zig_exe = "./zig.exe";
53#define NL "\r\n"
54#else
55static const char *tmp_exe_path = "./.tmp_exe";
56static const char *zig_exe = "./zig";
57#define NL "\n"
58#endif
59
60static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warnings,
61 const char *source, size_t count, ...)
62{
63 va_list ap;
64 va_start(ap, count);
65
66 TestCase *test_case = allocate<TestCase>(1);
67 test_case->case_name = case_name;
68 test_case->is_parseh = true;
69 test_case->allow_warnings = allow_warnings;
70
71 test_case->source_files.resize(1);
72 test_case->source_files.at(0).relative_path = tmp_h_path;
73 test_case->source_files.at(0).source_code = source;
74
75 for (size_t i = 0; i < count; i += 1) {
76 const char *arg = va_arg(ap, const char *);
77 test_case->compile_errors.append(arg);
78 }
79
80 test_case->compiler_args.append("parseh");
81 test_case->compiler_args.append(tmp_h_path);
82 //test_case->compiler_args.append("--verbose");
83
84 test_cases.append(test_case);
85
86 va_end(ap);
87 return test_case;
88}
89
90//////////////////////////////////////////////////////////////////////////////
91
92static void add_parseh_test_cases(void) {
93 add_parseh_case("simple data types", AllowWarningsYes, R"SOURCE(
94#include <stdint.h>
95int foo(char a, unsigned char b, signed char c);
96int foo(char a, unsigned char b, signed char c); // test a duplicate prototype
97void bar(uint8_t a, uint16_t b, uint32_t c, uint64_t d);
98void baz(int8_t a, int16_t b, int32_t c, int64_t d);
99 )SOURCE", 3,
100 "pub extern fn foo(a: u8, b: u8, c: i8) -> c_int;",
101 "pub extern fn bar(a: u8, b: u16, c: u32, d: u64);",
102 "pub extern fn baz(a: i8, b: i16, c: i32, d: i64);");
103
104 add_parseh_case("noreturn attribute", AllowWarningsNo, R"SOURCE(
105void foo(void) __attribute__((noreturn));
106 )SOURCE", 1, R"OUTPUT(pub extern fn foo() -> noreturn;)OUTPUT");
107
108 add_parseh_case("enums", AllowWarningsNo, R"SOURCE(
109enum Foo {
110 FooA,
111 FooB,
112 Foo1,
113};
114 )SOURCE", 5, R"(pub const enum_Foo = extern enum {
115 A,
116 B,
117 @"1",
118};)",
119 R"(pub const FooA = 0;)",
120 R"(pub const FooB = 1;)",
121 R"(pub const Foo1 = 2;)",
122 R"(pub const Foo = enum_Foo;)");
123
124 add_parseh_case("restrict -> noalias", AllowWarningsNo, R"SOURCE(
125void foo(void *restrict bar, void *restrict);
126 )SOURCE", 1, R"OUTPUT(pub extern fn foo(noalias bar: ?&c_void, noalias arg1: ?&c_void);)OUTPUT");
127
128 add_parseh_case("simple struct", AllowWarningsNo, R"SOURCE(
129struct Foo {
130 int x;
131 char *y;
132};
133 )SOURCE", 2,
134 R"OUTPUT(const struct_Foo = extern struct {
135 x: c_int,
136 y: ?&u8,
137};)OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
138
139 add_parseh_case("qualified struct and enum", AllowWarningsNo, R"SOURCE(
140struct Foo {
141 int x;
142 int y;
143};
144enum Bar {
145 BarA,
146 BarB,
147};
148void func(struct Foo *a, enum Bar **b);
149 )SOURCE", 7, R"OUTPUT(pub const struct_Foo = extern struct {
150 x: c_int,
151 y: c_int,
152};)OUTPUT", R"OUTPUT(pub const enum_Bar = extern enum {
153 A,
154 B,
155};)OUTPUT",
156 R"OUTPUT(pub const BarA = 0;)OUTPUT",
157 R"OUTPUT(pub const BarB = 1;)OUTPUT",
158 "pub extern fn func(a: ?&struct_Foo, b: ?&?&enum_Bar);",
159 R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT",
160 R"OUTPUT(pub const Bar = enum_Bar;)OUTPUT");
161
162 add_parseh_case("constant size array", AllowWarningsNo, R"SOURCE(
163void func(int array[20]);
164 )SOURCE", 1, "pub extern fn func(array: ?&c_int);");
165
166
167 add_parseh_case("self referential struct with function pointer",
168 AllowWarningsNo, R"SOURCE(
169struct Foo {
170 void (*derp)(struct Foo *foo);
171};
172 )SOURCE", 2, R"OUTPUT(pub const struct_Foo = extern struct {
173 derp: ?extern fn(?&struct_Foo),
174};)OUTPUT", R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
175
176
177 add_parseh_case("struct prototype used in func", AllowWarningsNo, R"SOURCE(
178struct Foo;
179struct Foo *some_func(struct Foo *foo, int x);
180 )SOURCE", 3, R"OUTPUT(pub const struct_Foo = @OpaqueType();)OUTPUT",
181 R"OUTPUT(pub extern fn some_func(foo: ?&struct_Foo, x: c_int) -> ?&struct_Foo;)OUTPUT",
182 R"OUTPUT(pub const Foo = struct_Foo;)OUTPUT");
183
184
185 add_parseh_case("#define a char literal", AllowWarningsNo, R"SOURCE(
186#define A_CHAR 'a'
187 )SOURCE", 1, R"OUTPUT(pub const A_CHAR = 97;)OUTPUT");
188
189
190 add_parseh_case("#define an unsigned integer literal", AllowWarningsNo,
191 R"SOURCE(
192#define CHANNEL_COUNT 24
193 )SOURCE", 1, R"OUTPUT(pub const CHANNEL_COUNT = 24;)OUTPUT");
194
195
196 add_parseh_case("#define referencing another #define", AllowWarningsNo,
197 R"SOURCE(
198#define THING2 THING1
199#define THING1 1234
200 )SOURCE", 2,
201 "pub const THING1 = 1234;",
202 "pub const THING2 = THING1;");
203
204
205 add_parseh_case("variables", AllowWarningsNo, R"SOURCE(
206extern int extern_var;
207static const int int_var = 13;
208 )SOURCE", 2,
209 "pub extern var extern_var: c_int;",
210 "pub const int_var: c_int = 13;");
211
212
213 add_parseh_case("circular struct definitions", AllowWarningsNo, R"SOURCE(
214struct Bar;
215
216struct Foo {
217 struct Bar *next;
218};
219
220struct Bar {
221 struct Foo *next;
222};
223 )SOURCE", 2,
224 R"SOURCE(pub const struct_Bar = extern struct {
225 next: ?&struct_Foo,
226};)SOURCE",
227 R"SOURCE(pub const struct_Foo = extern struct {
228 next: ?&struct_Bar,
229};)SOURCE");
230
231
232 add_parseh_case("typedef void", AllowWarningsNo, R"SOURCE(
233typedef void Foo;
234Foo fun(Foo *a);
235 )SOURCE", 2,
236 "pub const Foo = c_void;",
237 "pub extern fn fun(a: ?&c_void);");
238
239 add_parseh_case("generate inline func for #define global extern fn", AllowWarningsNo,
240 R"SOURCE(
241extern void (*fn_ptr)(void);
242#define foo fn_ptr
243
244extern char (*fn_ptr2)(int, float);
245#define bar fn_ptr2
246 )SOURCE", 4,
247 "pub extern var fn_ptr: ?extern fn();",
248 "pub fn foo();",
249 "pub extern var fn_ptr2: ?extern fn(c_int, f32) -> u8;",
250 "pub fn bar(arg0: c_int, arg1: f32) -> u8;");
251
252
253 add_parseh_case("#define string", AllowWarningsNo, R"SOURCE(
254#define foo "a string"
255 )SOURCE", 1, "pub const foo: &const u8 = &(c str lit);");
256
257 add_parseh_case("__cdecl doesn't mess up function pointers", AllowWarningsNo, R"SOURCE(
258void foo(void (__cdecl *fn_ptr)(void));
259 )SOURCE", 1, "pub extern fn foo(fn_ptr: ?extern fn());");
260
261 add_parseh_case("comment after integer literal", AllowWarningsNo, R"SOURCE(
262#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
263 )SOURCE", 1, "pub const SDL_INIT_VIDEO = 32;");
264
265 add_parseh_case("zig keywords in C code", AllowWarningsNo, R"SOURCE(
266struct comptime {
267 int defer;
268};
269 )SOURCE", 2, R"(pub const struct_comptime = extern struct {
270 @"defer": c_int,
271};)", R"(pub const @"comptime" = struct_comptime;)");
272
273 add_parseh_case("macro defines string literal with octal", AllowWarningsNo, R"SOURCE(
274#define FOO "aoeu\023 derp"
275#define FOO2 "aoeu\0234 derp"
276#define FOO_CHAR '\077'
277 )SOURCE", 3,
278 R"(pub const FOO: &const u8 = &(c str lit);)",
279 R"(pub const FOO2: &const u8 = &(c str lit);)",
280 R"(pub const FOO_CHAR = 63;)");
281}
282
283static void print_compiler_invocation(TestCase *test_case) {
284 printf("%s", zig_exe);
285 for (size_t i = 0; i < test_case->compiler_args.length; i += 1) {
286 printf(" %s", test_case->compiler_args.at(i));
287 }
288 printf("\n");
289}
290
291static void print_linker_invocation(TestCase *test_case) {
292 printf("%s", zig_exe);
293 for (size_t i = 0; i < test_case->linker_args.length; i += 1) {
294 printf(" %s", test_case->linker_args.at(i));
295 }
296 printf("\n");
297}
298
299
300static void print_exe_invocation(TestCase *test_case) {
301 printf("%s", tmp_exe_path);
302 for (size_t i = 0; i < test_case->program_args.length; i += 1) {
303 printf(" %s", test_case->program_args.at(i));
304 }
305 printf("\n");
306}
307
308static void run_test(TestCase *test_case) {
309 for (size_t i = 0; i < test_case->source_files.length; i += 1) {
310 TestSourceFile *test_source = &test_case->source_files.at(i);
311 os_write_file(
312 buf_create_from_str(test_source->relative_path),
313 buf_create_from_str(test_source->source_code));
314 }
315
316 Buf zig_stderr = BUF_INIT;
317 Buf zig_stdout = BUF_INIT;
318 int err;
319 Termination term;
320 if ((err = os_exec_process(zig_exe, test_case->compiler_args, &term, &zig_stderr, &zig_stdout))) {
321 fprintf(stderr, "Unable to exec %s: %s\n", zig_exe, err_str(err));
322 }
323
324 if (!test_case->is_parseh && test_case->compile_errors.length) {
325 if (term.how != TerminationIdClean || term.code != 0) {
326 for (size_t i = 0; i < test_case->compile_errors.length; i += 1) {
327 const char *err_text = test_case->compile_errors.at(i);
328 if (!strstr(buf_ptr(&zig_stderr), err_text)) {
329 printf("\n");
330 printf("========= Expected this compile error: =========\n");
331 printf("%s\n", err_text);
332 printf("================================================\n");
333 print_compiler_invocation(test_case);
334 printf("%s\n", buf_ptr(&zig_stderr));
335 exit(1);
336 }
337 }
338 return; // success
339 } else {
340 printf("\nCompile failed with return code 0 (Expected failure):\n");
341 print_compiler_invocation(test_case);
342 printf("%s\n", buf_ptr(&zig_stderr));
343 exit(1);
344 }
345 }
346
347 if (term.how != TerminationIdClean || term.code != 0) {
348 printf("\nCompile failed:\n");
349 print_compiler_invocation(test_case);
350 printf("%s\n", buf_ptr(&zig_stderr));
351 exit(1);
352 }
353
354 if (test_case->is_parseh) {
355 if (buf_len(&zig_stderr) > 0) {
356 printf("\nparseh emitted warnings:\n");
357 printf("------------------------------\n");
358 print_compiler_invocation(test_case);
359 printf("%s\n", buf_ptr(&zig_stderr));
360 printf("------------------------------\n");
361 if (test_case->allow_warnings == AllowWarningsNo) {
362 exit(1);
363 }
364 }
365
366 for (size_t i = 0; i < test_case->compile_errors.length; i += 1) {
367 const char *output = test_case->compile_errors.at(i);
368
369 if (!strstr(buf_ptr(&zig_stdout), output)) {
370 printf("\n");
371 printf("========= Expected this output: =========\n");
372 printf("%s\n", output);
373 printf("================================================\n");
374 print_compiler_invocation(test_case);
375 printf("%s\n", buf_ptr(&zig_stdout));
376 exit(1);
377 }
378 }
379 } else {
380 if (test_case->special == TestSpecialLinkStep) {
381 Buf link_stderr = BUF_INIT;
382 Buf link_stdout = BUF_INIT;
383 int err;
384 Termination term;
385 if ((err = os_exec_process(zig_exe, test_case->linker_args, &term, &link_stderr, &link_stdout))) {
386 fprintf(stderr, "Unable to exec %s: %s\n", zig_exe, err_str(err));
387 }
388
389 if (term.how != TerminationIdClean || term.code != 0) {
390 printf("\nLink failed:\n");
391 print_linker_invocation(test_case);
392 printf("%s\n", buf_ptr(&zig_stderr));
393 exit(1);
394 }
395 }
396
397 Buf program_stderr = BUF_INIT;
398 Buf program_stdout = BUF_INIT;
399 os_exec_process(tmp_exe_path, test_case->program_args, &term, &program_stderr, &program_stdout);
400
401 if (term.how != TerminationIdClean || term.code != 0) {
402 printf("\nProgram exited with error\n");
403 print_compiler_invocation(test_case);
404 print_exe_invocation(test_case);
405 printf("%s\n", buf_ptr(&program_stderr));
406 exit(1);
407 }
408
409 if (test_case->output != nullptr && !buf_eql_str(&program_stdout, test_case->output)) {
410 printf("\n");
411 print_compiler_invocation(test_case);
412 print_exe_invocation(test_case);
413 printf("==== Test failed. Expected output: ====\n");
414 printf("%s\n", test_case->output);
415 printf("========= Actual output: ==============\n");
416 printf("%s\n", buf_ptr(&program_stdout));
417 printf("=======================================\n");
418 exit(1);
419 }
420 }
421
422 for (size_t i = 0; i < test_case->source_files.length; i += 1) {
423 TestSourceFile *test_source = &test_case->source_files.at(i);
424 remove(test_source->relative_path);
425 }
426}
427
428static void run_all_tests(const char *grep_text) {
429 for (size_t i = 0; i < test_cases.length; i += 1) {
430 TestCase *test_case = test_cases.at(i);
431 if (grep_text != nullptr && strstr(test_case->case_name, grep_text) == nullptr) {
432 continue;
433 }
434
435 printf("Test %zu/%zu %s...", i + 1, test_cases.length, test_case->case_name);
436 fflush(stdout);
437 run_test(test_case);
438 printf("OK\n");
439 }
440 printf("%zu tests passed.\n", test_cases.length);
441}
442
443static void cleanup(void) {
444 remove(tmp_source_path);
445 remove(tmp_h_path);
446 remove(tmp_exe_path);
447}
448
449static int usage(const char *arg0) {
450 fprintf(stderr, "Usage: %s [--grep text]\n", arg0);
451 return 1;
452}
453
454int main(int argc, char **argv) {
455 const char *grep_text = nullptr;
456 for (int i = 1; i < argc; i += 1) {
457 const char *arg = argv[i];
458 if (i + 1 >= argc) {
459 return usage(argv[0]);
460 } else {
461 i += 1;
462 if (strcmp(arg, "--grep") == 0) {
463 grep_text = argv[i];
464 } else {
465 return usage(argv[0]);
466 }
467 }
468 }
469 add_parseh_test_cases();
470 run_all_tests(grep_text);
471 cleanup();
472}
test/tests.zig+206-6
...@@ -10,13 +10,14 @@ const mem = std.mem;...@@ -10,13 +10,14 @@ const mem = std.mem;
10const fmt = std.fmt;10const fmt = std.fmt;
11const List = std.list.List;11const List = std.list.List;
1212
13error TestFailed;13const compare_output = @import("compare_output.zig");
14const build_examples = @import("build_examples.zig");
15const compile_errors = @import("compile_errors.zig");
16const assemble_and_link = @import("assemble_and_link.zig");
17const debug_safety = @import("debug_safety.zig");
18const parseh = @import("parseh.zig");
1419
15pub const compare_output = @import("compare_output.zig");20error TestFailed;
16pub const build_examples = @import("build_examples.zig");
17pub const compile_errors = @import("compile_errors.zig");
18pub const assemble_and_link = @import("assemble_and_link.zig");
19pub const debug_safety = @import("debug_safety.zig");
2021
21pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {22pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
22 const cases = %%b.allocator.create(CompareOutputContext);23 const cases = %%b.allocator.create(CompareOutputContext);
...@@ -88,6 +89,20 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> &...@@ -88,6 +89,20 @@ pub fn addAssembleAndLinkTests(b: &build.Builder, test_filter: ?[]const u8) -> &
88 return cases.step;89 return cases.step;
89}90}
9091
92pub fn addParseHTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
93 const cases = %%b.allocator.create(ParseHContext);
94 *cases = ParseHContext {
95 .b = b,
96 .step = b.step("test-parseh", "Run the C header file parsing tests"),
97 .test_index = 0,
98 .test_filter = test_filter,
99 };
100
101 parseh.addCases(cases);
102
103 return cases.step;
104}
105
91pub const CompareOutputContext = struct {106pub const CompareOutputContext = struct {
92 b: &build.Builder,107 b: &build.Builder,
93 step: &build.Step,108 step: &build.Step,
...@@ -645,3 +660,188 @@ pub const BuildExamplesContext = struct {...@@ -645,3 +660,188 @@ pub const BuildExamplesContext = struct {
645 }660 }
646 }661 }
647};662};
663
664pub const ParseHContext = struct {
665 b: &build.Builder,
666 step: &build.Step,
667 test_index: usize,
668 test_filter: ?[]const u8,
669
670 const TestCase = struct {
671 name: []const u8,
672 sources: List(SourceFile),
673 expected_lines: List([]const u8),
674 allow_warnings: bool,
675
676 const SourceFile = struct {
677 filename: []const u8,
678 source: []const u8,
679 };
680
681 pub fn addSourceFile(self: &TestCase, filename: []const u8, source: []const u8) {
682 %%self.sources.append(SourceFile {
683 .filename = filename,
684 .source = source,
685 });
686 }
687
688 pub fn addExpectedError(self: &TestCase, text: []const u8) {
689 %%self.expected_lines.append(text);
690 }
691 };
692
693 const ParseHCmpOutputStep = struct {
694 step: build.Step,
695 context: &ParseHContext,
696 name: []const u8,
697 test_index: usize,
698 case: &const TestCase,
699
700 pub fn create(context: &ParseHContext, name: []const u8, case: &const TestCase) -> &ParseHCmpOutputStep {
701 const allocator = context.b.allocator;
702 const ptr = %%allocator.create(ParseHCmpOutputStep);
703 *ptr = ParseHCmpOutputStep {
704 .step = build.Step.init("ParseHCmpOutput", allocator, make),
705 .context = context,
706 .name = name,
707 .test_index = context.test_index,
708 .case = case,
709 };
710 context.test_index += 1;
711 return ptr;
712 }
713
714 fn make(step: &build.Step) -> %void {
715 const self = @fieldParentPtr(ParseHCmpOutputStep, "step", step);
716 const b = self.context.b;
717
718 const root_src = %%os.path.join(b.allocator, "test_artifacts", self.case.sources.items[0].filename);
719
720 var zig_args = List([]const u8).init(b.allocator);
721 %%zig_args.append("parseh");
722 %%zig_args.append(b.pathFromRoot(root_src));
723
724 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
725
726 if (b.verbose) {
727 printInvocation(b.zig_exe, zig_args.toSliceConst());
728 }
729
730 var child = os.ChildProcess.spawn(b.zig_exe, zig_args.toSliceConst(), &b.env_map,
731 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
732 {
733 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
734 };
735
736 const term = child.wait() %% |err| {
737 debug.panic("Unable to spawn {}: {}\n", b.zig_exe, @errorName(err));
738 };
739 switch (term) {
740 Term.Clean => |code| {
741 if (code != 0) {
742 %%io.stderr.printf("Compilation failed with exit code {}\n", code);
743 return error.TestFailed;
744 }
745 },
746 Term.Signal => |code| {
747 %%io.stderr.printf("Compilation failed with signal {}\n", code);
748 return error.TestFailed;
749 },
750 else => {
751 %%io.stderr.printf("Compilation terminated unexpectedly\n");
752 return error.TestFailed;
753 },
754 };
755
756 var stdout_buf = %%Buffer0.initEmpty(b.allocator);
757 var stderr_buf = %%Buffer0.initEmpty(b.allocator);
758
759 %%(??child.stdout).readAll(&stdout_buf);
760 %%(??child.stderr).readAll(&stderr_buf);
761
762 const stdout = stdout_buf.toSliceConst();
763 const stderr = stderr_buf.toSliceConst();
764
765 if (stderr.len != 0 and !self.case.allow_warnings) {
766 %%io.stderr.printf(
767 \\====== parseh emitted warnings: ============
768 \\{}
769 \\============================================
770 \\
771 , stderr);
772 return error.TestFailed;
773 }
774
775 for (self.case.expected_lines.toSliceConst()) |expected_line| {
776 if (mem.indexOf(u8, stdout, expected_line) == null) {
777 %%io.stderr.printf(
778 \\
779 \\========= Expected this output: ================
780 \\{}
781 \\================================================
782 \\{}
783 \\
784 , expected_line, stdout);
785 return error.TestFailed;
786 }
787 }
788 %%io.stderr.printf("OK\n");
789 }
790 };
791
792 fn printInvocation(exe_path: []const u8, args: []const []const u8) {
793 %%io.stderr.printf("{}", exe_path);
794 for (args) |arg| {
795 %%io.stderr.printf(" {}", arg);
796 }
797 %%io.stderr.printf("\n");
798 }
799
800 pub fn create(self: &ParseHContext, allow_warnings: bool, name: []const u8,
801 source: []const u8, expected_lines: ...) -> &TestCase
802 {
803 const tc = %%self.b.allocator.create(TestCase);
804 *tc = TestCase {
805 .name = name,
806 .sources = List(TestCase.SourceFile).init(self.b.allocator),
807 .expected_lines = List([]const u8).init(self.b.allocator),
808 .allow_warnings = allow_warnings,
809 };
810 tc.addSourceFile("source.h", source);
811 comptime var arg_i = 0;
812 inline while (arg_i < expected_lines.len; arg_i += 1) {
813 // TODO mem.dupe is because of issue #336
814 tc.addExpectedError(%%mem.dupe(self.b.allocator, u8, expected_lines[arg_i]));
815 }
816 return tc;
817 }
818
819 pub fn add(self: &ParseHContext, name: []const u8, source: []const u8, expected_lines: ...) {
820 const tc = self.create(false, name, source, expected_lines);
821 self.addCase(tc);
822 }
823
824 pub fn addAllowWarnings(self: &ParseHContext, name: []const u8, source: []const u8, expected_lines: ...) {
825 const tc = self.create(true, name, source, expected_lines);
826 self.addCase(tc);
827 }
828
829 pub fn addCase(self: &ParseHContext, case: &const TestCase) {
830 const b = self.b;
831
832 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "parseh {}", case.name);
833 if (const filter ?= self.test_filter) {
834 if (mem.indexOf(u8, annotated_case_name, filter) == null)
835 return;
836 }
837
838 const parseh_and_cmp = ParseHCmpOutputStep.create(self, annotated_case_name, case);
839 self.step.dependOn(&parseh_and_cmp.step);
840
841 for (case.sources.toSliceConst()) |src_file| {
842 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
843 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
844 parseh_and_cmp.step.dependOn(&write_src.step);
845 }
846 }
847};