Skip to content

Commit e50d690

Browse files
committed
test: integrate Unity and add core unit tests
Integrate the Unity test framework as a Meson subproject and introduce extensive unit tests for core modules (utility, link, config, cache). - Add Unity subproject wrap and a local 'meson-test' pre-commit hook. - Update .gitignore to ignore build files and downloaded subprojects. - Update build.yml to execute 'meson test' in macOS and Ubuntu CI. - Refactor top-level meson.build to define 'lib_srcs' separately. - Remove the unused 'round_div' helper from utility module. - Add utility unit tests for path_append, generate_md5sum, str_to_hex, and generate_salt. - Add link unit tests for LinkTable_alloc and LinkTable_add. - Add config unit tests verifying default configuration values. - Add cache unit tests verifying CacheSystem_get_cache_dir.
1 parent 6a88d4d commit e50d690

13 files changed

Lines changed: 366 additions & 19 deletions

File tree

.github/workflows/build.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ jobs:
3636
- name: Compile
3737
run: meson compile -C builddir
3838

39+
- name: Test
40+
run: meson test -C builddir
41+
3942
build-ubuntu:
4043
name: Build (Ubuntu, ${{ matrix.compiler }})
4144
runs-on: ubuntu-latest
@@ -66,3 +69,6 @@ jobs:
6669
6770
- name: Compile
6871
run: meson compile -C builddir
72+
73+
- name: Test
74+
run: meson test -C builddir

.gitignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@ doxygen
88

99
# Generated by astyle
1010
*.orig
11+
12+
# Build directories
13+
/builddir/
14+
15+
# Meson subprojects (ignore cloned sources but keep wrap files tracked)
16+
/subprojects/*
17+
!/subprojects/*.wrap
18+
!/subprojects/.wraplock

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,9 @@ repos:
3030
entry: clang-format -i
3131
language: system
3232
files: \.(c|h)$
33+
- id: meson-test
34+
name: Meson Test
35+
entry: meson test -C builddir
36+
language: system
37+
pass_filenames: false
38+
files: \.(c|h)$

meson.build

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ project('httpdirfs', 'c',
77
]
88
)
99

10-
srcs = [
11-
'src/main.c',
10+
lib_srcs = [
1211
'src/network.c',
1312
'src/fuse_local.c',
1413
'src/link.c',
@@ -45,9 +44,26 @@ expat_dep = dependency('expat')
4544
openssl_dep = dependency('openssl')
4645
execinfo_dep = cc.find_library('execinfo', required: false)
4746

47+
httpdirfs_deps = [
48+
gumbo_dep,
49+
libcurl_dep,
50+
fuse_dep,
51+
uuid_dep,
52+
expat_dep,
53+
openssl_dep,
54+
execinfo_dep
55+
]
56+
57+
httpdirfs_lib = static_library('httpdirfs_lib',
58+
lib_srcs,
59+
dependencies : httpdirfs_deps,
60+
c_args: c_args,
61+
)
62+
4863
httpdirfs = executable('httpdirfs',
49-
srcs,
50-
dependencies : [gumbo_dep, libcurl_dep, fuse_dep, uuid_dep, expat_dep, openssl_dep, execinfo_dep],
64+
'src/main.c',
65+
link_with: httpdirfs_lib,
66+
dependencies : httpdirfs_deps,
5167
c_args: c_args,
5268
install: true,
5369
install_dir: get_option('bindir'),
@@ -74,3 +90,5 @@ run_target('format',
7490

7591
run_target('doxygen',
7692
command : 'scripts/doxygen.sh')
93+
94+
subdir('tests')

src/util.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,36 @@ static pthread_mutex_t mem_mutex = PTHREAD_MUTEX_INITIALIZER;
3737

3838
char *path_append(const char *path, const char *filename)
3939
{
40+
if (!path || !filename) {
41+
lprintf(fatal, "path_append: path or filename is NULL\n");
42+
}
4043
size_t ul = strnlen(path, PATH_MAX);
44+
size_t fl = strnlen(filename, PATH_MAX);
45+
size_t skip = 0;
4146
int needs_separator = 0;
42-
if (ul > 0 && (path[ul - 1] != '/') && (filename[0] != '/')) {
43-
needs_separator = 1;
47+
const char *f = filename;
48+
49+
if (ul > 0) {
50+
if (path[ul - 1] != '/') {
51+
needs_separator = 1;
52+
}
53+
while (skip < fl && filename[skip] == '/') {
54+
skip++;
55+
}
56+
f = filename + skip;
4457
}
4558

4659
char *str;
47-
size_t sl = strnlen(filename, NAME_MAX);
60+
size_t sl = fl - skip;
4861
str = CALLOC(ul + sl + needs_separator + 1, sizeof(char));
49-
strncpy(str, path, ul);
62+
memcpy(str, path, ul);
5063
if (needs_separator) {
5164
str[ul] = '/';
5265
}
53-
strncat(str, filename, sl);
66+
memcpy(str + ul + needs_separator, f, sl);
5467
return str;
5568
}
5669

57-
int64_t round_div(int64_t a, int64_t b)
58-
{
59-
return (a + (b / 2)) / b;
60-
}
61-
6270
void pthread_mutex_init_wrapper(pthread_mutex_t *x,
6371
const pthread_mutexattr_t *attr,
6472
const char *file, const char *func, int line,

src/util.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020
*/
2121
char *path_append(const char *path, const char *filename);
2222

