test: reorganize unit tests

This commit is contained in:
lohhiiccc 2026-01-12 10:18:47 +01:00
parent 8c0ed3462f
commit 5170f70152
16 changed files with 1338 additions and 5 deletions

View file

@ -18,8 +18,18 @@ SRCS = $(SRC_DIR)/main.c \
$(SRC_DIR)/validator/validator.c
TESTS_DIR = tests
TESTS = $(TESTS_DIR)/test_utils.c \
$(TESTS_DIR)/test_map.c \
$(TESTS_DIR)/test_transpile.c \
$(TESTS_DIR)/test_cli.c \
$(TESTS_DIR)/test_integration.c
TESTS = $(TESTS_DIR)/test_integration.c \
$(TESTS_DIR)/io/test_streams.c \
$(TESTS_DIR)/utils/io/test_read_line.c \
$(TESTS_DIR)/utils/string/test_starts_with.c \
$(TESTS_DIR)/utils/string/test_extract_fence_ext.c \
$(TESTS_DIR)/utils/string/test_extract_file_ext.c \
$(TESTS_DIR)/utils/string/test_infer_ext_from_filename.c \
$(TESTS_DIR)/cli/test_cli.c \
$(TESTS_DIR)/cli/test_help.c \
$(TESTS_DIR)/map/test_map_core.c \
$(TESTS_DIR)/map/test_map_io.c \
$(TESTS_DIR)/transpile/test_transpile_core.c \
$(TESTS_DIR)/transpile/test_transpile_fence.c \
$(TESTS_DIR)/transpile/test_transpile_state.c \
$(TESTS_DIR)/transpile/test_transpile_code.c

162
tests/cli/test_cli.c Normal file
View file

@ -0,0 +1,162 @@
#include <criterion/criterion.h>
#include "cli.h"
Test(cli, parse_ext_short)
{
t_args args;
char *argv[] = {"c-md", "-e", "c"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.ext);
cr_assert_str_eq(args.ext, "c");
cr_assert_eq(args.show_help, 0);
}
Test(cli, parse_ext_long)
{
t_args args;
char *argv[] = {"c-md", "--ext", "python"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.ext);
cr_assert_str_eq(args.ext, "python");
}
/*
** TESTS: cli/cli.c - Input option
*/
Test(cli, parse_input_short)
{
t_args args;
char *argv[] = {"c-md", "-i", "input.md"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.input);
cr_assert_str_eq(args.input, "input.md");
}
Test(cli, parse_input_long)
{
t_args args;
char *argv[] = {"c-md", "--input", "input.md"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.input);
cr_assert_str_eq(args.input, "input.md");
}
/*
** TESTS: cli/cli.c - Output option
*/
Test(cli, parse_output)
{
t_args args;
char *argv[] = {"c-md", "-o", "output.c"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.output);
cr_assert_str_eq(args.output, "output.c");
}
/*
** TESTS: cli/cli.c - Map option
*/
Test(cli, parse_map_short)
{
t_args args;
char *argv[] = {"c-md", "-m", "output.map"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.map_path);
cr_assert_str_eq(args.map_path, "output.map");
}
Test(cli, parse_map_long)
{
t_args args;
char *argv[] = {"c-md", "--map", "output.map"};
int8_t ret;
ret = cli_parse(&args, 3, argv);
cr_assert_eq(ret, 0);
cr_assert_not_null(args.map_path);
cr_assert_str_eq(args.map_path, "output.map");
}
/*
** TESTS: cli/cli.c - Multiple arguments
*/
Test(cli, parse_multiple_args)
{
t_args args;
char *argv[] = {
"c-md", "-e", "c", "-i", "input.c.md",
"-o", "output.c", "-m", "output.map"
};
int8_t ret;
ret = cli_parse(&args, 9, argv);
cr_assert_eq(ret, 0);
cr_assert_str_eq(args.ext, "c");
cr_assert_str_eq(args.input, "input.c.md");
cr_assert_str_eq(args.output, "output.c");
cr_assert_str_eq(args.map_path, "output.map");
cr_assert_eq(args.show_help, 0);
}
/*
** TESTS: cli/cli.c - Edge cases
*/
Test(cli, parse_no_args)
{
t_args args;
char *argv[] = {"c-md"};
int8_t ret;
ret = cli_parse(&args, 1, argv);
cr_assert_eq(ret, 0);
cr_assert_null(args.ext);
cr_assert_null(args.input);
cr_assert_null(args.output);
cr_assert_null(args.map_path);
cr_assert_eq(args.show_help, 0);
}
//TODO: mute stderr
Test(cli, parse_invalid_arg)
{
t_args args;
char *argv[] = {"c-md", "-x"};
int8_t ret;
ret = cli_parse(&args, 2, argv);
cr_assert_neq(ret, 0);
}

