Skip to content

Commit

Permalink
Merge branch 'ps/clar-unit-test' into seen
Browse files Browse the repository at this point in the history
* ps/clar-unit-test:
  clar: add CMake support
  t/unit-tests: convert ctype tests to use clar
  t/unit-tests: convert strvec tests to use clar
  Makefile: wire up the clar unit testing framework
  Makefile: do not use sparse on third-party sources
  Makefile: make hdr-check depend on generated headers
  Makefile: fix sparse dependency on GENERATED_H
  clar: stop including `shellapi.h` unnecessarily
  clar(win32): avoid compile error due to unused `fs_copy()`
  clar: avoid compile error with mingw-w64
  t/clar: fix compatibility with NonStop
  t: import the clar unit testing framework
  t: do not pass GIT_TEST_OPTS to unit tests with prove
  • Loading branch information
gitster committed Aug 20, 2024
2 parents 8bbfbe3 + 4c99a4c commit ec184e3
Show file tree
Hide file tree
Showing 31 changed files with 3,409 additions and 235 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/GIT-PYTHON-VARS
/GIT-SCRIPT-DEFINES
/GIT-SPATCH-DEFINES
/GIT-TEST-SUITES
/GIT-USER-AGENT
/GIT-VERSION-FILE
/bin-wrappers/
Expand Down
2 changes: 2 additions & 0 deletions Documentation/technical/unit-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ GitHub / GitLab stars to estimate this.
:criterion: https://github.com/Snaipe/Criterion[Criterion]
:c-tap: https://github.com/rra/c-tap-harness/[C TAP]
:check: https://libcheck.github.io/check/[Check]
:clar: https://github.com/clar-test/clar[Clar]

[format="csv",options="header",width="33%",subs="specialcharacters,attributes,quotes,macros"]
|=====
Expand All @@ -212,6 +213,7 @@ Framework,"<<license,License>>","<<vendorable-or-ubiquitous,Vendorable or ubiqui
{criterion},{mit},{false},{partial},{true},{true},{true},{true},{true},{false},{true},19,1800
{c-tap},{expat},{true},{partial},{partial},{true},{false},{true},{false},{false},{false},4,33
{check},{lgpl},{false},{partial},{true},{true},{true},{false},{false},{false},{true},17,973
{clar},{isc},{false},{partial},{true},{true},{true},{true},{false},{false},{true},1,192
|=====

=== Additional framework candidates
Expand Down
53 changes: 42 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,8 @@ REFTABLE_TEST_LIB = reftable/libreftable_test.a
GENERATED_H += command-list.h
GENERATED_H += config-list.h
GENERATED_H += hook-list.h
GENERATED_H += $(UNIT_TEST_DIR)/clar-decls.h
GENERATED_H += $(UNIT_TEST_DIR)/clar.suite

.PHONY: generated-hdrs
generated-hdrs: $(GENERATED_H)
Expand Down Expand Up @@ -1334,9 +1336,17 @@ THIRD_PARTY_SOURCES += compat/poll/%
THIRD_PARTY_SOURCES += compat/regex/%
THIRD_PARTY_SOURCES += sha1collisiondetection/%
THIRD_PARTY_SOURCES += sha1dc/%
THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/%
THIRD_PARTY_SOURCES += $(UNIT_TEST_DIR)/clar/clar/%

UNIT_TESTS_SUITES += ctype
UNIT_TESTS_SUITES += strvec
UNIT_TESTS_PROG = $(UNIT_TEST_BIN)/unit-tests$(X)
UNIT_TESTS_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(UNIT_TESTS_SUITES))
UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/clar/clar.o
UNIT_TESTS_OBJS += $(UNIT_TEST_DIR)/unit-test.o

UNIT_TEST_PROGRAMS += t-apply
UNIT_TEST_PROGRAMS += t-ctype
UNIT_TEST_PROGRAMS += t-example-decorate
UNIT_TEST_PROGRAMS += t-hash
UNIT_TEST_PROGRAMS += t-hashmap
Expand All @@ -1353,7 +1363,6 @@ UNIT_TEST_PROGRAMS += t-reftable-record
UNIT_TEST_PROGRAMS += t-reftable-tree
UNIT_TEST_PROGRAMS += t-strbuf
UNIT_TEST_PROGRAMS += t-strcmp-offset
UNIT_TEST_PROGRAMS += t-strvec
UNIT_TEST_PROGRAMS += t-trailer
UNIT_TEST_PROGRAMS += t-urlmatch-normalization
UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS))
Expand Down Expand Up @@ -2719,6 +2728,7 @@ OBJECTS += $(FUZZ_OBJS)
OBJECTS += $(REFTABLE_OBJS) $(REFTABLE_TEST_OBJS)
OBJECTS += $(UNIT_TEST_OBJS)
OBJECTS += contrib/cgit-rs/cgit-sys/public_symbol_export.o
OBJECTS += $(UNIT_TESTS_OBJS)