23-
/**
24-
* \brief division, but rounded to the nearest integer rather than truncating
25-
*/
26-
int64_t round_div(int64_t a, int64_t b);
27-
2823
/**
2924
* \brief wrapper for pthread_mutex_init(), with error handling
3025
*/

subprojects/.wraplock

Whitespace-only changes.

subprojects/unity.wrap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[wrap-git]
2+
directory = unity
3+
url = https://github.com/ThrowTheSwitch/Unity.git
4+
revision = 860062d51b2e8a75d150337b63ca2a472840d13c

tests/meson.build

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
unity_sub = subproject('unity')
2+
unity_dep = unity_sub.get_variable('unity_dep')
3+
4+
test_deps = [unity_dep] + httpdirfs_deps
5+
6+
test_util = executable('test_util',
7+
sources: ['test_util.c'],
8+
link_with: httpdirfs_lib,
9+
dependencies: test_deps,
10+
include_directories: include_directories('../src'),
11+
c_args: c_args
12+
)
13+
test('test_util', test_util)
14+
15+
test_cache = executable('test_cache',
16+
sources: ['test_cache.c'],
17+
link_with: httpdirfs_lib,
18+
dependencies: test_deps,
19+
include_directories: include_directories('../src'),
20+
c_args: c_args
21+
)
22+
test('test_cache', test_cache)
23+
24+
test_config = executable('test_config',
25+
sources: ['test_config.c'],
26+
link_with: httpdirfs_lib,
27+
dependencies: test_deps,
28+
include_directories: include_directories('../src'),
29+
c_args: c_args
30+
)
31+
test('test_config', test_config)
32+
33+
test_link = executable('test_link',
34+
sources: ['test_link.c'],
35+
link_with: httpdirfs_lib,
36+
dependencies: test_deps,
37+
include_directories: include_directories('../src'),
38+
c_args: c_args
39+
)
40+
test('test_link', test_link)

tests/test_cache.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <unity.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include "../src/cache.h"
5+
#include "../src/config.h"
6+
#include "../src/util.h"
7+
8+
void setUp(void)
9+
{
10+
Config_init();
11+
}
12+
13+
void tearDown(void)
14+
{
15+
// clean stuff up here
16+
}
17+
18+
void test_CacheSystem_get_cache_dir(void)
19+
{
20+
char *dir;
21+
22+
// 1. Test when CONFIG.cache_dir is explicitly set
23+
CONFIG.cache_dir = "/tmp/explicit_cache";
24+
dir = CacheSystem_get_cache_dir();
25+
TEST_ASSERT_NOT_NULL(dir);
26+
TEST_ASSERT_EQUAL_STRING("/tmp/explicit_cache", dir);
27+
// Not dynamically allocated in cache.c when CONFIG.cache_dir is used
28+
CONFIG.cache_dir = NULL;
29+
30+
// 2. Test fallback to XDG_CACHE_HOME
31+
setenv("XDG_CACHE_HOME", "/tmp/xdg_cache", 1);
32+
dir = CacheSystem_get_cache_dir();
33+
TEST_ASSERT_NOT_NULL(dir);
34+
TEST_ASSERT_EQUAL_STRING("/tmp/xdg_cache", dir);
35+
FREE(dir);
36+
unsetenv("XDG_CACHE_HOME");
37+
38+
// 3. Test fallback to HOME/.cache
39+
setenv("HOME", "/tmp/my_home", 1);
40+
dir = CacheSystem_get_cache_dir();
41+
TEST_ASSERT_NOT_NULL(dir);
42+
TEST_ASSERT_EQUAL_STRING("/tmp/my_home/.cache", dir);
43+
FREE(dir);
44+
unsetenv("HOME");
45+
46+
// 4. Test fallback when neither is set
47+
dir = CacheSystem_get_cache_dir();
48+
TEST_ASSERT_NOT_NULL(dir);
49+
char *expected_cur_dir = REALPATH("./", NULL);
50+
TEST_ASSERT_NOT_NULL(expected_cur_dir);
51+
char *expected_dir = path_append(expected_cur_dir, ".cache");
52+
TEST_ASSERT_NOT_NULL(expected_dir);
53+
TEST_ASSERT_EQUAL_STRING(expected_dir, dir);
54+
FREE(expected_cur_dir);
55+
FREE(expected_dir);
56+
FREE(dir);
57+
}
58+
59+
int main(void)
60+
{
61+
UNITY_BEGIN();
62+
RUN_TEST(test_CacheSystem_get_cache_dir);
63+
return UNITY_END();
64+
}

0 commit comments

Comments
 (0)