diff options
| author | Albert Cervin <albert@acervin.com> | 2024-09-17 08:47:03 +0200 |
|---|---|---|
| committer | Albert Cervin <albert@acervin.com> | 2025-11-01 22:11:14 +0100 |
| commit | 4459b8b3aa9d73895391785a99dcc87134e80601 (patch) | |
| tree | a5204f447a0b2b05f63504c7fe958ef9bbf1918a /test | |
| parent | 4689f3f38277bb64981fc960e8e384e2d065d659 (diff) | |
| download | dged-4459b8b3aa9d73895391785a99dcc87134e80601.tar.gz dged-4459b8b3aa9d73895391785a99dcc87134e80601.tar.xz dged-4459b8b3aa9d73895391785a99dcc87134e80601.zip | |
More lsp support
This makes the LSP support complete for now:
- Completion
- Diagnostics
- Goto implementation/declaration
- Rename
- Documentation
- Find references
Diffstat (limited to 'test')
| -rw-r--r-- | test/assert.c | 39 | ||||
| -rw-r--r-- | test/assert.h | 10 | ||||
| -rw-r--r-- | test/buffer.c | 33 | ||||
| -rw-r--r-- | test/bufread.c | 63 | ||||
| -rw-r--r-- | test/json.c | 124 | ||||
| -rw-r--r-- | test/json/diag.json | 54 | ||||
| -rw-r--r-- | test/json/diag2.json | 1 | ||||
| -rw-r--r-- | test/main.c | 3 | ||||
| -rw-r--r-- | test/test.h | 1 |
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 |
