summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/assert.c39
-rw-r--r--test/assert.h10
-rw-r--r--test/buffer.c33
-rw-r--r--test/bufread.c63
-rw-r--r--test/json.c124
-rw-r--r--test/json/diag.json54
-rw-r--r--test/json/diag2.json1
-rw-r--r--test/main.c3
-rw-r--r--test/test.h1
9 files changed, 301 insertions, 27 deletions
diff --git a/test/assert.c b/test/assert.c
index b252d36..2fa8a89 100644
--- a/test/assert.c
+++ b/test/assert.c
@@ -1,20 +1,47 @@
#include "assert.h"
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-void assert(bool cond, const char *cond_str, const char *file, int line,
- const char *msg) {
+static void assert_internal(bool cond, const char *cond_str, const char *file,
+ int line, const char *msg, va_list args) {
if (!cond) {
- printf("\n%s:%d: assert failed (%s): %s\n", file, line, cond_str, msg);
+ va_list args2;
+ va_copy(args2, args);
+
+ ssize_t res = vsnprintf(NULL, 0, msg, args);
+ char *buf = (char *)msg;
+
+ if (res != -1) {
+ buf = malloc(res + 1);
+ vsnprintf(buf, res + 1, msg, args2);
+ }
+
+ va_end(args);
+
+ printf("\n%s:%d: assert failed (%s): %s\n", file, line, cond_str, buf);
+
+ if (buf != msg) {
+ free(buf);
+ }
raise(SIGABRT);
}
}
+void assert(bool cond, const char *cond_str, const char *file, int line,
+ const char *msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ assert_internal(cond, cond_str, file, line, msg, args);
+}
+
void assert_streq(const char *left, const char *right, const char *file,
- int line, const char *msg) {
- assert(strcmp(left, right) == 0, "<left string> == <right string>", file,
- line, msg);
+ int line, const char *msg, ...) {
+ va_list args;
+ va_start(args, msg);
+ assert_internal(strcmp(left, right) == 0, "<left string> == <right string>",
+ file, line, msg, args);
}
diff --git a/test/assert.h b/test/assert.h
index 8b730b2..b9b5719 100644
--- a/test/assert.h
+++ b/test/assert.h
@@ -1,10 +1,10 @@
#include <stdbool.h>
-#define ASSERT(cond, msg) assert(cond, #cond, __FILE__, __LINE__, msg)
-#define ASSERT_STR_EQ(left, right, msg) \
- assert_streq(left, right, __FILE__, __LINE__, msg)
+#define ASSERT(cond, msg, ...) assert(cond, #cond, __FILE__, __LINE__, msg, ##__VA_ARGS__)
+#define ASSERT_STR_EQ(left, right, msg, ...) \
+ assert_streq(left, right, __FILE__, __LINE__, msg, ##__VA_ARGS__)
void assert(bool cond, const char *cond_str, const char *file, int line,
- const char *msg);
+ const char *msg, ...);
void assert_streq(const char *left, const char *right, const char *file,
- int line, const char *msg);
+ int line, const char *msg, ...);
diff --git a/test/buffer.c b/test/buffer.c
index 514671b..a8268da 100644
--- a/test/buffer.c
+++ b/test/buffer.c
@@ -103,12 +103,19 @@ static void test_delete(void) {
static void test_word_at(void) {
struct buffer b = buffer_create("test-word-at-buffer");
- const char *txt = "word1 (word2). Another";
- buffer_add(&b, (struct location){.line = 0, .col = 0}, (uint8_t *)txt,
- strlen(txt));
+ const char *txt = "word1";
+ struct location at = buffer_add(&b, (struct location){.line = 0, .col = 0},
+ (uint8_t *)txt, strlen(txt));
struct region word1 =
- buffer_word_at(&b, (struct location){.line = 0, .col = 0});
+ buffer_word_at(&b, (struct location){.line = 0, .col = 5});
+ ASSERT(region_has_size(word1), "expected 0,0 to be a word even if only word");
+ ASSERT(word1.begin.col == 0 && word1.end.col == 5,
+ "Expected only word to end at col 5");
+
+ const char *txt2 = " (word2). Another";
+ buffer_add(&b, at, (uint8_t *)txt2, strlen(txt2));
+ word1 = buffer_word_at(&b, (struct location){.line = 0, .col = 0});
ASSERT(region_has_size(word1), "expected 0,0 to be a word");
ASSERT(word1.begin.col == 0 && word1.end.col == 5,
"Expected word to end at col 5");
@@ -179,7 +186,7 @@ static void test_char_movement(void) {
static void test_word_movement(void) {
struct buffer b = buffer_create("test-word-movement-buffer");
- const char *txt = " word1, word2 \"word3\" word4";
+ const char *txt = " word1, word2 \"word3\" word4";
buffer_add(&b, buffer_end(&b), (uint8_t *)txt, strlen(txt));
struct location next =
buffer_next_word(&b, (struct location){.line = 0, .col = 0});
@@ -192,19 +199,29 @@ static void test_word_movement(void) {
ASSERT(next.col == 15, "Expected next word to start at col 15");
next = buffer_next_word(&b, (struct location){.line = 0, .col = 15});
- ASSERT(next.col == 22, "Expected next word to start at col 22");
+ ASSERT(next.col == 24, "Expected next word to start at col 24");
struct location prev =
buffer_previous_word(&b, (struct location){.line = 0, .col = 26});
- ASSERT(prev.col == 22, "Expected previous word to start at col 22");
+ ASSERT(prev.col == 24, "Expected previous word to start at col 24");
- prev = buffer_previous_word(&b, (struct location){.line = 0, .col = 22});
+ prev = buffer_previous_word(&b, (struct location){.line = 0, .col = 24});
ASSERT(prev.col == 15, "Expected previous word to start at col 15");
+ prev = buffer_previous_word(&b, (struct location){.line = 0, .col = 3});
+ ASSERT(prev.col == 0 && prev.line == 0,
+ "Expected first word to start at start of first line");
+
prev = buffer_previous_word(&b, (struct location){.line = 0, .col = 0});
ASSERT(prev.col == 0 && prev.line == 0,
"Expected previous word to not go before beginning of buffer");
+ const char *txt2 = " word";
+ buffer_add(&b, buffer_end(&b), (uint8_t *)txt2, strlen(txt2));
+ prev = buffer_previous_word(&b, (struct location){.line = 1, .col = 8});
+ ASSERT(prev.col == 0 && prev.line == 1,
+ "Expected to be at start of line if there are no words");
+
buffer_destroy(&b);
}
diff --git a/test/bufread.c b/test/bufread.c
new file mode 100644
index 0000000..d477946
--- /dev/null
+++ b/test/bufread.c
@@ -0,0 +1,63 @@
+#ifdef LINUX
+#define _GNU_SOURCE
+#endif
+
+#include "assert.h"
+#include "test.h"
+
+#include "dged/bufread.h"
+
+#include <stdint.h>
+#include <unistd.h>
+
+#ifdef LINUX
+#include <sys/mman.h>
+#endif
+
+static void test_read(void) {
+#ifdef LINUX
+ int memfd = memfd_create("bufread-test", 0);
+ ASSERT(memfd >= 0, "Failed to create memfd");
+#endif
+ for (int i = 0; i < 256; ++i) {
+ int a = write(memfd, (uint8_t *)&i, 1);
+ (void)a;
+ }
+ lseek(memfd, 0, SEEK_SET);
+
+ struct bufread *br = bufread_create(memfd, 128);
+ uint8_t buf[32];
+ ssize_t read = bufread_read(br, buf, 32);
+ ASSERT(read > 0, "Expected to be able to read");
+ for (int i = 0; i < 32; ++i) {
+ ASSERT(i == buf[i], "Expected buffer to be monotonically increasing");
+ }
+ bufread_read(br, buf, 32);
+ bufread_read(br, buf, 32);
+ bufread_read(br, buf, 32);
+
+ read = bufread_read(br, buf, 32);
+ ASSERT(read > 0, "Expected to be able to read");
+ for (int i = 0; i < 32; ++i) {
+ ASSERT((i + 128) == buf[i],
+ "Expected buffer to be monotonically increasing");
+ }
+ bufread_destroy(br);
+}
+
+void test_empty_read(void) {
+#ifdef LINUX
+ int memfd = memfd_create("bufread-test", 0);
+ ASSERT(memfd >= 0, "Failed to create memfd");
+#endif
+ struct bufread *br = bufread_create(memfd, 128);
+ uint8_t buf[32];
+ ssize_t read = bufread_read(br, buf, 32);
+ ASSERT(read == 0, "Expected to not be able to read from empty stream");
+ bufread_destroy(br);
+}
+
+void run_bufread_tests(void) {
+ run_test(test_read);
+ run_test(test_empty_read);
+}
diff --git a/test/json.c b/test/json.c
index c67fc75..0243ee3 100644
--- a/test/json.c
+++ b/test/json.c
@@ -3,16 +3,64 @@
#include "dged/json.h"
+#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+
+struct parsed_json {
+ struct json_result result;
+ uint8_t *buf;
+};
+
+static struct parsed_json json_parse_error(const char *msg) {
+ return (struct parsed_json){
+ .result =
+ (struct json_result){
+ .ok = false,
+ .result.error = msg,
+ },
+ .buf = NULL,
+ };
+}
+
+static struct parsed_json parse_json_file(const char *path) {
+ struct stat sb;
+ if (stat(path, &sb) != 0) {
+ return json_parse_error("file not found");
+ }
+
+ FILE *file = fopen(path, "r");
+ if (fseek(file, 0, SEEK_END) != 0) {
+ return json_parse_error("fseek to end failed");
+ }
+
+ long sz = ftell(file);
+ if (sz == -1) {
+ return json_parse_error("ftell failed");
+ }
+
+ rewind(file);
+
+ uint8_t *buff = malloc(sz);
+ int bytes = fread(buff, 1, sz, file);
+ if (bytes != sz) {
+ return json_parse_error("did not read whole file");
+ }
+
+ return (struct parsed_json){
+ .result = json_parse(buff, sz),
+ .buf = buff,
+ };
+}
-void test_empty_parse(void) {
+static void test_empty_parse(void) {
struct json_result res = json_parse((uint8_t *)"", 0);
ASSERT(res.ok, "Expected empty parse to work");
json_destroy(&res.result.document);
}
-void test_empty_array(void) {
+static void test_empty_array(void) {
struct json_result res = json_parse((uint8_t *)"[]", 2);
ASSERT(res.ok, "Expected parse of empty array to work");
@@ -23,7 +71,7 @@ void test_empty_array(void) {
json_destroy(&root);
}
-void test_array(void) {
+static void test_array(void) {
struct json_result res = json_parse((uint8_t *)"[ 1, 2, 4 ]", 11);
ASSERT(res.ok, "Expected parse of number array to work");
@@ -33,7 +81,7 @@ void test_array(void) {
json_destroy(&root);
- const char *jsn = "[ \"hello\", \"world\" ]";
+ const char *jsn = "[ \"hello\", \"world\", \"\\\"\" ]";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of string array to work");
root = res.result.document;
@@ -46,7 +94,7 @@ void test_array(void) {
json_destroy(&root);
}
-void test_object(void) {
+static void test_object(void) {
struct json_result res = json_parse((uint8_t *)"{ }", 3);
ASSERT(res.ok, "Expected parse of empty object to work");
struct json_value root = res.result.document;
@@ -55,7 +103,8 @@ void test_object(void) {
json_destroy(&root);
- const char *jsn = "{ \"name\": \"Kalle Kula\", \"age\": 33, }";
+ const char *jsn = "{ \"name\": \"Kalle Kula\", \"age\": 33, \"ball\": true, "
+ "\"square\": false }";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of simple object to work");
root = res.result.document;
@@ -67,13 +116,17 @@ void test_object(void) {
ASSERT(age->type == Json_Number, "Expected age to (just?) be a number");
ASSERT(age->value.number == 33, "Expected age to be 33");
+ struct json_value *ball = json_get(root.value.object, s8("ball"));
+ ASSERT(ball->type == Json_Bool, "Expected ball to be a boolean.");
+ ASSERT(ball->value.boolean, "Expected Kalle Kulla to be a ball.");
+
json_destroy(&root);
jsn = "{ \"name\": \"Kalle Kula\", \"age\": 33, \"kids\": "
"[ "
"{ \"name\": \"Sune Kula\", \"age\": 10, }, "
- "{ \"name\": \"Suna Kula\", \"age\": 7 } "
- "] }";
+ "{ \"name\": \"Suna Kula\", \"age\": 7 }, "
+ "], \"pet_names\": [ \"fido\", \"fado\" ], \"ball\": true }";
res = json_parse((uint8_t *)jsn, strlen(jsn));
ASSERT(res.ok, "Expected parse of nested object to work");
root = res.result.document;
@@ -84,12 +137,67 @@ void test_object(void) {
struct json_value *kids = json_get(root.value.object, s8("kids"));
ASSERT(kids->type == Json_Array, "Expected kids to be array");
+ ball = json_get(root.value.object, s8("ball"));
+ ASSERT(ball->type == Json_Bool, "Expected ball to be a boolean.");
+ ASSERT(ball->value.boolean, "Expected Kalle Kulla to be a ball.");
+
json_destroy(&root);
}
+#define xstr(s) str(s)
+#define str(s) #s
+
+#define test_parse_file(path) \
+ { \
+ struct parsed_json parsed = parse_json_file(xstr(TEST_ROOT) "/" path); \
+ ASSERT(parsed.result.ok, "Expected parsing of " #path " to work: %s", \
+ parsed.result.result.error); \
+ json_destroy(&parsed.result.result.document); \
+ free(parsed.buf); \
+ }
+
+static void test_files(void) { test_parse_file("json/diag.json"); }
+
+static void test_brackets_in_strings(void) {
+ struct parsed_json parsed =
+ parse_json_file(xstr(TEST_ROOT) "/json/diag2.json");
+ ASSERT(parsed.result.ok, "Expected parsing of diag2.json to work");
+
+ struct json_value *params =
+ json_get(parsed.result.result.document.value.object, s8("params"));
+ ASSERT(params != NULL, "Expected JSON object to contain params");
+ ASSERT(params->type == Json_Object, "Expected params to be a JSON object");
+
+ struct json_value *diagnostics =
+ json_get(params->value.object, s8("diagnostics"));
+ ASSERT(diagnostics != NULL, "Expected params to contain diagnostics");
+ ASSERT(diagnostics->type == Json_Array, "Expected params to be a JSON array");
+
+ struct json_array *diags = diagnostics->value.array;
+ ASSERT(json_array_len(diags) == 5,
+ "Expected diagnostics array to contain five items");
+
+ json_destroy(&parsed.result.result.document);
+ free(parsed.buf);
+}
+
+static void test_str_escape(void) {
+ struct s8 res = unescape_json_string(s8("a\n\\n\r\\rb"));
+ ASSERT(s8eq(res, s8("a\n\n\r\rb")), "Expected \\n and \\r to not be removed");
+
+ s8delete(res);
+
+ struct s8 res2 = unescape_json_string(s8(" \\\\\\n"));
+ ASSERT(s8eq(res2, s8(" \\\n")), "Expected \\ and \\n to not be removed");
+ s8delete(res2);
+}
+
void run_json_tests(void) {
run_test(test_empty_parse);
run_test(test_empty_array);
run_test(test_array);
run_test(test_object);
+ run_test(test_files);
+ run_test(test_brackets_in_strings);
+ run_test(test_str_escape);
}
diff --git a/test/json/diag.json b/test/json/diag.json
new file mode 100644
index 0000000..4384ea3
--- /dev/null
+++ b/test/json/diag.json
@@ -0,0 +1,54 @@
+{
+ "jsonrpc": "2.0",
+ "method": "textDocument/publishDiagnostics",
+ "params": {
+ "diagnostics": [
+ {
+ "code": "unused-includes",
+ "codeDescription": {
+ "href": "https://clangd.llvm.org/guides/include-cleaner"
+ },
+ "message": "Included header errno.h is not used directly (fixes available)",
+ "range": {
+ "end": {
+ "character": 18,
+ "line": 4
+ },
+ "start": {
+ "character": 0,
+ "line": 4
+ }
+ },
+ "severity": 2,
+ "source": "clangd",
+ "tags": [
+ 1
+ ]
+ },
+ {
+ "code": "unused-includes",
+ "codeDescription": {
+ "href": "https://clangd.llvm.org/guides/include-cleaner"
+ },
+ "message": "Included header hash.h is not used directly (fixes available)",
+ "range": {
+ "end": {
+ "character": 17,
+ "line": 16
+ },
+ "start": {
+ "character": 0,
+ "line": 16
+ }
+ },
+ "severity": 2,
+ "source": "clangd",
+ "tags": [
+ 1
+ ]
+ }
+ ],
+ "uri": "file:///home/abbe/code/dged/src/dged/syntax.c",
+ "version": 0
+ }
+}
diff --git a/test/json/diag2.json b/test/json/diag2.json
new file mode 100644
index 0000000..3c0989d
--- /dev/null
+++ b/test/json/diag2.json
@@ -0,0 +1 @@
+{"jsonrpc":"2.0","method":"textDocument/publishDiagnostics","params":{"diagnostics":[{"code":"expected_after","message":"Expected ';' after struct (fix available)","range":{"end":{"character":3,"line":4},"start":{"character":0,"line":4}},"severity":1,"source":"clang"},{"code":"-Wmissing-declarations","message":"Declaration does not declare anything","range":{"end":{"character":6,"line":1},"start":{"character":0,"line":1}},"severity":1,"source":"clang"},{"code":"expected","message":"Expected '}'\n\ntest.c:9:13: note: to match this '{'","range":{"end":{"character":13,"line":8},"start":{"character":13,"line":8}},"severity":1,"source":"clang"},{"message":"To match this '{'\n\ntest.c:9:14: error: expected '}'","range":{"end":{"character":13,"line":8},"start":{"character":12,"line":8}},"severity":3},{"code":"expected_after","message":"Expected ';' after struct (fix available)","range":{"end":{"character":13,"line":8},"start":{"character":13,"line":8}},"severity":1,"source":"clang"}],"uri":"file:///home/abbe/code/dged/test.c","version":33}}
diff --git a/test/main.c b/test/main.c
index f8e1eca..eba54a6 100644
--- a/test/main.c
+++ b/test/main.c
@@ -53,6 +53,9 @@ int main(void) {
printf("\nšŸŽ \x1b[1;36mRunning container tests...\x1b[0m\n");
run_container_tests();
+ printf("\n🐃 \x1b[1;36mRunning bufread tests...\x1b[0m\n");
+ run_bufread_tests();
+
#if defined(LSP_ENABLED)
printf("\nšŸ“ƒ \x1b[1;36mRunning JSON tests...\x1b[0m\n");
run_json_tests();
diff --git a/test/test.h b/test/test.h
index d099cc3..3f734ad 100644
--- a/test/test.h
+++ b/test/test.h
@@ -21,5 +21,6 @@ void run_minibuffer_tests(void);
void run_settings_tests(void);
void run_container_tests(void);
void run_json_tests(void);
+void run_bufread_tests(void);
#endif