32
tests/cli/test_help.c Normal file
View file

@ -0,0 +1,32 @@
#include <criterion/criterion.h>
#include "cli.h"
/*
** TESTS: cli/cli.c - Help option
*/
Test(cli, parse_help_short)
{
t_args args;
char *argv[] = {"c-md", "-h"};
int8_t ret;
ret = cli_parse(&args, 2, argv);
cr_assert_eq(ret, 0);
cr_assert_eq(args.show_help, 1);
}
Test(cli, parse_help_long)
{
t_args args;
char *argv[] = {"c-md", "--help"};
int8_t ret;
ret = cli_parse(&args, 2, argv);
cr_assert_eq(ret, 0);
cr_assert_eq(args.show_help, 1);
}

103
tests/io/test_streams.c Normal file
View file

@ -0,0 +1,103 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "io.h"
/*
** TESTS: io/streams.c
*/
Test(io, open_with_files)
{
t_io io;
int8_t ret;
FILE *f = fopen("/tmp/test_io_in.md", "w");
fprintf(f, "test\n");
fclose(f);
ret = io_open(&io, "/tmp/test_io_in.md", "/tmp/test_io_out.c");
cr_assert_eq(ret, 0);
cr_assert_not_null(io.in);
cr_assert_not_null(io.out);
cr_assert_neq(io.in, stdin);
cr_assert_neq(io.out, stdout);
io_close(&io);
remove("/tmp/test_io_in.md");
remove("/tmp/test_io_out.c");
}
Test(io, open_with_stdin_stdout)
{
t_io io;
int8_t ret;
ret = io_open(&io, NULL, NULL);
cr_assert_eq(ret, 0);
cr_assert_eq(io.in, stdin);
cr_assert_eq(io.out, stdout);
io_close(&io);
}
Test(io, open_with_invalid_input)
{
t_io io;
int8_t ret;
ret = io_open(&io, "/tmp/nonexistent_file_123456.md", "/tmp/test_io_out.c");
cr_assert_eq(ret, 1);
}
Test(io, open_input_only)
{
t_io io;
int8_t ret;
FILE *f = fopen("/tmp/test_io_input.md", "w");
fprintf(f, "test\n");
fclose(f);
ret = io_open(&io, "/tmp/test_io_input.md", NULL);
cr_assert_eq(ret, 0);
cr_assert_not_null(io.in);
cr_assert_neq(io.in, stdin);
cr_assert_eq(io.out, stdout);
io_close(&io);
remove("/tmp/test_io_input.md");
}
Test(io, open_output_only)
{
t_io io;
int8_t ret;
ret = io_open(&io, NULL, "/tmp/test_io_output.c");
cr_assert_eq(ret, 0);
cr_assert_eq(io.in, stdin);
cr_assert_not_null(io.out);
cr_assert_neq(io.out, stdout);
io_close(&io);
remove("/tmp/test_io_output.c");
}
Test(io, close_does_not_close_stdin_stdout)
{
t_io io;
io.in = stdin;
io.out = stdout;
io_close(&io);
cr_assert_eq(io.in, stdin);
cr_assert_eq(io.out, stdout);
}

118
tests/map/test_map_core.c Normal file
View file

