authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-26 01:29:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-26 01:29:52-07:00
log763ce1c4852eaee22c648c6909190f73d2ca775b
tree21655b93329db0ded45e08a9e7f3296f5fb96205
parent893e152dabd6352eaa6aaff95c521cea5cd2d9a5

add tests


7 files changed, 262 insertions(+), 7 deletions(-)

CMakeLists.txt+19-1
......@@ -33,17 +33,30 @@ set(ZIG_SOURCES
3333 "${CMAKE_SOURCE_DIR}/src/os.cpp"
3434)
3535
36set(TEST_SOURCES
37 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
38 "${CMAKE_SOURCE_DIR}/src/util.cpp"
39 "${CMAKE_SOURCE_DIR}/src/os.cpp"
40 "${CMAKE_SOURCE_DIR}/test/standalone.cpp"
41)
42
43
3644set(CONFIGURE_OUT_FILE "${CMAKE_BINARY_DIR}/config.h")
3745configure_file (
3846 "${CMAKE_SOURCE_DIR}/src/config.h.in"
3947 ${CONFIGURE_OUT_FILE}
4048)
4149
50include_directories(
51 ${CMAKE_SOURCE_DIR}
52 ${CMAKE_BINARY_DIR}
53 "${CMAKE_SOURCE_DIR}/src"
54)
55
4256set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-unused-variable -Wno-unused-but-set-variable")
4357
4458set(EXE_CFLAGS "-std=c++11 -fno-exceptions -fno-rtti -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -Werror -Wall -Werror=strict-prototypes -Werror=old-style-definition -Werror=missing-prototypes")
4559
46
4760add_executable(zig ${ZIG_SOURCES})
4861set_target_properties(zig PROPERTIES
4962 COMPILE_FLAGS ${EXE_CFLAGS})
......@@ -52,3 +65,8 @@ target_link_libraries(zig LINK_PUBLIC
5265)
5366install(TARGETS zig DESTINATION bin)
5467
68add_executable(run_tests ${TEST_SOURCES})
69target_link_libraries(run_tests)
70set_target_properties(run_tests PROPERTIES
71 COMPILE_FLAGS ${EXE_CFLAGS}
72)
README.md+11-2
......@@ -31,7 +31,6 @@ readable, safe, optimal, and concise code to solve any computing problem.
3131
3232## Roadmap
3333
34 * Unit tests.
3534 * C style comments.
3635 * Simple .so library
3736 * Multiple files
......@@ -66,7 +65,7 @@ Root : many(TopLevelDecl) token(EOF)
6665
6766TopLevelDecl : FnDef | ExternBlock
6867
69ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnProtoDecl) token(RBrace)
68ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
7069
7170FnProto : token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
7271
......@@ -96,3 +95,13 @@ FnCall : token(Symbol) token(LParen) list(Expression, token(Comma)) token(RParen
9695
9796Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
9897```
98
99### Building
100
101```
102mkdir build
103cd build
104cmake ..
105make
106./run_tests
107```
src/os.cpp+84
......@@ -10,6 +10,11 @@
1010
1111#include <unistd.h>
1212#include <errno.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <sys/wait.h>
16#include <stdio.h>
17#include <fcntl.h>
1318
1419void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) {
1520 pid_t pid = fork();
......@@ -32,6 +37,24 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detache
3237 zig_panic("execvp failed: %s", strerror(errno));
3338}
3439
40static void read_all_fd(int fd, Buf *out_buf) {
41 static const ssize_t buf_size = 8192;
42 buf_resize(out_buf, buf_size);
43 ssize_t actual_buf_len = 0;
44 for (;;) {
45 ssize_t amt_read = read(fd, buf_ptr(out_buf), buf_len(out_buf));
46 if (amt_read < 0)
47 zig_panic("fd read error");
48 actual_buf_len += amt_read;
49 if (amt_read == 0) {
50 buf_resize(out_buf, actual_buf_len);
51 return;
52 }
53
54 buf_resize(out_buf, actual_buf_len + buf_size);
55 }
56}
57
3558void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
3659 int last_index = buf_len(full_path) - 1;
3760 if (last_index >= 0 && buf_ptr(full_path)[last_index] == '/') {
......@@ -49,3 +72,64 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
4972 buf_init_from_buf(out_basename, full_path);
5073}
5174
75void os_exec_process(const char *exe, ZigList<const char *> &args,
76 int *return_code, Buf *out_stderr, Buf *out_stdout)
77{
78 int stdin_pipe[2];
79 int stdout_pipe[2];
80 int stderr_pipe[2];
81
82 int err;
83 if ((err = pipe(stdin_pipe)))
84 zig_panic("pipe failed");
85 if ((err = pipe(stdout_pipe)))
86 zig_panic("pipe failed");
87 if ((err = pipe(stderr_pipe)))
88 zig_panic("pipe failed");
89
90 pid_t pid = fork();
91 if (pid == -1)
92 zig_panic("fork failed");
93 if (pid == 0) {
94 // child
95 if (dup2(stdin_pipe[0], STDIN_FILENO) == -1)
96 zig_panic("dup2 failed");
97
98 if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1)
99 zig_panic("dup2 failed");
100
101 if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)
102 zig_panic("dup2 failed");
103
104 const char **argv = allocate<const char *>(args.length + 2);
105 argv[0] = exe;
106 argv[args.length + 1] = nullptr;
107 for (int i = 0; i < args.length; i += 1) {
108 argv[i + 1] = args.at(i);
109 }
110 execvp(exe, const_cast<char * const *>(argv));
111 zig_panic("execvp failed: %s", strerror(errno));
112 } else {
113 // parent
114 close(stdin_pipe[0]);
115 close(stdout_pipe[1]);
116 close(stderr_pipe[1]);
117
118 waitpid(pid, return_code, 0);
119
120 read_all_fd(stdout_pipe[0], out_stdout);
121 read_all_fd(stderr_pipe[0], out_stderr);
122
123 }
124}
125
126void os_write_file(Buf *full_path, Buf *contents) {
127 int fd;
128 if ((fd = open(buf_ptr(full_path), O_CREAT|O_CLOEXEC|O_WRONLY|O_TRUNC, S_IRWXU)) == -1)
129 zig_panic("open failed");
130 ssize_t amt_written = write(fd, buf_ptr(contents), buf_len(contents));
131 if (amt_written != buf_len(contents))
132 zig_panic("write failed: %s", strerror(errno));
133 if (close(fd) == -1)
134 zig_panic("close failed");
135}
src/os.hpp+4
......@@ -12,8 +12,12 @@
1212#include "buffer.hpp"
1313
1414void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached);
15void os_exec_process(const char *exe, ZigList<const char *> &args,
16 int *return_code, Buf *out_stderr, Buf *out_stdout);
1517
1618void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
1719
20void os_write_file(Buf *full_path, Buf *contents);
21
1822
1923#endif
test/add.h deleted-1
......@@ -1 +0,0 @@
1int add(int a, int b);
test/add.zig deleted-3
......@@ -1,3 +0,0 @@
1export fn add(a: i32, b: i32) -> i32 {
2 return a + b;
3}
test/standalone.cpp created+144
......@@ -0,0 +1,144 @@
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
12#include <stdio.h>
13
14struct TestSourceFile {
15 const char *relative_path;
16 const char *text;
17};
18
19struct TestCase {
20 const char *case_name;
21 const char *output;
22 const char *source;
23 ZigList<const char *> compile_errors;
24 ZigList<const char *> compiler_args;
25 ZigList<const char *> program_args;
26};
27
28ZigList<TestCase*> test_cases = {0};
29const char *tmp_source_path = ".tmp_source.zig";
30const char *tmp_exe_path = "./.tmp_exe";
31
32static void add_simple_case(const char *case_name, const char *source, const char *output) {
33 TestCase *test_case = allocate<TestCase>(1);
34 test_case->case_name = case_name;
35 test_case->output = output;
36 test_case->source = source;
37
38 test_case->compiler_args.append("build");
39 test_case->compiler_args.append(tmp_source_path);
40 test_case->compiler_args.append("--output");
41 test_case->compiler_args.append(tmp_exe_path);
42 test_case->compiler_args.append("--release");
43 test_case->compiler_args.append("--strip");
44
45 test_cases.append(test_case);
46}
47
48static void add_all_test_cases(void) {
49 add_simple_case("hello world with libc", R"SOURCE(
50 #link("c")
51 extern {
52 fn puts(s: *mut u8) -> i32;
53 fn exit(code: i32) -> unreachable;
54 }
55
56 fn _start() -> unreachable {
57 puts("Hello, world!");
58 exit(0);
59 }
60 )SOURCE", "Hello, world!\n");
61
62 add_simple_case("function call", R"SOURCE(
63 #link("c")
64 extern {
65 fn puts(s: *mut u8) -> i32;
66 fn exit(code: i32) -> unreachable;
67 }
68
69 fn _start() -> unreachable {
70 this_is_a_function();
71 }
72
73 fn this_is_a_function() -> unreachable {
74 puts("OK");
75 exit(0);
76 }
77 )SOURCE", "OK\n");
78}
79
80static void run_test(TestCase *test_case) {
81 os_write_file(buf_create_from_str(tmp_source_path), buf_create_from_str(test_case->source));
82
83 Buf zig_stderr = BUF_INIT;
84 Buf zig_stdout = BUF_INIT;
85 int return_code;
86 os_exec_process("./zig", test_case->compiler_args, &return_code, &zig_stderr, &zig_stdout);
87
88 if (return_code != 0) {
89 printf("\nCompile failed with return code %d:\n", return_code);
90 printf("zig");
91 for (int i = 0; i < test_case->compiler_args.length; i += 1) {
92 printf(" %s", test_case->compiler_args.at(i));
93 }
94 printf("\n");
95 printf("%s\n", buf_ptr(&zig_stderr));
96 exit(1);
97 }
98
99 Buf program_stderr = BUF_INIT;
100 Buf program_stdout = BUF_INIT;
101 os_exec_process(tmp_exe_path, test_case->program_args, &return_code, &program_stderr, &program_stdout);
102
103 if (return_code != 0) {
104 printf("\nProgram exited with return code %d:\n", return_code);
105 printf("zig");
106 for (int i = 0; i < test_case->compiler_args.length; i += 1) {
107 printf(" %s", test_case->compiler_args.at(i));
108 }
109 printf("\n");
110 printf("%s\n", buf_ptr(&program_stderr));
111 exit(1);
112 }
113
114 if (!buf_eql_str(&program_stdout, test_case->output)) {
115 printf("\n");
116 printf("==== Test failed. Expected output: ====\n");
117 printf("%s\n", test_case->output);
118 printf("========= Actual output: ==============\n");
119 printf("%s\n", buf_ptr(&program_stdout));
120 printf("=======================================\n");
121 exit(1);
122 }
123}
124
125static void run_all_tests(void) {
126 for (int i = 0; i < test_cases.length; i += 1) {
127 TestCase *test_case = test_cases.at(i);
128 printf("Test %d/%d %s...", i + 1, test_cases.length, test_case->case_name);
129 run_test(test_case);
130 printf("OK\n");
131 }
132 printf("%d tests passed.\n", test_cases.length);
133}
134
135static void cleanup(void) {
136 remove(tmp_source_path);
137 remove(tmp_exe_path);
138}
139
140int main(int argc, char **argv) {
141 add_all_test_cases();
142 run_all_tests();
143 cleanup();
144}