ifndef NO_CURL
OBJECTS += http.o http-walker.o remote-curl.o
Expand Down Expand Up @@ -3221,7 +3231,7 @@ endif

test_bindir_programs := $(patsubst %,bin-wrappers/%,$(BINDIR_PROGRAMS_NEED_X) $(BINDIR_PROGRAMS_NO_X) $(TEST_PROGRAMS_NEED_X))

all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS)
all:: $(TEST_PROGRAMS) $(test_bindir_programs) $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG)

bin-wrappers/%: wrap-for-bin.sh
$(call mkdir_p_parent_template)
Expand Down Expand Up @@ -3257,9 +3267,10 @@ t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS) $(REFTABLE_TEST_LIB)
check-sha1:: t/helper/test-tool$X
t/helper/test-sha1.sh

SP_OBJ = $(patsubst %.o,%.sp,$(OBJECTS))
SP_SRC = $(filter-out $(THIRD_PARTY_SOURCES),$(patsubst %.o,%.c,$(OBJECTS)))
SP_OBJ = $(patsubst %.c,%.sp,$(SP_SRC))

$(SP_OBJ): %.sp: %.c %.o
$(SP_OBJ): %.sp: %.c %.o $(GENERATED_H)
$(QUIET_SP)cgcc -no-compile $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
-Wsparse-error \
$(SPARSE_FLAGS) $(SP_EXTRA_FLAGS) $< && \
Expand All @@ -3268,7 +3279,7 @@ $(SP_OBJ): %.sp: %.c %.o
.PHONY: sparse
sparse: $(SP_OBJ)

EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/%
EXCEPT_HDRS := $(GENERATED_H) unicode-width.h compat/% xdiff/% $(UNIT_TEST_DIR)/clar/% $(UNIT_TEST_DIR)/clar/clar/%
ifndef OPENSSL_SHA1
EXCEPT_HDRS += sha1/openssl.h
endif
Expand All @@ -3289,7 +3300,7 @@ HCC = $(HCO:hco=hcc)
@echo '#include "git-compat-util.h"' >$@
@echo '#include "$<"' >>$@

$(HCO): %.hco: %.hcc FORCE
$(HCO): %.hco: %.hcc $(GENERATED_H) FORCE
$(QUIET_HDR)$(CC) $(ALL_CFLAGS) -o /dev/null -c -xc $<

.PHONY: hdr-check $(HCO)
Expand All @@ -3300,7 +3311,7 @@ style:
git clang-format --style file --diff --extensions c,h

.PHONY: check
check: $(GENERATED_H)
check:
@if sparse; \
then \
echo >&2 "Use 'make sparse' instead"; \
Expand Down Expand Up @@ -3652,7 +3663,7 @@ endif

artifacts-tar:: $(ALL_COMMANDS_TO_INSTALL) $(SCRIPT_LIB) $(OTHER_PROGRAMS) \
GIT-BUILD-OPTIONS $(TEST_PROGRAMS) $(test_bindir_programs) \
$(UNIT_TEST_PROGS) $(MOFILES)
$(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) $(MOFILES)
$(QUIET_SUBDIR0)templates $(QUIET_SUBDIR1) \
SHELL_PATH='$(SHELL_PATH_SQ)' PERL_PATH='$(PERL_PATH_SQ)'
test -n "$(ARTIFACTS_DIRECTORY)"
Expand Down Expand Up @@ -3708,6 +3719,7 @@ cocciclean:

clean: profile-clean coverage-clean cocciclean
$(RM) -r .build $(UNIT_TEST_BIN)
$(RM) GIT-TEST-SUITES
$(RM) po/git.pot po/git-core.pot
$(RM) git.res
$(RM) $(OBJECTS)
Expand Down Expand Up @@ -3868,9 +3880,28 @@ $(UNIT_TEST_PROGS): $(UNIT_TEST_BIN)/%$X: $(UNIT_TEST_DIR)/%.o \
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
$(filter %.o,$^) $(filter %.a,$^) $(LIBS)

GIT-TEST-SUITES: FORCE
@FLAGS='$(UNIT_TESTS_SUITES)'; \
if test x"$$FLAGS" != x"`cat GIT-TEST-SUITES 2>/dev/null`" ; then \
echo >&2 " * new test suites"; \
echo "$$FLAGS" >GIT-TEST-SUITES; \
fi

