diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index eb2cb7f3..27253072 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -2,7 +2,9 @@ name: CI pipeline on: push: - branches: [dev] + branches: + - dev + - 'dev-*' env: build_dir: build @@ -84,7 +86,7 @@ jobs: - name: Debug if: ${{always()}} - run: sed '4019q;d' ${{env.build_dir}}/src/reader/functional/cowl_func_yyparser.c + run: sed '4019q;d' ${{env.build_dir}}/src/formats/functional/reader/cowl_func_yyparser.c shell: bash - name: Configure tests (Windows) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb200ab9..641e955c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,8 +42,7 @@ set(COWL_LIB_DIR "${COWL_PROJECT_DIR}/lib") set(COWL_SRC_DIR "${COWL_PROJECT_DIR}/src") set(COWL_PUBLIC_HEADERS_DIR "${COWL_PROJECT_DIR}/include") set(COWL_PRIVATE_HEADERS_DIR "${COWL_SRC_DIR}") -set(COWL_READER_DIR "${COWL_SRC_DIR}/reader") -set(COWL_WRITER_DIR "${COWL_SRC_DIR}/writer") +set(COWL_FORMATS_DIR "${COWL_SRC_DIR}/formats") set(COWL_DATA_DIR "${COWL_PROJECT_DIR}/data") set(COWL_DOCS_DIR "${COWL_PROJECT_DIR}/docs") @@ -121,7 +120,7 @@ if(COWL_READERS) set(READER_OPT "COWL_READER_${READER_OPT}") string(TOLOWER "${READER}" READER) - add_subdirectory("${COWL_READER_DIR}/${READER}") + add_subdirectory("${COWL_FORMATS_DIR}/${READER}/reader") list(APPEND COWL_READER_DEFINES "${READER_OPT}") endforeach() @@ -135,13 +134,15 @@ endif() # Writers +add_custom_target(cowl-writers COMMENT "Generate builtin writers.") + if(COWL_WRITERS) foreach(WRITER IN LISTS COWL_WRITERS) string(TOUPPER "${WRITER}" WRITER_OPT) set(WRITER_OPT "COWL_WRITER_${WRITER_OPT}") string(TOLOWER "${WRITER}" WRITER) - add_subdirectory("${COWL_WRITER_DIR}/${WRITER}") + add_subdirectory("${COWL_FORMATS_DIR}/${WRITER}/writer") list(APPEND COWL_WRITER_DEFINES "${WRITER_OPT}") endforeach() @@ -175,7 +176,7 @@ target_compile_definitions(cowl PUBLIC ${COWL_PUBLIC_DEFINES} PRIVATE ${COWL_PRIVATE_DEFINES}) target_link_libraries(cowl PUBLIC ulib) -add_dependencies(cowl cowl-readers) +add_dependencies(cowl cowl-readers cowl-writers) if(COWL_LIBRARY_TYPE STREQUAL "SHARED") target_compile_definitions(cowl PUBLIC COWL_SHARED) diff --git a/src/reader/functional/CMakeLists.txt b/src/formats/functional/reader/CMakeLists.txt similarity index 70% rename from src/reader/functional/CMakeLists.txt rename to src/formats/functional/reader/CMakeLists.txt index 81812f52..10fc1bec 100644 --- a/src/reader/functional/CMakeLists.txt +++ b/src/formats/functional/reader/CMakeLists.txt @@ -5,8 +5,8 @@ find_package(FLEX 2.6.4 REQUIRED) # Directories -set(COWL_PARSER_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") -set(COWL_PARSER_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") +set(COWL_READER_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +set(COWL_READER_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") # Target settings @@ -22,20 +22,20 @@ list(JOIN COWL_FUNC_FLEX_FLAGS " " COWL_FUNC_FLEX_FLAGS) # Header dirs -list(APPEND COWL_PRIVATE_HEADERS_DIRS "${COWL_PARSER_OUT_DIR}") +list(APPEND COWL_PRIVATE_HEADERS_DIRS "${COWL_READER_OUT_DIR}") # Sources -file(GLOB COWL_FUNC_PARSER_SOURCES CONFIGURE_DEPENDS "${COWL_PARSER_SRC_DIR}/*.c") -list(APPEND COWL_SOURCES ${COWL_FUNC_PARSER_SOURCES}) +file(GLOB COWL_FUNC_READER_SOURCES CONFIGURE_DEPENDS "${COWL_READER_SRC_DIR}/*.c") +list(APPEND COWL_SOURCES ${COWL_FUNC_READER_SOURCES}) -set(COWL_FUNC_LEXER_IN "${COWL_PARSER_SRC_DIR}/cowl_functional.l") -set(COWL_FUNC_LEXER_HEADER "${COWL_PARSER_OUT_DIR}/cowl_func_yylexer.h") -set(COWL_FUNC_LEXER_OUT "${COWL_PARSER_OUT_DIR}/cowl_func_yylexer.c") +set(COWL_FUNC_LEXER_IN "${COWL_READER_SRC_DIR}/cowl_functional.l") +set(COWL_FUNC_LEXER_HEADER "${COWL_READER_OUT_DIR}/cowl_func_yylexer.h") +set(COWL_FUNC_LEXER_OUT "${COWL_READER_OUT_DIR}/cowl_func_yylexer.c") -set(COWL_FUNC_PARSER_IN "${COWL_PARSER_SRC_DIR}/cowl_functional.y") -set(COWL_FUNC_PARSER_HEADER "${COWL_PARSER_OUT_DIR}/cowl_func_yyparser.h") -set(COWL_FUNC_PARSER_OUT "${COWL_PARSER_OUT_DIR}/cowl_func_yyparser.c") +set(COWL_FUNC_PARSER_IN "${COWL_READER_SRC_DIR}/cowl_functional.y") +set(COWL_FUNC_PARSER_HEADER "${COWL_READER_OUT_DIR}/cowl_func_yyparser.h") +set(COWL_FUNC_PARSER_OUT "${COWL_READER_OUT_DIR}/cowl_func_yyparser.c") ############### ### Targets ### diff --git a/src/reader/functional/cowl_func_reader.c b/src/formats/functional/reader/cowl_func_reader.c similarity index 100% rename from src/reader/functional/cowl_func_reader.c rename to src/formats/functional/reader/cowl_func_reader.c diff --git a/src/reader/functional/cowl_functional.l b/src/formats/functional/reader/cowl_functional.l similarity index 100% rename from src/reader/functional/cowl_functional.l rename to src/formats/functional/reader/cowl_functional.l diff --git a/src/reader/functional/cowl_functional.y b/src/formats/functional/reader/cowl_functional.y similarity index 100% rename from src/reader/functional/cowl_functional.y rename to src/formats/functional/reader/cowl_functional.y diff --git a/src/formats/functional/writer/CMakeLists.txt b/src/formats/functional/writer/CMakeLists.txt new file mode 100644 index 00000000..9d7d8304 --- /dev/null +++ b/src/formats/functional/writer/CMakeLists.txt @@ -0,0 +1,12 @@ +# Directories + +set(COWL_WRITER_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") + +# Sources + +file(GLOB COWL_WRITER_SOURCES CONFIGURE_DEPENDS "${COWL_WRITER_SRC_DIR}/*.c") +list(APPEND COWL_SOURCES ${COWL_WRITER_SOURCES}) + +# Propagate changes in the parent project + +set(COWL_SOURCES ${COWL_SOURCES} PARENT_SCOPE) diff --git a/src/writer/functional/cowl_func_writer.c b/src/formats/functional/writer/cowl_func_writer.c similarity index 100% rename from src/writer/functional/cowl_func_writer.c rename to src/formats/functional/writer/cowl_func_writer.c diff --git a/src/writer/functional/CMakeLists.txt b/src/writer/functional/CMakeLists.txt deleted file mode 100644 index 51cd2efb..00000000 --- a/src/writer/functional/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ -# Directories - -set(COWL_SERIALIZER_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - -# Sources - -file(GLOB COWL_SERIALIZER_SOURCES CONFIGURE_DEPENDS "${COWL_SERIALIZER_SRC_DIR}/*.c") -list(APPEND COWL_SOURCES ${COWL_SERIALIZER_SOURCES}) - -# Propagate changes in the parent project - -set(COWL_SOURCES ${COWL_SOURCES} PARENT_SCOPE) diff --git a/test/tests/cowl_manager_tests.c b/test/tests/cowl_manager_tests.c index a30bd8f8..2595fda0 100644 --- a/test/tests/cowl_manager_tests.c +++ b/test/tests/cowl_manager_tests.c @@ -13,6 +13,7 @@ #include "cowl_test_utils.h" #include "ulib.h" #include +#include // Utils @@ -105,18 +106,54 @@ bool cowl_test_manager_read_ontology(void) { return true; } -static bool cowl_test_manager_write_ontology_path(UString path) { +static bool equal_ontologies(CowlOntology *a, CowlOntology *b) { + if (cowl_ontology_get_iri(a) != cowl_ontology_get_iri(b)) return false; + if (cowl_ontology_get_version(a) != cowl_ontology_get_version(b)) return false; + + UVec(CowlObjectPtr) imports_a = uvec(CowlObjectPtr); + CowlIterator iter = cowl_iterator_vec(&imports_a, false); + cowl_ontology_iterate_import_iris(a, &iter, false); + + UVec(CowlObjectPtr) imports_b = uvec(CowlObjectPtr); + iter = cowl_iterator_vec(&imports_b, false); + cowl_ontology_iterate_import_iris(b, &iter, false); + + bool equal = uvec_equals(CowlObjectPtr, &imports_a, &imports_b); + + uvec_deinit(CowlObjectPtr, &imports_a); + uvec_deinit(CowlObjectPtr, &imports_b); + + if (!equal) return false; + + CowlVector *annot_a = cowl_ontology_get_annot(a); + CowlVector *annot_b = cowl_ontology_get_annot(b); + if (!cowl_equals(annot_a, annot_b)) return false; + + UHash(CowlObjectTable) axioms_a = uhset(CowlObjectTable); + iter = cowl_iterator_set(&axioms_a, false); + cowl_ontology_iterate_axioms(a, &iter, false); + + UHash(CowlObjectTable) axioms_b = uhset(CowlObjectTable); + iter = cowl_iterator_set(&axioms_b, false); + cowl_ontology_iterate_axioms(b, &iter, false); + + equal = uhset_equals(CowlObjectTable, &axioms_a, &axioms_b); + + uhash_deinit(CowlObjectTable, &axioms_a); + uhash_deinit(CowlObjectTable, &axioms_b); + + return equal; +} + +static bool test_format(UString path, CowlReader reader, CowlWriter writer) { CowlManager *manager = cowl_manager(); utest_assert_not_null(manager); CowlOntology *onto_in = cowl_manager_read_path(manager, path); utest_assert_not_null(onto_in); - CowlSymTable *st = cowl_ontology_get_sym_table(onto_in); - cowl_sym_table_register_prefix_raw(st, ustring_literal("dc"), - ustring_literal("http://purl.org/dc/elements/1.1/"), false); - cowl_sym_table_register_prefix_raw(st, ustring_literal("dcterms"), - ustring_literal("http://purl.org/dc/terms/"), false); + cowl_manager_set_reader(manager, reader); + cowl_manager_set_writer(manager, writer); cowl_ret ret = cowl_manager_write_path(manager, onto_in, ustring_literal(COWL_ONTOLOGY_OUT)); utest_assert_uint(ret, ==, COWL_OK); @@ -124,43 +161,37 @@ static bool cowl_test_manager_write_ontology_path(UString path) { CowlOntology *onto_out = cowl_manager_read_path(manager, ustring_literal(COWL_ONTOLOGY_OUT)); utest_assert_not_null(onto_out); - // Check that the written ontology is syntactically equal to the test ontology. - utest_assert_ptr(cowl_ontology_get_iri(onto_in), ==, cowl_ontology_get_iri(onto_out)); - utest_assert_ptr(cowl_ontology_get_version(onto_in), ==, cowl_ontology_get_version(onto_out)); - - UVec(CowlObjectPtr) imports_in = uvec(CowlObjectPtr); - CowlIterator iter = cowl_iterator_vec(&imports_in, false); - cowl_ontology_iterate_import_iris(onto_in, &iter, false); - UVec(CowlObjectPtr) imports_out = uvec(CowlObjectPtr); - iter = cowl_iterator_vec(&imports_out, false); - cowl_ontology_iterate_import_iris(onto_out, &iter, false); - utest_assert(uvec_equals(CowlObjectPtr, &imports_in, &imports_out)); - uvec_deinit(CowlObjectPtr, &imports_in); - uvec_deinit(CowlObjectPtr, &imports_out); + bool equal = equal_ontologies(onto_in, onto_out); - CowlVector *annot_in = cowl_ontology_get_annot(onto_in); - CowlVector *annot_out = cowl_ontology_get_annot(onto_out); - cowl_assert_equal(vector, annot_in, annot_out); + if (!equal) { + cowl_manager_set_writer(manager, cowl_writer_functional()); + cowl_manager_write_path(manager, onto_in, ustring_literal(COWL_ONTOLOGY_LOG)); + } - UHash(CowlObjectTable) axioms_in = uhset(CowlObjectTable); - iter = cowl_iterator_set(&axioms_in, false); - cowl_ontology_iterate_axioms(onto_in, &iter, false); - - UHash(CowlObjectTable) axioms_out = uhset(CowlObjectTable); - iter = cowl_iterator_set(&axioms_out, false); - cowl_ontology_iterate_axioms(onto_out, &iter, false); - - utest_assert(uhset_equals(CowlObjectTable, &axioms_in, &axioms_out)); - - uhash_deinit(CowlObjectTable, &axioms_in); - uhash_deinit(CowlObjectTable, &axioms_out); + utest_assert(equal); cowl_release_all(onto_in, onto_out, manager); return true; } bool cowl_test_manager_write_ontology(void) { - utest_assert(cowl_test_manager_write_ontology_path(ustring_literal(COWL_TEST_ONTOLOGY))); - utest_assert(cowl_test_manager_write_ontology_path(ustring_literal(COWL_TEST_IMPORT))); + UString const onto_path = ustring_literal(COWL_TEST_ONTOLOGY); + UString const import_path = ustring_literal(COWL_TEST_IMPORT); + + struct { + CowlReader reader; + CowlWriter writer; + } const formats[] = { +#if COWL_READER_FUNCTIONAL && COWL_WRITER_FUNCTIONAL + { cowl_reader_functional(), cowl_writer_functional() }, +#endif + }; + + for (ulib_uint i = 0; i < ulib_array_count(formats); ++i) { + printf("Testing %s format.\n", formats[i].reader.name); + utest_assert(test_format(onto_path, formats[i].reader, formats[i].writer)); + utest_assert(test_format(import_path, formats[i].reader, formats[i].writer)); + } + return true; }