You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@celix.apache.org by pe...@apache.org on 2026/08/10 04:39:05 UTC

(celix) 35/35: Add jansson_ext conan test_package support and update CMake configuration

This is an automated email from the ASF dual-hosted git repository.

PengZheng pushed a commit to branch feature/json-schema
in repository https://gitbox.apache.org/repos/asf/celix.git

commit 6a9a357804ee8b7edc5fb2629a110c4099329036
Author: PengZheng <ho...@gmail.com>
AuthorDate: Mon Aug 10 11:01:30 2026 +0800

    Add jansson_ext conan test_package support and update CMake configuration
---
 conanfile.py                    |   9 ++-
 libs/jansson_ext/CMakeLists.txt |   6 +-
 test_package/CMakeLists.txt     |   6 ++
 test_package/conanfile.py       |   8 +++
 test_package/test_jansson_ext.c | 139 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 164 insertions(+), 4 deletions(-)

diff --git a/conanfile.py b/conanfile.py
index ba28528a7..bf9b910cb 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -50,6 +50,10 @@ class CelixConan(ConanFile):
         "enable_fuzzing": False,
         "enable_benchmarking": False,
         "install_find_modules": False,
+        # Celix is always built as shared libraries by its CMake build system.
+        # Declared so that Conan treats the package as shared (e.g. adds the lib
+        # dir to the consumer run environment) and to allow for static builds later.
+        "shared": True,
         "build_all": False,
         "build_http_admin": False,
         "build_log_service": False,
@@ -129,6 +133,9 @@ class CelixConan(ConanFile):
         if self.settings.os != "Linux" and self.settings.os != "Macos":
             raise ConanInvalidConfiguration("Celix is only supported for Linux/Macos")
 
+        if not self.options.shared:
+            raise ConanInvalidConfiguration("Celix is only packaged with shared libraries")
+
         if self.options.build_rsa_remote_service_admin_shm_v2 and self.settings.os != "Linux":
             raise ConanInvalidConfiguration("Celix build_rsa_remote_service_admin_shm_v2 is only supported for Linux")
 
@@ -415,7 +422,7 @@ class CelixConan(ConanFile):
 
     def generate(self):
         tc = CMakeToolchain(self)
-        conan_internal_options = ["build_all"] #options are not used in CMake
+        conan_internal_options = ["build_all", "shared"] #options are not used in CMake
         for opt in self._celix_defaults.keys():
             if opt not in conan_internal_options:
                 tc.cache_variables[opt.upper()] = self.options.get_safe(opt)
diff --git a/libs/jansson_ext/CMakeLists.txt b/libs/jansson_ext/CMakeLists.txt
index 3270b363c..2a009fe35 100644
--- a/libs/jansson_ext/CMakeLists.txt
+++ b/libs/jansson_ext/CMakeLists.txt
@@ -42,10 +42,10 @@ if (JANSSON_EXT)
         PRIVATE src
         PUBLIC
             $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
-            $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}/celix/gen/includes/jansson_ext>)
+            $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/celix/gen/includes/jansson_ext>)
     generate_export_header(jansson_ext 
         BASE_NAME CELIX_JANSSON_EXT
-        EXPORT_FILE_NAME "${CMAKE_BINARY_DIR}/celix/gen/includes/jansson_ext/celix_jansson_ext_export.h")
+        EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/celix/gen/includes/jansson_ext/celix_jansson_ext_export.h")
     add_library(Celix::jansson_ext ALIAS jansson_ext)
 
     # Install (always, no option gate)
@@ -70,7 +70,7 @@ if (JANSSON_EXT)
             PUBLIC
                 ${CMAKE_CURRENT_LIST_DIR}/include
                 ${CMAKE_CURRENT_LIST_DIR}/src
-                ${CMAKE_BINARY_DIR}/celix/gen/includes/jansson_ext)
+                ${CMAKE_CURRENT_BINARY_DIR}/celix/gen/includes/jansson_ext)
         target_compile_definitions(jansson_ext_cut PUBLIC CELIX_JANSSON_EXT_STATIC_DEFINE)
         add_subdirectory(gtest)
     endif ()