$(UNIT_TEST_DIR)/clar-decls.h: $(patsubst %,$(UNIT_TEST_DIR)/%.c,$(UNIT_TESTS_SUITES)) GIT-TEST-SUITES
$(QUIET_GEN)for suite in $(UNIT_TESTS_SUITES); do \
sed -ne "s/^\(void test_$${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*(void)$$\)/extern \1;/p" $(UNIT_TEST_DIR)/$$suite.c; \
done >$@
$(UNIT_TEST_DIR)/clar.suite: $(UNIT_TEST_DIR)/clar-decls.h
$(QUIET_GEN)awk -f $(UNIT_TEST_DIR)/clar-generate.awk $< >$(UNIT_TEST_DIR)/clar.suite
$(UNIT_TESTS_OBJS): $(UNIT_TEST_DIR)/clar-decls.h
$(UNIT_TESTS_OBJS): EXTRA_CPPFLAGS = -I$(UNIT_TEST_DIR)
$(UNIT_TESTS_PROG): $(UNIT_TEST_DIR)/clar.suite $(UNIT_TESTS_OBJS) $(GITLIBS) GIT-LDFLAGS
$(call mkdir_p_parent_template)
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)

.PHONY: build-unit-tests unit-tests
build-unit-tests: $(UNIT_TEST_PROGS)
unit-tests: $(UNIT_TEST_PROGS) t/helper/test-tool$X
build-unit-tests: $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG)
unit-tests: $(UNIT_TEST_PROGS) $(UNIT_TESTS_PROG) t/helper/test-tool$X
$(MAKE) -C t/ unit-tests

contrib/cgit-rs/cgit-sys/partial_symbol_export.o: contrib/cgit-rs/cgit-sys/public_symbol_export.o libgit.a reftable/libreftable.a xdiff/lib.a
Expand Down
53 changes: 53 additions & 0 deletions contrib/buildsystems/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,59 @@ foreach(unit_test ${unit_test_PROGRAMS})
endif()
endforeach()

parse_makefile_for_scripts(unit_tests_SUITES "UNIT_TESTS_SUITES" "")

set(clar_decls "")
set(clar_cbs "")
set(clar_cbs_count 0)
set(clar_suites "static struct clar_suite _clar_suites[] = {\n")
list(LENGTH unit_tests_SUITES clar_suites_count)
foreach(suite ${unit_tests_SUITES})
file(STRINGS "${CMAKE_SOURCE_DIR}/t/unit-tests/${suite}.c" decls
REGEX "^void test_${suite}__[a-zA-Z_0-9][a-zA-Z_0-9]*\\(void\\)$")

list(LENGTH decls decls_count)
string(REGEX REPLACE "void (test_${suite}__([a-zA-Z_0-9]*))\\(void\\)" " { \"\\2\", &\\1 },\n" cbs ${decls})
string(JOIN "" cbs ${cbs})
list(TRANSFORM decls PREPEND "extern ")
string(JOIN ";\n" decls ${decls})

string(APPEND clar_decls "${decls};\n")
string(APPEND clar_cbs
"static const struct clar_func _clar_cb_${suite}[] = {\n"
${cbs}
"};\n")
string(APPEND clar_suites
" {\n"
" \"${suite}\",\n"
" { NULL, NULL },\n"
" { NULL, NULL },\n"
" _clar_cb_${suite}, ${decls_count}, 1\n"
" },\n")
math(EXPR clar_cbs_count "${clar_cbs_count}+${decls_count}")
endforeach()
string(APPEND clar_suites
"};\n"
"static const size_t _clar_suite_count = ${clar_suites_count};\n"
"static const size_t _clar_callback_count = ${clar_cbs_count};\n")
file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar-decls.h" "${clar_decls}")
file(WRITE "${CMAKE_BINARY_DIR}/t/unit-tests/clar.suite" "${clar_decls}" "${clar_cbs}" "${clar_suites}")

