Separate the tests and the main program.
This commit is contained in:
1 parent
46af5238ce
commit
20e45f363c
5 files changed
+141
-117
No files matched your search
@@ -8,8 +8,6 @@ clean:
|
|||||||
sed 's/.*`\(.*\)'\''.*/\1/' | grep -v '^all$$' | \
|
sed 's/.*`\(.*\)'\''.*/\1/' | grep -v '^all$$' | \
|
||||||
xargs rm
|
xargs rm
|
||||||
|
|
||||||
jv_utf8_tables.gen.h: gen_utf8_tables.py
|
|
||||||
python $^ > $@
|
|
||||||
|
|
||||||
lexer.gen.c: lexer.l
|
lexer.gen.c: lexer.l
|
||||||
flex -o lexer.gen.c --header-file=lexer.gen.h lexer.l
|
flex -o lexer.gen.c --header-file=lexer.gen.h lexer.l
|
||||||
@@ -19,21 +17,20 @@ parser.gen.c: parser.y lexer.gen.h
|
|||||||
bison -W -d parser.y -v --report-file=parser.gen.info -o $@
|
bison -W -d parser.y -v --report-file=parser.gen.info -o $@
|
||||||
parser.gen.h: parser.gen.c
|
parser.gen.h: parser.gen.c
|
||||||
|
|
||||||
|
jv_utf8_tables.gen.h: gen_utf8_tables.py
|
||||||
|
python $^ > $@
|
||||||
jv_unicode.c: jv_utf8_tables.gen.h
|
jv_unicode.c: jv_utf8_tables.gen.h
|
||||||
|
|
||||||
parsertest: parser.gen.c lexer.gen.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c
|
JQ_SRC=parser.gen.c lexer.gen.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c
|
||||||
|
|
||||||
|
|
||||||
|
jq_test: $(JQ_SRC) jq_test.c
|
||||||
$(CC) -DJQ_DEBUG=1 -o $@ $^
|
$(CC) -DJQ_DEBUG=1 -o $@ $^
|
||||||
|
|
||||||
jq: parser.gen.c lexer.gen.c main.c opcode.c bytecode.c compile.c execute.c builtin.c jv.c jv_parse.c jv_print.c jv_dtoa.c jv_unicode.c
|
jq: $(JQ_SRC) main.c
|
||||||
$(CC) -DJQ_DEBUG=0 -o $@ $^
|
$(CC) -DJQ_DEBUG=0 -o $@ $^
|
||||||
|
|
||||||
jv_test: jv_test.c jv.c jv_print.c jv_dtoa.c jv_unicode.c
|
|
||||||
$(CC) -DNO_JANSSON -o $@ $^
|
|
||||||
|
|
||||||
jv_parse: jv_parse.c jv.c jv_print.c jv_dtoa.c
|
test: jq_test
|
||||||
$(CC) -DNO_JANSSON -o $@ $^ -DJV_PARSE_MAIN
|
valgrind --error-exitcode=1 -q --leak-check=full ./jq_test >/dev/null
|
||||||
|
|
||||||
|
|
||||||
test: jv_test
|
|
||||||
valgrind --error-exitcode=1 -q --leak-check=full ./jv_test
|
|
||||||
|
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
#include "opcode.h"
|
#include "opcode.h"
|
||||||
#include "bytecode.h"
|
#include "bytecode.h"
|
||||||
#include "compile.h"
|
#include "compile.h"
|
||||||
@@ -10,8 +12,10 @@
|
|||||||
#include "forkable_stack.h"
|
#include "forkable_stack.h"
|
||||||
#include "frame_layout.h"
|
#include "frame_layout.h"
|
||||||
|
|
||||||
|
#include "locfile.h"
|
||||||
#include "jv.h"
|
#include "jv.h"
|
||||||
|
#include "parser.h"
|
||||||
|
#include "builtin.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
jv value;
|
jv value;
|
||||||
@@ -500,3 +504,22 @@ void jq_teardown() {
|
|||||||
pathbuf = 0;
|
pathbuf = 0;
|
||||||
pathsize = 0;
|
pathsize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct bytecode* jq_compile(const char* str) {
|
||||||
|
struct locfile locations;
|
||||||
|
locfile_init(&locations, str, strlen(str));
|
||||||
|
block program;
|
||||||
|
struct bytecode* bc = 0;
|
||||||
|
int nerrors = jq_parse(&locations, &program);
|
||||||
|
if (nerrors == 0) {
|
||||||
|
block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
|
||||||
|
program = builtins_bind(program);
|
||||||
|
nerrors = block_compile(program, &locations, &bc);
|
||||||
|
block_free(program);
|
||||||
|
}
|
||||||
|
if (nerrors) {
|
||||||
|
fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
|
||||||
|
}
|
||||||
|
locfile_free(&locations);
|
||||||
|
return bc;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef EXECUTE_H
|
||||||
|
#define EXECUTE_H
|
||||||
|
#include "bytecode.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct bytecode* jq_compile(const char* str);
|
||||||
|
|
||||||
|
void jq_init(struct bytecode* bc, jv value);
|
||||||
|
jv jq_next();
|
||||||
|
void jq_teardown();
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+94
-6
@@ -1,9 +1,97 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include "jv.h"
|
#include "jv.h"
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
int main(){
|
static void jv_test();
|
||||||
|
static void run_jq_tests();
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
jv_test();
|
||||||
|
run_jq_tests();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int skipline(const char* buf) {
|
||||||
|
int p = 0;
|
||||||
|
while (buf[p] == ' ' || buf[p] == '\t') p++;
|
||||||
|
if (buf[p] == '#' || buf[p] == '\n' || buf[p] == 0) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void run_jq_tests() {
|
||||||
|
FILE* testdata = fopen("testdata","r");
|
||||||
|
char buf[4096];
|
||||||
|
int tests = 0, passed = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (!fgets(buf, sizeof(buf), testdata)) break;
|
||||||
|
if (skipline(buf)) continue;
|
||||||
|
printf("Testing %s\n", buf);
|
||||||
|
int pass = 1;
|
||||||
|
struct bytecode* bc = jq_compile(buf);
|
||||||
|
assert(bc);
|
||||||
|
printf("Disassembly:\n");
|
||||||
|
dump_disassembly(2, bc);
|
||||||
|
printf("\n");
|
||||||
|
fgets(buf, sizeof(buf), testdata);
|
||||||
|
jv input = jv_parse(buf);
|
||||||
|
assert(jv_is_valid(input));
|
||||||
|
jq_init(bc, input);
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), testdata)) {
|
||||||
|
if (skipline(buf)) break;
|
||||||
|
jv expected = jv_parse(buf);
|
||||||
|
assert(jv_is_valid(expected));
|
||||||
|
jv actual = jq_next();
|
||||||
|
if (!jv_is_valid(actual)) {
|
||||||
|
jv_free(actual);
|
||||||
|
printf("Insufficient results\n");
|
||||||
|
pass = 0;
|
||||||
|
break;
|
||||||
|
} else if (!jv_equal(jv_copy(expected), jv_copy(actual))) {
|
||||||
|
printf("Expected ");
|
||||||
|
jv_dump(jv_copy(expected), 0);
|
||||||
|
printf(", but got ");
|
||||||
|
jv_dump(jv_copy(actual), 0);
|
||||||
|
printf("\n");
|
||||||
|
pass = 0;
|
||||||
|
}
|
||||||
|
jv as_string = jv_dump_string(jv_copy(expected), rand());
|
||||||
|
jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length(jv_copy(as_string)));
|
||||||
|
assert(jv_equal(jv_copy(expected), jv_copy(reparsed)));
|
||||||
|
jv_free(as_string);
|
||||||
|
jv_free(reparsed);
|
||||||
|
jv_free(expected);
|
||||||
|
jv_free(actual);
|
||||||
|
}
|
||||||
|
if (pass) {
|
||||||
|
jv extra = jq_next();
|
||||||
|
if (jv_is_valid(extra)) {
|
||||||
|
printf("Superfluous result: ");
|
||||||
|
jv_dump(extra, 0);
|
||||||
|
printf("\n");
|
||||||
|
pass = 0;
|
||||||
|
} else {
|
||||||
|
jv_free(extra);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
jq_teardown();
|
||||||
|
bytecode_free(bc);
|
||||||
|
tests++;
|
||||||
|
passed+=pass;
|
||||||
|
}
|
||||||
|
fclose(testdata);
|
||||||
|
printf("%d of %d tests passed\n", passed,tests);
|
||||||
|
if (passed != tests) exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void jv_test() {
|
||||||
/// Arrays and numbers
|
/// Arrays and numbers
|
||||||
{
|
{
|
||||||
jv a = jv_array();
|
jv a = jv_array();
|
||||||
@@ -82,7 +170,7 @@ int main(){
|
|||||||
assert(jv_array_length(jv_array_get(jv_copy(a), 1)) == 1);
|
assert(jv_array_length(jv_array_get(jv_copy(a), 1)) == 1);
|
||||||
|
|
||||||
|
|
||||||
jv_dump(jv_copy(a)); printf("\n");
|
jv_dump(jv_copy(a), 0); printf("\n");
|
||||||
jv_free(a);
|
jv_free(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +180,8 @@ int main(){
|
|||||||
assert(jv_equal(jv_string("foo"), jv_string_sized("foo", 3)));
|
assert(jv_equal(jv_string("foo"), jv_string_sized("foo", 3)));
|
||||||
char nasty[] = "foo\0";
|
char nasty[] = "foo\0";
|
||||||
jv shortstr = jv_string(nasty), longstr = jv_string_sized(nasty, sizeof(nasty));
|
jv shortstr = jv_string(nasty), longstr = jv_string_sized(nasty, sizeof(nasty));
|
||||||
assert(jv_string_length(shortstr) == strlen(nasty));
|
assert(jv_string_length(shortstr) == (int)strlen(nasty));
|
||||||
assert(jv_string_length(longstr) == sizeof(nasty));
|
assert(jv_string_length(longstr) == (int)sizeof(nasty));
|
||||||
|
|
||||||
|
|
||||||
char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye";
|
char a1s[] = "hello", a2s[] = "hello", bs[] = "goodbye";
|
||||||
@@ -111,7 +199,7 @@ int main(){
|
|||||||
|
|
||||||
assert(jv_equal(jv_string("hello42!"), jv_string_fmt("hello%d%s", 42, "!")));
|
assert(jv_equal(jv_string("hello42!"), jv_string_fmt("hello%d%s", 42, "!")));
|
||||||
char big[20000];
|
char big[20000];
|
||||||
for (int i=0; i<sizeof(big); i++) big[i] = 'a';
|
for (int i=0; i<(int)sizeof(big); i++) big[i] = 'a';
|
||||||
big[sizeof(big)-1] = 0;
|
big[sizeof(big)-1] = 0;
|
||||||
jv str = jv_string_fmt("%s", big);
|
jv str = jv_string_fmt("%s", big);
|
||||||
assert(jv_string_length(jv_copy(str)) == sizeof(big) - 1);
|
assert(jv_string_length(jv_copy(str)) == sizeof(big) - 1);
|
||||||
@@ -135,7 +223,7 @@ int main(){
|
|||||||
jv_free(o1);
|
jv_free(o1);
|
||||||
assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("bar"))) == 240);
|
assert(jv_number_value(jv_object_get(jv_copy(o2), jv_string("bar"))) == 240);
|
||||||
|
|
||||||
jv_dump(jv_copy(o2)); printf("\n");
|
jv_dump(jv_copy(o2), 0); printf("\n");
|
||||||
|
|
||||||
jv_free(o2);
|
jv_free(o2);
|
||||||
}
|
}
|
||||||
@@ -6,106 +6,9 @@
|
|||||||
#include "jv_parse.h"
|
#include "jv_parse.h"
|
||||||
#include "locfile.h"
|
#include "locfile.h"
|
||||||
#include "parser.h"
|
#include "parser.h"
|
||||||
|
#include "execute.h"
|
||||||
|
|
||||||
void jq_init(struct bytecode* bc, jv value);
|
|
||||||
jv jq_next();
|
|
||||||
void jq_teardown();
|
|
||||||
|
|
||||||
struct bytecode* jq_compile(const char* str) {
|
|
||||||
struct locfile locations;
|
|
||||||
locfile_init(&locations, str, strlen(str));
|
|
||||||
block program;
|
|
||||||
struct bytecode* bc = 0;
|
|
||||||
int nerrors = jq_parse(&locations, &program);
|
|
||||||
if (nerrors == 0) {
|
|
||||||
block_append(&program, block_join(gen_op_simple(YIELD), gen_op_simple(BACKTRACK)));
|
|
||||||
program = builtins_bind(program);
|
|
||||||
nerrors = block_compile(program, &locations, &bc);
|
|
||||||
block_free(program);
|
|
||||||
}
|
|
||||||
if (nerrors) {
|
|
||||||
fprintf(stderr, "%d compile %s\n", nerrors, nerrors > 1 ? "errors" : "error");
|
|
||||||
}
|
|
||||||
locfile_free(&locations);
|
|
||||||
return bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
int skipline(const char* buf) {
|
|
||||||
int p = 0;
|
|
||||||
while (buf[p] == ' ' || buf[p] == '\t') p++;
|
|
||||||
if (buf[p] == '#' || buf[p] == '\n' || buf[p] == 0) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void run_tests() {
|
|
||||||
FILE* testdata = fopen("testdata","r");
|
|
||||||
char buf[4096];
|
|
||||||
int tests = 0, passed = 0;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
if (!fgets(buf, sizeof(buf), testdata)) break;
|
|
||||||
if (skipline(buf)) continue;
|
|
||||||
printf("Testing %s\n", buf);
|
|
||||||
int pass = 1;
|
|
||||||
struct bytecode* bc = jq_compile(buf);
|
|
||||||
assert(bc);
|
|
||||||
printf("Disassembly:\n");
|
|
||||||
dump_disassembly(2, bc);
|
|
||||||
printf("\n");
|
|
||||||
fgets(buf, sizeof(buf), testdata);
|
|
||||||
jv input = jv_parse(buf);
|
|
||||||
assert(jv_is_valid(input));
|
|
||||||
jq_init(bc, input);
|
|
||||||
|
|
||||||
while (fgets(buf, sizeof(buf), testdata)) {
|
|
||||||
if (skipline(buf)) break;
|
|
||||||
jv expected = jv_parse(buf);
|
|
||||||
assert(jv_is_valid(expected));
|
|
||||||
jv actual = jq_next();
|
|
||||||
if (!jv_is_valid(actual)) {
|
|
||||||
jv_free(actual);
|
|
||||||
printf("Insufficient results\n");
|
|
||||||
pass = 0;
|
|
||||||
break;
|
|
||||||
} else if (!jv_equal(jv_copy(expected), jv_copy(actual))) {
|
|
||||||
printf("Expected ");
|
|
||||||
jv_dump(jv_copy(expected), 0);
|
|
||||||
printf(", but got ");
|
|
||||||
jv_dump(jv_copy(actual), 0);
|
|
||||||
printf("\n");
|
|
||||||
pass = 0;
|
|
||||||
}
|
|
||||||
jv as_string = jv_dump_string(jv_copy(expected), rand());
|
|
||||||
jv reparsed = jv_parse_sized(jv_string_value(as_string), jv_string_length(jv_copy(as_string)));
|
|
||||||
assert(jv_equal(jv_copy(expected), jv_copy(reparsed)));
|
|
||||||
jv_free(as_string);
|
|
||||||
jv_free(reparsed);
|
|
||||||
jv_free(expected);
|
|
||||||
jv_free(actual);
|
|
||||||
}
|
|
||||||
if (pass) {
|
|
||||||
jv extra = jq_next();
|
|
||||||
if (jv_is_valid(extra)) {
|
|
||||||
printf("Superfluous result: ");
|
|
||||||
jv_dump(extra, 0);
|
|
||||||
printf("\n");
|
|
||||||
pass = 0;
|
|
||||||
} else {
|
|
||||||
jv_free(extra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
jq_teardown();
|
|
||||||
bytecode_free(bc);
|
|
||||||
tests++;
|
|
||||||
passed+=pass;
|
|
||||||
}
|
|
||||||
fclose(testdata);
|
|
||||||
printf("%d of %d tests passed\n", passed,tests);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc == 1) { run_tests(); return 0; }
|
|
||||||
struct bytecode* bc = jq_compile(argv[1]);
|
struct bytecode* bc = jq_compile(argv[1]);
|
||||||
if (!bc) return 1;
|
if (!bc) return 1;
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user