commit 9cbcd3f1ca58337bc6c39e6aa115fbf22369fc53
parent 6a65aa86cab3e5f2f5616bb3706d28ad0e00c8b7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 3 Mar 2026 16:44:17 +0100
Test the gas creation API
Diffstat:
| M | Makefile | | | 57 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
| A | src/test_sgas.c | | | 225 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 279 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
@@ -23,7 +23,7 @@ LIBNAME_SHARED = libsgas.so
LIBNAME = $(LIBNAME_$(LIB_TYPE))
default: library
-all: default util
+all: default util tests
################################################################################
# Library
@@ -88,7 +88,7 @@ util: library $(UTIL_DEP)
$(MAKE) -fMakefile -f$(UTIL_DEP) sgas-lint
$(UTIL_DEP): config.mk sgas-local.pc
- $(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+ @$(CC) $(CFLAGS_UTIL) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
$(UTIL_OBJ): config.mk sgas-local.pc
$(CC) $(CFLAGS_UTIL) -c $(@:.o=.c) -o $@
@@ -147,9 +147,60 @@ uninstall:
rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-gas/COPYING"
rm -f "$(DESTDIR)$(PREFIX)/share/doc/star-gas/README.md"
-clean: clean_util
+clean: clean_test clean_util
rm -f $(DEP) $(OBJ) $(LIBNAME)
rm -f .config libsgas.o sgas.pc sgas-local.pc
lint:
mandoc -Tlint -Wwarning doc/sgas-lint.1
+
+################################################################################
+# Tests
+################################################################################
+TEST_SRC = src/test_sgas.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_DEP = $(TEST_SRC:.c=.d)
+TEST_TGT = $(TEST_SRC:.c=.t)
+
+INCS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --cflags rsys sgas-local)
+LIBS_TEST = $$($(PKG_CONFIG_LOCAL) $(PCFLAGS) --libs rsys sgas-local)
+
+CFLAGS_TEST = -std=c89 $(CFLAGS_EXE) $(INCS_TEST)
+LDFLAGS_TEST = $(LDFLAGS_EXE) $(LIBS_TEST)
+
+tests: library $(TEST_DEP) $(TEST_TGT)
+ @$(MAKE) -fMakefile \
+ $$(for i in $(TEST_DEP); do echo -f"$${i}"; done) \
+ $$(for i in $(TEST_TGT); do echo -f"$${i}"; done) \
+ test_list
+
+$(TEST_TGT):
+ @{ \
+ exe="$$(basename "$@" ".t")"; \
+ printf '%s: %s\n' "$${exe}" $(@:.t=.o); \
+ printf 'test_list: %s\n' "$${exe}"; \
+ } > $@
+
+$(TEST_DEP): config.mk sgas-local.pc
+ @$(CC) $(CFLAGS_TEST) -MM -MT "$(@:.d=.o) $@" $(@:.d=.c) -MF $@
+
+$(TEST_OBJ): config.mk sgas-local.pc
+ $(CC) $(CFLAGS_TEST) -c $(@:.o=.c) -o $@
+
+test_sgas: config.mk sgas-local.pc $(LIBNAME)
+ $(CC) $(CFLAGS_TEST) -o $@ src/$@.o $(LDFLAGS_TEST)
+
+clean_test:
+ rm -f $(TEST_DEP) $(TEST_OBJ) $(TEST_TGT)
+ rm -f mesh.smsh props.atrtp props_list.txt
+
+test: tests
+ @err=0; \
+ printf 'test_sgas'; \
+ if "./test_sgas" > /dev/null 2>&1; then \
+ printf '\n'; \
+ else \
+ printf ': error %s\n' "$$?"; \
+ err=$$((err+1)); \
+ fi; \
+ [ "$${err}" -eq 0 ]
diff --git a/src/test_sgas.c b/src/test_sgas.c
@@ -0,0 +1,225 @@
+/* Copyright (C) 2025, 2026 |Méso|Star> (contact@meso-star.com)
+ * Copyright (C) 2025, 2026 Université de Lorraine
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "sgas.h"
+#include <rsys/mem_allocator.h>
+
+static const double box_vertices[9/*#vertices*/*3/*#coords per vertex*/] = {
+ 0.0, 0.0, 0.0,
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 1.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0,
+ 1.0, 0.0, 1.0,
+ 0.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0,
+ 0.5, 0.5, 0.5
+};
+static const uint64_t box_nverts =
+ (uint64_t)(sizeof(box_vertices) / (sizeof(double)*3));
+
+/* The following array lists the indices toward the 3D vertices of each
+ * boundary triangle. The index 8 references the vertex at the center of the
+ * box.
+ * ,2---,3 ,2----3
+ * ,' | ,'/| ,'/| \ | Y
+ * 6----7' / | 6' / | \ | |
+ * |', | / ,1 | / ,0---,1 o--X
+ * | ',|/,' |/,' | ,' /
+ * 4----5' 4----5' Z */
+static const uint64_t box_indices[12/*#tetras*/*4/*#indices per tetra*/] = {
+ 0, 1, 2, 8, 1, 3, 2, 8, /* -Z */
+ 0, 2, 4, 8, 2, 6, 4, 8, /* -X */
+ 4, 6, 5, 8, 6, 7, 5, 8, /* +Z */
+ 3, 5, 7, 8, 5, 3, 1, 8, /* +X */
+ 2, 7, 6, 8, 7, 2, 3, 8, /* +Y */
+ 0, 5, 1, 8, 5, 0, 4, 8 /* -Y */
+};
+static const uint64_t box_ntetras =
+ (uint64_t)(sizeof(box_indices) / (sizeof(uint64_t)*4));
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+write_smsh
+ (FILE* fp,
+ const double* verts,
+ const uint64_t nverts,
+ const uint64_t* ids,
+ const uint64_t ntetras)
+{
+ const uint64_t pagesize = 8192;
+ const uint32_t dimnode = 3;
+ const uint32_t dimcell = 4;
+
+
+ #define WRITE(Item, Count) \
+ CHK(fwrite(Item, sizeof(*Item), (Count), fp) == (Count))
+
+ #define PADDING { \
+ char byte = 0; \
+ CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize)-1, SEEK_SET) == 0); \
+ CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1); /* EOF indicator */ \
+ } (void)0
+
+ /* Header */
+ WRITE(&pagesize, 1);
+ WRITE(&nverts, 1);
+ WRITE(&ntetras, 1);
+ WRITE(&dimnode, 1);
+ WRITE(&dimcell, 1);
+ PADDING;
+
+ /* Nodes */
+ WRITE(verts, nverts*dimnode);
+ PADDING;
+
+ /* Cells */
+ WRITE(ids, ntetras*dimcell);
+ PADDING;
+
+ CHK(fflush(fp) == 0);
+
+ #undef WRITE
+ #undef PADDING
+}
+
+static void
+write_atrtp
+ (FILE* fp,
+ const uint64_t ntetras,
+ const uint64_t time_index)
+{
+ const uint64_t pagesize = 8192;
+ size_t i = 9;
+
+ #define WRITE(Item, Count) \
+ CHK(fwrite(Item, sizeof(*Item), (Count), fp) == (Count))
+
+ #define PADDING { \
+ char byte = 0; \
+ CHK(fseek(fp, (long)ALIGN_SIZE((size_t)ftell(fp), pagesize)-1, SEEK_SET) == 0); \
+ CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1); /* EOF indicator */ \
+ } (void)0
+
+ /* Header */
+ WRITE(&pagesize, 1);
+ WRITE(&ntetras, 1);
+ PADDING;
+
+ FOR_EACH(i, 0, ntetras) {
+ /* Define an offset to be applied to thermodynamic properties in order to
+ * discriminate them by tetrahedron and temporal step */
+ const double offset = (double)time_index*10 + (double)i*100;
+ const double pressure = 1 + offset;
+ const double temperature = 2 + offset;
+ const double xH2O = 3 + offset;
+ const double xCO2 = 4 + offset;
+ const double xCO = 5 + offset;
+ const double dummy = 0;
+ WRITE(&pressure, 1);
+ WRITE(&temperature, 1);
+ WRITE(&xH2O, 1);
+ WRITE(&xCO2, 1);
+ WRITE(&xCO, 1);
+ WRITE(&dummy, 1); /* vf-soot */
+ WRITE(&dummy, 1); /* np-soot */
+ WRITE(&dummy, 1); /* dp-soot */
+ }
+ PADDING;
+}
+
+static void
+test_gas_creation(void)
+{
+ struct sgas_create_args args = SGAS_CREATE_ARGS_DEFAULT;
+ struct sgas* gas = NULL;
+
+ const char* name_mesh = "mesh.smsh";
+ const char* name_props = "props.atrtp";
+ const char* name_props_list = "props_list.txt";
+ FILE* fp_mesh = NULL;
+ FILE* fp_props = NULL;
+ FILE* fp_props_list = NULL;
+
+ CHK(fp_mesh = fopen(name_mesh, "w+"));
+ write_smsh(fp_mesh, box_vertices, box_nverts, box_indices, box_ntetras);
+
+ CHK(fp_props = fopen(name_props, "w"));
+ write_atrtp(fp_props, box_ntetras, 0/*time step*/);
+ CHK(fclose(fp_props) == 0);
+
+ CHK(fp_props_list = fopen(name_props_list, "w+"));
+ CHK(fprintf(fp_props_list, "0 %s\n", name_props));
+ CHK(fflush(fp_props_list) == 0);
+
+ args.mesh.name = name_mesh;
+ args.therm_props_list.name = name_props_list;
+ args.verbose = 3;
+
+ CHK(sgas_create(NULL, &gas) == RES_BAD_ARG);
+ CHK(sgas_create(&args, NULL) == RES_BAD_ARG);
+ CHK(sgas_create(&args, &gas) == RES_OK);
+
+ CHK(sgas_ref_get(NULL) == RES_BAD_ARG);
+ CHK(sgas_ref_get(gas) == RES_OK);
+ CHK(sgas_ref_put(NULL) == RES_BAD_ARG);
+ CHK(sgas_ref_put(gas) == RES_OK);
+ CHK(sgas_ref_put(gas) == RES_OK);
+
+ /* Missing mesh */
+ args.mesh.name = NULL;
+ CHK(sgas_create(&args, &gas) == RES_BAD_ARG);
+
+ /* Missing therm props list */
+ args.mesh.name = name_mesh;
+ args.therm_props_list.name = NULL;
+ CHK(sgas_create(&args, &gas) == RES_BAD_ARG);
+
+ /* Invalid stream of therm propos list */
+ args.mesh.name = name_mesh;
+ args.therm_props_list.name = NULL;
+ args.therm_props_list.stream = fp_props_list;
+ CHK(sgas_create(&args, &gas) == RES_BAD_ARG);
+
+ rewind(fp_props_list);
+ CHK(sgas_create(&args, &gas) == RES_OK);
+ CHK(sgas_ref_put(gas) == RES_OK);
+
+ /* Invalid stream of mesh */
+ rewind(fp_props_list);
+ args.mesh.stream = fp_mesh;
+ CHK(sgas_create(&args, &gas) != RES_OK);
+
+ rewind(fp_mesh);
+ CHK(sgas_create(&args, &gas) == RES_OK);
+ CHK(sgas_ref_put(gas) == RES_OK);
+
+ CHK(fclose(fp_mesh) == 0);
+ CHK(fclose(fp_props_list) == 0);
+}
+
+/*******************************************************************************
+ * The test
+ ******************************************************************************/
+int
+main(void)
+{
+ test_gas_creation();
+ CHK(mem_allocated_size() == 0);
+ return 0;
+}