Skip to content

Commit 0e51e89

Browse files
authored
Merge pull request #7 from tsoding/4
(#4) Automatic testing
2 parents 017aaa5 + 8dc849a commit 0e51e89

File tree

6 files changed

+272
-2
lines changed

6 files changed

+272
-2
lines changed

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
name: CI
2+
on: [push, pull_request]
3+
4+
jobs:
5+
build-linux-gcc:
6+
runs-on: ubuntu-18.04
7+
steps:
8+
- uses: actions/checkout@v1
9+
- name: build all and examples
10+
run: |
11+
make -k
12+
./test
13+
env:
14+
CC: gcc
15+
CXX: g++
16+
build-linux-clang:
17+
runs-on: ubuntu-18.04
18+
steps:
19+
- uses: actions/checkout@v1
20+
- name: build all and examples
21+
run: |
22+
make -k
23+
./test
24+
env:
25+
CC: clang
26+
CXX: clang++
27+
build-macos:
28+
runs-on: macOS-latest
29+
steps:
30+
- uses: actions/checkout@v1
31+
- name: build all and examples
32+
run: |
33+
make -k
34+
./test
35+
env:
36+
CC: clang
37+
CXX: clang++
38+
# TODO: there is not build for Windows

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
example
1+
example
2+
test

Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
1+
CFLAGS=-Wall -Wextra -Wswitch-enum -std=c99 -pedantic -ggdb
2+
3+
.PHONY: all
4+
all: example test
5+
16
example: example.c jim.h
2-
cc -Wall -Wextra -Wswitch-enum -std=c99 -pedantic -o example example.c
7+
$(CC) $(CFLAGS) -o example example.c
8+
9+
test: test.c jim.h
10+
$(CC) $(CFLAGS) -o test test.c

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,19 @@ $ ./example | jq .
9393
}
9494
```
9595

96+
## Testing
97+
98+
```console
99+
$ make
100+
$ ./test
101+
```
102+
103+
The expected outputs of the test cases are stored in [./test_expected.h](./test_expected.h). To regenerate it just run:
104+
105+
```console
106+
$ ./test record
107+
```
108+
96109
## Notes
97110

98111
1. Does not depends on libc. Could be theoretically used in embedded, but I know nothing about embedded, so maybe not.

test.c

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
#define JIM_IMPLEMENTATION
6+
#include "./jim.h"
7+
8+
#include "./test_expected.h"
9+
10+
#define ARRAY_LEN(xs) (sizeof(xs) / sizeof((xs)[0]))
11+
12+
typedef struct {
13+
size_t capacity;
14+
size_t size;
15+
char *data;
16+
} Buffer;
17+
18+
void buffer_clean(Buffer *buffer)
19+
{
20+
buffer->size = 0;
21+
}
22+
23+
size_t buffer_write(const void *ptr, size_t size, size_t nmemb,
24+
Buffer *sink)
25+
{
26+
size_t esize = size * nmemb; // effective size
27+
28+
if (sink->size + esize <= sink->capacity) {
29+
memcpy(sink->data + sink->size,
30+
ptr,
31+
esize);
32+
sink->size += esize;
33+
return esize;
34+
} else {
35+
return 0;
36+
}
37+
}
38+
39+
static char static_memory_for_buffer[1024];
40+
41+
static Buffer buffer = {
42+
.capacity = sizeof(static_memory_for_buffer),
43+
.data = static_memory_for_buffer
44+
};
45+
46+
void case_01(Jim *jim)
47+
{
48+
jim_object_begin(jim);
49+
{
50+
jim_member_key(jim, "keys", NULL);
51+
jim_array_begin(jim);
52+
{
53+
for (int key = 0; key < 10; ++key) {
54+
jim_integer(jim, key);
55+
}
56+
}
57+
jim_array_end(jim);
58+
59+
jim_member_key(jim, "names", NULL);
60+
jim_array_begin(jim);
61+
{
62+
jim_string(jim, "foo", NULL);
63+
jim_string(jim, "bar", NULL);
64+
jim_string(jim, "baz", NULL);
65+
}
66+
jim_array_end(jim);
67+
}
68+
jim_object_end(jim);
69+
}
70+
71+
void case_02(Jim *jim)
72+
{
73+
jim_object_begin(jim);
74+
{
75+
jim_member_key(jim, "null", NULL);
76+
jim_null(jim);
77+
78+
jim_member_key(jim, "bool", NULL);
79+
jim_array_begin(jim);
80+
{
81+
jim_bool(jim, 0);
82+
jim_bool(jim, 1);
83+
}
84+
jim_array_end(jim);
85+
86+
jim_member_key(jim, "integers", NULL);
87+
jim_array_begin(jim);
88+
{
89+
for (int i = -3; i <= 3; ++i) {
90+
jim_integer(jim, i);
91+
}
92+
}
93+
jim_array_end(jim);
94+
95+
jim_member_key(jim, "floats", NULL);
96+
jim_array_begin(jim);
97+
{
98+
jim_float(jim, 0.0, 4);
99+
jim_float(jim, -0.0, 4);
100+
jim_float(jim, 3.1415, 4);
101+
jim_float(jim, 2.71828, 5);
102+
jim_float(jim, 1.6180, 4);
103+
jim_float(jim, 0.0 / 0.0, 4);
104+
jim_float(jim, 1.0 / 0.0, 4);
105+
jim_float(jim, -1.0 / 0.0, 4);
106+
}
107+
jim_array_end(jim);
108+
109+
jim_member_key(jim, "string", NULL);
110+
jim_array_begin(jim);
111+
{
112+
jim_string(jim, "Hello\tWorld\n", NULL);
113+
unsigned int size = 4;
114+
jim_string(jim, "\0\0\0\0", &size);
115+
}
116+
jim_array_end(jim);
117+
}
118+
jim_object_end(jim);
119+
}
120+
121+
typedef struct {
122+
const char *name;
123+
void (*run)(Jim *jim);
124+
} Test_Case;
125+
126+
#define TEST_CASE(case_name) \
127+
{ \
128+
.name = #case_name, \
129+
.run = case_name \
130+
}
131+
132+
const Test_Case test_cases[] = {
133+
TEST_CASE(case_01),
134+
TEST_CASE(case_02)
135+
};
136+
137+
void record(const char *header_path)
138+
{
139+
FILE *stream = fopen(header_path, "w");
140+
141+
Jim jim_stream = {
142+
.sink = stream,
143+
.write = (Jim_Write) fwrite,
144+
};
145+
146+
Jim jim_buffer = {
147+
.sink = &buffer,
148+
.write = (Jim_Write) buffer_write,
149+
};
150+
151+
fprintf(stream, "const char *test_cases_expected[] = {\n");
152+
for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
153+
buffer_clean(&buffer);
154+
test_cases[i].run(&jim_buffer);
155+
fprintf(stream, " ");
156+
const unsigned int size = buffer.size;
157+
jim_string(&jim_stream, buffer.data, &size);
158+
fprintf(stream, ",\n");
159+
}
160+
fprintf(stream, "};\n");
161+
162+
fclose(stream);
163+
164+
printf("Updated %s\n", header_path);
165+
}
166+
167+
void test(void)
168+
{
169+
Jim jim_buffer = {
170+
.sink = &buffer,
171+
.write = (Jim_Write) buffer_write,
172+
};
173+
174+
for (size_t i = 0; i < ARRAY_LEN(test_cases); ++i) {
175+
printf("%s ... ", test_cases[i].name);
176+
177+
buffer_clean(&buffer);
178+
test_cases[i].run(&jim_buffer);
179+
180+
if (buffer.size != strlen(test_cases_expected[i])
181+
|| memcmp(buffer.data, test_cases_expected[i], buffer.size) != 0) {
182+
printf("FAILED!\n");
183+
printf("Expected: %s\n", test_cases_expected[i]);
184+
printf("Actual: ");
185+
fwrite(buffer.data, 1, buffer.size, stdout);
186+
printf("\n");
187+
exit(1);
188+
}
189+
190+
printf("OK\n");
191+
}
192+
}
193+
194+
int main(int argc, char **argv)
195+
{
196+
if (argc >= 2) {
197+
if (strcmp(argv[1], "record") == 0) {
198+
record("test_expected.h");
199+
} else {
200+
fprintf(stderr, "Usage: ./test [record]\n");
201+
fprintf(stderr, "ERROR: unknown subcommand %s.\n", argv[1]);
202+
}
203+
} else {
204+
test();
205+
}
206+
}

test_expected.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const char *test_cases_expected[] = {
2+
"{\"keys\":[0,1,2,3,4,5,6,7,8,9],\"names\":[\"foo\",\"bar\",\"baz\"]}",
3+
"{\"null\":null,\"bool\":[false,true],\"integers\":[-3,-2,-1,0,1,2,3],\"floats\":[0.0,0.0,3.1415,2.71828,1.6180,null,null,null],\"string\":[\"Hello\\tWorld\\n\",\"\\u0000\\u0000\\u0000\\u0000\"]}",
4+
};

0 commit comments

Comments
 (0)