diff --git a/test/ikc3/struct.kc3 b/test/ikc3/struct.kc3
index 3266efa..f147cff 100644
--- a/test/ikc3/struct.kc3
+++ b/test/ikc3/struct.kc3
@@ -8,13 +8,3 @@ quote [position: %GL.Vec3{},
[position: %GL.Vec3{},
normal: %GL.Vec3{},
tex_coord: %GL.Vec2{}]
-quote offsetof(FactW, :subject)
-offsetof(FactW, :subject)
-quote offsetof(FactW, :predicate)
-offsetof(FactW, :predicate)
-quote offsetof(FactW, :object)
-offsetof(FactW, :object)
-quote offsetof(FactW, :id)
-offsetof(FactW, :id)
-quote Sym.type_size(FactW)
-Sym.type_size(FactW)
diff --git a/test/ikc3/struct.out.expected b/test/ikc3/struct.out.expected
index 822a117..2cbc357 100644
--- a/test/ikc3/struct.out.expected
+++ b/test/ikc3/struct.out.expected
@@ -15,13 +15,3 @@
z: 0.0f},
tex_coord: %GL.Vec2{x: 0.0f,
y: 0.0f}]
-offsetof(FactW, :subject)
-(Uw) 0
-offsetof(FactW, :predicate)
-(Uw) 112
-offsetof(FactW, :object)
-(Uw) 224
-offsetof(FactW, :id)
-(Uw) 336
-Sym.type_size(FactW)
-(Uw) 352
diff --git a/test/libkc3_test.c b/test/libkc3_test.c
index 0989b44..302ca9c 100644
--- a/test/libkc3_test.c
+++ b/test/libkc3_test.c
@@ -35,120 +35,52 @@ void set__fact_test (void);
void set__tag_test (void);
void skiplist__fact_test (void);
void str_test (void);
+void struct_test (void);
void sym_test (void);
void tag_test (void);
void tuple_test (void);
void types_test (void);
+#define TEST_TARGET(name) \
+ do { \
+ if (test_target(# name)) { \
+ fprintf(stderr, "\n" # name " "); \
+ name ## _test(); \
+ } \
+ } while (0)
+
int main (int argc, char **argv)
{
if (! kc3_init(NULL, &argc, &argv))
return 1;
test_init(g_kc3_env.argv[0], &argc, &argv);
- if (test_target("types")) {
- fprintf(stderr, "\ntypes ");
- types_test();
- }
- if (test_target("array")) {
- fprintf(stderr, "\narray ");
- array_test();
- }
- if (test_target("bool")) {
- fprintf(stderr, "\nbool ");
- bool_test();
- }
- if (test_target("character")) {
- fprintf(stderr, "\ncharacter ");
- character_test();
- }
- if (test_target("buf")) {
- fprintf(stderr, "\nbuf ");
- buf_test();
- }
- if (test_target("buf_parse")) {
- fprintf(stderr, "\nbuf_parse ");
- buf_parse_test();
- }
- if (test_target("buf_inspect")) {
- fprintf(stderr, "\nbuf_inspect ");
- buf_inspect_test();
- }
- if (test_target("buf_file")) {
- fprintf(stderr, "\nbuf_file ");
- buf_file_test();
- }
- if (test_target("str")) {
- fprintf(stderr, "\nstr ");
- str_test();
- }
- if (test_target("sym")) {
- fprintf(stderr, "\nsym ");
- sym_test();
- }
- if (test_target("ident")) {
- fprintf(stderr, "\nident ");
- ident_test();
- }
- if (test_target("list")) {
- fprintf(stderr, "\nlist ");
- list_test();
- }
- if (test_target("tuple")) {
- fprintf(stderr, "\ntuple ");
- tuple_test();
- }
- if (test_target("fn")) {
- fprintf(stderr, "\nfn ");
- fn_test();
- }
- if (test_target("call")) {
- fprintf(stderr, "\ncall ");
- call_test();
- }
- if (test_target("tag")) {
- fprintf(stderr, "\ntag ");
- tag_test();
- }
- if (test_target("inspect")) {
- fprintf(stderr, "\ninspect ");
- inspect_test();
- }
- if (test_target("fact")) {
- fprintf(stderr, "\nfact ");
- fact_test();
- }
- if (test_target("compare")) {
- fprintf(stderr, "\ncompare ");
- compare_test();
- }
- if (test_target("set__tag")) {
- fprintf(stderr, "\nset__tag ");
- set__tag_test();
- }
- if (test_target("set__fact")) {
- fprintf(stderr, "\nset__fact ");
- set__fact_test();
- }
- if (test_target("skiplist__fact")) {
- fprintf(stderr, "\nskiplist__fact ");
- skiplist__fact_test();
- }
- if (test_target("facts")) {
- fprintf(stderr, "\nfacts ");
- facts_test();
- }
- if (test_target("facts_cursor")) {
- fprintf(stderr, "\nfacts_cursor ");
- facts_cursor_test();
- }
- if (test_target("facts_with")) {
- fprintf(stderr, "\nfacts_with ");
- facts_with_test();
- }
- if (test_target("env")) {
- fprintf(stderr, "\nenv ");
- env_test();
- }
+ TEST_TARGET(types);
+ TEST_TARGET(array);
+ TEST_TARGET(bool);
+ TEST_TARGET(character);
+ TEST_TARGET(buf);
+ TEST_TARGET(buf_parse);
+ TEST_TARGET(buf_inspect);
+ TEST_TARGET(buf_file);
+ TEST_TARGET(str);
+ TEST_TARGET(sym);
+ TEST_TARGET(ident);
+ TEST_TARGET(list);
+ TEST_TARGET(tuple);
+ TEST_TARGET(fn);
+ TEST_TARGET(call);
+ TEST_TARGET(tag);
+ TEST_TARGET(inspect);
+ TEST_TARGET(fact);
+ TEST_TARGET(compare);
+ TEST_TARGET(set__tag);
+ TEST_TARGET(set__fact);
+ TEST_TARGET(skiplist__fact);
+ TEST_TARGET(facts);
+ TEST_TARGET(facts_cursor);
+ TEST_TARGET(facts_with);
+ TEST_TARGET(env);
+ TEST_TARGET(struct);
test_summary();
test_clean();
kc3_clean(NULL);
diff --git a/test/sources.mk b/test/sources.mk
index cf74282..37bed6a 100644
--- a/test/sources.mk
+++ b/test/sources.mk
@@ -42,6 +42,7 @@ SOURCES = \
"set__tag_test.c" \
"skiplist__fact_test.c" \
"str_test.c" \
+ "struct_test.c" \
"sym_test.c" \
"tag_test.c" \
"test.c" \
diff --git a/test/sources.sh b/test/sources.sh
index ae02300..8632c43 100644
--- a/test/sources.sh
+++ b/test/sources.sh
@@ -1,3 +1,3 @@
# sources.sh generated by update_sources
HEADERS='buf_parse_test.h buf_parse_test_su.h compare_test.h fact_test.h tag_test.h test.h '
-SOURCES='array_test.c bool_test.c buf_file_test.c buf_inspect_test.c buf_parse_test.c buf_parse_test_s16.c buf_parse_test_s32.c buf_parse_test_s64.c buf_parse_test_s8.c buf_parse_test_u16.c buf_parse_test_u32.c buf_parse_test_u64.c buf_parse_test_u8.c buf_test.c call_test.c cfn_test.c character_test.c compare_test.c env_test.c fact_test.c facts_cursor_test.c facts_test.c facts_with_test.c fn_test.c hash_test.c ident_test.c inspect_test.c libkc3_test.c list_test.c ratio_test.c set__fact_test.c set__tag_test.c skiplist__fact_test.c str_test.c sym_test.c tag_test.c test.c tuple_test.c types_test.c '
+SOURCES='array_test.c bool_test.c buf_file_test.c buf_inspect_test.c buf_parse_test.c buf_parse_test_s16.c buf_parse_test_s32.c buf_parse_test_s64.c buf_parse_test_s8.c buf_parse_test_u16.c buf_parse_test_u32.c buf_parse_test_u64.c buf_parse_test_u8.c buf_test.c call_test.c cfn_test.c character_test.c compare_test.c env_test.c fact_test.c facts_cursor_test.c facts_test.c facts_with_test.c fn_test.c hash_test.c ident_test.c inspect_test.c libkc3_test.c list_test.c ratio_test.c set__fact_test.c set__tag_test.c skiplist__fact_test.c str_test.c struct_test.c sym_test.c tag_test.c test.c tuple_test.c types_test.c '
diff --git a/test/struct_test.c b/test/struct_test.c
new file mode 100644
index 0000000..566e147
--- /dev/null
+++ b/test/struct_test.c
@@ -0,0 +1,58 @@
+/* kc3
+ * Copyright 2022,2023,2024 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted the above
+ * copyright notice and this permission paragraph are included in all
+ * copies and substantial portions of this software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include "../libkc3/kc3_main.h"
+#include "../libkc3/struct.h"
+#include "../libkc3/sym.h"
+#include "test.h"
+
+#define STRUCT_TEST_OFFSETOF(type, module, key) \
+ do { \
+ const s_sym *sym_module; \
+ const s_sym *sym_key; \
+ uw offset; \
+ test_context("KC3.offsetof(" # module ", " # key ") = offsetof(" \
+ # type ", " # key ")"); \
+ sym_module = sym_1(# module); \
+ sym_key = sym_1(# key); \
+ TEST_EQ(kc3_offsetof(&sym_module, &sym_key, &offset), &offset); \
+ TEST_EQ(offset, offsetof(type, key)); \
+ test_context(NULL); \
+ } while (0)
+
+#define STRUCT_TEST_SIZEOF(type, module) \
+ do { \
+ uw size; \
+ const s_sym *sym; \
+ test_context("sym_type_size(" # module ") = sizeof(" # type ")"); \
+ sym = sym_1(# module); \
+ TEST_EQ(sym_type_size(&sym, &size), &size); \
+ TEST_EQ(size, sizeof(type)); \
+ test_context(NULL); \
+ } while (0)
+
+TEST_CASE_PROTOTYPE(struct_test_fact_w);
+
+void struct_test (void)
+{
+ TEST_CASE_RUN(struct_test_fact_w);
+}
+
+TEST_CASE(struct_test_fact_w)
+{
+ STRUCT_TEST_OFFSETOF(s_fact_w, FactW, subject);
+ STRUCT_TEST_OFFSETOF(s_fact_w, FactW, predicate);
+ STRUCT_TEST_OFFSETOF(s_fact_w, FactW, object);
+ STRUCT_TEST_OFFSETOF(s_fact_w, FactW, id);
+ STRUCT_TEST_SIZEOF( s_fact_w, FactW);
+}
+TEST_CASE_END(struct_test_fact_w)