From 5d29ca6ebe2431440822e630ed82213d0bb00033 Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Wed, 2 Apr 2025 20:56:17 +1100 Subject: [PATCH 1/8] Added bazel build support --- .gitignore | 39 +++++++++++++++++++++++ BUILD.bazel | 68 ++++++++++++++++++++++++++++++++++++++++ MODULE.bazel | 14 +++++++++ tests/BUILD.bazel | 62 ++++++++++++++++++++++++++++++++++++ tests/json_patch_tests.c | 10 ++++-- tests/parse_examples.c | 9 +++++- tests/tools.bzl | 44 ++++++++++++++++++++++++++ tests/unity/BUILD.bazel | 22 +++++++++++++ 8 files changed, 264 insertions(+), 4 deletions(-) create mode 100644 BUILD.bazel create mode 100644 MODULE.bazel create mode 100644 tests/BUILD.bazel create mode 100644 tests/tools.bzl create mode 100644 tests/unity/BUILD.bazel diff --git a/.gitignore b/.gitignore index 65fa89b6..921d8446 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,42 @@ libcjson_utils.so.* cmake-build-debug *.lst *.lss + +# Bazel +MODULE.bazel.lock +# Ignore backup files. +*~ +# Ignore Vim swap files. +.*.swp +# macOS-specific excludes +.DS_Store +# Ignore files generated by IDEs. +/.aswb/ +/.bazelbsp/ +/.cache/ +/.classpath +/.clwb/ +/.factorypath +/.idea/ +/.ijwb/ +/.project +/.settings +/.vscode/ +.eclipse/ +.settings/ +.classpath +.project +eclipse-*bin/ +/bazel.iml +# Ignore all bazel-* symlinks. There is no full list since this can change +# based on the name of the directory bazel is cloned into. +/bazel-* +# Ignore outputs generated during Bazel bootstrapping. +/output/ +# Ignore jekyll build output. +/production +/.sass-cache +# Bazelisk version file +.bazelversion +# User-specific .bazelrc +user.bazelrc diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 00000000..d6649118 --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,68 @@ +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + +CJSON_COPTS = select({ + "@bazel_tools//src/conditions:darwin": [ + "-std=c89", # Standards compliance + "-Wc++-compat", # C++ compatibility + "-fvisibility=hidden", # Symbol visibility + ], + "@bazel_tools//src/conditions:linux": [ + "-std=c89", # Standards compliance + "-Wc++-compat", # C++ compatibility + "-fstack-protect-strong", # Security (GCC/Clang on Linux supports this) + "-fvisibility=hidden", # Symbol visibility + ], + "@bazel_tools//src/conditions:windows": [ + "/Za", # Equivalent to -std=c89 (enforce ANSI C) + "/W3", # Moderate warning level (instead of -Wc++-compat) + "/GS", # Stack protection (equivalent to -fstack-protect-strong) + ], +}) + +cc_library( + name = "cjson", + srcs = ["cJSON.c"], + hdrs = ["cJSON.h"], + copts = CJSON_COPTS + [ + "-DCJSON_EXPORT_SYMBOLS", + "-DCJSON_API_VISIBILITY", + ], + linkopts = select({ + "@bazel_tools//src/conditions:windows": [], + "//conditions:default": ["-lm"], # Link math library on non-Windows + }), + visibility = ["//visibility:public"], +) + +cc_library( + name = "cjson_utils", + srcs = ["cJSON_Utils.c"], + hdrs = ["cJSON_Utils.h"], + copts = CJSON_COPTS, + visibility = ["//visibility:public"], + deps = [":cjson"], +) + +cc_library( + name = "cjson_tests", # Some tests directly include the .c file + hdrs = ["cJSON.c"], + visibility = ["//tests:__pkg__"], +) + +cc_test( + name = "cjson_test", + size = "small", + srcs = ["test.c"], + copts = CJSON_COPTS + ["-fno-sanitize=float-divide-by-zero"], + deps = [":cjson"], +) + +test_suite( + name = "all_tests", + tests = [ + ":cjson_test", + "//tests:json_patch_tests", + "//tests:parse_examples", + "//tests:unity_tests", + ], +) diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 00000000..06f600de --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,14 @@ +""" +Module: cjson +Purpose: Provides the cjson library compileable as a Bazel target. Includes general and unity tests through Bazel +Note: cjson_utils target is also available +""" + +module( + name = "cjson", + version = "1.7.19-0.20240923110858-12c4bf1986c2", + compatibility_level = 1, +) + +bazel_dep(name = "rules_cc", version = "0.1.1") +bazel_dep(name = "platforms", version = "0.0.11") diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel new file mode 100644 index 00000000..380c73f6 --- /dev/null +++ b/tests/BUILD.bazel @@ -0,0 +1,62 @@ +load("@rules_cc//cc:defs.bzl", "cc_test") +load(":tools.bzl", "test_set") + +DEPS = [ + "//:cjson", + "//:cjson_tests", + "//:cjson_utils", + "//tests/unity", + "//tests/unity:unity-examples", +] + +DATA = [ + ":patch-test_inputs", + ":test_inputs", +] + +HDRS = glob(["*.h"]) + +filegroup( + name = "test_inputs", + srcs = glob(["inputs/*"]), + visibility = ["//tests:__pkg__"], +) + +filegroup( + name = "patch-test_inputs", + srcs = glob(["json-patch-tests/*.json"]), + visibility = ["//tests:__pkg__"], +) + +test_suite( + name = "unity_tests", + tests = test_set( + srcs = HDRS, + data = DATA, + test_files = glob( + ["*.c"], + exclude = [ + "unity_setup.c", + "parse_examples.c", + "json_patch_tests.c", + ], + ), + deps = DEPS, + ), +) + +cc_test( + name = "parse_examples", + srcs = HDRS + ["parse_examples.c"], + copts = ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], + data = DATA, + deps = DEPS, +) + +cc_test( + name = "json_patch_tests", + srcs = HDRS + ["json_patch_tests.c"], + copts = ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], + data = DATA, + deps = DEPS, +) diff --git a/tests/json_patch_tests.c b/tests/json_patch_tests.c index 7c3d6aed..731da6e1 100644 --- a/tests/json_patch_tests.c +++ b/tests/json_patch_tests.c @@ -29,6 +29,10 @@ #include "common.h" #include "../cJSON_Utils.h" +#ifndef TEST_DIR_PATH +#define TEST_DIR_PATH "json-patch-tests/" +#endif + static cJSON *parse_test_file(const char * const filename) { char *file = NULL; @@ -182,7 +186,7 @@ static cJSON_bool test_generate_test(cJSON *test) static void cjson_utils_should_pass_json_patch_test_tests(void) { - cJSON *tests = parse_test_file("json-patch-tests/tests.json"); + cJSON *tests = parse_test_file(TEST_DIR_PATH "tests.json"); cJSON *test = NULL; cJSON_bool failed = false; @@ -199,7 +203,7 @@ static void cjson_utils_should_pass_json_patch_test_tests(void) static void cjson_utils_should_pass_json_patch_test_spec_tests(void) { - cJSON *tests = parse_test_file("json-patch-tests/spec_tests.json"); + cJSON *tests = parse_test_file(TEST_DIR_PATH "spec_tests.json"); cJSON *test = NULL; cJSON_bool failed = false; @@ -216,7 +220,7 @@ static void cjson_utils_should_pass_json_patch_test_spec_tests(void) static void cjson_utils_should_pass_json_patch_test_cjson_utils_tests(void) { - cJSON *tests = parse_test_file("json-patch-tests/cjson-utils-tests.json"); + cJSON *tests = parse_test_file(TEST_DIR_PATH "cjson-utils-tests.json"); cJSON *test = NULL; cJSON_bool failed = false; diff --git a/tests/parse_examples.c b/tests/parse_examples.c index d35d6cfb..1e12e89b 100644 --- a/tests/parse_examples.c +++ b/tests/parse_examples.c @@ -58,7 +58,9 @@ static void do_test(const char *test_name) test_name_length = strlen(test_name); /* allocate file paths */ +#ifndef TEST_DIR_PATH #define TEST_DIR_PATH "inputs/" +#endif test_path = (char*)malloc(sizeof(TEST_DIR_PATH) + test_name_length); TEST_ASSERT_NOT_NULL_MESSAGE(test_path, "Failed to allocate test_path buffer."); expected_path = (char*)malloc(sizeof(TEST_DIR_PATH) + test_name_length + sizeof(".expected")); @@ -136,7 +138,12 @@ static void file_test6_should_not_be_parsed(void) char *test6 = NULL; cJSON *tree = NULL; - test6 = read_file("inputs/test6"); + char *test_path = NULL; + const char * test_name = "test6"; + test_path = (char*)malloc(sizeof(TEST_DIR_PATH) + strlen(test_name)); + TEST_ASSERT_NOT_NULL_MESSAGE(test_path, "Failed to allocate test_path buffer."); + sprintf(test_path, TEST_DIR_PATH"%s", test_name); + test6 = read_file(test_path); TEST_ASSERT_NOT_NULL_MESSAGE(test6, "Failed to read test6 data."); tree = cJSON_Parse(test6); diff --git a/tests/tools.bzl b/tests/tools.bzl new file mode 100644 index 00000000..6098b6c5 --- /dev/null +++ b/tests/tools.bzl @@ -0,0 +1,44 @@ +"""Tool for generating C++ test targets efficiently using Bazel rules. +""" + +load("@rules_cc//cc:defs.bzl", "cc_test") + +def test_set( + test_files = None, + size = "small", + srcs = [], + file_extensions = ".c", + **kwargs): + """Creates C++ test targets from a list of test files. + + Args: + test_files: List of test file paths to process. Defaults to None. + size: Test size parameter for cc_test rule. Defaults to "small". + srcs: Additional source files to include in all tests. Defaults to empty list. + file_extensions: Expected extension of test files. Defaults to ".cpp". + **kwargs: Additional arguments to pass to cc_test rule. + + Returns: + List of test target names (e.g., [":test1", ":test2"]). + + Note: + Only files ending with the specified file_extensions are processed. + Each test target is created with the filename (without extension) as its name. + """ + test_targets = [] + + # Process positive tests + for file in test_files: + if not file.endswith(file_extensions): + continue + name = file[:-len(file_extensions)] + target = ":" + name + cc_test( + name = name, + size = size, + srcs = srcs + [file], + **kwargs + ) + test_targets.append(target) + + return test_targets diff --git a/tests/unity/BUILD.bazel b/tests/unity/BUILD.bazel new file mode 100644 index 00000000..83faea1c --- /dev/null +++ b/tests/unity/BUILD.bazel @@ -0,0 +1,22 @@ +load("@rules_cc//cc:defs.bzl", "cc_library") + +cc_library( + name = "unity", + srcs = glob(["src/*.c"]), + hdrs = glob(["src/*.h"]), + copts = [ + "-Wno-error", # Disable -Werror + "-fvisibility=default", # Disable -fvisibility=hidden + "-fno-sanitize=float-divide-by-zero", # GCC bug workaround + "-Wno-switch-enum", # Disable -Wswitch-enum + ], + includes = ["src"], + visibility = ["//tests:__pkg__"], + deps = [":unity-examples"], +) + +cc_library( + name = "unity-examples", + hdrs = ["examples/unity_config.h"], + visibility = ["//tests:__pkg__"], +) From e2feceb6694099dc55e0575576847194183db72b Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 07:57:51 +1100 Subject: [PATCH 2/8] fix typo and windows copts --- BUILD.bazel | 9 +++++++-- tests/unity/BUILD.bazel | 17 +++++++++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index d6649118..4bdf3a95 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -9,7 +9,7 @@ CJSON_COPTS = select({ "@bazel_tools//src/conditions:linux": [ "-std=c89", # Standards compliance "-Wc++-compat", # C++ compatibility - "-fstack-protect-strong", # Security (GCC/Clang on Linux supports this) + "-fstack-protector-strong", # Security (GCC/Clang on Linux supports this) "-fvisibility=hidden", # Symbol visibility ], "@bazel_tools//src/conditions:windows": [ @@ -53,7 +53,12 @@ cc_test( name = "cjson_test", size = "small", srcs = ["test.c"], - copts = CJSON_COPTS + ["-fno-sanitize=float-divide-by-zero"], + copts = CJSON_COPTS + select({ + "@platforms//os:windows": [], + "//conditions:default": [ + "-fno-sanitize=float-divide-by-zero", + ], + }), deps = [":cjson"], ) diff --git a/tests/unity/BUILD.bazel b/tests/unity/BUILD.bazel index 83faea1c..e8c4d59a 100644 --- a/tests/unity/BUILD.bazel +++ b/tests/unity/BUILD.bazel @@ -4,12 +4,17 @@ cc_library( name = "unity", srcs = glob(["src/*.c"]), hdrs = glob(["src/*.h"]), - copts = [ - "-Wno-error", # Disable -Werror - "-fvisibility=default", # Disable -fvisibility=hidden - "-fno-sanitize=float-divide-by-zero", # GCC bug workaround - "-Wno-switch-enum", # Disable -Wswitch-enum - ], + copts = select({ + "@platforms//os:windows": [ + "/wd4100", # Disable warning C4100: unreferenced formal parameter (similar to -Wno-error) + "/wd4065", # Disable warning C4065: switch statement contains default but no case (similar to -Wno-switch-enum) + ], + "//conditions:default": [ + "-fvisibility=default", + "-fno-sanitize=float-divide-by-zero", + "-Wno-switch-enum", + ], + }), includes = ["src"], visibility = ["//tests:__pkg__"], deps = [":unity-examples"], From acea4c69eac9f70f65377b772152719283c37fbf Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 08:58:02 +1100 Subject: [PATCH 3/8] c++17 required for some tests --- tests/BUILD.bazel | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 380c73f6..f38ae199 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -32,6 +32,10 @@ test_suite( name = "unity_tests", tests = test_set( srcs = HDRS, + copts = select({ + "@bazel_tools//src/conditions:windows": ["/std:c++17"], + "//conditions:default": ["-std=c++17"], + }), data = DATA, test_files = glob( ["*.c"], From dd1b4f6260645db959c4818770939a63f180e7e7 Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 09:02:56 +1100 Subject: [PATCH 4/8] Added copts to all tests --- tests/BUILD.bazel | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index f38ae199..b902fd90 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -14,6 +14,11 @@ DATA = [ ":test_inputs", ] +COPTS = select({ + "@bazel_tools//src/conditions:windows": ["/std:c++17"], + "//conditions:default": ["-std=c++17"], +}) + HDRS = glob(["*.h"]) filegroup( @@ -32,10 +37,7 @@ test_suite( name = "unity_tests", tests = test_set( srcs = HDRS, - copts = select({ - "@bazel_tools//src/conditions:windows": ["/std:c++17"], - "//conditions:default": ["-std=c++17"], - }), + copts = COPTS, data = DATA, test_files = glob( ["*.c"], @@ -53,6 +55,7 @@ cc_test( name = "parse_examples", srcs = HDRS + ["parse_examples.c"], copts = ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], + copts = COPTS, data = DATA, deps = DEPS, ) @@ -61,6 +64,7 @@ cc_test( name = "json_patch_tests", srcs = HDRS + ["json_patch_tests.c"], copts = ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], + copts = COPTS, data = DATA, deps = DEPS, ) From 5268aa1bacc195d154e712174aca6081b46dfb8c Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 09:08:22 +1100 Subject: [PATCH 5/8] Fixed duplicate copts --- tests/BUILD.bazel | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index b902fd90..5de8c7b7 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -54,8 +54,7 @@ test_suite( cc_test( name = "parse_examples", srcs = HDRS + ["parse_examples.c"], - copts = ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], - copts = COPTS, + copts = COPTS + ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], data = DATA, deps = DEPS, ) @@ -63,8 +62,7 @@ cc_test( cc_test( name = "json_patch_tests", srcs = HDRS + ["json_patch_tests.c"], - copts = ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], - copts = COPTS, + copts = COPTS + ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], data = DATA, deps = DEPS, ) From 4503ad11de5892c5ccf573bde265ea0bc3989cfe Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 09:13:20 +1100 Subject: [PATCH 6/8] removed incorrect copts --- tests/BUILD.bazel | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 5de8c7b7..380c73f6 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -14,11 +14,6 @@ DATA = [ ":test_inputs", ] -COPTS = select({ - "@bazel_tools//src/conditions:windows": ["/std:c++17"], - "//conditions:default": ["-std=c++17"], -}) - HDRS = glob(["*.h"]) filegroup( @@ -37,7 +32,6 @@ test_suite( name = "unity_tests", tests = test_set( srcs = HDRS, - copts = COPTS, data = DATA, test_files = glob( ["*.c"], @@ -54,7 +48,7 @@ test_suite( cc_test( name = "parse_examples", srcs = HDRS + ["parse_examples.c"], - copts = COPTS + ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], + copts = ['-DTEST_DIR_PATH=\\"tests/inputs/\\"'], data = DATA, deps = DEPS, ) @@ -62,7 +56,7 @@ cc_test( cc_test( name = "json_patch_tests", srcs = HDRS + ["json_patch_tests.c"], - copts = COPTS + ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], + copts = ['-DTEST_DIR_PATH=\\"tests/json-patch-tests/\\"'], data = DATA, deps = DEPS, ) From 3d5d982342e4bfa05dd8fa594ed40828fddf0035 Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 09:29:40 +1100 Subject: [PATCH 7/8] Added symbol visibility to utils --- BUILD.bazel | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/BUILD.bazel b/BUILD.bazel index 4bdf3a95..60e3a76f 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -38,7 +38,10 @@ cc_library( name = "cjson_utils", srcs = ["cJSON_Utils.c"], hdrs = ["cJSON_Utils.h"], - copts = CJSON_COPTS, + copts = CJSON_COPTS + [ + "-DCJSON_EXPORT_SYMBOLS", + "-DCJSON_API_VISIBILITY", + ], visibility = ["//visibility:public"], deps = [":cjson"], ) From eb08a52555f48567d503e3c3ecea76010c67962a Mon Sep 17 00:00:00 2001 From: Luke Aguilar Date: Thu, 3 Apr 2025 09:48:05 +1100 Subject: [PATCH 8/8] fix win unity tests --- tests/BUILD.bazel | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 380c73f6..baed64da 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -1,4 +1,4 @@ -load("@rules_cc//cc:defs.bzl", "cc_test") +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") load(":tools.bzl", "test_set") DEPS = [ @@ -7,7 +7,10 @@ DEPS = [ "//:cjson_utils", "//tests/unity", "//tests/unity:unity-examples", -] +] + select({ + "@platforms//os:windows": [":unity-win"], + "//conditions:default": [], +}) DATA = [ ":patch-test_inputs", @@ -16,6 +19,11 @@ DATA = [ HDRS = glob(["*.h"]) +cc_library( + name = "unity-win", + srcs = ["unity_setup.c"], +) + filegroup( name = "test_inputs", srcs = glob(["inputs/*"]),