list(TRANSFORM unit_tests_SUITES PREPEND "${CMAKE_SOURCE_DIR}/t/unit-tests/")
list(TRANSFORM unit_tests_SUITES APPEND ".c")
add_library(unit-tests-lib ${unit_tests_SUITES} "${CMAKE_SOURCE_DIR}/t/unit-tests/clar/clar.c")
target_include_directories(unit-tests-lib PRIVATE "${CMAKE_SOURCE_DIR}/t/unit-tests")
add_executable(unit-tests "${CMAKE_SOURCE_DIR}/t/unit-tests/unit-test.c")
target_link_libraries(unit-tests unit-tests-lib common-main)
set_target_properties(unit-tests
PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
if(MSVC)
set_target_properties(unit-tests
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
set_target_properties(unit-tests
PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/t/unit-tests/bin)
endif()

#test-tool
parse_makefile_for_sources(test-tool_SOURCES "TEST_BUILTINS_OBJS")
add_library(test-lib OBJECT ${CMAKE_SOURCE_DIR}/t/unit-tests/test-lib.c)
Expand Down
4 changes: 3 additions & 1 deletion t/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ CHAINLINTTESTS = $(sort $(patsubst chainlint/%.test,%,$(wildcard chainlint/*.tes
CHAINLINT = '$(PERL_PATH_SQ)' chainlint.pl
UNIT_TEST_SOURCES = $(wildcard unit-tests/t-*.c)
UNIT_TEST_PROGRAMS = $(patsubst unit-tests/%.c,unit-tests/bin/%$(X),$(UNIT_TEST_SOURCES))
UNIT_TEST_PROGRAMS += unit-tests/bin/unit-tests$(X)
UNIT_TESTS = $(sort $(UNIT_TEST_PROGRAMS))
UNIT_TESTS_NO_DIR = $(notdir $(UNIT_TESTS))

Expand All @@ -68,7 +69,8 @@ failed:
test -z "$$failed" || $(MAKE) $$failed

prove: pre-clean check-chainlint $(TEST_LINT)
@echo "*** prove (shell & unit tests) ***"; $(CHAINLINTSUPPRESS) TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS) :: $(GIT_TEST_OPTS)
@echo "*** prove (shell & unit tests) ***"
@$(CHAINLINTSUPPRESS) TEST_OPTIONS='$(GIT_TEST_OPTS)' TEST_SHELL_PATH='$(TEST_SHELL_PATH_SQ)' $(PROVE) --exec ./run-test.sh $(GIT_PROVE_OPTS) $(T) $(UNIT_TESTS)
$(MAKE) clean-except-prove-cache

$(T):
Expand Down
2 changes: 1 addition & 1 deletion t/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ case "$1" in
echo >&2 "ERROR: TEST_SHELL_PATH is empty or not set"
exit 1
fi
exec "${TEST_SHELL_PATH}" "$@"
exec "${TEST_SHELL_PATH}" "$@" ${TEST_OPTIONS}
;;
*)
exec "$@"
Expand Down
2 changes: 2 additions & 0 deletions t/unit-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
/bin
/clar.suite
/clar-decls.h
50 changes: 50 additions & 0 deletions t/unit-tests/clar-generate.awk
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
function add_suite(suite, initialize, cleanup, count) {
if (!suite) return
suite_count++
callback_count += count
suites = suites " {\n"
suites = suites " \"" suite "\",\n"
suites = suites " " initialize ",\n"
suites = suites " " cleanup ",\n"
suites = suites " _clar_cb_" suite ", " count ", 1\n"
suites = suites " },\n"
}

BEGIN {
suites = "static struct clar_suite _clar_suites[] = {\n"
}

{
print
name = $3; sub(/\(.*$/, "", name)
suite = name; sub(/^test_/, "", suite); sub(/__.*$/, "", suite)
short_name = name; sub(/^.*__/, "", short_name)
cb = "{ \"" short_name "\", &" name " }"
if (suite != prev_suite) {
add_suite(prev_suite, initialize, cleanup, count)
if (callbacks) callbacks = callbacks "};\n"
callbacks = callbacks "static const struct clar_func _clar_cb_" suite "[] = {\n"
initialize = "{ NULL, NULL }"
cleanup = "{ NULL, NULL }"
count = 0
prev_suite = suite
}
if (short_name == "initialize") {
initialize = cb
} else if (short_name == "cleanup") {
cleanup = cb
} else {
callbacks = callbacks " " cb ",\n"
count++
}
}

END {
add_suite(suite, initialize, cleanup, count)
suites = suites "};"
if (callbacks) callbacks = callbacks "};"
print callbacks
print suites
print "static const size_t _clar_suite_count = " suite_count ";"
print "static const size_t _clar_callback_count = " callback_count ";"
}
23 changes: 23 additions & 0 deletions t/unit-tests/clar/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
strategy:
matrix:
os: [ ubuntu-latest, macos-latest ]

runs-on: ${{ matrix.os }}

steps:
- name: Check out
uses: actions/checkout@v2
- name: Build
run: |
cd test
make
15 changes: 15 additions & 0 deletions t/unit-tests/clar/COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ISC License

Copyright (c) 2011-2015 Vicent Marti

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Loading

0 comments on commit ec184e3

Please sign in to comment.