@ -0,0 +1,118 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include <string.h>
#include "map.h"
/*
** TESTS: map/core.c - Initialization
*/
Test(map_core, init)
{
t_map map;
map_init(&map);
cr_assert_null(map.ranges);
cr_assert_eq(map.count, 0);
cr_assert_eq(map.capacity, 0);
}
/*
** TESTS: map/core.c - Adding ranges
*/
Test(map_core, add_single_range)
{
t_map map;
map_init(&map);
map_add(&map, 10, 20, 5, 15);
cr_assert_not_null(map.ranges);
cr_assert_eq(map.count, 1);
cr_assert_geq(map.capacity, 1);
cr_assert_eq(map.ranges[0].src_start, 10);
cr_assert_eq(map.ranges[0].src_end, 20);
cr_assert_eq(map.ranges[0].dst_start, 5);
cr_assert_eq(map.ranges[0].dst_end, 15);
map_free(&map);
}
Test(map_core, add_multiple_ranges)
{
t_map map;
map_init(&map);
map_add(&map, 1, 5, 1, 5);
map_add(&map, 10, 15, 7, 12);
map_add(&map, 20, 25, 14, 19);
cr_assert_eq(map.count, 3);
cr_assert_geq(map.capacity, 3);
cr_assert_eq(map.ranges[0].src_start, 1);
cr_assert_eq(map.ranges[1].src_start, 10);
cr_assert_eq(map.ranges[2].src_start, 20);
map_free(&map);
}
/*
** TESTS: map/core.c - Dynamic growth
*/
Test(map_core, capacity_growth)
{
t_map map;
size_t i;
map_init(&map);
for (i = 0; i < 100; i++)
{
map_add(&map, i, i + 10, i, i + 10);
}
cr_assert_eq(map.count, 100);
cr_assert_geq(map.capacity, 100);
for (i = 0; i < 100; i++)
{
cr_assert_eq(map.ranges[i].src_start, i);
cr_assert_eq(map.ranges[i].src_end, i + 10);
}
map_free(&map);
}
/*
** TESTS: map/core.c - Memory management
*/
Test(map_core, free_after_init)
{
t_map map;
map_init(&map);
map_free(&map);
cr_assert_null(map.ranges);
cr_assert_eq(map.count, 0);
cr_assert_eq(map.capacity, 0);
}
Test(map_core, free_after_add)
{
t_map map;
map_init(&map);
map_add(&map, 1, 10, 1, 10);
map_free(&map);
cr_assert_null(map.ranges);
cr_assert_eq(map.count, 0);
cr_assert_eq(map.capacity, 0);
}

78
tests/map/test_map_io.c Normal file
View file

@ -0,0 +1,78 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "map.h"
/*
** TESTS: map/io.c - Writing to file
*/
Test(map_io, write_to_file)
{
t_map map;
FILE *f;
char buffer[256];
const char *path = "/tmp/test_c_md_map.map";
map_init(&map);
map_add(&map, 2, 8, 1, 7);
map_add(&map, 15, 22, 9, 16);
cr_assert_eq(map_write(&map, path, "main.c.md", "main.c"), 0);
f = fopen(path, "r");
cr_assert_not_null(f);
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "C-MD MAP v1\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "source: main.c.md\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "target: main.c\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "---\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "2-8:1-7\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "15-22:9-16\n");
fclose(f);
remove(path);
map_free(&map);
}
Test(map_io, write_empty_map)
{
t_map map;
FILE *f;
char buffer[256];
const char *path = "/tmp/test_c_md_empty_map.map";
map_init(&map);
cr_assert_eq(map_write(&map, path, "test.c.md", "test.c"), 0);
f = fopen(path, "r");
cr_assert_not_null(f);
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "C-MD MAP v1\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "source: test.c.md\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "target: test.c\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "---\n");
fclose(f);
remove(path);
map_free(&map);
}

197
tests/test_integration.c Normal file
View file