diff --git a/test_package/CMakeLists.txt b/test_package/CMakeLists.txt
index 5ba1b25e2..34d660c06 100644
--- a/test_package/CMakeLists.txt
+++ b/test_package/CMakeLists.txt
@@ -298,6 +298,12 @@ if (TEST_CELIX_DFI)
     target_link_libraries(use_celix_dfi PRIVATE Celix::dfi)
 endif ()
 
+option(TEST_JANSSON_EXT "Test jansson_ext" OFF)
+if (TEST_JANSSON_EXT)
+    add_executable(use_jansson_ext test_jansson_ext.c)
+    target_link_libraries(use_jansson_ext PRIVATE Celix::jansson_ext)
+endif ()
+
 option(TEST_UTILS "Test utils" OFF)
 if (TEST_UTILS)
     add_executable(use_utils test_utils.c)
diff --git a/test_package/conanfile.py b/test_package/conanfile.py
index 57a2ddc97..a7b8e613e 100644
--- a/test_package/conanfile.py
+++ b/test_package/conanfile.py
@@ -32,6 +32,11 @@ class TestPackageConan(ConanFile):
 
     def requirements(self):
         self.requires(self.tested_reference_str)
+        # The public API of Celix::jansson_ext is built on jansson types (json_t), so the
+        # tests call jansson functions directly. Celix is a shared package, and Conan does
+        # not propagate the link dependencies of shared packages to consumers, so jansson
+        # must be required directly to be linkable here.
+        self.requires("jansson/[>=2.12 <3.0.0]")
 
     def generate(self):
         tc = CMakeToolchain(self)
@@ -63,6 +68,7 @@ class TestPackageConan(ConanFile):
         tc.cache_variables["TEST_CXX_REMOTE_SERVICE_ADMIN"] = celix_options.build_cxx_remote_service_admin
         tc.cache_variables["TEST_SHELL_API"] = celix_options.build_shell_api
         tc.cache_variables["TEST_CELIX_DFI"] = celix_options.build_celix_dfi
+        tc.cache_variables["TEST_JANSSON_EXT"] = celix_options.build_jansson_ext
         tc.cache_variables["TEST_UTILS"] = celix_options.build_utils
         tc.cache_variables["TEST_EVENT_ADMIN"] = celix_options.build_event_admin
         tc.cache_variables["TEST_EVENT_ADMIN_REMOTE_PROVIDER_MQTT"] = celix_options.build_event_admin_remote_provider_mqtt
@@ -138,6 +144,8 @@ class TestPackageConan(ConanFile):
                     self.run("./use_shell_api", env="conanrun")
                 if celix_options.build_celix_dfi:
                     self.run("./use_celix_dfi", env="conanrun")
+                if celix_options.build_jansson_ext:
+                    self.run("./use_jansson_ext", env="conanrun")
                 if celix_options.build_utils:
                     self.run("./use_utils", env="conanrun")
                 if celix_options.build_event_admin:
diff --git a/test_package/test_jansson_ext.c b/test_package/test_jansson_ext.c
new file mode 100644
index 000000000..6699f7592
--- /dev/null
+++ b/test_package/test_jansson_ext.c
@@ -0,0 +1,139 @@
+//  Licensed to the Apache Software Foundation (ASF) under one
+//  or more contributor license agreements.  See the NOTICE file
+//  distributed with this work for additional information
+//  regarding copyright ownership.  The ASF licenses this file
+//  to you under the Apache License, Version 2.0 (the
+//  "License"); you may not use this file except in compliance
+//  with the License.  You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing,
+//  software distributed under the License is distributed on an
+//  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+//  KIND, either express or implied.  See the License for the
+//  specific language governing permissions and limitations
+//  under the License.
+//
+
+#include <celix_jansson_pointer.h>
+#include <celix_jansson_schema.h>
+#include <celix_json_patch.h>
+#include <jansson.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main() {
+    /* ── JSON Schema draft-7 validation ─────────────────────────────────── */
+    json_error_t jerr;
+    json_t* schema = json_loads(
+        "{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"}},\"required\":[\"name\"]}",
+        0, &jerr);
+    if (!schema) {
+        fprintf(stderr, "Error parsing schema: %s\n", jerr.text);
+        return 1;
+    }
+
+    celix_jansson_schema_validator_t* validator = celix_jansson_schema_validator_create(
+        NULL, NULL, celix_jansson_schema_default_format_check, NULL, NULL, NULL);
+    if (!validator) {
+        fprintf(stderr, "Failed to create validator\n");
+        json_decref(schema);
+        return 1;
+    }
+
+    char* errmsg = NULL;
+    int rc = celix_jansson_schema_set_root_schema(validator, schema, &errmsg);
+    if (rc != CELIX_JANSSON_SCHEMA_OK) {
+        fprintf(stderr, "Schema compilation error: %s\n", errmsg ? errmsg : celix_jansson_schema_strerror(rc));
+        free(errmsg);
+        json_decref(schema);
+        celix_jansson_schema_validator_destroy(validator);
+        return 1;
+    }
+    free(errmsg);
+    json_decref(schema);
+
+    json_t* instance = json_loads("{\"name\":\"celix\"}", 0, &jerr);
+    if (!instance) {
+        fprintf(stderr, "Error parsing instance: %s\n", jerr.text);
+        celix_jansson_schema_validator_destroy(validator);
+        return 1;
+    }
+    int errors = celix_jansson_schema_validate(validator, instance, NULL, NULL, NULL);
+    printf("valid instance errors = %d\n", errors);
+    json_decref(instance);
+    if (errors != 0) {
+        celix_jansson_schema_validator_destroy(validator);
+        return 1;
+    }
+
+    instance = json_loads("{}", 0, &jerr);
+    if (!instance) {
+        fprintf(stderr, "Error parsing instance: %s\n", jerr.text);
+        celix_jansson_schema_validator_destroy(validator);
+        return 1;
+    }
+    errors = celix_jansson_schema_validate(validator, instance, NULL, NULL, NULL);
+    printf("invalid instance errors = %d\n", errors);
+    json_decref(instance);
+    celix_jansson_schema_validator_destroy(validator);
+    if (errors == 0) {
+        fprintf(stderr, "Expected invalid instance to be rejected\n");
+        return 1;
+    }
+
+    /* ── JSON Pointer (RFC 6901) ───────────────────────────────────────── */
+    json_t* doc = json_loads("{\"foo\":{\"bar\":1}}", 0, &jerr);
+    if (!doc) {
+        fprintf(stderr, "Error parsing document: %s\n", jerr.text);
+        return 1;
+    }
+    celix_json_pointer_t* ptr = celix_json_pointer_create("/foo/bar");
+    json_t* value = ptr ? celix_json_pointer_get(doc, ptr) : NULL;
+    char* ptr_str = ptr ? celix_json_pointer_to_string(ptr) : NULL;
+    if (!ptr || !value || !ptr_str || strcmp(ptr_str, "/foo/bar") != 0) {
+        fprintf(stderr, "JSON pointer resolution failed\n");
+        free(ptr_str);
+        celix_json_pointer_destroy(ptr);
+        json_decref(doc);
+        return 1;
+    }
+    printf("pointer = %s, value = %lld\n", ptr_str, json_integer_value(value));
+    free(ptr_str);
+
+    if (celix_json_pointer_set_new(doc, ptr, json_integer(42)) != 0) {
+        fprintf(stderr, "JSON pointer set failed\n");
+        celix_json_pointer_destroy(ptr);
+        json_decref(doc);
+        return 1;
+    }
+    printf("value after set = %lld\n", json_integer_value(celix_json_pointer_get(doc, ptr)));
+    celix_json_pointer_destroy(ptr);
+
+    /* ── JSON Patch (RFC 6902) ─────────────────────────────────────────── */
+    json_t* patch = json_array();
+    if (!patch || celix_json_patch_add(patch, "/foo/bar", json_integer(7)) != 0) {
+        fprintf(stderr, "JSON patch add failed\n");
+        json_decref(patch);
+        json_decref(doc);
+        return 1;
+    }
+    json_t* patched = celix_json_patch_apply(doc, patch);
+    if (!patched || json_integer_value(json_object_get(json_object_get(patched, "foo"), "bar")) != 7) {
+        fprintf(stderr, "JSON patch apply failed\n");
+        json_decref(patched);
+        json_decref(patch);
+        json_decref(doc);
+        return 1;
+    }
+    char* patched_str = json_dumps(patched, 0);
+    printf("patched = %s\n", patched_str ? patched_str : "?");
+    free(patched_str);
+    json_decref(patched);
+    json_decref(patch);
+    json_decref(doc);
+
+    return 0;
+}