@ -0,0 +1,197 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "cli.h"
#include "validator.h"
#include "transpile.h"
#include "map.h"
static const char *sample_input =
"# Sample C Program\n"
"\n"
"This is a simple C program.\n"
"\n"
"```c\n"
"#include <stdio.h>\n"
"```\n"
"\n"
"Main function:\n"
"\n"
"```c\n"
"int main(void) {\n"
" printf(\"Hello, World!\\n\");\n"
" return 0;\n"
"}\n"
"```\n";
/*
** TESTS: Integration - File mode
*/
Test(integration, file_mode_basic)
{
const char *in_path = "/tmp/test_integration_in.c.md";
const char *out_path = "/tmp/test_integration_out.c";
FILE *in;
FILE *out;
FILE *f;
t_map map;
char buffer[256];
int8_t ret;
f = fopen(in_path, "w");
fprintf(f, "%s", sample_input);
fclose(f);
in = fopen(in_path, "r");
out = fopen(out_path, "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
map_free(&map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
f = fopen(out_path, "r");
cr_assert_not_null(f);
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "#include <stdio.h>\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "\n");
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "int main(void) {\n");
fclose(f);
remove(in_path);
remove(out_path);
}
Test(integration, file_mode_with_map)
{
const char *in_path = "/tmp/test_integration_map_in.c.md";
const char *out_path = "/tmp/test_integration_map_out.c";
const char *map_path = "/tmp/test_integration.map";
FILE *in;
FILE *out;
FILE *f;
t_map map;
char buffer[256];
int8_t ret;
f = fopen(in_path, "w");
fprintf(f, "%s", sample_input);
fclose(f);
in = fopen(in_path, "r");
out = fopen(out_path, "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
if (0 == ret)
ret = map_write(&map, map_path, in_path, out_path);
map_free(&map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
f = fopen(map_path, "r");
cr_assert_not_null(f);
fgets(buffer, sizeof(buffer), f);
cr_assert_str_eq(buffer, "C-MD MAP v1\n");
fclose(f);
remove(in_path);
remove(out_path);
remove(map_path);
}
/*
** TESTS: Integration - Validator
*/
Test(integration, validator_with_input_and_output)
{
t_args args;
args.ext = "c";
args.input = "test.c.md";
args.output = "test.c";
args.map_path = NULL;
args.show_help = 0;
cr_assert_eq(validator_validate_args(&args), 0);
}
Test(integration, validator_stdin_missing_ext)
{
t_args args;
args.ext = NULL;
args.input = NULL;
args.output = "test.c";
args.map_path = NULL;
args.show_help = 0;
cr_assert_eq(validator_validate_args(&args), 1);
}
Test(integration, validator_file_missing_ext)
{
t_args args;
args.ext = NULL;
args.input = "readme.md";
args.output = NULL;
args.map_path = NULL;
args.show_help = 0;
cr_assert_eq(validator_validate_args(&args), 2);
}
Test(integration, validator_extract_ext_from_input)
{
t_args args;
args.ext = NULL;
args.input = "test.c.md";
args.output = "test.c";
args.map_path = NULL;
args.show_help = 0;
cr_assert_eq(validator_validate_args(&args), 0);
cr_assert_not_null(args.ext);
cr_assert_str_eq(args.ext, "c");
}
/*
** TESTS: Integration - CLI + Validator
*/
Test(integration, cli_and_validator_pipe_mode)
{
t_args args;
char *argv[] = {"c-md", "-e", "c"};
cli_parse(&args, 3, argv);
cr_assert_eq(validator_validate_args(&args), 0);
cr_assert_str_eq(args.ext, "c");
cr_assert_null(args.input);
cr_assert_null(args.output);
}
Test(integration, cli_and_validator_file_mode)
{
t_args args;
char *argv[] = {"c-md", "-e", "c", "-i", "input.md", "-o", "output.c"};
cli_parse(&args, 7, argv);
cr_assert_eq(validator_validate_args(&args), 0);
cr_assert_str_eq(args.ext, "c");
cr_assert_str_eq(args.input, "input.md");
cr_assert_str_eq(args.output, "output.c");
}

View file

@ -0,0 +1,103 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "internal/transpile_internal.h"
/*
** TESTS: transpile/code.c - Handle code lines
*/
Test(transpile_code, handle_single_line)
{
t_state s;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
out = fopen("/tmp/test_code_out.c", "w");
map_init(&map);
state_init(&s, NULL, out, "c", &map);
ret = handle_code_line(&s, "int x = 42;\n");
cr_assert_eq(ret, 0);
cr_assert_eq(s.dst_line, 1);
fclose(out);
out = fopen("/tmp/test_code_out.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "int x = 42;\n");
fclose(out);
map_free(&map);
remove("/tmp/test_code_out.c");
}
Test(transpile_code, handle_multiple_lines)
{
t_state s;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
out = fopen("/tmp/test_code_multi.c", "w");
map_init(&map);
state_init(&s, NULL, out, "c", &map);
ret = handle_code_line(&s, "int main() {\n");
cr_assert_eq(ret, 0);
cr_assert_eq(s.dst_line, 1);
ret = handle_code_line(&s, " return 0;\n");
cr_assert_eq(ret, 0);
cr_assert_eq(s.dst_line, 2);
ret = handle_code_line(&s, "}\n");
cr_assert_eq(ret, 0);
cr_assert_eq(s.dst_line, 3);
fclose(out);
out = fopen("/tmp/test_code_multi.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "int main() {\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, " return 0;\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "}\n");
fclose(out);
map_free(&map);
remove("/tmp/test_code_multi.c");
}
Test(transpile_code, handle_empty_line)
{
t_state s;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
out = fopen("/tmp/test_code_empty.c", "w");
map_init(&map);
state_init(&s, NULL, out, "c", &map);
ret = handle_code_line(&s, "\n");
cr_assert_eq(ret, 0);
cr_assert_eq(s.dst_line, 1);
fclose(out);
out = fopen("/tmp/test_code_empty.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "\n");
fclose(out);
map_free(&map);
remove("/tmp/test_code_empty.c");
}

View file

@ -0,0 +1,173 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "transpile.h"
#include "map.h"
static const char *sample_md_1 =
"# Test\n"
"```c\n"
"int main() {\n"
" return 0;\n"
"}\n"
"```\n";
static const char *sample_md_2 =
"# Multiple blocks\n"
"```c\n"
"#include <stdio.h>\n"
"```\n"
"Some text\n"
"```c\n"
"int main() {\n"
" return 0;\n"
"}\n"
"```\n";
/*
** TESTS: transpile/core.c - Single code block
*/
Test(transpile, single_code_block)
{
FILE *in;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
in = fopen("/tmp/test_transpile_in.md", "w");
fprintf(in, "%s", sample_md_1);
fclose(in);
in = fopen("/tmp/test_transpile_in.md", "r");
out = fopen("/tmp/test_transpile_out.c", "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
cr_assert_eq(map.count, 1);
cr_assert_eq(map.ranges[0].src_start, 3);
cr_assert_eq(map.ranges[0].src_end, 5);
cr_assert_eq(map.ranges[0].dst_start, 1);
cr_assert_eq(map.ranges[0].dst_end, 3);
out = fopen("/tmp/test_transpile_out.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "int main() {\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, " return 0;\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "}\n");
fclose(out);
map_free(&map);
remove("/tmp/test_transpile_in.md");
remove("/tmp/test_transpile_out.c");
}
/*
** TESTS: transpile/core.c - Multiple blocks
*/
Test(transpile, multiple_blocks)
{
FILE *in;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
in = fopen("/tmp/test_transpile_multi_in.md", "w");
fprintf(in, "%s", sample_md_2);
fclose(in);
in = fopen("/tmp/test_transpile_multi_in.md", "r");
out = fopen("/tmp/test_transpile_multi_out.c", "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
cr_assert_eq(map.count, 2);
out = fopen("/tmp/test_transpile_multi_out.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "#include <stdio.h>\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "\n");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "int main() {\n");
fclose(out);
map_free(&map);
remove("/tmp/test_transpile_multi_in.md");
remove("/tmp/test_transpile_multi_out.c");
}
/*
** TESTS: transpile/core.c - Edge cases
*/
Test(transpile, empty_input)
{
FILE *in;
FILE *out;
t_map map;
int8_t ret;
in = fopen("/tmp/test_transpile_empty_in.md", "w");
fclose(in);
in = fopen("/tmp/test_transpile_empty_in.md", "r");
out = fopen("/tmp/test_transpile_empty_out.c", "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
cr_assert_eq(map.count, 0);
map_free(&map);
remove("/tmp/test_transpile_empty_in.md");
remove("/tmp/test_transpile_empty_out.c");
}
Test(transpile, no_matching_blocks)
{
FILE *in;
FILE *out;
t_map map;
int8_t ret;
const char *no_match = "```python\nprint('hello')\n```\n";
in = fopen("/tmp/test_transpile_nomatch_in.md", "w");
fprintf(in, "%s", no_match);
fclose(in);
in = fopen("/tmp/test_transpile_nomatch_in.md", "r");
out = fopen("/tmp/test_transpile_nomatch_out.c", "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
cr_assert_eq(map.count, 0);
map_free(&map);
remove("/tmp/test_transpile_nomatch_in.md");
remove("/tmp/test_transpile_nomatch_out.c");
}

View file

@ -0,0 +1,55 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "transpile.h"
#include "map.h"
static const char *sample_md_mixed =
"# Mixed languages\n"
"```python\n"
"print('hello')\n"
"```\n"
"```c\n"
"int x = 42;\n"
"```\n";
/*
** TESTS: transpile/fence.c - Filter by extension
*/
Test(transpile, filter_by_extension)
{
FILE *in;
FILE *out;
t_map map;
char buffer[256];
int8_t ret;
in = fopen("/tmp/test_transpile_filter_in.md", "w");
fprintf(in, "%s", sample_md_mixed);
fclose(in);
in = fopen("/tmp/test_transpile_filter_in.md", "r");
out = fopen("/tmp/test_transpile_filter_out.c", "w");
map_init(&map);
ret = transpile(in, out, "c", &map);
fclose(in);
fclose(out);
cr_assert_eq(ret, 0);
cr_assert_eq(map.count, 1);
cr_assert_eq(map.ranges[0].src_start, 6);
cr_assert_eq(map.ranges[0].src_end, 6);
out = fopen("/tmp/test_transpile_filter_out.c", "r");
fgets(buffer, sizeof(buffer), out);
cr_assert_str_eq(buffer, "int x = 42;\n");
cr_assert_null(fgets(buffer, sizeof(buffer), out));
fclose(out);
map_free(&map);
remove("/tmp/test_transpile_filter_in.md");
remove("/tmp/test_transpile_filter_out.c");
}

View file

@ -0,0 +1,64 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include "internal/transpile_internal.h"
/*
** TESTS: transpile/state.c - State initialization
*/
Test(transpile_state, init_sets_all_fields)
{
t_state s;
FILE *in;
FILE *out;
t_map map;
const char *ext = "c";
in = fopen("/tmp/test_state_in.md", "w");
out = fopen("/tmp/test_state_out.c", "w");
map_init(&map);
state_init(&s, in, out, ext, &map);
cr_assert_eq(s.in, in);
cr_assert_eq(s.out, out);
cr_assert_str_eq(s.ext, "c");
cr_assert_eq(s.map, &map);
cr_assert_eq(s.src_line, 0);
cr_assert_eq(s.dst_line, 0);
cr_assert_eq(s.block_src_start, 0);
cr_assert_eq(s.block_dst_start, 0);
cr_assert_eq(s.in_block, 0);
cr_assert_eq(s.first_block, 1);
fclose(in);
fclose(out);
map_free(&map);
remove("/tmp/test_state_in.md");
remove("/tmp/test_state_out.c");
}
Test(transpile_state, init_with_different_extension)
{
t_state s;
FILE *in;
FILE *out;
t_map map;
const char *ext = "py";
in = fopen("/tmp/test_state_in.md", "w");
out = fopen("/tmp/test_state_out.py", "w");
map_init(&map);
state_init(&s, in, out, ext, &map);
cr_assert_str_eq(s.ext, "py");
cr_assert_eq(s.first_block, 1);
fclose(in);
fclose(out);
map_free(&map);
remove("/tmp/test_state_in.md");
remove("/tmp/test_state_out.py");
}

View file

@ -0,0 +1,59 @@
#include <criterion/criterion.h>
#include <stdio.h>
#include <stdlib.h>
#include "utils.h"
/*
** TESTS: io/read_line.c
*/
Test(utils_io, read_line_from_file)
{
FILE *f;
char *line;
f = fopen("/tmp/test_c_md_utils.txt", "w");
cr_assert_not_null(f);
fprintf(f, "line1\n");
fprintf(f, "line2\n");
fclose(f);
f = fopen("/tmp/test_c_md_utils.txt", "r");
cr_assert_not_null(f);
line = read_line(f);
cr_assert_not_null(line);
cr_assert_str_eq(line, "line1\n");
free(line);
line = read_line(f);
cr_assert_not_null(line);
cr_assert_str_eq(line, "line2\n");
free(line);
line = read_line(f);
cr_assert_null(line);
fclose(f);
remove("/tmp/test_c_md_utils.txt");
}
Test(utils_io, read_line_empty_file)
{
FILE *f;
char *line;
f = fopen("/tmp/test_c_md_empty.txt", "w");
cr_assert_not_null(f);
fclose(f);
f = fopen("/tmp/test_c_md_empty.txt", "r");
cr_assert_not_null(f);
line = read_line(f);
cr_assert_null(line);
fclose(f);
remove("/tmp/test_c_md_empty.txt");
}

View file

@ -0,0 +1,50 @@
#include <criterion/criterion.h>
#include <stdlib.h>
#include "utils.h"
/*
** TESTS: string/extract_fence_ext.c
*/
Test(utils_string, extract_fence_ext_valid)
{
char *ext;
ext = extract_fence_ext("```c");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
free(ext);
ext = extract_fence_ext("```python");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "python");
free(ext);
ext = extract_fence_ext("``` c ");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
free(ext);
ext = extract_fence_ext("```\tc\n");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
free(ext);
}
Test(utils_string, extract_fence_ext_invalid)
{
char *ext;
ext = extract_fence_ext("```");
cr_assert_null(ext);
ext = extract_fence_ext("```\n");
cr_assert_null(ext);
ext = extract_fence_ext("not a fence");
cr_assert_null(ext);
ext = extract_fence_ext("");
cr_assert_null(ext);
}

View file

@ -0,0 +1,45 @@
#include <criterion/criterion.h>
#include "utils.h"
/*
** TESTS: string/extract_file_ext.c
*/
Test(utils_string, extract_file_ext_valid)
{
const char *ext;
ext = extract_file_ext("file.c");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
ext = extract_file_ext("test.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "md");
ext = extract_file_ext("path/to/file.txt");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "txt");
ext = extract_file_ext("file.c.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "md");
}
Test(utils_string, extract_file_ext_invalid)
{
const char *ext;
ext = extract_file_ext("noext");
cr_assert_null(ext);
ext = extract_file_ext(".hidden");
cr_assert_null(ext);
ext = extract_file_ext("");
cr_assert_null(ext);
ext = extract_file_ext("path/to/dir/");
cr_assert_null(ext);
}

View file

@ -0,0 +1,63 @@
#include <criterion/criterion.h>
#include <criterion/internal/assert.h>
#include <criterion/internal/test.h>
#include "utils.h"
/*
** TESTS: string/infer_ext_from_filename.c
*/
Test(utils_string, infer_ext_from_filename_valid)
{
const char *ext;
ext = infer_ext_from_filename("test.c.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
ext = infer_ext_from_filename("main.py.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "py");
ext = infer_ext_from_filename("path/to/file.js.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "js");
}
Test(utils_string, infer_ext_from_filename_invalid)
{
const char *ext;
ext = infer_ext_from_filename("test.md");
cr_assert_null(ext);
ext = infer_ext_from_filename("noext");
cr_assert_null(ext);
ext = infer_ext_from_filename("test.c");
cr_assert_null(ext);
ext = infer_ext_from_filename("");
cr_assert_null(ext);
ext = infer_ext_from_filename(NULL);
cr_assert_null(ext);
}
Test(utils_string, infer_ext_from_filename_edge_cases)
{
const char *ext;
ext = infer_ext_from_filename(".c.md");
cr_assert_null(ext);
ext = infer_ext_from_filename("a.c.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "c");
ext = infer_ext_from_filename("a.cpp.md");
cr_assert_not_null(ext);
cr_assert_str_eq(ext, "cpp");
}

View file

@ -0,0 +1,21 @@
#include <criterion/criterion.h>
#include "utils.h"
/*
** TESTS: string/starts_with.c
*/
Test(utils_string, starts_with_true)
{
cr_assert_eq(starts_with("```c", "```"), 1);
cr_assert_eq(starts_with("hello world", "hello"), 1);
cr_assert_eq(starts_with("abc", "abc"), 1);
}
Test(utils_string, starts_with_false)
{
cr_assert_eq(starts_with("hello", "world"), 0);
cr_assert_eq(starts_with("abc", "abcd"), 0);
cr_assert_eq(starts_with("", "test"), 0);
}