libzt_0.3.1/.pvs-studio.cfg0000644000175000017500000000023413632013546014305 0ustar zygazygaexclude-path = /usr/lib exclude-path = /usr/lib64 preprocessor = gcc #platform = macos platform = linux64 #General Analysis analysis-mode = 4 language = C libzt_0.3.1/.version0000664000175000017500000000000613675422474013131 0ustar zygazyga0.3.1 libzt_0.3.1/GNUmakefile0000664000175000017500000001135413675422322013515 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of libzt. # # Libzt is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Libzt 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Libzt. If not, see . NAME = libzt VERSION = 0.3.1 srcdir ?= . # Include optional generated makefile from the configuration system. -include GNUmakefile.configure.mk # Use bundled ZMK include $(srcdir)/z.mk $(eval $(call ZMK.Import,Toolchain)) $(eval $(call ZMK.Import,Configure)) $(eval $(call ZMK.Import,OS)) $(eval $(call ZMK.Import,GitVersion)) # Manual pages manpages = \ libzt-test.1 \ libzt.3 \ zt_check.3 \ zt_claim.3 \ ZT_CMP_BOOL.3 \ ZT_CMP_INT.3 \ ZT_CMP_PTR.3 \ ZT_CMP_RUNE.3 \ ZT_CMP_UINT.3 \ ZT_CURRENT_LOCATION.3 \ ZT_FALSE.3 \ zt_location.3 \ zt_location_at.3 \ zt_main.3 \ ZT_NOT_NULL.3 \ ZT_NULL.3 \ zt_pack_boolean.3 \ zt_pack_integer.3 \ zt_pack_nothing.3 \ zt_pack_pointer.3 \ zt_pack_rune.3 \ zt_pack_string.3 \ zt_pack_unsigned.3 \ zt_test.3 \ zt_test_case_func.3 \ zt_test_suite_func.3 \ ZT_TRUE.3 \ zt_value.3 \ zt_visit_test_case.3 \ zt_visitor.3 # The release tarball. $(NAME)_$(VERSION).tar.gz.Files += zt.h zt.c zt-test.c $(NAME)_$(VERSION).tar.gz.Files += libzt.map libzt.export_list libzt.def $(NAME)_$(VERSION).tar.gz.Files += configure GNUmakefile build.bat Makefile.nmake.mk $(NAME)_$(VERSION).tar.gz.Files += examples/demo.c examples/test-root-user.c examples/GNUmakefile $(NAME)_$(VERSION).tar.gz.Files += .pvs-studio.cfg $(NAME)_$(VERSION).tar.gz.Files += README.md LICENSE NEWS $(NAME)_$(VERSION).tar.gz.Files += $(foreach m,$(manpages),man/$m.in) $(eval $(call ZMK.Expand,Tarball.Src,$(NAME)_$(VERSION).tar.gz)) # The custom configuration script sets the variable Configure.Configured # In its absence provide defaults appropriate for each compiler. ifeq (,$(Configure.Configured)) $(info NOTE: Build tree is not configured, using curated compiler options.) $(info NOTE: Use ./configure to disable this mechanism) # Optimize a little by default. CFLAGS += -O2 # -Werror is enabled when building without a configuration file created # by the configure script. This is explicitly meant to find bugs, break the # build and be noticed. CFLAGS += -Werror # Extra careful when using gcc or clang. ifneq (,$(or $(Toolchain.CC.IsGcc),$(Toolchain.CC.IsClang))) CFLAGS += -Wall -Wextra -Wpedantic -Wconversion -Wchar-subscripts endif # gcc || clang # More careful than default when using watcom ifneq (,$(Toolchain.CC.IsWatcom)) CFLAGS += -Wall -Wextra endif endif # !configured # The configure script configure.Interpreter = sh configure.InstallDir = noinst $(eval $(call ZMK.Expand,Script,configure)) # Public header file $(eval $(call ZMK.Expand,Header,zt.h)) # Libraries (.a, .so and .dylib) libzt.a.Sources = zt.c $(eval $(call ZMK.Expand,Library.A,libzt.a)) ifeq ($(Toolchain.CC.ImageFormat),ELF) libzt.so.1.Sources = zt.c libzt.so.1.VersionScript = $(srcdir)/libzt.map $(eval $(call ZMK.Expand,Library.So,libzt.so.1)) endif ifeq ($(Toolchain.CC.ImageFormat),Mach-O) libzt.1.dylib.Sources = zt.c libzt.1.dylib.ExportList = $(srcdir)/libzt.export_list $(eval $(call ZMK.Expand,Library.DyLib,libzt.1.dylib)) endif # Manual pages, generated from .in files all:: $(foreach m,$(manpages),man/$m) clean:: rm -f $(addprefix man/,$(manpages)) ifneq ($(srcdir),.) test -d man && rmdir man || : endif $(CURDIR)/man: # For out-of-tree builds. install -d $@ man/%: man/%.in | $(CURDIR)/man sed -e 's/@VERSION@/$(VERSION)/g' $< >$@ $(foreach m,$(manpages),$(eval $(call ZMK.Expand,ManPage,man/$m))) # The test program libzt-test.Sources = zt-test.c libzt-test.SourcesCoverage = zt.c $(eval $(call ZMK.Expand,Program.Test,libzt-test)) ifneq (,$(Toolchain.CC.IsGcc)) libzt-test: CFLAGS += -Wno-overlength-strings # Old gcc complains about the assert() in zt-test.c endif # Support formatting using clang-format, if installed. ifneq ($(shell command -v clang-format 2>/dev/null),) fmt:: $(wildcard $(srcdir)/*.[ch] $(srcdir)/examples/*.[ch]) clang-format -i -style=WebKit $^ else fmt: echo "error: clang-format not found, cannot format" >&2 exit 1 endif # Static analysis using PVS Studio. PVS.Sources=zt.c zt-test.c PLOG_CONVERTER_FLAGS += -d V1042 # libzt is FOSS, no need to tell us. $(eval $(call ZMK.Import,PVS)) # Static analysis using Coverity Coverity.Sources=zt.c zt.h zt-test.c $(eval $(call ZMK.Import,Coverity)) libzt_0.3.1/LICENSE0000644000175000017500000001674313640205631012447 0ustar zygazyga GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. libzt_0.3.1/Makefile.nmake.mk0000664000175000017500000000057713651643626014616 0ustar zygazyga!if [set CL=/nologo /Wall /wd4820 /wd4100 /wd4996 /wd4710 /wd5045] !endif all: libzt-test.exe zt.dll clean: del /F zt.obj zt-test.obj libzt-test.exe zt.dll zt.lib zt.exp check: libzt-test.exe libzt-test.exe libzt-test.exe: zt-test.obj cl /Fe: $@ $? zt.dll: zt.obj cl /LD /DEF libzt.def /Fe: $@ $? zt.obj: zt.c zt.h cl /c zt.c zt-test.obj: zt-test.c zt.c zt.h cl /c zt-test.c libzt_0.3.1/NEWS0000664000175000017500000000536313675422336012152 0ustar zygazygaChanges in 0.3.1: * The build system has been updated to ZMK 0.3.6. This should fix current build issues encountered in Debian. Changes in 0.3: * Pointers captured in zt_value by zt_pack_pointer() are now constant. This allows testing pointers to constants with ZT_NULL and ZT_NOT_NULL. This does not impact the ABI. * Added ZT_CMP_PTR for comparing pointers for equality and inequality. Other relations are explicitly left out, at least for now. * ZT_CMP_INT and ZT_CMP_UINT now support maximum integral types of the architecture. This allows ZT_CMP_UINT to safely work with size_t values. This is achieved in a backwards compatible way. Existing test programs compiled and linked with libzt 0.1 or 0.2 retain their current semantic. The type zt_value has grown two new kinds, ZT_INTMAX and ZT_UINTMAX, along with new union members. The static inline pack functions zt_pack_integer and zt_pack_unsigned now take intmax_t and uintmax_t arguments respectively. Since they are always inlined this is not an ABI break. Test programs built with older definitions of the two pack functions use distinct kind (ZT_INTEGER instead of ZT_INTMAX and ZT_UNSIGNED instead of ZT_UINTMAX) which is now detected and handled by zt_cmp_int and zt_cmp_uint. Internally the values are promoted and comparison is always performed on the extended types. * The function zt_main() now displays both the test case name and the outcome of each test when invoked with "-v" command-line argument. * Libzt can now build for DOS as either 16bit or extended mode 32bit. Note that libzt-test.exe requires the DOS extender as it is too large to fit into 64K code segment. * The configuration system is more robust and can now detect the use of Gcc, Clang and the OpenWatcom compilers. Using OpenWatcom from the open-watcom snap allows cross-compiling libzt for DOS and other older targets. * The build system is now decoupled from libzt and can be used for other projects. Currently a copy resides in-tree but at some later date it may become a new development-only dependency. Distribution tarballs will not require any new dependencies. * The tree now contains comprehensive integration tests that build and exercise the library on several different Linux distributions. One of the tests cross builds libzt for DOS and tests it with DosBox and DOS/32 extender. Changes in 0.2: * Argument type to all unit test functions was typedef'd to zt_t, to abbreviate the boilerplate text and to avoid having to type struct zt_test. * The field zt_claim.verifier was renamed to zt_claim.make_verifier. There is no public API breakage on this as claims are not constructed by user code apart from the existing stable helpers. libzt_0.3.1/README.md0000644000175000017500000000244613641710542012717 0ustar zygazyga![C CI](https://github.com/zyga/libzt/workflows/C%20CI/badge.svg) # libzt is an unit test library for C libzt is a simple and robust unit test library for C. ## Features - Robust, allowing you to focus on your code. - Simple and small, making it quick to learn and use. - Doesn't use dynamic memory allocation, reducing error handling. - Equipped with useful helpers for writing test cases. - Portable and supported on Linux, MacOS, Windows and DOS. - Documented and fully coverage and integration tested. ## Example ``` #include #include static const char *greeting(void) { return "hello there"; } static void test_smoke(zt_t t) { zt_check(t, ZT_TRUE(2 + 2 == 4)); zt_check(t, ZT_CMP_INT(2 + 2, ==, 4)); zt_check(t, ZT_CMP_STR(greeting(), ==, "hello there")); } static void test_writing_to_tmpfile(zt_t t) { FILE *f = tmpfile(); zt_assert(t, ZT_NOT_NULL(f)); // stops test on failure zt_check(t, ZT_CMP_INT(fprintf(f, "%s", greeting()), >, 0); zt_check(t, ZT_CMP_INT(ftell(f), ==, strlen(greeting())); zt_check(t, ZT_CMP_INT(fclose(f), ==, 0); } static void test_suite(zt_visitor v) { ZT_VISIT_TEST(v, test_smoke); ZT_VISIT_TEST(v, test_writing_to_tmpfile); } int main(int argc, char **argv, char **envp) { return zt_main(argc, argv, envp, test_suite); } ``` libzt_0.3.1/build.bat0000664000175000017500000000003313651643626013230 0ustar zygazyganmake /f Makefile.nmake.mk libzt_0.3.1/configure0000775000175000017500000003061113675422474013357 0ustar zygazyga#!/bin/sh # Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # This script was automatically generated by zmk version 0.3.6. while [ "$#" -ge 1 ]; do case "$1" in -h|--help) echo "Usage: ./configure [OPTIONS]" echo echo "Compilation options:" echo " --build=GNU_TRIPLET Describe the build machine with the given GNU_TRIPLET" echo " --host=GNU_TRIPLET Describe the host machine with the given GNU_TRIPLET" echo " --enable-dependency-tracking" echo " Track dependencies between files (implicit)" echo " --disable-dependency-tracking" echo " Do not generate or use dependency data during builds" echo " --enable-maintainer-mode Enable maintainer mode (implicit)" echo " --disable-maintainer-mode Disable maintainer mode" echo echo "Build-time directory selection:" echo " --prefix=PREFIX Set prefix for all directories to PREFIX" echo " --exec-prefix=PREFIX Set prefix for libraries and programs to PREFIX" echo echo " --bindir=DIR Install user programs to DIR" echo " --sbindir=DIR Install super-user programs to DIR" echo " --libdir=DIR Install runtime and development libraries to DIR" echo " --libexecdir=DIR Install library-internal programs to DIR" echo " --includedir=DIR Install development header files to DIR" echo " --mandir=DIR Install manual pages to DIR" echo " --infodir=DIR Install GNU info pages to DIR" echo " --sysconfdir=DIR Install system configuration files to DIR" echo " --datadir=DIR Install read-only data files to DIR" echo echo " --localstatedir=DIR Store persistent state specific to a machine in DIR" echo " --runstatedir=DIR Store ephemeral state specific to a machine in DIR" echo " --sharedstatedir=DIR Store state shared across machines in DIR" echo echo "Options for altering program names:" echo " --program-prefix=PREFIX Put PREFIX before installed program names" echo " --program-suffix=SUFFIX Put SUFFIX after installed program names" echo " --program-transform-name=PROGRAM" echo " Use sed PROGRAM to transform installed program names" echo echo "Miscellaneous options:" echo " --enable-option-checking Report unrecognized configuration options (implicit)" echo " --disable-option-checking Ignore unrecognized configuration options" echo " --enable-silent-rules Do not display commands while building" echo " --disable-silent-rules Display commands while building (implicit)" echo echo "Memorized environment variables:" echo " CC Name of the C compiler" echo " CXX Name of the C++ compiler" echo " CFLAGS Options for the C compiler" echo " CXXFLAGS Options for the C++ compiler" echo " CPPFLAGS Options for the preprocessor" echo " LDFLAGS Options for the linker" exit 0 ;; --version) echo "z.mk configure script version 0.3.6" exit 0 ;; *) break ;; esac done { # Given key=value or key="value value", print the value rhs() { echo "$*" | cut -d '=' -f 2- | sed -e 's/^"//' -e 's/"$//' } echo "# Generated by zmk configuration script version 0.3.6" echo "# ./configure $*" configureOptions="$*" echo echo "# Location of the source code." if [ -n "${srcdir:-}" ]; then echo "srcdir=$srcdir" else echo "srcdir=$(dirname "$0")" fi echo echo "# Set VPATH for make (for out-of-tree builds)." echo "VPATH=\$(srcdir)" while [ "$#" -ge 1 ]; do case "$1" in --build=*) buildArchTriplet="$(rhs "$1")" && shift ;; --host=*) hostArchTriplet="$(rhs "$1")" && shift ;; --enable-dependency-tracking) dependencyTracking=yes && shift ;; --disable-dependency-tracking) dependencyTracking=no && shift ;; --enable-maintainer-mode) maintainerMode=yes && shift ;; --disable-maintainer-mode) maintainerMode=no && shift ;; --enable-silent-rules) silentRules=yes && shift ;; --disable-silent-rules) silentRules=no && shift ;; --enable-option-checking) disableOptionChecking=no && shift ;; --disable-option-checking) disableOptionChecking=yes && shift ;; --program-prefix=*) programPrefix="$(rhs "$1")" && shift ;; --program-suffix=*) programSuffix="$(rhs "$1")" && shift ;; --program-transform-name=*) programTransformName="$(rhs "$1")" && shift ;; --exec-prefix=*) exec_prefix="$(rhs "$1")" && shift ;; --prefix=*) prefix="$(rhs "$1")" && shift ;; --bindir=*) bindir="$(rhs "$1")" && shift ;; --sbindir=*) sbindir="$(rhs "$1")" && shift ;; --libdir=*) libdir="$(rhs "$1")" && shift ;; --libexecdir=*) libexecdir="$(rhs "$1")" && shift ;; --datadir=*) datadir="$(rhs "$1")" && shift ;; --includedir=*) includedir="$(rhs "$1")" && shift ;; --infodir=*) infodir="$(rhs "$1")" && shift ;; --mandir=*) mandir="$(rhs "$1")" && shift ;; --sysconfdir=*) sysconfdir="$(rhs "$1")" && shift ;; --localstatedir=*) localstatedir="$(rhs "$1")" && shift ;; --runstatedir=*) runstatedir="$(rhs "$1")" && shift ;; --sharedstatedir=*) sharedstatedir="$(rhs "$1")" && shift ;; CC=*) CC="$(rhs "$1")" && shift ;; CXX=*) CXX="$(rhs "$1")" && shift ;; CFLAGS=*) CFLAGS="$(rhs "$1")" && shift ;; OBJCFLAGS=*) OBJCFLAGS="$(rhs "$1")" && shift ;; CXXFLAGS=*) CXXFLAGS="$(rhs "$1")" && shift ;; CPPFLAGS=*) CPPFLAGS="$(rhs "$1")" && shift ;; LDFLAGS=*) LDFLAGS="$(rhs "$1")" && shift ;; *) if [ "${disableOptionChecking:-}" != yes ]; then echo "configure: unknown option $1" >&2 configureFailed=1 fi shift ;; esac done echo echo "# Build and host architecture triplets." echo "# Note that those impact compiler selection unless overridden." test -n "${buildArchTriplet:-}" && echo "Configure.BuildArchTriplet=$buildArchTriplet" || echo "# Configure.BuildArchTriplet was not specified." test -n "${hostArchTriplet:-}" && echo "Configure.HostArchTriplet=$hostArchTriplet" || echo "# Configure.HostArchTriplet was not specified." echo echo "# Build-time configuration of application directories." test -n "${prefix:-}" && echo "prefix=$prefix" || echo "# prefix was not specified." test -n "${exec_prefix:-}" && echo "exec_prefix=$exec_prefix" || echo "# exec_prefix was not specified." test -n "${bindir:-}" && echo "bindir=$bindir" || echo "# bindir was not specified." test -n "${sbindir:-}" && echo "sbindir=$sbindir" || echo "# sbindir was not specified." test -n "${datadir:-}" && echo "datadir=$datadir" || echo "# datadir was not specified." test -n "${includedir:-}" && echo "includedir=$includedir" || echo "# includedir was not specified." test -n "${infodir:-}" && echo "infodir=$infodir" || echo "# infodir was not specified." test -n "${libdir:-}" && echo "libdir=$libdir" || echo "# libdir was not specified." test -n "${libexecdir:-}" && echo "libexecdir=$libexecdir" || echo "# libexecdir was not specified." test -n "${localstatedir:-}" && echo "localstatedir=$localstatedir" || echo "# localstatedir was not specified." test -n "${mandir:-}" && echo "mandir=$mandir" || echo "# mandir was not specified." test -n "${runstatedir:-}" && echo "runstatedir=$runstatedir" || echo "# runstatedir was not specified." test -n "${sharedstatedir:-}" && echo "sharedstatedir=$sharedstatedir" || echo "# sharedstatedir was not specified." test -n "${sysconfdir:-}" && echo "sysconfdir=$sysconfdir" || echo "# sysconfdir was not specified." echo echo "# Inherited environment variables and overrides." test -n "$CC" && echo "CC=$CC" || echo "# CC was not specified." test -n "$CXX" && echo "CXX=$CXX" || echo "# CXX was not specified." test -n "$CFLAGS" && echo "CFLAGS=$CFLAGS" || echo "# CFLAGS was not specified." test -n "$CXXFLAGS" && echo "CXXFLAGS=$CXXFLAGS" || echo "# CXXFLAGS was not specified." test -n "$OBJCFLAGS" && echo "OBJCFLAGS=$OBJCFLAGS" || echo "# OBJCFLAGS was not specified." test -n "$CPPFLAGS" && echo "CPPFLAGS=$CPPFLAGS" || echo "# CPPFLAGS was not specified." test -n "$LDFLAGS" && echo "LDFLAGS=$LDFLAGS" || echo "# LDFLAGS was not specified." echo echo "# Track dependencies between objects and source and header files." case "${dependencyTracking:-implicit}" in yes) echo "Configure.DependencyTracking=yes" ;; no) echo "Configure.DependencyTracking=" ;; implicit) echo "# Configure.DependencyTracking was not specified." ;; esac echo echo "# Additional options for package maintainers." case "${maintainerMode:-implicit}" in yes) echo "Configure.MaintainerMode=yes" ;; no) echo "Configure.MaintainerMode=" ;; implicit) echo "# Configure.MaintainerMode was not specified." ;; esac echo echo "# Silence shell commands used by make." case "${silentRules:-implicit}" in yes) echo "Configure.SilentRules=yes" ;; no) echo "Configure.SilentRules=" ;; implicit) echo "# Configure.SilentRules was not specified." ;; esac echo echo "# Program name customization options." test -n "${programPrefix:-}" && echo "Configure.ProgramPrefix=$programPrefix" || echo "# Configure.ProgramPrefix was not specified." test -n "${programSuffix:-}" && echo "Configure.ProgramSuffix=$programSuffix" || echo "# Configure.ProgramSuffix was not specified." test -n "${programTransformName:-}" && echo "Configure.ProgramTransformName=$programTransformName" || echo "# Configure.ProgramTransformName was not specified." echo echo "# Remember that the configuration script was executed." echo "Configure.Configured=yes" echo "Configure.Options=$configureOptions" } > "${ZMK_CONFIGURE_MAKEFILE:=GNUmakefile.configure.mk}" if [ "${configureFailed:-0}" -eq 1 ]; then rm -f "${ZMK_CONFIGURE_MAKEFILE}" exit 1 fi if [ ! -e Makefile ] && [ ! -e GNUmakefile ]; then ln -s "$(dirname "$0")"/GNUmakefile GNUmakefile fi libzt_0.3.1/examples/GNUmakefile0000644000175000017500000000017613632013546015326 0ustar zygazyga.PHONY: all clean CFLAGS ?= -Wall -Werror -O2 LDLIBS += -lzt all: demo test-root-user clean: rm -f *.o demo test-root-user libzt_0.3.1/examples/demo.c0000644000175000017500000000165413632013546014346 0ustar zygazyga#include #include #include #include static void passing_test(zt_t t) { zt_check(t, ZT_TRUE(2 + 2 == 4)); zt_check(t, ZT_FALSE(2 + 2 == 5)); zt_check(t, ZT_CMP_INT(2 + 2, ==, 4)); zt_check(t, ZT_CMP_BOOL(false, ==, false)); } static void failing_test(zt_t t) { zt_check(t, ZT_TRUE(2 + 2 != 4)); zt_check(t, ZT_FALSE(2 + 2 != 5)); zt_check(t, ZT_CMP_INT(2 + 2, ==, 5)); zt_check(t, ZT_CMP_BOOL(false, ==, true)); } static void badly_failing_test(zt_t t) { zt_assert(t, ZT_CMP_INT(0, ==, -1)); abort(); } static void passing_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, passing_test); } static void test_suite(zt_visitor v) { ZT_VISIT_TEST_SUITE(v, passing_suite); ZT_VISIT_TEST_CASE(v, failing_test); ZT_VISIT_TEST_CASE(v, badly_failing_test); } int main(int argc, char** argv, char** envp) { return zt_main(argc, argv, envp, test_suite); } libzt_0.3.1/examples/test-root-user.c0000644000175000017500000000076513632013546016340 0ustar zygazyga#include #include #include static void test_root_user(zt_t t) { struct passwd* p = getpwnam("root"); zt_assert(t, ZT_NOT_NULL(p)); zt_check(t, ZT_CMP_CSTR(p->pw_name, ==, "root")); zt_check(t, ZT_CMP_INT(p->pw_uid, ==, 0)); zt_check(t, ZT_CMP_INT(p->pw_gid, ==, 0)); } static void test_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, test_root_user); } int main(int argc, char** argv, char** envp) { return zt_main(argc, argv, envp, test_suite); } libzt_0.3.1/libzt.def0000664000175000017500000000037413675422322013247 0ustar zygazygaLIBRARY ZT VERSION 0.3 EXPORTS zt_assert zt_check zt_cmp_bool zt_cmp_cstr zt_cmp_int zt_cmp_ptr zt_cmp_rune zt_cmp_uint zt_false zt_main zt_not_null zt_null zt_pack_rune zt_true zt_visit_test_case zt_visit_test_suite libzt_0.3.1/libzt.export_list0000664000175000017500000000031213675422322015055 0ustar zygazyga_zt_assert _zt_check _zt_cmp_bool _zt_cmp_cstr _zt_cmp_int _zt_cmp_ptr _zt_cmp_rune _zt_cmp_uint _zt_false _zt_main _zt_not_null _zt_null _zt_pack_rune _zt_true _zt_visit_test_case _zt_visit_test_suite libzt_0.3.1/libzt.map0000664000175000017500000000050613675422322013263 0ustar zygazygaVERS_0_1 { global: zt_assert; zt_check; zt_cmp_bool; zt_cmp_cstr; zt_cmp_int; zt_cmp_rune; zt_cmp_uint; zt_false; zt_main; zt_not_null; zt_null; zt_pack_rune; zt_true; zt_visit_test_case; zt_visit_test_suite; local: *; }; VERS_0_2 { } VERS_0_1; VERS_0_3 { global: zt_cmp_ptr; } VERS_0_2; libzt_0.3.1/man/ZT_CMP_BOOL.3.in0000644000175000017500000000267213673206643014563 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CMP_BOOL 3 PRM .Sh NAME .Nm ZT_CMP_BOOL , .Nm zt_cmp_bool .Nd construct a claim of a relation between two booleans .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_CMP_BOOL(left, rel, right) \\ zt_cmp_bool( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_boolean((left), (#left)), \\ zt_pack_string((#rel), (#rel)), \\ zt_pack_boolean((right), (#right))) .Ed .Ft zt_claim .Fo zt_cmp_bool .Fa "zt_location location" .Fa "zt_value left" .Fa "zt_value rel" .Fa "zt_value right" .Fc .Sh DESCRIPTION .Fn zt_cmp_bool constructs a claim of a relation between two booleans. It should be used through the macro .Fn ZT_CMP_BOOL which passes source code location and packs arguments. .Pp The relation must be either .Em == or .Em != . .Pp It may be more natural to use .Fn ZT_TRUE or .Fn ZT_FALSE instead. .Sh IMPLEMENTATION NOTES .Fn ZT_CMP_BOOL evaluates .Em left and .Em right exactly once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_CMP_BOOL macro and the .Fn zt_cmp_bool function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_CMP_INT.3.in0000644000175000017500000000301213673206643014447 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CMP_INT 3 PRM .Sh NAME .Nm ZT_CMP_INT , .Nm zt_cmp_int .Nd construct a claim of a relation between two integers .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_CMP_INT(left, rel, right) \\ zt_cmp_int( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_integer((left), (#left)), \\ zt_pack_string((#rel), (#rel)), \\ zt_pack_integer((right), (#right))) .Ed .Ft zt_claim .Fo zt_cmp_int .Fa "zt_location location" .Fa "zt_value left" .Fa "zt_value rel" .Fa "zt_value right" .Fc .Sh DESCRIPTION .Fn zt_cmp_int constructs a claim of a relation between two integers. It should be used through the macro .Fn ZT_CMP_INT which passes source code location and packs arguments. .Pp The relation must be one of .Em == , .Em != , .Em < , .Em <= , .Em > or .Em >= . .Sh IMPLEMENTATION NOTES .Fn ZT_CMP_INT evaluates .Em left and .Em right exactly once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_CMP_INT macro and the .Fn zt_cmp_int function first appeared in libzt 0.1 .Pp Since libzt 0.3 .Fn zt_cmp_int internally promotes .Nm left and .Nm right arguments from .Nm ZT_INTEGER to .Nm ZT_INTMAX . .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_CMP_PTR.3.in0000644000175000017500000000254713673206643014476 0ustar zygazyga.Dd March 12, 2020 .Os libzt @VERSION@ .Dt ZT_CMP_PTR 3 PRM .Sh NAME .Nm ZT_CMP_PTR , .Nm zt_cmp_int .Nd construct a claim of a relation between two pointers .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_CMP_PTR(left, rel, right) \\ zt_cmp_ptr( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_pointer((left), (#left)), \\ zt_pack_string((#rel), (#rel)), \\ zt_pack_pointer((right), (#right))) .Ed .Ft zt_claim .Fo zt_cmp_ptr .Fa "zt_location location" .Fa "zt_value left" .Fa "zt_value rel" .Fa "zt_value right" .Fc .Sh DESCRIPTION .Fn zt_cmp_ptr constructs a claim of a relation between two integers. It should be used through the macro .Fn ZT_CMP_PTR which passes source code location and packs arguments. .Pp The relation must be either .Em == , or .Em != .Sh IMPLEMENTATION NOTES .Fn ZT_CMP_PTR evaluates .Em left and .Em right exactly once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_CHAR 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_CMP_PTR macro and the .Fn zt_cmp_ptr function first appeared in libzt 0.3 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_CMP_RUNE.3.in0000644000175000017500000000264313673206643014577 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CMP_RUNE 3 PRM .Sh NAME .Nm ZT_CMP_RUNE , .Nm zt_cmp_rune .Nd construct a claim of a relation between two characters (runes) .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_CMP_RUNE(left, rel, right) \\ zt_cmp_rune( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_rune((left), (#left)), \\ zt_pack_string((#rel), (#rel)), \\ zt_pack_rune((right), (#right))) .Ed .Ft zt_claim .Fo zt_cmp_rune .Fa "zt_location location" .Fa "zt_value left" .Fa "zt_value rel" .Fa "zt_value right" .Fc .Sh DESCRIPTION .Fn zt_cmp_rune constructs a claim of a relation between two unsigned integers. It should be used through the macro .Fn ZT_CMP_RUNE which passes source code location and packs arguments. .Pp The relation must be one of .Em == , .Em != , .Em < , .Em <= , .Em > or .Em >= . .Sh IMPLEMENTATION NOTES .Fn ZT_CMP_RUNE evaluates .Em left and .Em right exactly once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_CMP_RUNE macro and the .Fn zt_cmp_rune function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_CMP_UINT.3.in0000644000175000017500000000305413673206643014602 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CMP_UINT 3 PRM .Sh NAME .Nm ZT_CMP_UINT , .Nm zt_cmp_uint .Nd construct a claim of a relation between two unsigned integers .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_CMP_UINT(left, rel, right) \\ zt_cmp_uint( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_unsigned((left), (#left)), \\ zt_pack_string((#rel), (#rel)), \\ zt_pack_unsigned((right), (#right))) .Ed .Ft zt_claim .Fo zt_cmp_uint .Fa "zt_location location" .Fa "zt_value left" .Fa "zt_value rel" .Fa "zt_value right" .Fc .Sh DESCRIPTION .Fn zt_cmp_uint constructs a claim of a relation between two unsigned integers. It should be used through the macro .Fn ZT_CMP_UINT which passes source code location and packs arguments. .Pp The relation must be one of .Em == , .Em != , .Em < , .Em <= , .Em > or .Em >= . .Sh IMPLEMENTATION NOTES .Fn ZT_CMP_UINT evaluates .Em left and .Em right exactly once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_CMP_UINT macro and the .Fn zt_cmp_uint function first appeared in libzt 0.1 .Pp Since libzt 0.3 .Fn zt_cmp_uint internally promotes .Nm left and .Nm right arguments from .Nm ZT_UNSIGNED to .Nm ZT_UINTMAX . .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_CURRENT_LOCATION.3.in0000644000175000017500000000113213673206643015731 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CURRENT_LOCATION 3 PRM .Sh NAME .Nm ZT_CURRENT_LOCATION .Nd get the current location in the source file .Sh SYNOPSIS .In zt.h .Fd #define ZT_CURRENT_LOCATION() zt_location_at(__FILE__, __LINE__) .Sh DESCRIPTION .Nm provides .Nm zt_location describing the location of the source file invoking the macro. .Sh RETURN VALUES A .Nm zt_location containing the current values of .Nm __FILE__ and .Nm __LINE . .Sh SEE ALSO .Xr zt_location_at 3 , .Xr zt_location 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_FALSE.3.in0000644000175000017500000000251613673206643014160 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_FALSE 3 PRM .Sh NAME .Nm ZT_FALSE , .Nm zt_false .Nd construct a claim that a value is false .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_FALSE(value) \\ zt_false( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_boolean((value), #value)) \\ .Ed .Ft zt_claim .Fo zt_false .Fa "zt_location location" .Fa "zt_value value" .Fc .Sh DESCRIPTION .Fn zt_false constructs a claim that a given value is false. It should be used through the macro .Fn ZT_FALSE , which passes source code location and packs argument. .Pp .Fn zt_false can be used to check custom properties by calling arbitrary verification logic. The disadvantage of this approach is that on failure, the error message cannot precisely explain the problem. .Sh IMPLEMENTATION NOTES .Fn ZT_FALSE evaluates .Em value only once. .Sh RETURN VALUES Both the macro and the function return a claim structure with the right attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr zt_check 3 , .Sh HISTORY The .Fn ZT_FALSE macro and the .Fn zt_false function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_NOT_NULL.3.in0000644000175000017500000000271013673206643014614 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_NOT_NULL 3 PRM .Sh NAME .Nm ZT_NOT_NULL , .Nm zt_not_null .Nd construct a claim that a pointer is not NULL .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_NOT_NULL(value) \\ zt_not_null( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_pointer((value), #value)) .Ed .Ft zt_claim .Fo zt_not_null .Fa "zt_location location" .Fa "zt_value value" .Fc .Sh DESCRIPTION .Fn zt_not_null constructs a claim that a given pointer is not NULL. It should be used through the macro .Fn ZT_NOT_NULL , which passes source code location and packs argument. .Pp .Fn ZT_NOT_NULL can be useful, when coupled with .Fn zt_assert , to ensure that an object was correctly produced, allocated or returned and that the reminder of the test can inspect its properties using .Fn zt_check . .Sh IMPLEMENTATION NOTES .Fn ZT_NOT_NULL evaluates .Em value only once. .Sh RETURN VALUES Both the macro and the function return a .Nm zt_claim structure with the appropriate attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr zt_assert 3 , .Xr zt_check 3 , .Xr zt_claim 3 , .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NOT_NULL 3 .Xr zt_value 3 , .Sh HISTORY The .Fn ZT_NOT_NULL macro and the .Fn zt_not_null function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_NULL.3.in0000644000175000017500000000255413673206643014102 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_NULL 3 PRM .Sh NAME .Nm ZT_NULL , .Nm zt_null .Nd construct a claim that a pointer is NULL .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_NULL(value) \\ zt_null( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_pointer((value), #value)) .Ed .Ft zt_claim .Fo zt_null .Fa "zt_location location" .Fa "zt_value value" .Fc .Sh DESCRIPTION .Fn zt_null constructs a claim that a given pointer is NULL. It should be used through the macro .Fn ZT_NULL , which passes source code location and packs argument. .Pp .Fn ZT_NULL can be useful, when coupled with .Fn zt_assert , to ensure that something that the reminder of the test relies on did not happen, for example that no error had occurred. .Sh IMPLEMENTATION NOTES .Fn ZT_NULL evaluates .Em value only once. .Sh RETURN VALUES Both the macro and the function return a .Nm zt_claim structure with the appropriate attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr zt_assert 3 , .Xr zt_check 3 , .Xr zt_claim 3 , .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 .Xr zt_value 3 , .Sh HISTORY The .Fn ZT_NULL macro and the .Fn zt_null function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/ZT_TRUE.3.in0000664000175000017500000000257713675422322014112 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_TRUE 3 PRM .Sh NAME .Nm ZT_TRUE , .Nm zt_true .Nd construct a claim that a value is true .Sh SYNOPSIS .In zt.h .Bd -literal #define ZT_TRUE(value) \\ zt_true( \\ ZT_CURRENT_LOCATION(), \\ zt_pack_boolean((value), #value)) \\ .Ed .Ft zt_claim .Fo zt_true .Fa "zt_location location" .Fa "zt_value value" .Fc .Sh DESCRIPTION .Fn zt_true constructs a claim that a given value is true. It should be used through the macro .Fn ZT_TRUE , which passes source code location and packs argument. .Pp .Fn zt_true can be used to check custom properties by calling arbitrary verification logic. The disadvantage of this approach is that on failure, the error message cannot precisely explain the problem. .Sh IMPLEMENTATION NOTES .Fn ZT_TRUE evaluates .Em value only once. .Sh RETURN VALUES Both the macro and the function return a .Nm zt_claim structure with the appropriate attributes set. The returned claim is usually passed to .Fn zt_check or to .Fn zt_assert . .Sh SEE ALSO .Xr zt_assert 3 , .Xr zt_check 3 , .Xr zt_claim 3 , .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_RUNE 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 .Xr zt_value 3 , .Sh HISTORY The .Fn ZT_TRUE macro and the .Fn zt_true function first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/libzt-test.1.in0000644000175000017500000000076313673206643015012 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt LIBZT-TEST 1 PRM .Sh NAME .Nm libzt-test .Nd test suite for libzt .Sh SYNOPSIS .Nm libzt-test .Sh DESCRIPTION .Nm is a binary with internal test suite for libzt. .Pp The program takes no options and executes all tests sequentially. Upon success the message .Qq libzt self-test successful is printed to standard output. .Sh EXIT STATUS .Ex -std .Sh HISTORY The .Nm program first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/libzt.3.in0000644000175000017500000000312513673206643014032 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt libzt 3 PRM .Sh NAME .Nm libzt .Nd Library for unit testing C .Sh LIBRARY Library for unit testing C (-lzt) .Sh SYNOPSIS .In zt.h .Sh DESCRIPTION The .Nm library offers routines for writing C unit tests. It is focusing on simplicity, robustness and correctness, offering facilities for: .Bl -dash .It Defining test suites and test cases. .It Asserting relations between booleans, integers, strings and characters. Asserting properties of booleans and pointers. .It Creating command line interface that allows enumerating and invoking tests. The output of test programs integrates well with .Em make . .El .Pp The library code is portable between a wide range of C compilers and operating systems. All library code is covered by a self-test test suite. The library never allocates memory or uses the file system which makes it suitable for working on embedded targets. .Sh EXAMPLES The following fragment demonstrates a simple test program, comprised of a single test suite with a single test case checking the relations between two integers. .Bd -literal -offset indent #include static void test_math(zt_t t) { zt_check(t, ZT_CMP_INT(2 + 2, ==, 4)); } static void test_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, test_math); } int main(int argc, char** argv, char** envp) { return zt_main(argc, argv, envp, test_suite); } .Ed .Sh SEE ALSO .Xr zt_main 3 , .Xr ZT_VISIT_TEST_CASE 3 , .Xr ZT_VISIT_TEST_SUITE 3 , .Xr zt_check 3 , .Xr ZT_CMP_INT 3 .Sh HISTORY .Nm version 0.1 was first released in 2020 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_check.3.in0000664000175000017500000000544113675422322014501 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_CHECK 3 PRM .Sh NAME .Nm zt_check , .Nm zt_assert .Nd verify a test claim .Sh SYNOPSIS .In zt.h .Ft void .Fo zt_check .Fa "zt_t t" .Fa "zt_claim claim" .Fc .Ft void .Fo zt_assert .Fa "zt_t t" .Fa "zt_claim claim" .Fc .Sh DESCRIPTION Both .Fn zt_check and .Fn zt_assert verify a claim, encompassing a function with arguments, and is meant to be used inside test functions. .Pp The first argument is a pointer to opaque type encapsulating test outcome. The second argument is usually constructed with a helper macro, such as .Fn ZT_CMP_TRUE or .Fn ZT_CMP_FALSE . .Pp If the claim holds then happens and execution continues normally. If the claim does not hold then the test is marked as failed and a diagnostic message is printed to .Em stderr . .Pp The only difference between .Fn zt_check and .Fn zt_assert is that the former allows the test to continue executing while the latter performs a non-local exit from the test function. Note that only the currently executing test function is affected. Other tests cases and test suites will still execute normally. .Pp .Fn zt_check should be used when it is safe to execute remainder of the test even if the claim is not true. This approach allows each failure to be accompanied by as much diagnostic output as possible, without causing the test program to crash. .Pp .Fn zt_assert should be used when it is not safe or meaningless to execute remainder of the test on failure. .Sh IMPLEMENTATION NOTES Non-local exit from .Fn zt_assert is implemented using .Fn siglongjump . One should not depend on neither C++ destructors nor the GCC cleanup function extension for correct resource management. .Sh RETURN VALUES Neither function return anything. Failures are remembered inside the opaque .Nm zt_test structure passed by pointer (aka .Nm zt_t ) as the first argument. .Sh EXAMPLES A minimal test program that looks up the UNIX user .Em root and measures several properties of the returned record. .Bd -literal -offset indent #include #include #include static void test_root_user(zt_t t) { struct passwd *p = getpwnam("root"); zt_assert(t, ZT_NOT_NULL(p)); zt_check(t, ZT_CMP_CSTR(p->pw_name, ==, "root")); zt_check(t, ZT_CMP_INT(p->pw_uid, ==, 0)); zt_check(t, ZT_CMP_INT(p->pw_gid, ==, 0)); } static void test_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, test_root_user); } int main(int argc, char** argv, char** envp) { return zt_main(argc, argv, envp, test_suite); } .Ed .Sh SEE ALSO .Xr ZT_CMP_BOOL 3 , .Xr ZT_CMP_CSTR 3 , .Xr ZT_CMP_INT 3 , .Xr ZT_CMP_PTR 3 , .Xr ZT_CMP_UINT 3 , .Xr ZT_FALSE 3 , .Xr ZT_NOT_NULL 3 , .Xr ZT_NULL 3 , .Xr ZT_TRUE 3 .Sh HISTORY The .Fn zt_check and the .Fn zt_assert functions first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_claim.3.in0000644000175000017500000000500313673206643014505 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_claim 3 PRM .Sh NAME .Nm zt_claim .Nd structure capturing unevaluated assertion .Sh SYNOPSIS .In zt.h .Vt typedef struct zt_claim { ... } zt_claim; .Bl -column "struct zt_verifier *(*)(void) " "make_verifier " Description" .It Sy Type Ta Sy Member Ta Sy Description .It Vt struct zt_verifier *(*)(void) Ta make_verifier Ta Verifier factory .It Vt zt_value[3] Ta args Ta verifier arguments .It Vt zt_location Ta location Ta origin of the claim .El .Sh DESCRIPTION .Nm binds a verifier factory function with concrete arguments. This allows the entire claim to be passed around and evaluated on demand. In case of failure the location where the claim was made can be referenced for construction of error messages. .Sh IMPLEMENTATION NOTES The verification system is comprised of the following chain of cooperating elements. For example a trivial integer relationship assertion behaves as follows. .Fn ZT_CMP_INT , or another similar macro, invokes .Fn zt_cmp_int , providing source code location as .Nm zt_location , and packaging specific types into common variant type .Nm zt_value . The result is a .Nm zt_claim which is then passed to .Fn zt_assert or .Fn zt_check for evaluation. .Pp The roles of all the essential types and functions is summarized below. .Bl -bullet .It .Nm zt_value captures values expressed in a test case .It .Nm zt_claim transports up to three values and an opaque verifier .It .Fn zt_check and .Fn zt_assert validate the claim by instantiating .Nm zt_verifier. .It .Nm zt_verifier (private) wraps a verification function, including the arity and expected kind of each argument. .It .Nm zt_arg_info (private) pairs expected argument kind with a customized error message used on kind mismatch. .It .Fn zt_verify_claim (private) ensures verifier function arity and argument kind matches what is encoded in the claim and invokes the verifier function. .It The specific verifier function inspects the argument and performs the actual verification of the desired property that the test is measuring. .It .Nm zt_test (private) keeps track of test outcome, provides a stream for writing error messages and assists in performing non-local exit. .El .Sh SEE ALSO .Xr zt_assert 3 , .Xr zt_check 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh BUGS Part of the API is private which prevents third party verification functions from being written. This is done on purpose to to allow for some more experimentation before stabilizing the interface. .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_location.3.in0000644000175000017500000000155613673206643015241 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_location 3 PRM .Sh NAME .Nm zt_location .Nd description of a specific line in a source file .Sh SYNOPSIS .In zt.h .Vt typedef struct zt_location { ... } zt_location; .Sh DESCRIPTION .Nm contains a file name and a line number. .Bl -column "const char * " "fname " Description" .It Sy Type Ta Sy Entry Ta Sy Description .It Vt const char * Ta filename Ta Name of the source file, from __FILE__ .It Vt int Ta lineno Ta Number of the line in said file, from __LINE__ .El .Pp Use .Fn ZT_CURRENT_LOCATION macro to obtain a location describing the current file and line number. .Sh IMPLEMENTATION NOTES .Nm is used to report the location of failing test checks and assertions. .Sh SEE ALSO .Xr ZT_CURRENT_LOCATION 3 , .Xr zt_location_at 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_location_at.3.in0000644000175000017500000000200213673206643015710 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_location_at 3 PRM .Sh NAME .Nm zt_location_at .Nd pack file name and line number into a location value .Sh SYNOPSIS .In zt.h .Ft zt_location .Fo zt_location_at .Fa "const char* fname" .Fa "int lineno" .Fc .Sh DESCRIPTION .Nm packs both arguments into a .Nm zt_location . It exists to facilitate packing a .Nm zt_claim value without any temporary variables. It is useful for support of C compilers that do not support structure literals. .Pp For convenient definition of the current file and line number use the macro .Fn ZT_CURRENT_LOCATION .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Pp The fname argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh RETURN VALUES A .Nm zt_location containing the given file name and line number. .Sh SEE ALSO .Xr ZT_CURRENT_LOCATION 3 , .Xr zt_location 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_main.3.in0000644000175000017500000000140213673206643014343 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_main 3 PRM .Sh NAME .Nm zt_main .Nd command line interface for running tests .Sh SYNOPSIS .In zt.h .Ft int .Fo zt_main .Fa "int argc" .Fa "char **argv" .Fa "char **envp" .Fa "zt_test_suite_func tsuite" .Fc .Sh DESCRIPTION .Nm takes familiar arguments as well as a single test suite function. Depending on command line arguments some or all tests are enumerated and printed or executed. .Sh RETURN VALUES When tests are executed the return value is .Nm EXIT_SUCCESS or .Nm EXIT_FAILURE . If tests are only listed the return value is always .Nm EXIT_SUCCESS . .Sh SEE ALSO .Xr ZT_VISIT_TEST_CASE 3 , .Xr ZT_VISIT_TEST_SUITE 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_boolean.3.in0000644000175000017500000000157713673206643016051 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_boolean 3 PRM .Sh NAME .Nm zt_pack_boolean .Nd pack a boolean into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_boolean .Fa "bool value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs a boolean, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_boolean 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_integer.3.in0000644000175000017500000000233413673206643016057 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_integer 3 PRM .Sh NAME .Nm zt_pack_integer .Nd pack an integer into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_integer .Fa "intmax_t value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs an integer, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Pp In libzt 0.3 the type of the first argument changed to .Nm intmax_t , to accommodate for wider values. The resulting value structure encodes the new corresponding kind, .Nm ZT_INTMAX . Note that .Nm zt_value objects created by programs compiled with earlier versions of libzt are still valid and are internally promoted to the wider type. .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_nothing.3.in0000644000175000017500000000122013673206643016061 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_nothing 3 PRM .Sh NAME .Nm zt_pack_nothing .Nd pack nothing into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_nothing .Fa "void" .Fc .Sh DESCRIPTION .Nm returns an initialized, empty value. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Sh RETURN VALUES The empty value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_nothing 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_pointer.3.in0000644000175000017500000000162613673206643016105 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_pointer 3 PRM .Sh NAME .Nm zt_pack_pointer .Nd pack an opaque pointer into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_pointer .Fa "const void *value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs an opaque pointer, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_pointer 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_pointer 3 , .Xr zt_pack_pointer 3 , .Xr zt_pack_pointer 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_rune.3.in0000644000175000017500000000202113673206643015364 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_rune 3 PRM .Sh NAME .Nm zt_pack_rune .Nd pack a character into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_rune .Fa "int value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs a rune, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Pp Runes are generalized characters. Unlike char, they are never negative and can be though of as Unicode code points. .Sh IMPLEMENTATION NOTES .Fn zt_pack_rune compensates for signed negative characters by masking them with 0xFF. .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_integer 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_string.3.in0000644000175000017500000000210613673206643015725 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_string 3 PRM .Sh NAME .Nm zt_pack_string .Nd pack an C string into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_string .Fa "const char *value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs an C string, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Pp Memory referenced by the string is not copied. It is assumed that the memory reference stays valid during the execution of the verification of an assertion that relies on the .Nm zt_value . .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_string 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_string 3 , .Xr zt_pack_string 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_pack_unsigned.3.in0000644000175000017500000000236613673206643016243 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_pack_unsigned 3 PRM .Sh NAME .Nm zt_pack_unsigned .Nd pack an unsigned integer into a variant .Sh SYNOPSIS .In zt.h .Ft zt_value .Fo zt_pack_unsigned .Fa "uintmax_t value" .Fa "const char *source" .Fc .Sh DESCRIPTION .Nm packs an unsigned integer, as well as the string describing the expression evaluated to obtain it, into a variant-like .Ft zt_value . The source argument is retained by the value and is typically a constant string literal produced by the preprocessor. .Sh IMPLEMENTATION NOTES .Nm is only provided as a static inline function. .Sh RETURN VALUES The packed value. .Sh SEE ALSO .Xr zt_pack_nothing 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_rune 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_unsigned 3 , .Xr zt_pack_string 3 , .Xr zt_pack_pointer 3 .Xr zt_value 3 , .Sh HISTORY .Nm first appeared in libzt 0.1 .Pp In libzt 0.3 the type of the first argument changed to .Nm uintmax_t , to accommodate for wider values. The resulting value structure encodes the new corresponding kind, .Nm ZT_UINTMAX . Note that .Nm zt_value objects created by programs compiled with earlier versions of libzt are still valid and are internally promoted to the wider type. .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_test.3.in0000644000175000017500000000140513673206643014401 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_test 3 PRM .Sh NAME .Nm zt_test , zt_t .Nd private representation of test state .Sh SYNOPSIS .Vt struct zt_test .Vt typedef struct zt_test *zt_t .Sh DESCRIPTION .Nm is an opaque type that holds test state during execution. The test type is passed as an argument to each test function. It is further passed to both .Fn zt_check and .Fn zt_assert functions, to alter test state. .Pp .Nm zt_t is is a typedef that cuts the test case boilerplate size. .Pp Internally .Nm stores the outcome of the test as well as data required for non-local exit, necessary when .Fn zt_assert fails. .Sh HISTORY .Nm zt_test first appeared in libzt 0.1, .Nm zt_t first appeared in libzt 0.2. .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_test_case_func.3.in0000644000175000017500000000117613673206643016414 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_test_case_func 3 PRM .Sh NAME .Nm zt_test_case_func .Nd type of pointer to a test case function .Sh SYNOPSIS .Ft typedef void .Fo (*zt_test_case_func) .Fa "zt_t" .Fc .Sh DESCRIPTION .Nm is a pointer to a function implementing a single test case. .Sh IMPLEMENTATION NOTES The .Nm zt_test pointer (aka .Nm zt_t ) argument is meant to be passed to .Fn zt_check and .Fn zt_assert to alter the outcome of the test. .Sh SEE ALSO .Xr zt_test 3 , .Xr zt_visit_test_case 3 , .Xr zt_visit_test_suite 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_test_suite_func.3.in0000644000175000017500000000137313673206643016631 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_test_suite_func 3 PRM .Sh NAME .Nm zt_test_suite_func .Nd type of pointer to a test suite function .Sh SYNOPSIS .Ft typedef void .Fo (*zt_test_suite_func) .Fa "zt_visitor" .Fc .Sh DESCRIPTION .Nm is a pointer to a function implementing a test suite, which groups any number of test cases and other test suites. .Pp A single test suite, passed as an argument to .Fn zt_main , is used to enumerate and discover all the tests in a given test program. .Sh IMPLEMENTATION NOTES The .Nm zt_visitor argument is used to implement the test case and test suite enumeration system. .Sh SEE ALSO .Xr zt_main 3 , .Xr zt_visitor 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_value.3.in0000644000175000017500000000526513673206643014546 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_value 3 PRM .Sh NAME .Nm zt_value , zt_value_kind , .Nd variant type for passing data into claim verifiers .Sh SYNOPSIS .In zt.h .Vt typedef struct zt_value { ... } zt_value; .Bl -column "zt_value_kind " "unsigned_integer " Description" .It Sy Type Ta Sy Entry Ta Sy Description .It Vt zt_value_kind Ta kind Ta Discriminator for the union .It Vt const char * Ta source Ta Source code used to compute the value .It Vt union { ... } Ta as Ta Union containing the actual value .It Vt bool Ta as.boolean Ta Value when used as ZT_BOOLEAN .It Vt int Ta as.integer Ta Value when used as ZT_INTEGER .It Vt unsigned Ta as.unsigned_integer Ta Value when used as ZT_UNSIGNED .It Vt int Ta as.rune Ta Value when used as ZT_RUNE .It Vt const char * Ta as.string Ta Value when used as ZT_STRING .It Vt const void * Ta as.pointer Ta Value when used as ZT_POINTER .It Vt intmax_t Ta as.intmax Ta Value when used as ZT_INTMAX .It Vt uintmax_t Ta as.uintmax Ta Value when used as ZT_UINTMAX .El .Pp .Vt typedef enum zt_value_kind { ... } zt_value_kind; .Bl -column "ZT_NOTHING " " Description" .It Sy Kind Ta Sy Description .It Vt ZT_NOTHING Ta Placeholder for unused values .It Vt ZT_BOOLEAN Ta zt_value.as.boolean is valid .It Vt ZT_INTEGER Ta zt_value.as.integer is valid (deprecated) .It Vt ZT_UNSIGNED Ta zt_value.as.unsigned_integer is valid (deprecated) .It Vt ZT_RUNE Ta zt_value.as.rune is valid .It Vt ZT_STRING Ta zt_value.as.string is valid .It Vt ZT_POINTER Ta zt_value.as.pointer is valid .It Vt ZT_INTMAX Ta zt_value.as.intmax is valid .It Vt ZT_UINTMAX Ta zt_value.as.uintmax is valid .El .Sh DESCRIPTION .Nm zt_value is a variant-like type that is used to pass values around libzt internals. It is comprised of the .Em kind enumeration, the .Em as union as well as the .Em source string. .Pp .Nm zt_value_kind describes type of verification function arguments. .Sh IMPLEMENTATION NOTES .Nm zt_value exists to pass packed values of several types from the test source code, through the .Nm zt_claim type and into private verification functions that determine test outcome. .Pp Tests using binary relations encode the operator as an argument of kind .Em ZT_STRING . .Sh BUGS On some architectures .Nm ZT_INTEGER and .Nm ZT_UNSIGNED are too short to handle .Nm size_t and .Nm ssize_t values correctly. They are now deprecated and automatically promoted to .Nm ZT_INTMAX and .Nm ZT_UINTMAX respectively. .Sh SEE ALSO .Xr zt_visit_test_case 3 , .Xr zt_visit_test_suite 3 .Sh HISTORY .Nm zt_value and .Nm zt_value_kind first appeared in libzt 0.1 .Pp .Nm ZT_INTMAX , .Nm ZT_UINTMAX and the corresponding union members first appeared in libzt 0.3. .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_visit_test_case.3.in0000644000175000017500000000422513673206643016615 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt ZT_VISIT_TEST_CASE 3 PRM .Sh NAME .Nm zt_visit_test_case , .Nm ZT_VISIT_TEST_CASE , .Nm zt_visit_test_suite , .Nm ZT_VISIT_TEST_SUITE .Nd discover test cases and their structure .Sh SYNOPSIS .In zt.h .Ft void .Fo zt_visit_test_case .Fa "zt_visitor v" .Fa "zt_test_case_func func" .Fa "const char *name" .Fc .Fd #define ZT_VISIT_TEST_CASE(v, tcase) zt_visit_test_case(v, tcase, #tcase) .Ft void .Fo zt_visit_test_case .Fa "zt_visitor v" .Fa "zt_test_suite_func func" .Fa "const char *name" .Fc .Fd #define ZT_VISIT_TEST_SUITE(v, tsuite) zt_visit_test_suite(v, tsuite, #tsuite) .Sh DESCRIPTION .Fn zt_visit_test_case and .Fn zt_visit_test_suite , or more usually - under their macro from .Fn ZT_VISIT_TEST_CASE and .Fn ZT_VISIT_TEST_SUITE , are used to implement discovery for test suites and test cases. Test suites are represented as functions that visit other test suites and test cases. Test cases are represented as functions that execute actual test code. .Pp The macros are provided as convenience to avoid having to invent names. .Pp Typically the main test suite is passed as an argument to .Fn zt_main which handles the rest of the discovery, and if necessary, execution. .Sh RETURN VALUES Visit functions do not return any value. .Sh EXAMPLES The following example shows how to create a test suite with two test cases. A suite can contain any number of nested suites and test cases. .Bd -literal -offset indent #include static void test_foo(zt_t t) { printf("foo invoked\\n"); } static void suite_inner(zt_visitor v) { ZT_VISIT_TEST_CASE(v, test_foo); } static void test_bar(zt_t t) { printf("bar invoked\\n"); } static void main_suite(zt_visitor v) { ZT_VISIT_TEST_SUITE(v, suite_inner); ZT_VISIT_TEST_CASE(v, test_bar); } int main(int argc, char** argv, char** envp) { return zt_main(argc, argv, envp, main_suite); } .Ed .Sh SEE ALSO .Xr zt_main 3 , .Xr zt_test_suite_func 3 , .Xr zt_test_case_func 3 , .Sh HISTORY The .Fn zt_visit_test_case and the .Fn zt_visit_test_suite functions, as well as the corresponding macros, first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/man/zt_visitor.3.in0000644000175000017500000000263313673206643015125 0ustar zygazyga.Dd January 12, 2020 .Os libzt @VERSION@ .Dt zt_visitor 3 PRM .Sh NAME .Nm zt_visitor , zt_visitor_vtab .Nd interface for discovering test suites and test cases .Sh SYNOPSIS .In zt.h .Vt typedef struct zt_visitor { ... } zt_visitor; .Bl -column "struct zt_visitor_vtab * " "vtab " Description" .It Sy Type Ta Sy Entry Ta Sy Description .It Vt void * Ta id Ta Object implementing the interface .It Vt struct zt_visitor_vtab * Ta vtab Ta Table of interface functions .El .Sh DESCRIPTION .Nm is an interface for exploring test suites and test cases. The visitor type is used as an argument to all test suites. Test suites can enumerate test cases and other test suites. It is a part of the implementation and is not expected to be implemented by library users. .Pp .Nm zt_visitor_vtab is an opaque type comprised of functions that define the interface. The interface is only used internally so the implementation is private. .Sh IMPLEMENTATION NOTES Interface values combine an object pointer with a function table pointer and are passed by value. .Pp An interface can use the NULL pointer as an object pointer if there is no need to refer to any data specific to an instance. The function table pointer cannot be null as it defines the unique aspect of the implementation. .Sh SEE ALSO .Xr zt_visit_test_case 3 , .Xr zt_visit_test_suite 3 .Sh HISTORY .Nm first appeared in libzt 0.1 .Sh AUTHORS .An "Zygmunt Krynicki" Aq Mt me@zygoon.pl libzt_0.3.1/z.mk0000644000175000017500000001037613675422347012255 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . NAME ?= $(error define NAME - the name of the project) VERSION ?= $(error define VERSION - the static version of the project) # Speed up make by removing suffix rules. .SUFFIXES: # The location of the source code. srcdir ?= . # Version of the zmk library. ZMK.Version = 0.3.6 # Location of include files used by the makefile system. Normally this is the # zmk subdirectory of /usr/include, as this is where make is importing things # from. ZMK.z.mk := $(lastword $(MAKEFILE_LIST)) ZMK.Path ?= $(or $(patsubst %/,%,$(dir $(ZMK.z.mk))),.) # Modules and templates present in the package ZMK.modules = \ AllClean \ Configure \ Coverity \ Directories \ Directory \ GitVersion \ Header \ InstallUninstall \ Library.A \ Library.DyLib \ Library.So \ ManPage \ OS \ ObjectGroup \ PVS \ Program \ Program.Test \ Script \ Symlink \ Tarball \ Tarball.Src \ Toolchain \ toolchain.Clang \ toolchain.GCC \ toolchain.Tcc \ toolchain.Watcom \ internalTest # Manual pages present in the package. ZMK.manPages = \ zmk.AllClean.5 \ zmk.Configure.5 \ zmk.Directories.5 \ zmk.OS.5 \ zmk.Program.5 \ zmk.Script.5 \ zmk.Toolchain.5 # Files belonging to ZMK that need to be distributed in third-party release tarballs. ZMK.DistFiles = z.mk $(addprefix zmk/,$(foreach m,$(ZMK.modules),$m.mk) pvs-filter.awk) # If zmk is provided externally add rules to copy it to the source tree and # make the distclean target remove it from the tree. ifneq ($(ZMK.Path),$(srcdir)) $(srcdir)/zmk: install -d $@ $(srcdir)/zmk/%: $(ZMK.Path)/zmk/% | $(srcdir)/zmk install -m 644 $< $@ $(srcdir)/z.mk: $(ZMK.Path)/z.mk install -m 644 $< $@ distclean:: rm -rf $(srcdir)/zmk rm -f $(srcdir)/z.mk rm -f configure endif # ZMK Copyright Banner. Do not remove. # You are not allowed to remove or alter this while staying compliant with the LGPL license. MAKECMDGOALS ?= ifeq ($(MAKECMDGOALS),) $(info z.mk v$(ZMK.Version), Copyright (c) 2019-2020 Zygmunt Krynicki) endif # Meta-targets that don't have specific specific commands .PHONY: $(sort all clean coverage fmt static-check check install uninstall dist distclean) # Run static checks when checking check:: static-check # Default goal is to build everything, regardless of declaration order .DEFAULT_GOAL = all # Display diagnostic messages when DEBUG has specific items. ZMK.comma=, DEBUG ?= DEBUG := $(subst $(ZMK.comma), ,$(DEBUG)) # Define the module and template system. ZMK.ImportedModules ?= ZMK.expandStack = 0 ZMK.nesting.0 = > # ZMK.nesting.1 = ... > # ZMK.nesting.2 = ... ... > # ZMK.nesting.3 = ... ... ... > # ZMK.nesting.4 = ... ... ... ... > # define ZMK.Import ifeq (,$1) $$(error incorrect call to ZMK.Import, expected module name) endif ifeq (,$$(filter $1,$$(ZMK.ImportedModules))) $$(if $$(findstring import,$$(DEBUG)),$$(info DEBUG: importing »$1«)) ZMK.ImportedModules += $1 include $$(ZMK.Path)/zmk/$1.mk endif endef ZMK.variablesShown = define ZMK.showVariable ifeq (,$$(findstring $1,$$(ZMK.variablesShown))) $$(info DEBUG: $$(ZMK.nesting.$$(ZMK.expandStack))$1=$$($1)) ZMK.variablesShown += $1 endif endef define ZMK.Expand ifeq (,$1) $$(error incorrect call to ZMK.Expand, expected module name) endif ifeq (,$2) $$(error incorrect call to ZMK.Expand, expected variable name) endif $$(eval $$(call ZMK.Import,$1)) $$(if $$(findstring expand,$$(DEBUG)),$$(info DEBUG: $$(ZMK.nesting.$$(ZMK.expandStack))expanding template $1("$2"))) ZMK.expandStack := $$(shell expr $$(ZMK.expandStack) + 1) $$(eval $$(call $1.Template,$2)) ZMK.expandStack := $$(shell expr $$(ZMK.expandStack) - 1) $$(if $$(findstring expand,$$(DEBUG)),$$(foreach n,$$($1.Variables),$$(eval $$(call ZMK.showVariable,$2.$$n)))) endef libzt_0.3.1/zmk/AllClean.mk0000644000175000017500000000134313675422347014252 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . AllClean.Variables= define AllClean.Template all:: $1 clean:: rm -f $1 endef libzt_0.3.1/zmk/Configure.mk0000644000175000017500000003512313675422347014523 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Is zmk debugging enabled for this module? Configure.debug ?= $(findstring configure,$(DEBUG)) # Configuration system defaults, also changed by GNUMakefile.configure.mk Configure.HostArchTriplet ?= Configure.BuildArchTriplet ?= Configure.DependencyTracking ?= yes Configure.MaintainerMode ?= yes Configure.SilentRules ?= Configure.ProgramPrefix ?= Configure.ProgramSuffix ?= Configure.ProgramTransformName ?= Configure.Configured ?= Configure.Options ?= # Include optional generated makefile from the configuration system. # This makefile can only set one of the variables listed above. -include GNUmakefile.configure.mk $(if $(Configure.debug),$(foreach v,$(filter Configure.%,$(.VARIABLES)),$(info DEBUG: $v=$($v)))) # ZMK provides a custom configuration script, this is is the full text define Configure.script #!/bin/sh # Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # This script was automatically generated by zmk version $(ZMK.Version). while [ "$$#" -ge 1 ]; do case "$$1" in -h|--help) echo "Usage: ./configure [OPTIONS]" echo echo "Compilation options:" echo " --build=GNU_TRIPLET Describe the build machine with the given GNU_TRIPLET" echo " --host=GNU_TRIPLET Describe the host machine with the given GNU_TRIPLET" echo " --enable-dependency-tracking" echo " Track dependencies between files (implicit)" echo " --disable-dependency-tracking" echo " Do not generate or use dependency data during builds" echo " --enable-maintainer-mode Enable maintainer mode (implicit)" echo " --disable-maintainer-mode Disable maintainer mode" echo echo "Build-time directory selection:" echo " --prefix=PREFIX Set prefix for all directories to PREFIX" echo " --exec-prefix=PREFIX Set prefix for libraries and programs to PREFIX" echo echo " --bindir=DIR Install user programs to DIR" echo " --sbindir=DIR Install super-user programs to DIR" echo " --libdir=DIR Install runtime and development libraries to DIR" echo " --libexecdir=DIR Install library-internal programs to DIR" echo " --includedir=DIR Install development header files to DIR" echo " --mandir=DIR Install manual pages to DIR" echo " --infodir=DIR Install GNU info pages to DIR" echo " --sysconfdir=DIR Install system configuration files to DIR" echo " --datadir=DIR Install read-only data files to DIR" echo echo " --localstatedir=DIR Store persistent state specific to a machine in DIR" echo " --runstatedir=DIR Store ephemeral state specific to a machine in DIR" echo " --sharedstatedir=DIR Store state shared across machines in DIR" echo echo "Options for altering program names:" echo " --program-prefix=PREFIX Put PREFIX before installed program names" echo " --program-suffix=SUFFIX Put SUFFIX after installed program names" echo " --program-transform-name=PROGRAM" echo " Use sed PROGRAM to transform installed program names" echo echo "Miscellaneous options:" echo " --enable-option-checking Report unrecognized configuration options (implicit)" echo " --disable-option-checking Ignore unrecognized configuration options" echo " --enable-silent-rules Do not display commands while building" echo " --disable-silent-rules Display commands while building (implicit)" echo echo "Memorized environment variables:" echo " CC Name of the C compiler" echo " CXX Name of the C++ compiler" echo " CFLAGS Options for the C compiler" echo " CXXFLAGS Options for the C++ compiler" echo " CPPFLAGS Options for the preprocessor" echo " LDFLAGS Options for the linker" exit 0 ;; --version) echo "z.mk configure script version $(ZMK.Version)" exit 0 ;; *) break ;; esac done { # Given key=value or key="value value", print the value rhs() { echo "$$*" | cut -d '=' -f 2- | sed -e 's/^"//' -e 's/"$$//' } echo "# Generated by zmk configuration script version $(ZMK.Version)" echo "# ./configure $$*" configureOptions="$$*" echo echo "# Location of the source code." if [ -n "$${srcdir:-}" ]; then echo "srcdir=$$srcdir" else echo "srcdir=$$(dirname "$$0")" fi echo echo "# Set VPATH for make (for out-of-tree builds)." echo "VPATH=\$$(srcdir)" while [ "$$#" -ge 1 ]; do case "$$1" in --build=*) buildArchTriplet="$$(rhs "$$1")" && shift ;; --host=*) hostArchTriplet="$$(rhs "$$1")" && shift ;; --enable-dependency-tracking) dependencyTracking=yes && shift ;; --disable-dependency-tracking) dependencyTracking=no && shift ;; --enable-maintainer-mode) maintainerMode=yes && shift ;; --disable-maintainer-mode) maintainerMode=no && shift ;; --enable-silent-rules) silentRules=yes && shift ;; --disable-silent-rules) silentRules=no && shift ;; --enable-option-checking) disableOptionChecking=no && shift ;; --disable-option-checking) disableOptionChecking=yes && shift ;; --program-prefix=*) programPrefix="$$(rhs "$$1")" && shift ;; --program-suffix=*) programSuffix="$$(rhs "$$1")" && shift ;; --program-transform-name=*) programTransformName="$$(rhs "$$1")" && shift ;; --exec-prefix=*) exec_prefix="$$(rhs "$$1")" && shift ;; --prefix=*) prefix="$$(rhs "$$1")" && shift ;; --bindir=*) bindir="$$(rhs "$$1")" && shift ;; --sbindir=*) sbindir="$$(rhs "$$1")" && shift ;; --libdir=*) libdir="$$(rhs "$$1")" && shift ;; --libexecdir=*) libexecdir="$$(rhs "$$1")" && shift ;; --datadir=*) datadir="$$(rhs "$$1")" && shift ;; --includedir=*) includedir="$$(rhs "$$1")" && shift ;; --infodir=*) infodir="$$(rhs "$$1")" && shift ;; --mandir=*) mandir="$$(rhs "$$1")" && shift ;; --sysconfdir=*) sysconfdir="$$(rhs "$$1")" && shift ;; --localstatedir=*) localstatedir="$$(rhs "$$1")" && shift ;; --runstatedir=*) runstatedir="$$(rhs "$$1")" && shift ;; --sharedstatedir=*) sharedstatedir="$$(rhs "$$1")" && shift ;; CC=*) CC="$$(rhs "$$1")" && shift ;; CXX=*) CXX="$$(rhs "$$1")" && shift ;; CFLAGS=*) CFLAGS="$$(rhs "$$1")" && shift ;; OBJCFLAGS=*) OBJCFLAGS="$$(rhs "$$1")" && shift ;; CXXFLAGS=*) CXXFLAGS="$$(rhs "$$1")" && shift ;; CPPFLAGS=*) CPPFLAGS="$$(rhs "$$1")" && shift ;; LDFLAGS=*) LDFLAGS="$$(rhs "$$1")" && shift ;; *) if [ "$${disableOptionChecking:-}" != yes ]; then echo "configure: unknown option $$1" >&2 configureFailed=1 fi shift ;; esac done echo echo "# Build and host architecture triplets." echo "# Note that those impact compiler selection unless overridden." test -n "$${buildArchTriplet:-}" && echo "Configure.BuildArchTriplet=$$buildArchTriplet" || echo "# Configure.BuildArchTriplet was not specified." test -n "$${hostArchTriplet:-}" && echo "Configure.HostArchTriplet=$$hostArchTriplet" || echo "# Configure.HostArchTriplet was not specified." echo echo "# Build-time configuration of application directories." test -n "$${prefix:-}" && echo "prefix=$$prefix" || echo "# prefix was not specified." test -n "$${exec_prefix:-}" && echo "exec_prefix=$$exec_prefix" || echo "# exec_prefix was not specified." test -n "$${bindir:-}" && echo "bindir=$$bindir" || echo "# bindir was not specified." test -n "$${sbindir:-}" && echo "sbindir=$$sbindir" || echo "# sbindir was not specified." test -n "$${datadir:-}" && echo "datadir=$$datadir" || echo "# datadir was not specified." test -n "$${includedir:-}" && echo "includedir=$$includedir" || echo "# includedir was not specified." test -n "$${infodir:-}" && echo "infodir=$$infodir" || echo "# infodir was not specified." test -n "$${libdir:-}" && echo "libdir=$$libdir" || echo "# libdir was not specified." test -n "$${libexecdir:-}" && echo "libexecdir=$$libexecdir" || echo "# libexecdir was not specified." test -n "$${localstatedir:-}" && echo "localstatedir=$$localstatedir" || echo "# localstatedir was not specified." test -n "$${mandir:-}" && echo "mandir=$$mandir" || echo "# mandir was not specified." test -n "$${runstatedir:-}" && echo "runstatedir=$$runstatedir" || echo "# runstatedir was not specified." test -n "$${sharedstatedir:-}" && echo "sharedstatedir=$$sharedstatedir" || echo "# sharedstatedir was not specified." test -n "$${sysconfdir:-}" && echo "sysconfdir=$$sysconfdir" || echo "# sysconfdir was not specified." echo echo "# Inherited environment variables and overrides." test -n "$$CC" && echo "CC=$$CC" || echo "# CC was not specified." test -n "$$CXX" && echo "CXX=$$CXX" || echo "# CXX was not specified." test -n "$$CFLAGS" && echo "CFLAGS=$$CFLAGS" || echo "# CFLAGS was not specified." test -n "$$CXXFLAGS" && echo "CXXFLAGS=$$CXXFLAGS" || echo "# CXXFLAGS was not specified." test -n "$$OBJCFLAGS" && echo "OBJCFLAGS=$$OBJCFLAGS" || echo "# OBJCFLAGS was not specified." test -n "$$CPPFLAGS" && echo "CPPFLAGS=$$CPPFLAGS" || echo "# CPPFLAGS was not specified." test -n "$$LDFLAGS" && echo "LDFLAGS=$$LDFLAGS" || echo "# LDFLAGS was not specified." echo echo "# Track dependencies between objects and source and header files." case "$${dependencyTracking:-implicit}" in yes) echo "Configure.DependencyTracking=yes" ;; no) echo "Configure.DependencyTracking=" ;; implicit) echo "# Configure.DependencyTracking was not specified." ;; esac echo echo "# Additional options for package maintainers." case "$${maintainerMode:-implicit}" in yes) echo "Configure.MaintainerMode=yes" ;; no) echo "Configure.MaintainerMode=" ;; implicit) echo "# Configure.MaintainerMode was not specified." ;; esac echo echo "# Silence shell commands used by make." case "$${silentRules:-implicit}" in yes) echo "Configure.SilentRules=yes" ;; no) echo "Configure.SilentRules=" ;; implicit) echo "# Configure.SilentRules was not specified." ;; esac echo echo "# Program name customization options." test -n "$${programPrefix:-}" && echo "Configure.ProgramPrefix=$$programPrefix" || echo "# Configure.ProgramPrefix was not specified." test -n "$${programSuffix:-}" && echo "Configure.ProgramSuffix=$$programSuffix" || echo "# Configure.ProgramSuffix was not specified." test -n "$${programTransformName:-}" && echo "Configure.ProgramTransformName=$$programTransformName" || echo "# Configure.ProgramTransformName was not specified." echo echo "# Remember that the configuration script was executed." echo "Configure.Configured=yes" echo "Configure.Options=$$configureOptions" } > "$${ZMK_CONFIGURE_MAKEFILE:=GNUmakefile.configure.mk}" if [ "$${configureFailed:-0}" -eq 1 ]; then rm -f "$${ZMK_CONFIGURE_MAKEFILE}" exit 1 fi if [ ! -e Makefile ] && [ ! -e GNUmakefile ]; then ln -s "$$(dirname "$$0")"/GNUmakefile GNUmakefile fi endef # In maintainer mode the configure script is automatically updated. ifeq ($(Configure.MaintainerMode),yes) configure: export ZMK_CONFIGURE_SCRIPT = $(Configure.script) configure: $(ZMK.Path)/z.mk $(wildcard $(ZMK.Path)/zmk/*.mk) @echo "$${ZMK_CONFIGURE_SCRIPT}" >$@ chmod +x $@ # In maintainer mode, re-configure in response to updates to the configuration script. ifeq ($(Configure.Configured),yes) GNUmakefile.configure.mk: configure @echo "re-configuring, $< script is newer than $@" ./$< $(Configure.Options) endif # !configured endif # !maintainer mode distclean:: rm -f GNUmakefile.configure.mk libzt_0.3.1/zmk/Coverity.mk0000644000175000017500000000171013675422347014401 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . Coverity.Sources ?= $(error define Coverity.Sources - the list of source files to analyze with Coverity) clean:: rm -rf cov-int rm -f $(NAME)-$(VERSION)-coverity.tar.gz cov-int: $(Coverity.Sources) $(MAKEFILE_LIST) cov-build --dir $@ $(MAKE) $(NAME)-$(VERSION)-coverity.tar.gz: cov-int tar zcf $@ $< libzt_0.3.1/zmk/Directories.mk0000644000175000017500000000464713675422347015065 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Is zmk debugging enabled for this module? Directories.debug ?= $(findstring directories,$(DEBUG)) # Installation prefix. prefix ?= /usr/local $(if $(Directories.debug),$(info DEBUG: prefix=$(prefix))) exec_prefix ?= $(prefix) # Relevant UNIX-y directories. bindir ?= $(exec_prefix)/bin sbindir ?= $(exec_prefix)/sbin libexecdir ?= $(exec_prefix)/libexec datarootdir ?= $(prefix)/share datadir ?= $(datarootdir) sysconfdir ?= $(prefix)/etc sharedstatedir ?= $(prefix)/com localstatedir ?= $(prefix)/var runstatedir ?= $(localstatedir)/run includedir ?= $(prefix)/include infodir ?= $(datarootdir)info libdir ?= $(exec_prefix)/lib localedir ?= $(datarootdir)/locale mandir ?= $(datarootdir)/man man1dir ?= $(mandir)/man1 man2dir ?= $(mandir)/man2 man3dir ?= $(mandir)/man3 man4dir ?= $(mandir)/man4 man5dir ?= $(mandir)/man5 man6dir ?= $(mandir)/man6 man7dir ?= $(mandir)/man7 man8dir ?= $(mandir)/man8 man9dir ?= $(mandir)/man9 # List of standard directories. Those are created with a single rule below, and # can be safely used as a order-only dependency. Directories.POSIX = \ $(prefix) $(exec_prefix) $(bindir) $(sbindir) $(libexecdir) \ $(datarootdir) $(datadir) $(sysconfdir) $(sharedstatedir) \ $(localstatedir) $(runstatedir) $(includedir) \ $(infodir) $(libdir) $(localedir) $(mandir) $(man1dir) \ $(man2dir) $(man3dir) $(man4dir) $(man5dir) $(man6dir) $(man7dir) \ $(man8dir) $(man9dir) # If NAME is defined, also define docdir. ifneq ($(value NAME),$$(error define NAME - the name of the project)) docdir ?= $(datarootdir)/doc/$(NAME) Directories.POSIX += $(docdir) endif $(if $(Directories.debug),$(info DEBUG: Directories.POSIX=$(Directories.POSIX))) # Provide implicit rules for all the well-known directories. $(foreach d,$(Directories.POSIX),$(eval $(call ZMK.Expand,Directory,$d)))libzt_0.3.1/zmk/Directory.mk0000644000175000017500000000451513675422347014547 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # List of directories that need to be created and have corresponding rules. # Those are automatically handled, on demand, by expanding the Directory # template. That template handles order-only dependencies on the parent # directory, so, for example, creating /usr/share/man/man5 automatically # depends on /usr/share/man, and so on. Directory.known = Directory.debug ?= $(findstring directory,$(DEBUG)) # Define DESTDIR to an empty value so that make --warn-undefined-variables # does not complain about it. ifeq ($(origin DESTDIR),undefined) DESTDIR ?= else $(DESTDIR): mkdir -p $@ # Warn if DESTDIR is defined in a makefile. This is probably a mistake. ifeq ($(origin DESTDIR),file) $(warning DESTDIR should be set only through environment variable, not in a makefile) endif endif $(if $(Directory.debug),$(info DEBUG: DESTDIR=$(DESTDIR))) # Plain directory. This template is used by other parts of ZMK. Directory.Variables= define Directory.Template ifneq ($1,/) $1.cleaned=$$(patsubst %/,%,$1) else $1.cleaned=$1 endif ifneq ($$($1.cleaned),.) ifneq ($$($1.cleaned),/) ifeq (,$$(filter $$($1.cleaned),$$(Directory.known))) $1.parentDir = $$(patsubst %/,%,$$(dir $$($1.cleaned))) ifneq (,$$($1.parentDir)) ifeq (,$$(filter $$($1.parentDir),$$(Directory.known))) $$(eval $$(call ZMK.Expand,Directory,$$($1.parentDir))) endif # !parent known endif # !parent empty Directory.known += $$($1.cleaned) ifeq (/,$$(patsubst /%,/,$$($1.cleaned))) # Absolute directories respect DESTDIR $$(DESTDIR)$$($1.cleaned): | $$(DESTDIR)$$($1.parentDir) install -d $$@ else # Relative directories do not observe DESTDIR $$($1.cleaned): | $$($1.parentDir) install -d $$@ endif # !absolute endif # !known endif # !. endif # !/ endef libzt_0.3.1/zmk/GitVersion.mk0000644000175000017500000000574713675422347014704 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Craft a better version if we have Git. GitVersion.debug ?= $(findstring version,$(DEBUG)) GitVersion.versionFilePresent = $(if $(wildcard $(srcdir)/.version),yes) GitVersion.gitAvailable ?= $(if $(shell command -v git 2>/dev/null),yes) GitVersion.gitMetaDataPresent ?= $(if $(wildcard $(srcdir)/.git),yes) GitVersion.versionFromMakefile := $(strip $(VERSION)) GitVersion.versionFromFile = GitVersion.versionFromGit = GitVersion.Active = ifeq (yes,$(GitVersion.versionFilePresent)) # Note that we never generate this file from any rule in zmk! # If the source tree contains the .version file then it is authoritative. GitVersion.versionFromFile:=$(shell cat $(srcdir)/.version 2>/dev/null) else ifeq (yes,$(and $(GitVersion.gitAvailable),$(GitVersion.gitMetaDataPresent))) # If we have the git program and the .git directory then we can also ask git. GitVersion.versionFromGit=$(shell GIT_DIR=$(srcdir)/.git git describe --abbrev=10 --tags 2>/dev/null | sed -e 's/^v//') ifneq (,$(value CI)) # If we are in CI and git version was empty then perhaps this is a shallow clone? ifeq (,$(GitVersion.versionFromGit)) $(error zmk cannot compute project version from git, did the CI system use a shallow clone?)) endif # ! git version endif # ! CI endif # version from git endif # !version from version file # If we have a version from git, offer a rule that writes it to the source # tree. This file is picked up by the Tarball.Src module and internally renamed # to .version inside the archive. When we see the .version file we do not look # for git information anymore, as it may no longer be the "same" git history. ifneq (,$(GitVersion.versionFromGit)) $(srcdir)/.version-from-git: $(srcdir)/.git echo $(GitVersion.versionFromGit) >$@ endif # Set the new effective VERSION. VERSION=$(or $(GitVersion.versionFromFile),$(GitVersion.versionFromGit),$(GitVersion.versionFromMakefile)) # If the effective version is different from the version in the makefile then # set the active flag. This information is used by the Tarball.Src module. ifneq ($(VERSION),$(GitVersion.versionFromMakefile)) GitVersion.Active = yes endif $(if $(GitVersion.debug),$(foreach v,versionFilePresent gitAvailable gitMetaDataPresent versionFromMakefile versionFromFile versionFromGit Active,$(info DEBUG: GitVersion.$v=$(GitVersion.$v)))) $(if $(GitVersion.debug),$(info DEBUG: effective VERSION=$(VERSION))) libzt_0.3.1/zmk/Header.mk0000644000175000017500000000152113675422347013765 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) Header.Variables= define Header.Template $1.InstallDir = $(includedir) $1.InstallMode = 0644 $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) endef libzt_0.3.1/zmk/InstallUninstall.mk0000644000175000017500000000315113675422347016076 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) # A file that gets installed to a desired location. The location can be set # using the .InstallDir instance variable. The special value of noinst prevents # installation. This template is used by other parts of ZMK, to install # components they produce. InstallUninstall.Variables=InstallDir InstallName InstallMode define InstallUninstall.Template $1.InstallDir ?= $$(error define $1.InstallDir - the destination directory, or noinst to skip installation) $1.InstallMode ?= 0644 $1.InstallName ?= $$(notdir $1) # Unless we don't want to install the file, look below. ifneq ($$($1.InstallDir),noinst) install:: $$(DESTDIR)$$($1.InstallDir)/$$($1.InstallName) uninstall:: rm -f $$(DESTDIR)$$($1.InstallDir)/$$($1.InstallName) $$(eval $$(call ZMK.Expand,Directory,$$($1.InstallDir))) $$(DESTDIR)$$($1.InstallDir)/$$($1.InstallName): $1 | $$(DESTDIR)$$($1.InstallDir) $$(strip install -m $$($1.InstallMode) $$^ $$@) endif # noinst endef libzt_0.3.1/zmk/Library.A.mk0000644000175000017500000000226513675422347014366 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,Toolchain)) Library.A.Variables=Sources Objects define Library.A.Template ifneq ($$(suffix $1),.a) $$(error library name $1 must end with ".a") endif # Compile library objects. $$(eval $$(call ZMK.Expand,ObjectGroup,$1)) # Create library archive. $1: $$($1.Objects) $$(AR) $$(ARFLAGS) $$@ $$^ # Install library archive. $1.InstallDir ?= $$(libdir) $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) # React to "all" and "clean". $$(eval $$(call ZMK.Expand,AllClean,$1)) endef libzt_0.3.1/zmk/Library.DyLib.mk0000644000175000017500000000403713675422347015210 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,Toolchain)) Library.DyLib.Variables=Sources ExportList define Library.DyLib.Template # Compile library objects. $1: CFLAGS += -fpic $1: CXXFLAGS += -fpic $1: OBJCFLAGS += -fpic $$(eval $$(call ZMK.Expand,ObjectGroup,$1)) # We are building a dynamic library. $1: LDFLAGS += -dynamiclib # Provide current and compatibility version # TODO: this is preliminary, implement the real thing $1: LDFLAGS += -compatibility_version 1.0 -current_version 1.0 # If we have a list of exported symbols then switch symbol # visibility to hidden and pass the list to the linker. $1.ExportList ?= $$(warning should define $1.ExportList) ifneq (,$$($1.ExportList)) $1: $$($1.ExportList) $1: LDFLAGS += -fvisibility=hidden $1: LDFLAGS += -exported_symbols_list=$$($1.ExportList) endif # Link library objects. $1: $$($1.Objects) $$(strip $$(if $$($1.ObjectsObjC),$$(LINK.m),$$(if $$($1.ObjectsCxx),$$(LINK.cc),$$(LINK.o))) -o $$@ $$(filter %.o,$$^) $$(LDLIBS)) # Install library binary. $1.InstallDir ?= $$(libdir) $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) # React to "all" and "clean". $$(eval $$(call ZMK.Expand,AllClean,$1)) # Create symlink (alias) to the versioned library. $1.alias ?= $$(basename $$(basename $1)).dylib $$($1.alias).InstallDir ?= $$($1.InstallDir) $$($1.alias).SymlinkTarget = $1 $$(eval $$(call ZMK.Expand,Symlink,$$($1.alias))) endef libzt_0.3.1/zmk/Library.So.mk0000644000175000017500000000465513675422347014574 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,Toolchain)) Library.So.Variables=Sources SoName InstallDir VersionScript define Library.So.Template # Compile library objects. $1: CFLAGS += -fpic $1: CXXFLAGS += -fpic $1: OBJCFLAGS += -fpic $$(eval $$(call ZMK.Expand,ObjectGroup,$1)) # Watcom doesn't build dynamic libraries. ifneq (,$$(Toolchain.$$(if $$($1.ObjectsObjC),CC,$$(if $$($1.ObjectsCxx),CXX,CC)).IsWatcom)) $$(error Watcom does not support shared libraries)) endif # watcom # We are building a shared library. $1: LDFLAGS += -shared # If we have a soname then store it in the shared library. $1.SoName ?= $1 ifneq (,$$($1.SoName)) $1: LDFLAGS += -Wl,-soname=$$($1.SoName) endif # soname # # If we have a version script switch symbol visibility to hidden # and use the version script to define precise version mapping. $1.VersionScript ?= $$(warning define $1.VersionScript - the name of a ELF symbol map) ifneq (,$$($1.VersionScript)) # Tcc does not support version scripts. # ifeq (,$$(Toolchain.$$(if $$($1.ObjectsObjC),CC,$$(if $$($1.ObjectsCxx),CXX,CC)).IsTcc)) $1: $$($1.VersionScript) $1: LDFLAGS += -fvisibility=hidden $1: LDFLAGS += -Wl,--version-script=$$($1.VersionScript) endif # !tcc endif # VersionScript # Link library objects. $1: $$($1.Objects) $$(strip $$(if $$($1.ObjectsObjC),$$(LINK.m),$$(if $$($1.ObjectsCxx),$$(LINK.cc),$$(LINK.o))) -o $$@ $$(filter %.o,$$^) $$(LDLIBS)) # Install library binary. $1.InstallDir ?= $$(libdir) $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) # React to "all" and "clean". $$(eval $$(call ZMK.Expand,AllClean,$1)) # Create symlink (alias) to the versioned library. $1.alias = $$(basename $1) $$($1.alias).InstallDir ?= $$($1.InstallDir) $$($1.alias).SymlinkTarget = $1 $$(eval $$(call ZMK.Expand,Symlink,$$($1.alias))) endef libzt_0.3.1/zmk/ManPage.mk0000644000175000017500000000253513675422347014113 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) # GNU man can be used to perform rudimentary validation of manual pages. #ifneq ($(and $(shell command -v man 2>/dev/null),$(shell man --help 2>&1 | grep -F -- --warning)),) #static-check-manpages: # LC_ALL=C MANROFFSEQ='' MANWIDTH=80 man --warnings -E UTF-8 -l -Tutf8 -Z $^ 2>&1 >/dev/null | diff -u - /dev/null #static-check:: static-check-manpages #endif ManPage.Variables=Section define ManPage.Template $1.Section ?= $$(patsubst .%,%,$$(suffix $1)) $1.InstallDir = $$(if $$(man$$($1.Section)dir),$$(man$$($1.Section)dir),$$(error unknown section $$($1.Section))) $1.InstallMode = 0644 $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) static-check-manpages: $1 endef libzt_0.3.1/zmk/OS.mk0000644000175000017500000000317213675422347013122 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Is zmk debugging enabled for this module? OS.debug ?= $(findstring os,$(DEBUG)) # OS.Kernel is the name of the operating system kernel. # There are multiple possibilities but most common include # Linux, Darwin and Windows_NT. ifeq ($(origin OS),environment) OS.Kernel = $(findstring $(OS),Windows_NT) else OS.Kernel := $(shell uname -s) endif # Format of the executable programs used by the OS. # In general all systems fall into one of the three # possible formats: ELF, Mach-O, PE and MZ (though unlikely). # Many UNIX systems, apart from Darwin, use elf. ifneq (,$(findstring $(OS.Kernel),Linux FreeBSD NetBSD OpenBSD GNU GNU/kFreeBSD SunOS Haiku)) OS.ImageFormat = ELF endif ifeq ($(OS.Kernel),Darwin) OS.ImageFormat = Mach-O endif ifeq ($(OS.Kernel),Windows_NT) OS.ImageFormat = PE endif OS.ImageFormat ?= $(error unsupported operating system kernel $(OS.Kernel)) $(if $(OS.debug),$(info DEBUG: OS.Kernel=$(OS.Kernel))) $(if $(OS.debug),$(info DEBUG: OS.ImageFormat=$(OS.ImageFormat))) libzt_0.3.1/zmk/ObjectGroup.mk0000644000175000017500000000326713675422347015031 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Toolchain)) $(eval $(call ZMK.Import,OS)) ObjectGroup.Variables=Sources Objects ObjectsC ObjectsCxx ObjectsObjC define ObjectGroup.Template $1.Sources ?= $$(error define $1.Sources - the list of source files to compile) $1.ObjectsC ?= $$(addsuffix .o,$$(addprefix $1-,$$(basename $$(filter %.c,$$($1.Sources))))) $1.ObjectsCxx ?= $$(addsuffix .o,$$(addprefix $1-,$$(basename $$(filter %.cpp,$$($1.Sources))))) $1.ObjectsObjC ?= $$(addsuffix .o,$$(addprefix $1-,$$(basename $$(filter %.m,$$($1.Sources))))) $1.Objects ?= $$(strip $$($1.ObjectsC) $$($1.ObjectsCxx) $$($1.ObjectsObjC)) # This is how to compile each type of source files. $$($1.ObjectsC): $1-%.o: %.c $$(strip $$(COMPILE.c) -o $$@ $$<) $$($1.ObjectsCxx): $1-%.o: %.cpp $$(strip $$(COMPILE.cc) -o $$@ $$<) $$($1.ObjectsObjC): $1-%.o: %.m $$(strip $$(COMPILE.m) -o $$@ $$<) clean:: rm -f $$($1.Objects) ifneq (,$$(Toolchain.DependencyTracking)) rm -f $$($1.Objects:.o=.d) endif ifneq (,$$(Toolchain.DependencyTracking)) -include $$($1.Objects:.o=.d) endif endef libzt_0.3.1/zmk/PVS.mk0000644000175000017500000000364713675422347013260 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . PVS.Sources ?= $(error define PVS.Sources - the list of source files to analyze with PVS Studio) PLOG_CONVERTER_FLAGS ?= # If we have pvs-studio then run it during static checks. ifneq (,$(shell command -v pvs-studio 2>/dev/null)) static-check:: static-check-pvs endif .PHONY: static-check-pvs static-check-pvs: $(addsuffix .PVS-Studio.log,$(PVS.Sources)) $(strip plog-converter \ --settings $(srcdir)/.pvs-studio.cfg \ $(PLOG_CONVERTER_FLAGS) \ --srcRoot $(srcdir) \ --renderTypes errorfile $^ | srcdir=$(srcdir) abssrcdir=$(abspath $(srcdir)) awk -f $(ZMK.Path)/zmk/pvs-filter.awk) pvs-report: $(addsuffix .PVS-Studio.log,$(PVS.Sources)) $(strip plog-converter \ --settings $(srcdir)/.pvs-studio.cfg \ $(PLOG_CONVERTER_FLAGS) \ --srcRoot $(srcdir) \ --projectName $(NAME) \ --projectVersion $(VERSION) \ --renderTypes fullhtml \ --output $@ \ $^) %.c.PVS-Studio.log: %.c.i ~/.config/PVS-Studio/PVS-Studio.lic | %.c $(strip pvs-studio \ --cfg $(srcdir)/.pvs-studio.cfg \ --i-file $< \ --source-file $(firstword $|) \ --output-file $@) %.c.i: %.c $(strip $(CC) $(CPPFLAGS) $< -E -o $@) %.cpp.i: %.cpp $(strip $(CXX) $(CPPFLAGS) $< -E -o $@) %.m.i: %.m $(strip $(CC) $(CPPFLAGS) $< -E -o $@) clean:: rm -f *.i rm -f *.PVS-Studio.log rm -rf pvs-report libzt_0.3.1/zmk/Program.Test.mk0000644000175000017500000000557613675422347015140 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,Toolchain)) $(eval $(call ZMK.Import,OS)) # xcrun is the helper for accessing toolchain programs on MacOS # It is defined as empty for non-Darwin build environments. xcrun ?= ifeq ($(OS.Kernel),Darwin) # MacOS uses xcrun helper for some toolchain binaries. xcrun := xcrun endif clean:: rm -f *.profdata *.profraw Program.Test.Variables=Sources SourcesCoverage InstallDir InstallMode define Program.Test.Template $1.SourcesCoverage ?= $$(error define $1.SourcesCoverage - the list of source files to include in coverage analysis) $$(eval $$(call ZMK.Expand,Program,$1)) # If we are using gcc or clang, build with debugging symbols. ifneq (,$$(or $$(Toolchain.IsGcc),$$(Toolchain.IsClang))) $1$$(exe): CFLAGS += -g endif # If we are not cross-compiling, run the test program on "make check" check:: $1$$(exe) ifneq (,$$(Toolchain.IsCross)) echo "not executing test program $$<$$(exe) when cross-compiling" else ./$$< endif # If we are not cross-compiling, and stars align, support coverage analysis. ifeq (,$$(Toolchain.IsCross)) # Support coverage analysis when building with clang and supplied with llvm # or when using xcrun. ifneq (,$$(or $$(xcrun),$$(and $$(Toolchain.IsClang),$$(shell command -v llvm-cov 2>/dev/null),$$(shell command -v llvm-profdata 2>/dev/null)))) # Build test program with code coverage measurements and show them via "coverage" target. $1$$(exe): CFLAGS += -fcoverage-mapping -fprofile-instr-generate $1$$(exe): LDFLAGS += -fcoverage-mapping -fprofile-instr-generate $1.profraw: %.profraw: % LLVM_PROFILE_FILE=$$@ ./$$^ $1.profdata: %.profdata: %.profraw $$(strip $$(xcrun) llvm-profdata merge -sparse $$< -o $$@) coverage:: $1.profdata $$(strip $$(xcrun) llvm-cov show ./$1$$(exe) -instr-profile=$$< $$(addprefix $$(srcdir)/,$$($1.sources_coverage))) .PHONY: coverage-todo coverage-todo:: $1.profdata $$(strip $$(xcrun) llvm-cov show ./$1$$(exe) -instr-profile=$$< -region-coverage-lt=100 $$(addprefix $$(srcdir)/,$$($1.sources_coverage))) .PHONY: coverage-report coverage-report:: $1.profdata $$(strip $$(xcrun) llvm-cov report ./$1$$(exe) -instr-profile=$$< $$(addprefix $$(srcdir)/,$$($1.sources_coverage))) endif # can use llvm-cov endif # not-cross-compiling endef libzt_0.3.1/zmk/Program.mk0000644000175000017500000000351713675422347014213 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,Toolchain)) $(eval $(call ZMK.Import,OS)) Program.Variables=Sources InstallDir InstallMode Linker define Program.Template # Compile program objects. $$(eval $$(call ZMK.Expand,ObjectGroup,$1)) $1.Linker ?= $$(if $$($1.ObjectsObjC),$$(CC),$$(if $$($1.ObjectsCxx),$$(CXX),$$(CC))) # Link program objects. ifneq (,$$($1.ObjectsObjC)) $1$$(exe): LDLIBS += -lobjc endif # no objective C objects $1$$(exe): $$($1.Objects) $$(strip $$(if $$($1.ObjectsObjC),$$(LINK.m),$$(if $$($1.ObjectsCxx),$$(LINK.cc),$$(LINK.o))) -o $$@ $$^ $$(LDLIBS)) # Install program binary. $1.InstallDir ?= $$(bindir) $1.InstallMode ?= 0755 $1.InstallName ?= $$(if $$(Configure.ProgramTransformName),$$(shell echo '$$(Configure.ProgramPrefix)$$(notdir $1)$$(Configure.ProgramSuffix)' | sed -e '$$(Configure.ProgramTransformName)'),$$(Configure.ProgramPrefix)$$(notdir $1)$$(Configure.ProgramSuffix)) $1$$(exe).InstallDir ?= $$($1.InstallDir) $1$$(exe).InstallMode ?= $$($1.InstallMode) $1$$(exe).InstallName ?= $$($1.InstallName) $$(eval $$(call ZMK.Expand,InstallUninstall,$1$$(exe))) # React to "all" and "clean". $$(eval $$(call ZMK.Expand,AllClean,$1$$(exe))) endef libzt_0.3.1/zmk/Script.mk0000644000175000017500000000311613675422347014043 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) ZMK.shellcheck ?= $(shell command -v shellcheck 2>/dev/null) static-check-shellcheck: ifneq (,$(ZMK.shellcheck)) $(ZMK.shellcheck) $^ else @echo "ZMK: install shellcheck to analyze $^" endif static-check:: static-check-shellcheck Script.Variables=Interpreter InstallDir InstallMode define Script.Template $1.InstallDir ?= $$(bindir) $1.InstallMode ?= 0755 $1.InstallName ?= $$(if $$(Configure.ProgramTransformName),$$(shell echo '$$(Configure.ProgramPrefix)$$(notdir $1)$$(Configure.ProgramSuffix)' | sed -e '$$(Configure.ProgramTransformName)'),$$(Configure.ProgramPrefix)$$(notdir $1)$$(Configure.ProgramSuffix)) $$(eval $$(call ZMK.Expand,InstallUninstall,$1)) $1.Interpreter ?= $$(if $$(suffix $1),$$(patsubst .%,%,$$(suffix $1)),$$(error define $1.Interpreter - the script interpreter name, sh, bash or other)) ifneq ($$(findstring $$($1.Interpreter),sh bash),) static-check-shellcheck: $1 endif endef libzt_0.3.1/zmk/Symlink.mk0000644000175000017500000000432113675422347014224 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Symbolic link. Gets installed to the desired location. The location can be # set using the .InstallDir instance variable. The special value of noinst # prevents installation. This template is used by other parts of ZMK, to # install components they produce. Symlink.Variables=SymlinkTarget InstallDir InstallName define Symlink.Template $1.InstallDir ?= $$(error define $1.InstallDir - the destination directory, or noinst to skip installation) $1.SymlinkTarget ?= $$(error define $1.SymlinkTarget - the target of the symbolic link) $1.InstallName ?= $$(notdir $1) $1.sourceDir = $$(patsubst %/,%,$$(dir $1)) # Create the directory where the symbolic link is built in. $$(eval $$(call ZMK.Expand,Directory,$$($1.sourceDir))) # Create the symbolic link in the build directory. $1: | $$($1.sourceDir) $$(strip ln -s $$($1.SymlinkTarget) $$@) # React to "all" and "clean" targets. $$(eval $$(call ZMK.Expand,AllClean,$1)) # Unless we don't want to install the file, look below. ifneq ($$($1.InstallDir),noinst) # Create the directory where the symbolic link is installed to. $1.targetDir = $$(patsubst %/,%,$$(dir $$($1.InstallDir)/$1)) $$(eval $$(call ZMK.Expand,Directory,$$($1.targetDir))) # Create the symbolic link in the install directory. $$(DESTDIR)$$($1.targetDir)/$$($1.InstallName):| $$(DESTDIR)$$($1.targetDir) $$(strip ln -s $$($1.SymlinkTarget) $$@) # React to "install" and "uninstall" targets. install:: $$(DESTDIR)$$($1.targetDir)/$$($1.InstallName) uninstall:: rm -f $$(DESTDIR)$$($1.targetDir)/$$($1.InstallName) else # noinst $1.targetDir = noinst endif # !noinst endef libzt_0.3.1/zmk/Tarball.Src.mk0000644000175000017500000000321213675422347014703 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . %.asc: % gpg --detach-sign --armor $< Tarball.Src.Variables=Name Files Sign define Tarball.Src.Template $1.Name ?= $$(patsubst %.tar$$(suffix $1),%,$1) $1.Files ?= $$(error define $1.Files - the list of files to include in the tarball) $1.Files += $$(ZMK.DistFiles) # Sign archives that are not git snapshots and if CI is unset $1.Sign ?= $$(if $$(or $$(value CI),$$(and $$(filter GitVersion,$$(ZMK.ImportedModules)),$$(GitVersion.Active))),,yes) # If the Configure module is imported then include the configure script. ifneq (,$$(filter Configure,$$(ZMK.ImportedModules))) $1.Files += configure endif # If the GitVersion module is imported then put the .version-from-git file # inside the source archive. This way the GitVersion module will not attempt to # refer to git after the archive is extracted for installation later. ifneq (,$$(filter GitVersion,$$(ZMK.ImportedModules))) $1.Files += .version-from-git endif ifneq (,$$($1.Sign)) dist:: $1.asc endif $$(eval $$(call ZMK.Expand,Tarball,$1)) endef libzt_0.3.1/zmk/Tarball.mk0000644000175000017500000000315713675422347014165 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,Directories)) $(eval $(call ZMK.Import,OS)) _bsd_tar_options ?= _tar_compress_flag ?= # If using a Mac, filter out extended meta-data files. ifeq ($(OS.Kernel),Darwin) _bsd_tar_options := --no-mac-metadata endif %.tar.gz: _tar_compress_flag=z %.tar.bz2: _tar_compress_flag=j %.tar.xz: _tar_compress_flag=J Tarball.Variables=Name Files define Tarball.Template $1.Name ?= $$(patsubst %.tar$$(suffix $1),%,$1) $1.Files ?= $$(error define $1.Files - the list of files to include in the tarball) dist:: $1 $1: $$(sort $$(addprefix $$(srcdir)/,$$($1.Files))) ifneq ($(shell tar --version 2>&1 | grep GNU),) tar -$$(or $$(_tar_compress_flag),a)cf $$@ -C $$(srcdir) --xform='s@^@$$($1.Name)/@g' --xform='s@.version-from-git@.version@' $$(patsubst $$(srcdir)/%,%,$$^) else tar $$(strip $$(_bsd_tar_options) -$$(or $$(_tar_compress_flag),a)cf) $$@ -C $$(srcdir) -s '@.@$$($1.Name)/~@' -s '@.version-from-git@.version@' $$(patsubst $$(srcdir)/%,%,$$^) endif endef libzt_0.3.1/zmk/Toolchain.mk0000644000175000017500000000667713675422347014536 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . $(eval $(call ZMK.Import,OS)) $(eval $(call ZMK.Import,Configure)) # Compiler defaults unless changed by GNUmakefile.configure.mk ifeq ($(OS.Kernel),SunOS) # Solaris doesn't seem to provide any aliases or symlinks for gcc but make wants to call it "cc". CC := gcc endif CPPFLAGS ?= CFLAGS ?= CXXFLAGS ?= OBJCFLAGS ?= ARFLAGS = -cr TARGET_ARCH ?= LDLIBS ?= LDFLAGS ?= # The exe variable expands to .exe when the compiled binary should have such suffix. exe ?= # Is zmk debugging enabled for this module? Toolchain.debug ?= $(findstring toolchain,$(DEBUG)) # What is the image format used by the C compiler? # If we are not cross compiling then image format is native. Toolchain.CC.ImageFormat ?= $(OS.ImageFormat) # What is the image format used by the C++ compiler? Toolchain.CXX.ImageFormat ?= $(OS.ImageFormat) # Is the C compiler a cross-compiler? Toolchain.CC.IsCross ?= # Is the C++ compiler a cross-compiler? Toolchain.CXX.IsCross ?= # Should compiling produce dependency information for make? Toolchain.DependencyTracking ?= $(Configure.DependencyTracking) # Deduce the kind of the selected compiler. Some build rules or compiler # options depend on the compiler used. As an alternative we could look at # preprocessor macros but this way seems sufficient for now. Toolchain.cc ?= $(shell sh -c "command -v $(CC)") Toolchain.cxx ?= $(shell sh -c "command -v $(CXX)") # When CC or CXX point to platform default compiler alias, resolve # them to the real value, which is better to identify the toolchain. Toolchain.cc := $(if $(findstring $(Toolchain.cc),/usr/bin/cc),$(realpath $(Toolchain.cc)),$(Toolchain.cc)) Toolchain.cxx := $(if $(findstring $(Toolchain.cxx),/usr/bin/c++ /usr/bin/g++),$(realpath $(Toolchain.cxx)),$(Toolchain.cxx)) # Import toolchain-specific knowledge. $(eval $(call ZMK.Import,toolchain.GCC)) $(eval $(call ZMK.Import,toolchain.Clang)) $(eval $(call ZMK.Import,toolchain.Watcom)) $(eval $(call ZMK.Import,toolchain.Tcc)) # Is either the C or C++ compiler a cross compiler? Toolchain.IsCross ?= $(or $(Toolchain.CC.IsCross),$(Toolchain.CXX.IsCross)) # Is the image format between C and C++ uniform? ifeq ($(Toolchain.CC.ImageFormat),$(Toolchain.CXX.ImageFormat)) Toolchain.ImageFormat = $(Toolchain.CC.ImageFormat) else Toolchain.ImageFormat = Mixed endif # If dependency tracking is enabled, pass extra options to the compiler, to # generate dependency data at the same time as compiling object files. ifneq (,$(and $(Toolchain.DependencyTracking),$(or $(Toolchain.IsGcc),$(Toolchain.IsClang)))) CPPFLAGS += -MMD $(if $(Toolchain.debug),$(info DEBUG: compiling object files will generate make dependency information)) endif $(if $(Toolchain.debug),$(foreach v,CC CXX CPP CFLAGS CXXFLAGS CPPFLAGS OBJCFLAGS ARFLAGS TARGET_ARCH LDLIBS LDFLAGS $(sort $(filter Toolchain.%,$(.VARIABLES))),$(info DEBUG: $v=$($v)))) libzt_0.3.1/zmk/internalTest.mk0000644000175000017500000000221113675422347015246 0ustar zygazyga# NOTE: This file is not a part of the public ZMK API. # It is used by zmk self-test suite and it is provided here for convenience. # Tests are grouped under the "t" target .PHONY: t t:: # Find the path of the zmk installation ZMK.Path := $(abspath $(dir $(lastword $(MAKEFILE_LIST)))/..) # Put extra test tools on PATH export PATH := $(ZMK.Path)/tests/bin:$(PATH) # Make overrides can be used in order to test specific behavior ZMK.makeOverrides ?= # Make target can be customized for each log file. # For default logic, see the rule below. ZMK.makeTarget ?= # Tests print a header, unless silent mode is used # Tests do not use localization # Tests always remake targets # Tests print commands instead of invoking them # Tests do not mention directory changes # Tests warn about undefined variables %.log: MAKEFLAGS=Bn %.log: Test.mk Makefile $(ZMK.Path)/z.mk $(wildcard $(ZMK.Path)/zmk/*.mk) $(strip LANG=C $(MAKE) $(ZMK.makeOverrides) -I $(ZMK.Path) \ --warn-undefined-variables \ --always-make \ --dry-run \ $(or $(ZMK.makeTarget),$(firstword $(subst -, ,$*))) >$@ 2>&1) || true configure: $(ZMK.Path)/zmk/internalTest.mk c:: rm -f *.log libzt_0.3.1/zmk/pvs-filter.awk0000644000175000017500000000247213675422347015051 0ustar zygazyga# Copyright 2019-2020 Zygmunt Krynicki. # # This file is part of zmk. # # Zmk is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation, either version 3 of the License. # # Zmk 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 Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License # along with Zmk. If not, see . # Awk script for taming the output of plog-converter. # Requires $srcdir and $abssrcdir environment variables. BEGIN { FAILED=0; SRCDIR=ENVIRON["srcdir"]; NSKIP=length(ENVIRON["abssrcdir"]); # print(sprintf("nskip %d", NSKIP)); } # Skip the annoying URL notice. /^www\.viva64\.com\/en\/w:1:1/ { next } # We know this is an open source project. /^.*: error: V1042 .*$/ { next } # Pick up warnings and errors. Use relative file names. # The +1 below is because awk uses 1-based indexing. /^.*: (warning|error):/ { FAILED=1; # print($0); print(sprintf("%s%s", SRCDIR, substr($0, NSKIP + 2))); } # Exit if warnings or errors were reported. END { if (FAILED) exit(1); } libzt_0.3.1/zmk/toolchain.Clang.mk0000644000175000017500000000042313675422347015600 0ustar zygazyga# Are we using Clang? Toolchain.CC.IsClang=$(if $(findstring clang,$(Toolchain.cc)),yes) Toolchain.CXX.IsClang=$(if $(findstring clang,$(Toolchain.cxx)),yes) Toolchain.IsClang=$(and $(Toolchain.CC.IsClang),$(Toolchain.CXX.IsClang)) # TODO: handle cross compiling with clang. libzt_0.3.1/zmk/toolchain.GCC.mk0000644000175000017500000000570413675422347015157 0ustar zygazyga# Are we using GCC? Toolchain.CC.IsGcc=$(if $(findstring gcc,$(Toolchain.cc)),yes) Toolchain.CXX.IsGcc=$(if $(and $(if $(findstring clang++,$(Toolchain.cxx)),,not-clang++),$(findstring g++,$(Toolchain.cxx))),yes) Toolchain.IsGcc=$(and $(Toolchain.CC.IsGcc),$(Toolchain.CXX.IsGcc)) # Logic specific to gcc ifneq (,$(Toolchain.CC.IsGcc)) # If we are configured then check for cross compilation by mismatch of host and # build triplets. When this happens set CC. This is important for # autoconf/automake compatibility. ifneq (,$(and $(Configure.Configured),$(Configure.HostArchTriplet),$(Configure.BuildArchTriplet))) ifneq ($(Configure.BuildArchTriplet),$(Configure.HostArchTriplet)) CC = $(Configure.HostArchTriplet)-gcc $(if $(Toolchain.debug),$(info DEBUG: gcc cross-compiler selected CC=$(CC))) endif # !cross-compiling endif # !configured # Indirection for testability. Toolchain.cc.dumpmachine ?= $(shell $(CC) -dumpmachine) Toolchain.gcc.dumpmachine ?= $(shell gcc -dumpmachine) # Are we targeting Windows with mingw? ifneq (,$(findstring mingw,$(Toolchain.cc.dumpmachine))) exe = .exe Toolchain.CC.ImageFormat = PE $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CC) -dumpmachine mentions mingw)) endif # !mingw # Are we targeting Linux? ifneq (,$(findstring linux,$(Toolchain.cc.dumpmachine))) Toolchain.CC.ImageFormat = ELF endif # !linux # Is gcc cross-compiling? ifneq ($(Toolchain.gcc.dumpmachine),$(Toolchain.cc.dumpmachine)) Toolchain.CC.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because gcc -dumpmachine and $(CC) -dumpmachine differ)) endif # !cross endif # !cc=gcc # Logic specific to g++ ifneq (,$(Toolchain.CXX.IsGcc)) # If we are configured then check for cross compilation by mismatch of host and # build triplets. When this happens set CXX. This is important for # autoconf/automake compatibility. ifneq (,$(and $(Configure.Configured),$(Configure.HostArchTriplet),$(Configure.BuildArchTriplet))) ifneq ($(Configure.BuildArchTriplet),$(Configure.HostArchTriplet)) CXX = $(Configure.HostArchTriplet)-g++ $(if $(Toolchain.debug),$(info DEBUG: g++ cross-compiler selected CXX=$(CXX))) endif # !cross-compiling endif # !configured # Indirection for testability. Toolchain.cxx.dumpmachine ?= $(shell $(CXX) -dumpmachine) Toolchain.g++.dumpmachine ?= $(shell g++ -dumpmachine) # Are we targeting Windows with mingw? ifneq (,$(findstring mingw,$(Toolchain.cxx.dumpmachine))) exe = .exe Toolchain.CXX.ImageFormat = PE $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CXX) -dumpmachine mentions mingw)) endif # !mingw # Are we targeting Linux? ifneq (,$(findstring linux,$(Toolchain.cxx.dumpmachine))) Toolchain.CXX.ImageFormat = ELF endif # !linux # Is g++ cross compiling? ifneq ($(Toolchain.g++.dumpmachine),$(Toolchain.cxx.dumpmachine)) Toolchain.CXX.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because g++ -dumpmachine and $(CXX) -dumpmachine differ)) endif # !cross endif # !cxx=gcc libzt_0.3.1/zmk/toolchain.Tcc.mk0000644000175000017500000000013113675422347015261 0ustar zygazyga# Is CC the tcc compiler? Toolchain.CC.IsTcc=$(if $(findstring tcc,$(Toolchain.cc)),yes) libzt_0.3.1/zmk/toolchain.Watcom.mk0000644000175000017500000000353313675422347016013 0ustar zygazyga# Are we using the open Watcom compiler? Toolchain.CC.IsWatcom=$(if $(findstring watcom,$(Toolchain.cc)),yes) Toolchain.CXX.IsWatcom=$(if $(findstring watcom,$(Toolchain.cxx)),yes) Toolchain.IsWatcom=$(and $(Toolchain.CC.IsWatcom),$(Toolchain.CXX.IsWatcom)) # Logic specific to Watcom compiler. ifneq (,$(Toolchain.CC.IsWatcom)) # Are we building for DOS or 16bit Windows? ifneq (,$(or $(findstring dos,$(Toolchain.cc)),$(findstring win16,$(Toolchain.cc)))) exe = .exe Toolchain.CC.ImageFormat = MZ Toolchain.CC.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CC) name)) $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because Watcom targets DOS)) endif # !cc win16 || dos # Are we building for 32bit Windows? ifneq (,$(findstring win32,$(Toolchain.cc))) exe = .exe Toolchain.CC.ImageFormat = PE Toolchain.CC.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CC) name)) $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because Watcom targets Windows)) endif # !cc win32 endif # !cc Watcom # Logic specific to Watcom ifneq (,$(Toolchain.CXX.IsWatcom)) # Are we building for DOS or 16bit Windows? ifneq (,$(or $(findstring dos,$(Toolchain.cxx)),$(findstring win16,$(Toolchain.cxx)))) exe = .exe Toolchain.CXX.ImageFormat = MZ Toolchain.CXX.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CXX) name)) $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because Watcom targets DOS)) endif # !cxx win16 || dos # Are we building for 32bit Windows? ifneq (,$(findstring win32,$(Toolchain.cxx))) exe = .exe Toolchain.CXX.ImageFormat = PE Toolchain.CXX.IsCross = yes $(if $(Toolchain.debug),$(info DEBUG: .exe suffix enabled because $(CXX) name)) $(if $(Toolchain.debug),$(info DEBUG: cross-compiling because Watcom targets Windows)) endif # !cxx win32 endif # !cxx Watcom libzt_0.3.1/zt-test.c0000664000175000017500000022742313675422322013227 0ustar zygazyga/* This is an open source non-commercial project. Dear PVS-Studio, please check it. * PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com * * Copyright 2019-2020 Zygmunt Krynicki. * * This file is part of libzt. * * Libzt is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * Libzt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Libzt. If not, see . */ #ifdef __linux__ #define _GNU_SOURCE #include #include #include #include #include #include #endif #include #include #include #define ZT_SELF_TEST_BUILD #include "zt.c" /* internal self-test helpers */ static FILE* selftest_temporary_file(void) { FILE* f; #if defined(__linux__) /* Hardened version for Linux. */ char tmpl[PATH_MAX]; const char* tmp_dir_name; int fd; tmp_dir_name = getenv("TMPDIR"); if (tmp_dir_name == NULL) { tmp_dir_name = "/tmp"; } #if defined(O_TMPFILE) fd = open(tmp_dir_name, O_TMPFILE | O_RDWR | O_EXCL, 0600); if (fd < 0) { if (errno != EOPNOTSUPP) { perror("cannot open temporary file via O_TMPFILE"); exit(1); } } tmpl[0] = '\0'; #else fd = -1; #endif if (fd < 0) { int n = snprintf(tmpl, sizeof tmpl - 1, "%s/libzt-test.XXXXXX", tmp_dir_name); if (n < 0 || (size_t)n >= sizeof tmpl - 1) { perror("cannot format temporary file name"); exit(1); } fd = mkostemp(tmpl, O_CLOEXEC); } if (fd < 0) { perror("cannot open temporary file"); exit(1); } if (tmpl[0] != '\0' && unlink(tmpl) < 0) { perror("cannot unlink temporary file"); exit(1); } f = fdopen(fd, "w+"); #else /* Portable version. */ f = tmpfile(); #endif if (f == NULL) { perror("cannot open temporary file"); exit(1); } return f; } static zt_test selftest_make_test(void) { zt_test t; memset(&t, 0, sizeof t); t.location.fname = "file.c"; t.location.lineno = 13; t.stream = selftest_temporary_file(); return t; } static void selftest_close_test(zt_t t) { fclose(t->stream); t->stream = NULL; } static void selftest_quote_str(FILE* stream, const char* str) { /* self-test quote function uses single-quotes. Meanwhile the production * quote function uses double quotes. This allows one to quote the other * without unnecessary escaping. */ fputs("\'", stream); for (;;) { int c = *str; if (c == '\0') { break; } str++; switch (c) { case '\'': fputs("\\'", stream); break; case '\n': fputs("\\n", stream); break; case '\r': fputs("\\r", stream); break; case '\t': fputs("\\t", stream); break; case '\v': fputs("\\v", stream); break; default: if (isprint(c)) { fputc(c, stream); } else { fprintf(stream, "\\%#04x", c); } break; } } fputs("\'", stream); } #define selftest_stream_eq(stream, expected) \ selftest_stream_eq_at( \ stream, __FILE__, __LINE__, "%s", expected) static void selftest_stream_eq_at(FILE* stream, const char* file, int lineno, const char* fmt, ...) { size_t nread; int nfmt; char buf1[1024], buf2[1024]; size_t buf1_size = sizeof buf1; size_t buf2_size = sizeof buf2; va_list ap; if (fseek(stream, 0, SEEK_SET) < 0) { perror("cannot seek in test stream"); exit(1); } nread = fread(buf1, 1, buf1_size - 1, stream); if (nread == 0 && !feof(stream) && ferror(stream) != 0) { perror("cannot read from test stream"); exit(1); } if (nread == buf1_size - 1 && !feof(stream)) { fprintf(stderr, "insufficient space to read entire stream\n"); exit(1); } buf1[nread] = '\0'; va_start(ap, fmt); nfmt = vsnprintf(buf2, buf2_size, fmt, ap); va_end(ap); if (nfmt < 0) { perror("cannot format expected stream contents"); exit(1); } if ((size_t)nfmt >= buf2_size) { fprintf(stderr, "insufficient space to format expected stream contents\n"); exit(1); } buf2[nfmt] = '\0'; if (strcmp(buf1, buf2) != 0) { fprintf(stderr, "%s:%d: error: stream content mismatch ", file, lineno); selftest_quote_str(stderr, buf1); fprintf(stderr, " ( <- actual) != "); selftest_quote_str(stderr, buf2); fprintf(stderr, " ( <- expected)\n"); exit(1); } } /* library version */ static void test_MAJOR_MINOR_VERSION(void) { assert(ZT_MAJOR_VERSION == 0); assert(ZT_MINOR_VERSION == 3); } /* packing arguments */ static void test_pack_boolean(void) { zt_value v; v = zt_pack_boolean(true, "true"); assert(zt_value_kind_of(v) == ZT_BOOLEAN); assert(v.as.boolean == true); assert(strcmp(zt_source_of(v), "true") == 0); v = zt_pack_boolean(false, "false"); assert(zt_value_kind_of(v) == ZT_BOOLEAN); assert(v.as.boolean == false); assert(strcmp(zt_source_of(v), "false") == 0); } static void test_pack_rune(void) { zt_value v; v = zt_pack_rune('a', "'a'"); assert(zt_value_kind_of(v) == ZT_RUNE); assert(v.as.rune == 'a'); assert(strcmp(zt_source_of(v), "'a'") == 0); v = zt_pack_rune('\x80', "'\\x80'"); assert(zt_value_kind_of(v) == ZT_RUNE); assert(v.as.rune == 0x80); assert(strcmp(zt_source_of(v), "'\\x80'") == 0); v = zt_pack_rune('\x01', "'\\x01'"); assert(v.as.rune == 0x01); v = zt_pack_rune('\x80', "'\\x80'"); assert(v.as.rune == 0x80); v = zt_pack_rune('\xFF', "'\\xFF'"); assert(v.as.rune == 0xFF); } static void test_pack_integer(void) { zt_value v; v = zt_pack_integer(42, "42"); assert(zt_value_kind_of(v) == ZT_INTMAX); assert(v.as.intmax == 42); assert(strcmp(zt_source_of(v), "42") == 0); } static void test_pack_unsigned(void) { zt_value v; v = zt_pack_unsigned(42U, "42U"); assert(zt_value_kind_of(v) == ZT_UINTMAX); assert(v.as.uintmax == 42U); assert(strcmp(zt_source_of(v), "42U") == 0); } static void test_pack_string(void) { zt_value v; v = zt_pack_string("foo", "\"foo\""); assert(zt_value_kind_of(v) == ZT_STRING); assert(strcmp(v.as.string, "foo") == 0); assert(strcmp(zt_source_of(v), "\"foo\"") == 0); } static void test_pack_pointer(void) { zt_value v; v = zt_pack_pointer(NULL, "NULL"); assert(zt_value_kind_of(v) == ZT_POINTER); assert(v.as.pointer == NULL); assert(strcmp(zt_source_of(v), "NULL") == 0); } static void test_promote_value(void) { zt_value v; v.kind = ZT_INTEGER; v.as.integer = -1; v.source = "-1"; zt_promote_value(&v); assert(zt_value_kind_of(v) == ZT_INTMAX); assert(v.as.intmax == -1); assert(strcmp(zt_source_of(v), "-1") == 0); v.kind = ZT_UNSIGNED; v.as.unsigned_integer = 1U; v.source = "1U"; zt_promote_value(&v); assert(zt_value_kind_of(v) == ZT_UINTMAX); assert(v.as.uintmax == 1U); assert(strcmp(zt_source_of(v), "1U") == 0); } /* binary relation */ static void test_find_binary_relation(void) { assert(zt_find_binary_relation("==") == ZT_REL_EQ); assert(zt_find_binary_relation("!=") == ZT_REL_NE); assert(zt_find_binary_relation("<=") == ZT_REL_LE); assert(zt_find_binary_relation(">=") == ZT_REL_GE); assert(zt_find_binary_relation("<") == ZT_REL_LT); assert(zt_find_binary_relation(">") == ZT_REL_GT); assert(zt_find_binary_relation("potato") == ZT_REL_INVALID); } static void test_invert_binary_relation(void) { assert(zt_invert_binary_relation(ZT_REL_EQ) == ZT_REL_NE); assert(zt_invert_binary_relation(ZT_REL_NE) == ZT_REL_EQ); assert(zt_invert_binary_relation(ZT_REL_LE) == ZT_REL_GT); assert(zt_invert_binary_relation(ZT_REL_GE) == ZT_REL_LT); assert(zt_invert_binary_relation(ZT_REL_LT) == ZT_REL_GE); assert(zt_invert_binary_relation(ZT_REL_GT) == ZT_REL_LE); assert(zt_invert_binary_relation(ZT_REL_INVALID) == ZT_REL_INVALID); assert(zt_invert_binary_relation(1000) == ZT_REL_INVALID); } static void test_binary_relation_as_text(void) { assert(strcmp(zt_binary_relation_as_text(ZT_REL_EQ), "==") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_NE), "!=") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_LE), "<=") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_GE), ">=") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_LT), "<") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_GT), ">") == 0); assert(strcmp(zt_binary_relation_as_text(ZT_REL_INVALID), "invalid") == 0); assert(strcmp(zt_binary_relation_as_text(1000), "invalid") == 0); } /* boolean formatting */ static void test_boolean_as_text(void) { assert(strcmp(zt_boolean_as_text(true), "true") == 0); assert(strcmp(zt_boolean_as_text(false), "false") == 0); } /* claim verification */ static bool selftest_passing_verify0_called; static bool selftest_passing_verify0(zt_t t) { assert(t != NULL); selftest_passing_verify0_called = true; return true; } static bool selftest_passing_verify1_called; static bool selftest_passing_verify1(zt_t t, ZT_UNUSED zt_value arg1) { (void)arg1; assert(t != NULL); selftest_passing_verify1_called = true; return true; } static bool selftest_passing_verify2_called; static bool selftest_passing_verify2(zt_t t, ZT_UNUSED zt_value arg1, ZT_UNUSED zt_value arg2) { (void)arg1; (void)arg2; assert(t != NULL); selftest_passing_verify2_called = true; return true; } static bool selftest_passing_verify3_called; static bool selftest_passing_verify3(zt_t t, ZT_UNUSED zt_value arg1, ZT_UNUSED zt_value arg2, ZT_UNUSED zt_value arg3) { (void)arg1; (void)arg2; (void)arg3; assert(t != NULL); selftest_passing_verify3_called = true; return true; } static zt_verifier selftest_passing_verifier0(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args0 = selftest_passing_verify0; verifier.nargs = 0; return verifier; } static zt_verifier selftest_passing_verifier1(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args1 = selftest_passing_verify1; verifier.nargs = 1; verifier.arg_infos[0].kind = ZT_INTMAX; verifier.arg_infos[0].kind_mismatch_msg = "arg[0] type mismatch"; return verifier; } static zt_verifier selftest_passing_verifier2(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args2 = selftest_passing_verify2; verifier.nargs = 2; verifier.arg_infos[0].kind = ZT_INTMAX; verifier.arg_infos[0].kind_mismatch_msg = "arg[0] type mismatch"; verifier.arg_infos[1].kind = ZT_INTMAX; verifier.arg_infos[1].kind_mismatch_msg = "arg[1] type mismatch"; return verifier; } static zt_verifier selftest_passing_verifier3(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = selftest_passing_verify3; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_INTMAX; verifier.arg_infos[0].kind_mismatch_msg = "arg[0] type mismatch"; verifier.arg_infos[1].kind = ZT_INTMAX; verifier.arg_infos[1].kind_mismatch_msg = "arg[1] type mismatch"; verifier.arg_infos[2].kind = ZT_INTMAX; verifier.arg_infos[2].kind_mismatch_msg = "arg[2] type mismatch"; return verifier; } static void test_verify_claim0(void) { zt_claim claim; bool result; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify0_called = true; claim.make_verifier = selftest_passing_verifier0; result = zt_verify_claim(&t, &claim); assert(result == true); assert(selftest_passing_verify0_called == true); selftest_close_test(&t); } static void test_verify_claim1(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify0_called = true; claim.make_verifier = selftest_passing_verifier1; result = zt_verify_claim(&t, &claim); assert(result == true); assert(selftest_passing_verify1_called == true); selftest_close_test(&t); } static void test_verify_claim2(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.args[1] = zt_pack_integer(123, "arg1"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify2_called = true; claim.make_verifier = selftest_passing_verifier2; result = zt_verify_claim(&t, &claim); assert(result == true); assert(selftest_passing_verify2_called == true); selftest_close_test(&t); } static void test_verify_claim3(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.args[1] = zt_pack_integer(123, "arg1"); claim.args[2] = zt_pack_integer(123, "arg2"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify3_called = true; claim.make_verifier = selftest_passing_verifier3; result = zt_verify_claim(&t, &claim); assert(result == true); assert(selftest_passing_verify3_called == true); selftest_close_test(&t); } static zt_verifier selftest_bogus_verifier4(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.nargs = 4; return verifier; } static void test_verify_bogus_claim4(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.make_verifier = selftest_bogus_verifier4; claim.location.fname = "file.c"; claim.location.lineno = 13; result = zt_verify_claim(&t, &claim); assert(result == false); selftest_stream_eq(t.stream, "file.c:13: unsupported number of arguments: 4\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim1of1(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_unsigned(123U, "arg0"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify1_called = false; claim.make_verifier = selftest_passing_verifier1; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify1_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[0] type mismatch\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim1of2(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_unsigned(123U, "arg0"); claim.args[1] = zt_pack_integer(123, "arg1"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify2_called = false; claim.make_verifier = selftest_passing_verifier2; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify2_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[0] type mismatch\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim2of2(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.args[1] = zt_pack_unsigned(123U, "arg1"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify2_called = false; claim.make_verifier = selftest_passing_verifier2; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify2_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[1] type mismatch\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim1of3(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_unsigned(123U, "arg0"); claim.args[1] = zt_pack_integer(123, "arg1"); claim.args[2] = zt_pack_integer(123, "arg2"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify3_called = false; claim.make_verifier = selftest_passing_verifier3; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify3_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[0] type mismatch\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim2of3(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.args[1] = zt_pack_unsigned(123U, "arg1"); claim.args[2] = zt_pack_integer(123, "arg2"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify3_called = false; claim.make_verifier = selftest_passing_verifier3; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify3_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[1] type mismatch\n"); selftest_close_test(&t); } static void test_verify_mismatch_claim3of3(void) { bool result; zt_claim claim; zt_test t = selftest_make_test(); memset(&claim, 0, sizeof claim); claim.args[0] = zt_pack_integer(123, "arg0"); claim.args[1] = zt_pack_integer(123, "arg1"); claim.args[2] = zt_pack_unsigned(123U, "arg2"); claim.location.fname = "file.c"; claim.location.lineno = 13; selftest_passing_verify3_called = false; claim.make_verifier = selftest_passing_verifier3; result = zt_verify_claim(&t, &claim); assert(result == false); assert(selftest_passing_verify3_called == false); selftest_stream_eq(t.stream, "file.c:13: arg[2] type mismatch\n"); selftest_close_test(&t); } /* verifier for true and verify true. */ static void test_verifier_for_true(void) { zt_verifier v = zt_verifier_for_true(); assert(v.nargs == 1); assert(v.func.args1 == zt_verify_true); assert(v.arg_infos[0].kind == ZT_BOOLEAN); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "value is not a boolean") == 0); assert(v.arg_infos[1].kind == ZT_NOTHING); assert(v.arg_infos[1].kind_mismatch_msg == NULL); assert(v.arg_infos[2].kind == ZT_NOTHING); assert(v.arg_infos[2].kind_mismatch_msg == NULL); } static void test_verify_true(void) { zt_test t; /* passing */ t = selftest_make_test(); assert(zt_verify_true(&t, zt_pack_boolean(true, "errno == EPERM")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing */ t = selftest_make_test(); assert(zt_verify_true(&t, zt_pack_boolean(false, "fd < 0")) == false); selftest_stream_eq(t.stream, "file.c:13: assertion failed because fd < 0 is false\n"); selftest_close_test(&t); } /* verifier for false and verify false. */ static void test_verifier_for_false(void) { zt_verifier v = zt_verifier_for_false(); assert(v.nargs == 1); assert(v.func.args1 == zt_verify_false); assert(v.arg_infos[0].kind == ZT_BOOLEAN); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "value is not a boolean") == 0); assert(v.arg_infos[1].kind == ZT_NOTHING); assert(v.arg_infos[1].kind_mismatch_msg == NULL); assert(v.arg_infos[2].kind == ZT_NOTHING); assert(v.arg_infos[2].kind_mismatch_msg == NULL); } static void test_verify_false(void) { zt_test t; /* passing */ t = selftest_make_test(); assert(zt_verify_false(&t, zt_pack_boolean(false, "errno == 0")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing */ t = selftest_make_test(); assert(zt_verify_false(&t, zt_pack_boolean(true, "errno == 0")) == false); selftest_stream_eq(t.stream, "file.c:13: assertion failed because errno == 0 is true\n"); selftest_close_test(&t); } /* verifier for boolean relation. */ static void test_verifier_for_boolean_relation(void) { zt_verifier v = zt_verifier_for_boolean_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_boolean_relation); assert(v.arg_infos[0].kind == ZT_BOOLEAN); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not a boolean") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_BOOLEAN); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not a boolean") == 0); } static void test_verify_boolean_relation(void) { zt_test t; /* passing == */ t = selftest_make_test(); assert(zt_verify_boolean_relation(&t, zt_pack_boolean(true, "L"), zt_pack_string("==", "=="), zt_pack_boolean(true, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_boolean_relation(&t, zt_pack_boolean(true, "L"), zt_pack_string("!=", "!="), zt_pack_boolean(false, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(!zt_verify_boolean_relation(&t, zt_pack_boolean(true, "L"), zt_pack_string("==", "=="), zt_pack_boolean(false, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L == R failed because true != false\n"); selftest_close_test(&t); t = selftest_make_test(); assert(!zt_verify_boolean_relation(&t, zt_pack_boolean(false, "L"), zt_pack_string("==", "=="), zt_pack_boolean(true, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L == R failed because false != true\n"); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(!zt_verify_boolean_relation(&t, zt_pack_boolean(false, "L"), zt_pack_string("!=", "!="), zt_pack_boolean(false, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R failed because false == false\n"); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(!zt_verify_boolean_relation(&t, zt_pack_boolean(true, "L"), zt_pack_string("~", "~"), zt_pack_boolean(true, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L ~ R uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(!zt_verify_boolean_relation(&t, zt_pack_boolean(true, "L"), zt_pack_string("!=", "=="), zt_pack_boolean(true, "R"))); selftest_stream_eq( t.stream, "file.c:13: L == R uses inconsistent relation !=\n"); selftest_close_test(&t); } /* verifier for rune relation. */ static void test_verifier_for_rune_relation(void) { zt_verifier v = zt_verifier_for_rune_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_rune_relation); assert(v.arg_infos[0].kind == ZT_RUNE); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not a rune") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_RUNE); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not a rune") == 0); } static void test_verify_rune_relation(void) { zt_test t; /* passing == */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("==", "=="), zt_pack_rune('a', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('\0', "L"), zt_pack_string("==", "=="), zt_pack_rune('\0', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('\xFF', "L"), zt_pack_string("==", "=="), zt_pack_rune('\xFF', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("!=", "!="), zt_pack_rune('b', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing <= */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("<=", "<="), zt_pack_rune('a', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("<=", "<="), zt_pack_rune('b', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('\0', "L"), zt_pack_string("<=", "<="), zt_pack_rune('\xFF', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing < */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("<", "<"), zt_pack_rune('b', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('\0', "L"), zt_pack_string("<", "<"), zt_pack_rune('\xFF', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing >= */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('\xFF', "L"), zt_pack_string(">=", ">="), zt_pack_rune('\xFF', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('b', "L"), zt_pack_string(">=", ">="), zt_pack_rune('a', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('b', "L"), zt_pack_string(">=", ">="), zt_pack_rune('b', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing > */ t = selftest_make_test(); assert(zt_verify_rune_relation(&t, zt_pack_rune('b', "L"), zt_pack_string(">", ">"), zt_pack_rune('a', "R"))); assert(zt_verify_rune_relation(&t, zt_pack_rune('\xFF', "L"), zt_pack_string(">", ">"), zt_pack_rune('a', "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("==", "=="), zt_pack_rune('b', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L == R failed because 'a' != 'b'\n"); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("!=", "!="), zt_pack_rune('a', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R failed because 'a' == 'a'\n"); selftest_close_test(&t); /* failing < */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('b', "L"), zt_pack_string("<", "<"), zt_pack_rune('a', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L < R failed because 'b' >= 'a'\n"); selftest_close_test(&t); /* failing <= */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('c', "L"), zt_pack_string("<=", "<="), zt_pack_rune('b', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L <= R failed because 'c' > 'b'\n"); selftest_close_test(&t); /* failing > */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string(">", ">"), zt_pack_rune('a', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L > R failed because 'a' <= 'a'\n"); selftest_close_test(&t); /* failing >= */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string(">=", ">="), zt_pack_rune('b', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L >= R failed because 'a' < 'b'\n"); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("~", "~"), zt_pack_rune('b', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L ~ R uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(!zt_verify_rune_relation(&t, zt_pack_rune('a', "L"), zt_pack_string("==", "!="), zt_pack_rune('b', "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R uses inconsistent relation ==\n"); selftest_close_test(&t); } /* verifier for integer relation. */ static void test_verifier_for_integer_relation(void) { zt_verifier v = zt_verifier_for_integer_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_integer_relation); assert(v.arg_infos[0].kind == ZT_INTMAX); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not an integer") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_INTMAX); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not an integer") == 0); } static void test_verify_integer_relation(void) { zt_test t; /* passing == */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("==", "=="), zt_pack_integer(1, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string("==", "=="), zt_pack_integer(INT_MAX, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MIN, "L"), zt_pack_string("==", "=="), zt_pack_integer(INT_MIN, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(0, "L"), zt_pack_string("!=", "!="), zt_pack_integer(-1, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MIN, "L"), zt_pack_string("!=", "!="), zt_pack_integer(INT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing <= */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(-1, "L"), zt_pack_string("<=", "<="), zt_pack_integer(-1, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(-1, "L"), zt_pack_string("<=", "<="), zt_pack_integer(0, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MIN, "L"), zt_pack_string("<=", "<="), zt_pack_integer(INT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing < */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(-1, "L"), zt_pack_string("<", "<"), zt_pack_integer(0, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(0, "L"), zt_pack_string("<", "<"), zt_pack_integer(1, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MIN, "L"), zt_pack_string("<", "<"), zt_pack_integer(0, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MIN, "L"), zt_pack_string("<", "<"), zt_pack_integer(INT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing >= */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string(">=", ">="), zt_pack_integer(INT_MAX, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string(">=", ">="), zt_pack_integer(INT_MIN, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string(">=", ">="), zt_pack_integer(INT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing > */ t = selftest_make_test(); assert(zt_verify_integer_relation(&t, zt_pack_integer(2, "L"), zt_pack_string(">", ">"), zt_pack_integer(1, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string(">", ">"), zt_pack_integer(INT_MIN, "R"))); assert(zt_verify_integer_relation(&t, zt_pack_integer(INT_MAX, "L"), zt_pack_string(">", ">"), zt_pack_integer(0, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("==", "=="), zt_pack_integer(2, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L == R failed because 1 != 2\n"); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("!=", "!="), zt_pack_integer(1, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R failed because 1 == 1\n"); selftest_close_test(&t); /* failing < */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("<", "<"), zt_pack_integer(1, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L < R failed because 1 >= 1\n"); selftest_close_test(&t); /* failing <= */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(3, "L"), zt_pack_string("<=", "<="), zt_pack_integer(2, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L <= R failed because 3 > 2\n"); selftest_close_test(&t); /* failing > */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string(">", ">"), zt_pack_integer(1, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L > R failed because 1 <= 1\n"); selftest_close_test(&t); /* failing >= */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string(">=", ">="), zt_pack_integer(2, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L >= R failed because 1 < 2\n"); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("~", "~"), zt_pack_integer(2, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L ~ R uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(!zt_verify_integer_relation(&t, zt_pack_integer(1, "L"), zt_pack_string("==", "!="), zt_pack_integer(2, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R uses inconsistent relation ==\n"); selftest_close_test(&t); } /* verifier for unsigned relation. */ static void test_verifier_for_unsigned_relation(void) { zt_verifier v = zt_verifier_for_unsigned_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_unsigned_relation); assert(v.arg_infos[0].kind == ZT_UINTMAX); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not an unsigned integer") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_UINTMAX); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not an unsigned integer") == 0); } static void test_verify_unsigned_relation(void) { zt_test t; /* passing == */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("==", "=="), zt_pack_unsigned(1U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(UINT_MAX, "L"), zt_pack_string("==", "=="), zt_pack_unsigned(UINT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string("!=", "!="), zt_pack_unsigned(1U, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing <= */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string("<=", "<="), zt_pack_unsigned(0U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string("<=", "<="), zt_pack_unsigned(UINT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing < */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string("<", "<"), zt_pack_unsigned(1U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string("<", "<"), zt_pack_unsigned(UINT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing >= */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(0U, "L"), zt_pack_string(">=", ">="), zt_pack_unsigned(0U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(UINT_MAX, "L"), zt_pack_string(">=", ">="), zt_pack_unsigned(0U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(UINT_MAX, "L"), zt_pack_string(">=", ">="), zt_pack_unsigned(UINT_MAX, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* passing > */ t = selftest_make_test(); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(2U, "L"), zt_pack_string(">", ">"), zt_pack_unsigned(1U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(UINT_MAX, "L"), zt_pack_string(">", ">"), zt_pack_unsigned(0U, "R"))); assert(zt_verify_unsigned_relation(&t, zt_pack_unsigned(UINT_MAX, "L"), zt_pack_string(">", ">"), zt_pack_unsigned(0U, "R"))); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("==", "=="), zt_pack_unsigned(2U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L == R failed because 1 != 2\n"); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("!=", "!="), zt_pack_unsigned(1U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R failed because 1 == 1\n"); selftest_close_test(&t); /* failing < */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("<", "<"), zt_pack_unsigned(1U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L < R failed because 1 >= 1\n"); selftest_close_test(&t); /* failing <= */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(3U, "L"), zt_pack_string("<=", "<="), zt_pack_unsigned(2U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L <= R failed because 3 > 2\n"); selftest_close_test(&t); /* failing > */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string(">", ">"), zt_pack_unsigned(1U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L > R failed because 1 <= 1\n"); selftest_close_test(&t); /* failing >= */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string(">=", ">="), zt_pack_unsigned(2U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L >= R failed because 1 < 2\n"); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("~", "~"), zt_pack_unsigned(2U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L ~ R uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(!zt_verify_unsigned_relation(&t, zt_pack_unsigned(1U, "L"), zt_pack_string("==", "!="), zt_pack_unsigned(2U, "R"))); selftest_stream_eq( t.stream, "file.c:13: assertion L != R uses inconsistent relation ==\n"); selftest_close_test(&t); } /* verifier for string relation. */ static void test_verifier_for_string_relation(void) { zt_verifier v = zt_verifier_for_string_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_string_relation); assert(v.arg_infos[0].kind == ZT_STRING); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not a string") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_STRING); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not a string") == 0); } static void test_verify_string_relation(void) { zt_test t; /* NULL on the left side */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string(NULL, "left"), zt_pack_string("==", "=="), zt_pack_string("abc", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left == right failed because left hand side is NULL\n"); selftest_close_test(&t); /* NULL on the right side */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("==", "=="), zt_pack_string(NULL, "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left == right failed because right hand side is NULL\n"); selftest_close_test(&t); /* passing == */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("==", "=="), zt_pack_string("abc", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("==", "=="), zt_pack_string("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left == right failed because \"abc\" != \"xyz\"\n"); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("!=", "!="), zt_pack_string("xyz", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("!=", "!="), zt_pack_string("abc", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left != right failed because \"abc\" == \"abc\"\n"); selftest_close_test(&t); /* passing < */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("<", "<"), zt_pack_string("xyz", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing < */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("<", "<"), zt_pack_string("abc", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left < right failed because \"abc\" >= \"abc\"\n"); selftest_close_test(&t); t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("xyz", "left"), zt_pack_string("<", "<"), zt_pack_string("abc", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left < right failed because \"xyz\" >= \"abc\"\n"); selftest_close_test(&t); /* passing <= */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("<=", "<="), zt_pack_string("xyz", "right")) == true); selftest_stream_eq(t.stream, ""); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("<=", "<="), zt_pack_string("abc", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing <= */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("xyz", "left"), zt_pack_string("<=", "<="), zt_pack_string("abc", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left <= right failed because \"xyz\" > \"abc\"\n"); selftest_close_test(&t); /* passing > */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("xyz", "left"), zt_pack_string(">", ">"), zt_pack_string("abc", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing > */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string(">", ">"), zt_pack_string("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left > right failed because \"abc\" <= \"xyz\"\n"); selftest_close_test(&t); /* passing >= */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("xyz", "left"), zt_pack_string(">=", ">="), zt_pack_string("abc", "right")) == true); selftest_stream_eq(t.stream, ""); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string(">=", ">="), zt_pack_string("abc", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing >= */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string(">=", ">="), zt_pack_string("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left >= right failed because \"abc\" < \"xyz\"\n"); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("~", "~"), zt_pack_string("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left ~ right uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(zt_verify_string_relation(&t, zt_pack_string("abc", "left"), zt_pack_string("==", "!="), zt_pack_string("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left != right uses inconsistent relation ==\n"); selftest_close_test(&t); } static void test_verifier_for_pointer_relation(void) { zt_verifier v = zt_verifier_for_pointer_relation(); assert(v.nargs == 3); assert(v.func.args3 == zt_verify_pointer_relation); assert(v.arg_infos[0].kind == ZT_POINTER); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "left hand side is not a pointer") == 0); assert(v.arg_infos[1].kind == ZT_STRING); assert(strcmp(v.arg_infos[1].kind_mismatch_msg, "relation is not a string") == 0); assert(v.arg_infos[2].kind == ZT_POINTER); assert(strcmp(v.arg_infos[2].kind_mismatch_msg, "right hand side is not a pointer") == 0); } static void test_verify_pointer_relation(void) { zt_test t; const char* non_null_ptr = ""; /* passing == */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer(NULL, "left"), zt_pack_string("==", "=="), zt_pack_pointer(NULL, "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing == */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer(NULL, "left"), zt_pack_string("==", "=="), zt_pack_pointer(non_null_ptr, "right")) == false); selftest_stream_eq_at( t.stream, __FILE__, __LINE__, "file.c:13: assertion left == right failed because %p != %p\n", NULL, non_null_ptr); selftest_close_test(&t); /* passing != */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer("abc", "left"), zt_pack_string("!=", "!="), zt_pack_pointer("xyz", "right")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing != */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer(non_null_ptr, "left"), zt_pack_string("!=", "!="), zt_pack_pointer(non_null_ptr, "right")) == false); selftest_stream_eq_at( t.stream, __FILE__, __LINE__, "file.c:13: assertion left != right failed because %p == %p\n", non_null_ptr, non_null_ptr); selftest_close_test(&t); /* unsupported relation */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer("abc", "left"), zt_pack_string("~", "~"), zt_pack_pointer("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left ~ right uses unsupported relation\n"); selftest_close_test(&t); /* inconsistent relation */ t = selftest_make_test(); assert(zt_verify_pointer_relation(&t, zt_pack_pointer("abc", "left"), zt_pack_string("==", "!="), zt_pack_pointer("xyz", "right")) == false); selftest_stream_eq( t.stream, "file.c:13: assertion left != right uses inconsistent relation ==\n"); selftest_close_test(&t); } /* verifier for null. */ static void test_verifier_for_null(void) { zt_verifier v = zt_verifier_for_null(); assert(v.nargs == 1); assert(v.func.args1 == zt_verify_null); assert(v.arg_infos[0].kind == ZT_POINTER); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "argument is not a pointer") == 0); assert(v.arg_infos[1].kind == ZT_NOTHING); assert(v.arg_infos[1].kind_mismatch_msg == NULL); assert(v.arg_infos[2].kind == ZT_NOTHING); assert(v.arg_infos[2].kind_mismatch_msg == NULL); } static void test_verify_null(void) { zt_test t; void* p; /* passing NULL */ p = NULL; t = selftest_make_test(); assert(zt_verify_null(&t, zt_pack_pointer(p, "p")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing non-NULL */ p = &p; t = selftest_make_test(); assert(zt_verify_null(&t, zt_pack_pointer(p, "p")) == false); selftest_stream_eq_at( t.stream, __FILE__, __LINE__, "file.c:13: assertion p == NULL failed because %p != NULL\n", p); selftest_close_test(&t); } /* verifier for not-null. */ static void test_verifier_for_not_null(void) { zt_verifier v = zt_verifier_for_not_null(); assert(v.nargs == 1); assert(v.func.args1 == zt_verify_not_null); assert(v.arg_infos[0].kind == ZT_POINTER); assert(strcmp(v.arg_infos[0].kind_mismatch_msg, "argument is not a pointer") == 0); assert(v.arg_infos[1].kind == ZT_NOTHING); assert(v.arg_infos[1].kind_mismatch_msg == NULL); assert(v.arg_infos[2].kind == ZT_NOTHING); assert(v.arg_infos[2].kind_mismatch_msg == NULL); } static void test_verify_not_null(void) { zt_test t; void* p; /* passing non-NULL */ p = &p; t = selftest_make_test(); assert(zt_verify_not_null(&t, zt_pack_pointer(p, "p")) == true); selftest_stream_eq(t.stream, ""); selftest_close_test(&t); /* failing NULL */ p = NULL; t = selftest_make_test(); assert(zt_verify_not_null(&t, zt_pack_pointer(p, "p")) == false); selftest_stream_eq(t.stream, "file.c:13: assertion p != NULL failed\n"); selftest_close_test(&t); } /* all the claim macros */ static void test_ZT_TRUE(void) { zt_claim claim = ZT_TRUE(1 > 0); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_true); assert(zt_value_kind_of(claim.args[0]) == ZT_BOOLEAN); assert(claim.args[0].as.boolean == true); assert(strcmp(zt_source_of(claim.args[0]), "1 > 0") == 0); } static void test_ZT_FALSE(void) { zt_claim claim = ZT_FALSE(0 < 1); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_false); assert(zt_value_kind_of(claim.args[0]) == ZT_BOOLEAN); assert(claim.args[0].as.boolean == true); assert(strcmp(zt_source_of(claim.args[0]), "0 < 1") == 0); } static void test_ZT_CMP_BOOL(void) { zt_claim claim = ZT_CMP_BOOL(true, ==, 1 == 1); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_boolean_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_BOOLEAN); assert(claim.args[0].as.boolean == true); assert(strcmp(zt_source_of(claim.args[0]), "true") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_BOOLEAN); assert(claim.args[2].as.boolean == true); assert(strcmp(zt_source_of(claim.args[2]), "1 == 1") == 0); } static void test_ZT_CMP_RUNE(void) { char a, b; zt_claim claim; a = 'a'; b = 'b'; claim = ZT_CMP_RUNE(a, ==, b); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_rune_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_RUNE); assert(claim.args[0].as.integer == 'a'); assert(strcmp(zt_source_of(claim.args[0]), "a") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_RUNE); assert(claim.args[2].as.integer == 'b'); assert(strcmp(zt_source_of(claim.args[2]), "b") == 0); } static void test_ZT_CMP_INT(void) { int a, b; zt_claim claim; a = 1; b = -2; claim = ZT_CMP_INT(a, ==, b); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_integer_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_INTMAX); assert(claim.args[0].as.integer == 1); assert(strcmp(zt_source_of(claim.args[0]), "a") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_INTMAX); assert(claim.args[2].as.integer == -2); assert(strcmp(zt_source_of(claim.args[2]), "b") == 0); } static inline zt_value zt_pack_legacy_integer(int value, const char* source) { zt_value v; v.as.integer = value; v.source = source; v.kind = ZT_INTEGER; return v; } static void test_zt_cmp_int_legacy(void) { int a, b; zt_claim claim; zt_value left, rel, right; a = 1; b = -2; left = zt_pack_legacy_integer(a, "a"); rel = zt_pack_string("==", "=="); right = zt_pack_legacy_integer(b, "b"); claim = zt_cmp_int(ZT_CURRENT_LOCATION(), left, rel, right); assert(left.kind == ZT_INTEGER); assert(right.kind == ZT_INTEGER); assert(claim.args[0].kind == ZT_INTMAX); assert(claim.args[2].kind == ZT_INTMAX); } static void test_ZT_CMP_UINT(void) { unsigned int a, b; zt_claim claim; a = 1; b = 2; claim = ZT_CMP_UINT(a, ==, b); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_unsigned_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_UINTMAX); assert(claim.args[0].as.unsigned_integer == 1); assert(strcmp(zt_source_of(claim.args[0]), "a") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_UINTMAX); assert(claim.args[2].as.unsigned_integer == 2); assert(strcmp(zt_source_of(claim.args[2]), "b") == 0); } static inline zt_value zt_pack_legacy_unsigned(unsigned value, const char* source) { zt_value v; v.source = source; v.as.unsigned_integer = value; v.kind = ZT_UNSIGNED; return v; } static void test_zt_cmp_uint_legacy(void) { unsigned int a, b; zt_claim claim; zt_value left, rel, right; a = 1; b = 2; left = zt_pack_legacy_unsigned(a, "a"); rel = zt_pack_string("==", "=="); right = zt_pack_legacy_unsigned(b, "b"); claim = zt_cmp_uint(ZT_CURRENT_LOCATION(), left, rel, right); assert(left.kind == ZT_UNSIGNED); assert(right.kind == ZT_UNSIGNED); assert(claim.args[0].kind == ZT_UINTMAX); assert(claim.args[2].kind == ZT_UINTMAX); } static void test_ZT_CMP_CSTR(void) { const char *a, *b; zt_claim claim; a = "foo"; b = "bar"; claim = ZT_CMP_CSTR(a, ==, b); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_string_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_STRING); assert(strcmp(claim.args[0].as.string, "foo") == 0); assert(strcmp(zt_source_of(claim.args[0]), "a") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_STRING); assert(strcmp(claim.args[2].as.string, "bar") == 0); assert(strcmp(zt_source_of(claim.args[2]), "b") == 0); } static void test_ZT_CMP_PTR(void) { int life = 42, not_life = 13; int *a, *b; zt_claim claim; a = &life; b = ¬_life; claim = ZT_CMP_PTR(a, ==, b); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_pointer_relation); assert(zt_value_kind_of(claim.args[0]) == ZT_POINTER); assert(claim.args[0].as.pointer == &life); assert(strcmp(zt_source_of(claim.args[0]), "a") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_STRING); assert(strcmp(claim.args[1].as.string, "==") == 0); assert(strcmp(zt_source_of(claim.args[1]), "==") == 0); assert(zt_value_kind_of(claim.args[2]) == ZT_POINTER); assert(claim.args[2].as.pointer == ¬_life); assert(strcmp(zt_source_of(claim.args[2]), "b") == 0); } static void test_ZT_NULL(void) { void* p = NULL; zt_claim claim = ZT_NULL(p); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_null); assert(zt_value_kind_of(claim.args[0]) == ZT_POINTER); assert(claim.args[0].as.pointer == NULL); assert(strcmp(zt_source_of(claim.args[0]), "p") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_NOTHING); assert(zt_source_of(claim.args[1]) == NULL); assert(zt_value_kind_of(claim.args[2]) == ZT_NOTHING); assert(zt_source_of(claim.args[2]) == NULL); } static void test_ZT_NOT_NULL(void) { void* p = &p; zt_claim claim = ZT_NOT_NULL(p); assert(strcmp(claim.location.fname, __FILE__) == 0); assert(claim.location.lineno == __LINE__ - 2); assert(claim.make_verifier == zt_verifier_for_not_null); assert(zt_value_kind_of(claim.args[0]) == ZT_POINTER); assert(claim.args[0].as.pointer == &p); assert(strcmp(zt_source_of(claim.args[0]), "p") == 0); assert(zt_value_kind_of(claim.args[1]) == ZT_NOTHING); assert(zt_source_of(claim.args[1]) == NULL); assert(zt_value_kind_of(claim.args[2]) == ZT_NOTHING); assert(zt_source_of(claim.args[2]) == NULL); } static void test_quote_string(void) { FILE* f = selftest_temporary_file(); zt_quote_string(f, "abc \n\r\t\v\b double:\" single:' hex:\x07 123"); selftest_stream_eq(f, "\"abc \\n\\r\\t\\v\\b double:\\\" single:' hex:\\0x07 123\""); fclose(f); } static void test_quote_rune(void) { FILE* f = selftest_temporary_file(); zt_quote_rune(f, '"'); selftest_stream_eq(f, "'\"'"); fclose(f); f = selftest_temporary_file(); zt_quote_rune(f, '\''); selftest_stream_eq(f, "'\\\''"); fclose(f); } static bool selftest_stub_nested_test_case_visited; static void selftest_stub_nested_test_case(zt_t t) { assert(t != NULL); selftest_stub_nested_test_case_visited = true; } static bool selftest_stub_nested_test_suite_visited; static void selftest_stub_nested_test_suite(zt_visitor visitor) { assert(visitor.id != NULL); assert(visitor.vtab != NULL); selftest_stub_nested_test_suite_visited = true; ZT_VISIT_TEST_CASE(visitor, selftest_stub_nested_test_case); } static bool selftest_stub_test_case_visited; static void selftest_stub_test_case(zt_t t) { assert(t != NULL); selftest_stub_test_case_visited = true; } static bool selftest_stub_test_suite_visited; static void selftest_stub_test_suite(zt_visitor visitor) { assert(visitor.id != NULL); assert(visitor.vtab != NULL); selftest_stub_test_suite_visited = true; ZT_VISIT_TEST_CASE(visitor, selftest_stub_test_case); ZT_VISIT_TEST_SUITE(visitor, selftest_stub_nested_test_suite); } static void test_lister_visitor_visit_suite(void) { FILE* f = selftest_temporary_file(); zt_test_lister lister; zt_visitor visitor; memset(&lister, 0, sizeof lister); lister.stream = f; visitor = zt_visitor_from_test_lister(&lister); selftest_stub_nested_test_suite_visited = false; selftest_stub_nested_test_case_visited = false; selftest_stub_test_suite_visited = false; selftest_stub_test_case_visited = false; ZT_VISIT_TEST_SUITE(visitor, selftest_stub_test_suite); /* test suites are visited, test cases are not. */ assert(selftest_stub_test_suite_visited == true); assert(selftest_stub_nested_test_suite_visited == true); assert(selftest_stub_test_case_visited == false); assert(selftest_stub_nested_test_case_visited == false); selftest_stream_eq( f, "" "- selftest_stub_test_suite\n" " - selftest_stub_test_case\n" " - selftest_stub_nested_test_suite\n" " - selftest_stub_nested_test_case\n"); fclose(f); } static void test_runner_visitor_visit_suite(void) { FILE* stream_out = selftest_temporary_file(); FILE* stream_err = selftest_temporary_file(); zt_test_runner runner; zt_visitor visitor; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; visitor = zt_visitor_from_test_runner(&runner); selftest_stub_nested_test_suite_visited = false; selftest_stub_nested_test_case_visited = false; selftest_stub_test_suite_visited = false; selftest_stub_test_case_visited = false; ZT_VISIT_TEST_SUITE(visitor, selftest_stub_test_suite); /* test suites and test cases are all visited. */ assert(selftest_stub_test_suite_visited == true); assert(selftest_stub_nested_test_suite_visited == true); assert(selftest_stub_test_case_visited == true); assert(selftest_stub_nested_test_case_visited == true); selftest_stream_eq(stream_out, ""); selftest_stream_eq(stream_err, ""); fclose(stream_out); fclose(stream_err); } static bool selftest_case_pending_visited; static void selftest_case_pending(zt_t t) { selftest_case_pending_visited = true; assert(t->outcome == ZT_PENDING); } static void test_runner_visitor_visit_case_outcome_pending(void) { FILE* stream_out = selftest_temporary_file(); FILE* stream_err = selftest_temporary_file(); zt_test_runner runner; zt_visitor visitor; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; visitor = zt_visitor_from_test_runner(&runner); selftest_case_pending_visited = false; ZT_VISIT_TEST_CASE(visitor, selftest_case_pending); assert(selftest_case_pending_visited == true); selftest_stream_eq(stream_out, ""); selftest_stream_eq(stream_err, ""); assert(runner.num_passed == 1); assert(runner.num_failed == 0); fclose(stream_out); fclose(stream_err); } static bool selftest_case_passed_visited; static void selftest_case_passed(zt_t t) { selftest_case_passed_visited = true; t->outcome = ZT_PASSED; } static void test_runner_visitor_visit_case_outcome_passed(void) { FILE* stream_out = selftest_temporary_file(); FILE* stream_err = selftest_temporary_file(); zt_test_runner runner; zt_visitor visitor; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; visitor = zt_visitor_from_test_runner(&runner); selftest_case_passed_visited = false; ZT_VISIT_TEST_CASE(visitor, selftest_case_passed); assert(selftest_case_passed_visited == true); selftest_stream_eq(stream_out, ""); selftest_stream_eq(stream_err, ""); assert(runner.num_passed == 1); assert(runner.num_failed == 0); fclose(stream_out); fclose(stream_err); } static bool selftest_case_failed_visited; static void selftest_case_failed(zt_t t) { selftest_case_failed_visited = true; t->outcome = ZT_FAILED; } static void test_runner_visitor_visit_case_outcome_failed(void) { FILE* stream_out = selftest_temporary_file(); FILE* stream_err = selftest_temporary_file(); zt_test_runner runner; zt_visitor visitor; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; visitor = zt_visitor_from_test_runner(&runner); selftest_case_failed_visited = false; ZT_VISIT_TEST_CASE(visitor, selftest_case_failed); assert(selftest_case_failed_visited == true); selftest_stream_eq(stream_out, ""); selftest_stream_eq(stream_err, ""); assert(runner.num_passed == 0); assert(runner.num_failed == 1); fclose(stream_out); fclose(stream_err); } static bool selftest_case_bogus_outcome_visited; static void selftest_case_bogus_outcome(zt_t t) { selftest_case_bogus_outcome_visited = true; t->outcome = 42; } static void test_runner_visitor_visit_case_outcome_bogus(void) { FILE* stream_out = selftest_temporary_file(); FILE* stream_err = selftest_temporary_file(); zt_test_runner runner; zt_visitor visitor; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; visitor = zt_visitor_from_test_runner(&runner); selftest_case_bogus_outcome_visited = false; ZT_VISIT_TEST_CASE(visitor, selftest_case_bogus_outcome); assert(selftest_case_bogus_outcome_visited == true); selftest_stream_eq(stream_out, ""); selftest_stream_eq(stream_err, "- selftest_case_bogus_outcome - unexpected outcome code 42\n"); assert(runner.num_passed == 0); assert(runner.num_failed == 1); fclose(stream_out); fclose(stream_err); } static void test_main_listing_tests(void) { char* test_argv[] = { "a.out", "-l" }; int exit_code; zt_mock_stdout = selftest_temporary_file(); zt_mock_stderr = selftest_temporary_file(); exit_code = zt_main(2, test_argv, NULL, selftest_stub_test_suite); assert(exit_code == 0); selftest_stream_eq( zt_mock_stdout, "" "- selftest_stub_test_case\n" "- selftest_stub_nested_test_suite\n" " - selftest_stub_nested_test_case\n"); selftest_stream_eq( zt_mock_stderr, ""); fclose(zt_mock_stdout); fclose(zt_mock_stderr); zt_mock_stdout = NULL; zt_mock_stderr = NULL; } static void selftest_passing_check(zt_t t) { zt_check(t, ZT_TRUE(1)); zt_check(t, ZT_CMP_INT(1, ==, 1)); } static void selftest_failing_check(zt_t t) { zt_check(t, ZT_TRUE(0)); zt_check(t, ZT_CMP_INT(1, !=, 1)); } static void selftest_passing_assert(zt_t t) { zt_assert(t, ZT_TRUE(1)); } static void selftest_failing_assert(zt_t t) { zt_assert(t, ZT_TRUE(0)); } static void selftest_empty_suite(ZT_UNUSED zt_visitor v) { (void)v; } static void selftest_passing_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, selftest_passing_check); ZT_VISIT_TEST_CASE(v, selftest_passing_assert); ZT_VISIT_TEST_SUITE(v, selftest_empty_suite); } static void selftest_failing_suite(zt_visitor v) { ZT_VISIT_TEST_CASE(v, selftest_failing_check); ZT_VISIT_TEST_CASE(v, selftest_failing_assert); ZT_VISIT_TEST_SUITE(v, selftest_empty_suite); } static void test_main_running_passing_tests(void) { char* test_argv[] = { "a.out" }; int exit_code; zt_mock_stdout = selftest_temporary_file(); zt_mock_stderr = selftest_temporary_file(); exit_code = zt_main(1, test_argv, NULL, selftest_passing_suite); assert(exit_code == EXIT_SUCCESS); selftest_stream_eq(zt_mock_stdout, ""); selftest_stream_eq(zt_mock_stderr, ""); fclose(zt_mock_stdout); fclose(zt_mock_stderr); zt_mock_stdout = NULL; zt_mock_stderr = NULL; } static void test_main_verbosely_running_passing_tests(void) { char* test_argv[] = { "a.out", "-v" }; int exit_code; zt_mock_stdout = selftest_temporary_file(); zt_mock_stderr = selftest_temporary_file(); exit_code = zt_main(2, test_argv, NULL, selftest_passing_suite); assert(exit_code == EXIT_SUCCESS); selftest_stream_eq( zt_mock_stdout, "- selftest_passing_check ok\n" "- selftest_passing_assert ok\n" "+ selftest_empty_suite\n"); selftest_stream_eq(zt_mock_stderr, ""); fclose(zt_mock_stdout); fclose(zt_mock_stderr); zt_mock_stdout = NULL; zt_mock_stderr = NULL; } static void test_main_verbosely_running_failing_tests(void) { char* test_argv[] = { "a.out", "-v" }; int exit_code; zt_mock_stdout = selftest_temporary_file(); zt_mock_stderr = selftest_temporary_file(); exit_code = zt_main(2, test_argv, NULL, selftest_failing_suite); assert(exit_code == EXIT_FAILURE); selftest_stream_eq( zt_mock_stdout, "- selftest_failing_check failed\n" "- selftest_failing_assert failed\n" "+ selftest_empty_suite\n"); selftest_stream_eq_at( zt_mock_stderr, __FILE__, __LINE__, "%s:%d: assertion failed because 0 is false\n" "%s:%d: assertion 1 != 1 failed because 1 == 1\n" "%s:%d: assertion failed because 0 is false\n", __FILE__, __LINE__ - 93, __FILE__, __LINE__ - 92, __FILE__, __LINE__ - 82); fclose(zt_mock_stdout); fclose(zt_mock_stderr); zt_mock_stdout = NULL; zt_mock_stderr = NULL; } static void selftest_mixed_suite(zt_visitor v) { ZT_VISIT_TEST_SUITE(v, selftest_passing_suite); ZT_VISIT_TEST_SUITE(v, selftest_failing_suite); ZT_VISIT_TEST_CASE(v, selftest_case_bogus_outcome); } static void test_main_verbosely_running_mixed_tests(void) { char* test_argv[] = { "a.out", "-v" }; int exit_code; zt_mock_stdout = selftest_temporary_file(); zt_mock_stderr = selftest_temporary_file(); exit_code = zt_main(2, test_argv, NULL, selftest_mixed_suite); assert(exit_code == EXIT_FAILURE); selftest_stream_eq( zt_mock_stdout, "+ selftest_passing_suite\n" " - selftest_passing_check ok\n" " - selftest_passing_assert ok\n" " + selftest_empty_suite\n" "+ selftest_failing_suite\n" " - selftest_failing_check failed\n" " - selftest_failing_assert failed\n" " + selftest_empty_suite\n" "- selftest_case_bogus_outcome outcome code 42 (?)\n"); /* ignore stderr as we just care about the -v output. */ fclose(zt_mock_stdout); fclose(zt_mock_stderr); zt_mock_stdout = NULL; zt_mock_stderr = NULL; } static void test_stdout_stderr(void) { assert(zt_stdout() == stdout); assert(zt_stderr() == stderr); } int main(ZT_UNUSED int argc, ZT_UNUSED char** argv, ZT_UNUSED char** envp) { (void)argc; (void)argv; (void)envp; test_MAJOR_MINOR_VERSION(); test_pack_boolean(); test_pack_rune(); test_pack_integer(); test_pack_unsigned(); test_pack_string(); test_pack_pointer(); test_promote_value(); test_find_binary_relation(); test_invert_binary_relation(); test_binary_relation_as_text(); test_boolean_as_text(); test_verify_claim0(); test_verify_claim1(); test_verify_claim2(); test_verify_claim3(); test_verify_bogus_claim4(); test_verify_mismatch_claim1of1(); test_verify_mismatch_claim1of2(); test_verify_mismatch_claim2of2(); test_verify_mismatch_claim1of3(); test_verify_mismatch_claim2of3(); test_verify_mismatch_claim3of3(); test_verifier_for_true(); test_verify_true(); test_verifier_for_false(); test_verify_false(); test_verifier_for_boolean_relation(); test_verify_boolean_relation(); test_verifier_for_rune_relation(); test_verify_rune_relation(); test_verifier_for_integer_relation(); test_verify_integer_relation(); test_verifier_for_unsigned_relation(); test_verify_unsigned_relation(); test_verifier_for_string_relation(); test_verify_string_relation(); test_verifier_for_pointer_relation(); test_verify_pointer_relation(); test_verifier_for_null(); test_verify_null(); test_verifier_for_not_null(); test_verify_not_null(); test_ZT_TRUE(); test_ZT_FALSE(); test_ZT_CMP_BOOL(); test_ZT_CMP_RUNE(); test_ZT_CMP_INT(); test_zt_cmp_int_legacy(); test_ZT_CMP_UINT(); test_zt_cmp_uint_legacy(); test_ZT_CMP_CSTR(); test_ZT_CMP_PTR(); test_ZT_NULL(); test_ZT_NOT_NULL(); test_quote_string(); test_quote_rune(); test_lister_visitor_visit_suite(); test_runner_visitor_visit_suite(); test_runner_visitor_visit_case_outcome_pending(); test_runner_visitor_visit_case_outcome_passed(); test_runner_visitor_visit_case_outcome_failed(); test_runner_visitor_visit_case_outcome_bogus(); test_main_listing_tests(); test_main_running_passing_tests(); test_main_verbosely_running_passing_tests(); test_main_verbosely_running_failing_tests(); test_main_verbosely_running_mixed_tests(); test_stdout_stderr(); printf("libzt self-test successful\n"); return 0; } libzt_0.3.1/zt.c0000664000175000017500000011051313675422322012241 0ustar zygazyga/* This is an open source non-commercial project. Dear PVS-Studio, please check it. * PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com * * Copyright 2019-2020 Zygmunt Krynicki. * * This file is part of libzt. * * Libzt is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * Libzt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Libzt. If not, see . */ #include "zt.h" #include #include #include #include #include #include #include #if !defined(__GNUC__) && !defined(__clang__) #define ZT_UNUSED #define ZT_FORMAT_PRINTF(a, b) #else #define ZT_UNUSED __attribute__((unused)) #define ZT_FORMAT_PRINTF(a, b) __attribute__((format(printf, a, b))) #endif static void zt_logv(FILE* stream, zt_location loc, const char* fmt, va_list ap); static void zt_logf(FILE* stream, zt_location loc, const char* fmt, ...) ZT_FORMAT_PRINTF(3, 4); static void zt_logv(FILE* stream, zt_location loc, const char* fmt, va_list ap) { if (stream != NULL) { if (loc.fname != NULL && loc.lineno != 0) { fprintf(stream, "%s:%d: ", loc.fname, loc.lineno); } vfprintf(stream, fmt, ap); fprintf(stream, "\n"); } } static void zt_logf(FILE* stream, zt_location loc, const char* fmt, ...) { va_list ap; va_start(ap, fmt); zt_logv(stream, loc, fmt, ap); va_end(ap); } static inline zt_value_kind zt_value_kind_of(zt_value value) { return value.kind; } static inline const char* zt_source_of(zt_value value) { return value.source; } zt_value zt_pack_rune(int value, const char* source) { zt_value v; /* Rune is meant to be an unsigned value but for practicality the pack helper is defined to take an integer. Negative values can arise when a non-7-bit byte is encoded in the string and the architecture uses signed characters. To counter this treat negative values as if they were created by sign-extending a signed character and cast to unsigned character. */ if (value < 0) { value &= 0xFF; } v.as.rune = value; v.source = source; v.kind = ZT_RUNE; return v; } static void zt_promote_value(zt_value* v) { switch (v->kind) { case ZT_INTEGER: v->as.intmax = v->as.integer; v->kind = ZT_INTMAX; break; case ZT_UNSIGNED: v->as.uintmax = v->as.unsigned_integer; v->kind = ZT_UINTMAX; break; default: break; } } /** zt_binary_relation describes one of typical binary relations. */ typedef enum zt_binary_relation { ZT_REL_INVALID, ZT_REL_EQ, ZT_REL_NE, ZT_REL_LE, ZT_REL_GE, ZT_REL_LT, ZT_REL_GT } zt_binary_relation; /** zt_find_binary_relation finds a binary relation given operator name. */ static zt_binary_relation zt_find_binary_relation(const char* rel) { if (strcmp(rel, "==") == 0) { return ZT_REL_EQ; } if (strcmp(rel, "!=") == 0) { return ZT_REL_NE; } if (strcmp(rel, "<=") == 0) { return ZT_REL_LE; } if (strcmp(rel, ">=") == 0) { return ZT_REL_GE; } if (strcmp(rel, "<") == 0) { return ZT_REL_LT; } if (strcmp(rel, ">") == 0) { return ZT_REL_GT; } return ZT_REL_INVALID; } /** zt_invert_binary_relation returns the inverted relation. */ static zt_binary_relation zt_invert_binary_relation(zt_binary_relation rel) { switch (rel) { default: case ZT_REL_INVALID: return ZT_REL_INVALID; case ZT_REL_EQ: return ZT_REL_NE; case ZT_REL_NE: return ZT_REL_EQ; case ZT_REL_LE: return ZT_REL_GT; case ZT_REL_GE: return ZT_REL_LT; case ZT_REL_LT: return ZT_REL_GE; case ZT_REL_GT: return ZT_REL_LE; } } /** zt_binary_relation_as_text returns text representation of a relation. */ static const char* zt_binary_relation_as_text(zt_binary_relation rel) { switch (rel) { default: case ZT_REL_INVALID: return "invalid"; case ZT_REL_EQ: return "=="; case ZT_REL_NE: return "!="; case ZT_REL_LE: return "<="; case ZT_REL_GE: return ">="; case ZT_REL_LT: return "<"; case ZT_REL_GT: return ">"; } } static bool zt_relation_inconsistent(zt_value rel) { return strcmp(rel.as.string, zt_source_of(rel)) != 0; } static void zt_quote_rune_inner(FILE* stream, int c, int quote) { switch (c) { case '\'': fputs(quote != '\'' ? "'" : "\\'", stream); break; case '"': fputs(quote != '\"' ? "\"" : "\\\"", stream); break; case '\n': fputs("\\n", stream); break; case '\r': fputs("\\r", stream); break; case '\t': fputs("\\t", stream); break; case '\v': fputs("\\v", stream); break; case '\b': fputs("\\b", stream); break; default: if (isprint(c)) { fputc(c, stream); } else { fprintf(stream, "\\%#04x", c); } break; } } static void zt_quote_rune(FILE* stream, int c) { fputc('\'', stream); zt_quote_rune_inner(stream, c, '\''); fputc('\'', stream); } static void zt_quote_string(FILE* stream, const char* str) { fputs("\"", stream); for (;;) { int c = *str; str++; if (c == '\0') { break; } zt_quote_rune_inner(stream, c, '"'); } fputs("\"", stream); } /** zt_outcome describes outcome of a single test. */ typedef enum zt_outcome { ZT_PENDING, ZT_PASSED, ZT_FAILED } zt_outcome; typedef struct zt_test { #if defined(_WIN32) || defined(__WATCOMC__) jmp_buf jump_buffer; #else sigjmp_buf jump_buffer; #endif const char* name; FILE* stream; zt_location location; /** location of the last verified claim. */ zt_outcome outcome; } zt_test; typedef struct zt_visitor_vtab { void (*visit_case)(void*, zt_test_case_func, const char* name); void (*visit_suite)(void*, zt_test_suite_func, const char* name); } zt_visitor_vtab; typedef struct zt_test_lister { FILE* stream; int nesting; } zt_test_lister; typedef struct zt_test_runner { FILE* stream_out; FILE* stream_err; int nesting; int num_passed; int num_failed; bool verbose; } zt_test_runner; /** zt_verify0_func is a type of verification function with no arguments. */ typedef bool (*zt_verify0_func)(struct zt_test*); /** zt_verify1_func is a type of verification function with one argument. */ typedef bool (*zt_verify1_func)(struct zt_test*, zt_value); /** zt_verify2_func is a type of verification function with two arguments. */ typedef bool (*zt_verify2_func)(struct zt_test*, zt_value, zt_value); /** zt_verify3_func is a type of verification function with three arguments. */ typedef bool (*zt_verify3_func)(struct zt_test*, zt_value, zt_value, zt_value); /** * zt_arg_info describes expected kind of arguments for verification * functions. * * Because verification functions use value variants as arguments there is an * additional layer that describes the desired type of each value. If the * actual value is of another kind a kind mismatch message contains useful * explanation about what is necessary. **/ typedef struct zt_arg_info { const char* kind_mismatch_msg; /**< failure message on kind mismatch. */ zt_value_kind kind; /**< expected kind of argument value. */ } zt_arg_info; /** * zt_verifier describes a verification function for a given claim. * * Verifiers are used to check if some property holds. For example, _not null_, * _integer value greater or equal than_, _has string prefix_ are all * verifiers. * * Verifiers are like functions, they don't contain specific values yet, those * are provided by the claim type below. **/ typedef struct zt_verifier { union { zt_verify0_func args0; /**< function pointer if nargs==0 */ zt_verify1_func args1; /**< function pointer if nargs==1 */ zt_verify2_func args2; /**< function pointer if nargs==2 */ zt_verify3_func args3; /**< function pointer if nargs==3 */ } func; /**< union storing typed function pointer. */ size_t nargs; /**< number of arguments of the referenced function. */ zt_arg_info arg_infos[3]; /**< arguments for the referenced function. */ } zt_verifier; void zt_visit_test_suite(zt_visitor v, zt_test_suite_func func, const char* name) { v.vtab->visit_suite(v.id, func, name); } void zt_visit_test_case(zt_visitor v, zt_test_case_func func, const char* name) { v.vtab->visit_case(v.id, func, name); } /* Lister visitor */ static zt_visitor zt_visitor_from_test_lister(zt_test_lister* lister); static void zt_test_lister__visit_suite(void* id, zt_test_suite_func func, const char* name) { zt_test_lister* lister = (zt_test_lister*)id; (void)func; fprintf(lister->stream, "%*c %s\n", lister->nesting * 3, '-', name); lister->nesting++; func(zt_visitor_from_test_lister(lister)); lister->nesting--; } static void zt_test_lister__visit_case(void* id, ZT_UNUSED zt_test_case_func func, const char* name) { zt_test_lister* lister = (zt_test_lister*)id; (void)func; fprintf(lister->stream, "%*c %s\n", lister->nesting * 3, '-', name); } static const zt_visitor_vtab zt_test_lister__visitor_vtab = { /* .visit_case = */ zt_test_lister__visit_case, /* .visit_suite = */ zt_test_lister__visit_suite, }; static zt_visitor zt_visitor_from_test_lister(zt_test_lister* lister) { zt_visitor visitor; memset(&visitor, 0, sizeof visitor); visitor.id = lister; visitor.vtab = &zt_test_lister__visitor_vtab; return visitor; } /** zt_list_tests_from lists tests from given suite to a given file. */ static void zt_list_tests_from(FILE* stream, zt_test_suite_func tsuite) { zt_test_lister lister; memset(&lister, 0, sizeof lister); lister.stream = stream; tsuite(zt_visitor_from_test_lister(&lister)); } /* Runner visitor */ static zt_visitor zt_visitor_from_test_runner(zt_test_runner* runner); static void zt_runner_visitor__visit_suite(void* id, zt_test_suite_func func, const char* name) { zt_test_runner* runner = (zt_test_runner*)id; if (runner->verbose && runner->stream_out) { fprintf(runner->stream_out, "%*c %s\n", runner->nesting * 3, '+', name); } runner->nesting++; func(zt_visitor_from_test_runner(runner)); runner->nesting--; } static void zt_runner_visitor__visit_case(void* id, zt_test_case_func func, const char* name) { zt_test_runner* runner = (zt_test_runner*)id; zt_test test; int jump_result; memset(&test, 0, sizeof test); test.stream = runner->stream_err; test.outcome = ZT_PENDING; #if defined(_WIN32) || defined(__WATCOMC__) jump_result = setjmp(test.jump_buffer); #else jump_result = sigsetjmp(test.jump_buffer, 1); #endif if (jump_result == 0) { if (runner->verbose && runner->stream_out) { fprintf(runner->stream_out, "%*c %s", runner->nesting * 3, '-', name); } func(&test); } switch (test.outcome) { case ZT_PENDING: case ZT_PASSED: if (runner->verbose && runner->stream_out) { fprintf(runner->stream_out, " ok\n"); } runner->num_passed++; break; case ZT_FAILED: if (runner->verbose && runner->stream_out) { fprintf(runner->stream_out, " failed\n"); } runner->num_failed++; break; default: if (runner->verbose && runner->stream_out) { fprintf(runner->stream_out, " outcome code %d (?)\n", test.outcome); } if (runner->stream_err) { fprintf(runner->stream_err, "%*c %s - unexpected outcome code %d\n", runner->nesting * 3, '-', name, test.outcome); } runner->num_failed++; break; } } static const zt_visitor_vtab zt_test_runner__visitor_vtab = { /* .visit_case = */ zt_runner_visitor__visit_case, /* .visit_suite = */ zt_runner_visitor__visit_suite, }; static zt_visitor zt_visitor_from_test_runner(zt_test_runner* runner) { zt_visitor visitor; visitor.id = runner; visitor.vtab = &zt_test_runner__visitor_vtab; return visitor; } /** zt_run_tests_from runs tests from given suite and returns the outcome. */ static zt_outcome zt_run_tests_from(FILE* stream_out, FILE* stream_err, bool verbose, void (*test_suite_func)(zt_visitor)) { zt_test_runner runner; memset(&runner, 0, sizeof runner); runner.stream_out = stream_out; runner.stream_err = stream_err; runner.verbose = verbose; test_suite_func(zt_visitor_from_test_runner(&runner)); if (runner.num_failed > 0) { return ZT_FAILED; } return ZT_PASSED; } /* claim verifier and test failure */ static bool zt_verify_claim(zt_test* test, const zt_claim* claim) { zt_verifier verifier = claim->make_verifier(); test->location = claim->location; switch (verifier.nargs) { case 0: return verifier.func.args0(test); case 1: if (zt_value_kind_of(claim->args[0]) != verifier.arg_infos[0].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[0].kind_mismatch_msg); return false; } return verifier.func.args1(test, claim->args[0]); case 2: if (zt_value_kind_of(claim->args[0]) != verifier.arg_infos[0].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[0].kind_mismatch_msg); return false; } if (zt_value_kind_of(claim->args[1]) != verifier.arg_infos[1].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[1].kind_mismatch_msg); return false; } return verifier.func.args2(test, claim->args[0], claim->args[1]); case 3: if (zt_value_kind_of(claim->args[0]) != verifier.arg_infos[0].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[0].kind_mismatch_msg); return false; } if (zt_value_kind_of(claim->args[1]) != verifier.arg_infos[1].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[1].kind_mismatch_msg); return false; } if (zt_value_kind_of(claim->args[2]) != verifier.arg_infos[2].kind) { zt_logf(test->stream, test->location, "%s", verifier.arg_infos[2].kind_mismatch_msg); return false; } return verifier.func.args3(test, claim->args[0], claim->args[1], claim->args[2]); default: zt_logf(test->stream, test->location, "unsupported number of arguments: %" PRIuMAX, (uintmax_t)verifier.nargs); return false; } } /* check and assert */ void zt_check(zt_test* test, zt_claim claim) { if (!zt_verify_claim(test, &claim)) { test->outcome = ZT_FAILED; } } void zt_assert(zt_test* test, zt_claim claim) { if (!zt_verify_claim(test, &claim)) { test->outcome = ZT_FAILED; #if defined(_WIN32) || defined(__WATCOMC__) longjmp(test->jump_buffer, 1); #else siglongjmp(test->jump_buffer, 1); #endif /* TODO: in C++ mode throw an exception. */ } } /* main */ #ifdef ZT_SELF_TEST_BUILD static FILE* zt_mock_stdout = NULL; static FILE* zt_mock_stderr = NULL; #endif static FILE* zt_stdout(void) { #ifdef ZT_SELF_TEST_BUILD if (zt_mock_stdout != NULL) { return zt_mock_stdout; } #endif return stdout; } static FILE* zt_stderr(void) { #ifdef ZT_SELF_TEST_BUILD if (zt_mock_stderr != NULL) { return zt_mock_stderr; } #endif return stderr; } int zt_main(int argc, char** argv, ZT_UNUSED char** envp, zt_test_suite_func tsuite) { (void)envp; if (argc == 2 && strcmp(argv[1], "-l") == 0) { zt_list_tests_from(zt_stdout(), tsuite); return EXIT_SUCCESS; } else { bool verbose = argc == 2 && strcmp(argv[1], "-v") == 0; return zt_run_tests_from( zt_stdout(), zt_stderr(), verbose, tsuite) == ZT_PASSED ? EXIT_SUCCESS : EXIT_FAILURE; } } /* verifiers and verification functions */ static bool zt_verify_true(zt_test* test, zt_value value) { if (value.as.boolean) { return true; } zt_logf(test->stream, test->location, "assertion failed because %s is false", zt_source_of(value)); return false; } static zt_verifier zt_verifier_for_true(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args1 = zt_verify_true; verifier.nargs = 1; verifier.arg_infos[0].kind = ZT_BOOLEAN; verifier.arg_infos[0].kind_mismatch_msg = "value is not a boolean"; return verifier; } zt_claim zt_true(zt_location location, zt_value value) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_true; claim.args[0] = value; return claim; } static bool zt_verify_false(zt_test* test, zt_value value) { if (!value.as.boolean) { return true; } zt_logf(test->stream, test->location, "assertion failed because %s is true", zt_source_of(value)); return false; } static zt_verifier zt_verifier_for_false(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args1 = zt_verify_false; verifier.nargs = 1; verifier.arg_infos[0].kind = ZT_BOOLEAN; verifier.arg_infos[0].kind_mismatch_msg = "value is not a boolean"; return verifier; } zt_claim zt_false(zt_location location, zt_value value) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_false; claim.args[0] = value; return claim; } static const char* zt_boolean_as_text(bool b) { return b ? "true" : "false"; } static bool zt_verify_boolean_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "%s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); switch (bin_rel) { case ZT_REL_EQ: if (left.as.boolean == right.as.boolean) { return true; } break; case ZT_REL_NE: if (left.as.boolean != right.as.boolean) { return true; } break; default: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), rel.as.string, zt_source_of(right)); return false; } zt_logf(test->stream, test->location, "assertion %s %s %s failed because %s %s %s", zt_source_of(left), zt_binary_relation_as_text(bin_rel), zt_source_of(right), zt_boolean_as_text(left.as.boolean), zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel)), zt_boolean_as_text(right.as.boolean)); return false; } static zt_verifier zt_verifier_for_boolean_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_boolean_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_BOOLEAN; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not a boolean"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_BOOLEAN; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not a boolean"; return verifier; } zt_claim zt_cmp_bool(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_boolean_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; return claim; } /** * zt_verify_rune_relation verifies a relation between two runes. * * Relation is one of: ==, !=, <=, =>, < and >. **/ static bool zt_verify_rune_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "assertion %s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); switch (bin_rel) { case ZT_REL_EQ: if (left.as.rune == right.as.rune) { return true; } break; case ZT_REL_NE: if (left.as.rune != right.as.rune) { return true; } break; case ZT_REL_LE: if (left.as.rune <= right.as.rune) { return true; } break; case ZT_REL_GE: if (left.as.rune >= right.as.rune) { return true; } break; case ZT_REL_LT: if (left.as.rune < right.as.rune) { return true; } break; case ZT_REL_GT: if (left.as.rune > right.as.rune) { return true; } break; case ZT_REL_INVALID: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), zt_source_of(rel), zt_source_of(right)); return false; } if (test->stream) { const zt_location loc = test->location; FILE* stream = test->stream; fprintf(stream, "%s:%d: ", loc.fname, loc.lineno); fprintf(stream, "assertion %s %s %s failed because ", zt_source_of(left), zt_binary_relation_as_text(bin_rel), zt_source_of(right)); zt_quote_rune(stream, left.as.rune); fprintf(stream, " %s ", zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel))); zt_quote_rune(stream, right.as.rune); fprintf(stream, "\n"); } return false; } /** * zt_verifier_for_rune_relation returns a verifier for rune relations. * * The returned verifier is used to implement ZT_CMP_RUNE(). **/ static zt_verifier zt_verifier_for_rune_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_rune_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_RUNE; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not a rune"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_RUNE; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not a rune"; return verifier; } zt_claim zt_cmp_rune(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_rune_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; return claim; } /** * zt_verify_integer_relation verifies a relation between two signed integers. * * Relation is one of: ==, !=, <=, =>, < and >. **/ static bool zt_verify_integer_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "assertion %s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); switch (bin_rel) { case ZT_REL_EQ: if (left.as.intmax == right.as.intmax) { return true; } break; case ZT_REL_NE: if (left.as.intmax != right.as.intmax) { return true; } break; case ZT_REL_LE: if (left.as.intmax <= right.as.intmax) { return true; } break; case ZT_REL_GE: if (left.as.intmax >= right.as.intmax) { return true; } break; case ZT_REL_LT: if (left.as.intmax < right.as.intmax) { return true; } break; case ZT_REL_GT: if (left.as.intmax > right.as.intmax) { return true; } break; case ZT_REL_INVALID: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), zt_source_of(rel), zt_source_of(right)); return false; } zt_logf(test->stream, test->location, "assertion %s %s %s failed because %jd %s %jd", zt_source_of(left), zt_source_of(rel), zt_source_of(right), left.as.intmax, zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel)), right.as.intmax); return false; } /** * zt_verifier_for_integer_relation returns a verifier for integer relations. * * The returned verifier is used to implement ZT_CMP_INT(). **/ static zt_verifier zt_verifier_for_integer_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_integer_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_INTMAX; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not an integer"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_INTMAX; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not an integer"; return verifier; } zt_claim zt_cmp_int(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_integer_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; zt_promote_value(&claim.args[0]); zt_promote_value(&claim.args[2]); return claim; } /** * zt_verify_unsigned_relation verifies a relation between two unsigned values. * * Relation is one of: ==, !=, <=, =>, < and >. **/ static bool zt_verify_unsigned_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "assertion %s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); switch (bin_rel) { case ZT_REL_EQ: if (left.as.uintmax == right.as.uintmax) { return true; } break; case ZT_REL_NE: if (left.as.uintmax != right.as.uintmax) { return true; } break; case ZT_REL_LE: if (left.as.uintmax <= right.as.uintmax) { return true; } break; case ZT_REL_GE: if (left.as.uintmax >= right.as.uintmax) { return true; } break; case ZT_REL_LT: if (left.as.uintmax < right.as.uintmax) { return true; } break; case ZT_REL_GT: if (left.as.uintmax > right.as.uintmax) { return true; } break; case ZT_REL_INVALID: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), rel.as.string, zt_source_of(right)); return false; } zt_logf(test->stream, test->location, "assertion %s %s %s failed because %ju %s %ju", zt_source_of(left), rel.as.string, zt_source_of(right), left.as.uintmax, zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel)), right.as.uintmax); return false; } /** * zt_verifier_for_unsigned_relation returns a verifier for unsigned relations. * * The returned verifier is used to implement ZT_CMP_UINT(). */ static zt_verifier zt_verifier_for_unsigned_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_unsigned_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_UINTMAX; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not an unsigned integer"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_UINTMAX; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not an unsigned integer"; return verifier; } zt_claim zt_cmp_uint(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_unsigned_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; zt_promote_value(&claim.args[0]); zt_promote_value(&claim.args[2]); return claim; } static bool zt_verify_string_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; int cmp; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "assertion %s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); if (left.as.string == NULL) { zt_logf(test->stream, test->location, "assertion %s %s %s failed because left hand side is NULL", zt_source_of(left), rel.as.string, zt_source_of(right)); return false; } if (right.as.string == NULL) { zt_logf(test->stream, test->location, "assertion %s %s %s failed because right hand side is NULL", zt_source_of(left), rel.as.string, zt_source_of(right)); return false; } cmp = strcmp(left.as.string, right.as.string); switch (bin_rel) { case ZT_REL_EQ: if (cmp == 0) { return true; } break; case ZT_REL_NE: if (cmp != 0) { return true; } break; case ZT_REL_LE: if (cmp <= 0) { return true; } break; case ZT_REL_GE: if (cmp >= 0) { return true; } break; case ZT_REL_LT: if (cmp < 0) { return true; } break; case ZT_REL_GT: if (cmp > 0) { return true; } break; case ZT_REL_INVALID: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), zt_source_of(rel), zt_source_of(right)); return false; } if (test->stream) { const zt_location loc = test->location; FILE* stream = test->stream; fprintf(stream, "%s:%d: ", loc.fname, loc.lineno); fprintf(stream, "assertion %s %s %s failed because ", zt_source_of(left), rel.as.string, zt_source_of(right)); zt_quote_string(stream, left.as.string); fprintf(stream, " %s ", zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel))); zt_quote_string(stream, right.as.string); fprintf(stream, "\n"); } return false; } /** * zt_verifier_for_string_relation returns a verifier for string relations. * * The returned verifier is used to implement ZT_CMP_CSTR(). */ static zt_verifier zt_verifier_for_string_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_string_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_STRING; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not a string"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_STRING; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not a string"; return verifier; } zt_claim zt_cmp_cstr(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_string_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; return claim; } static bool zt_verify_null(zt_test* test, zt_value value) { if (value.as.pointer == NULL) { return true; } zt_logf(test->stream, test->location, "assertion %s == NULL failed because %p != NULL", zt_source_of(value), value.as.pointer); return false; } static zt_verifier zt_verifier_for_null(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args1 = zt_verify_null; verifier.nargs = 1; verifier.arg_infos[0].kind = ZT_POINTER; verifier.arg_infos[0].kind_mismatch_msg = "argument is not a pointer"; return verifier; } zt_claim zt_null(zt_location location, zt_value value) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_null; claim.args[0] = value; return claim; } static bool zt_verify_not_null(zt_test* test, zt_value value) { if (value.as.pointer != NULL) { return true; } zt_logf(test->stream, test->location, "assertion %s != NULL failed", zt_source_of(value)); return false; } static zt_verifier zt_verifier_for_not_null(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args1 = zt_verify_not_null; verifier.nargs = 1; verifier.arg_infos[0].kind = ZT_POINTER; verifier.arg_infos[0].kind_mismatch_msg = "argument is not a pointer"; return verifier; } zt_claim zt_not_null(zt_location location, zt_value value) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_not_null; claim.args[0] = value; return claim; } static bool zt_verify_pointer_relation(zt_test* test, zt_value left, zt_value rel, zt_value right) { zt_binary_relation bin_rel; if (zt_relation_inconsistent(rel)) { zt_logf(test->stream, test->location, "assertion %s %s %s uses inconsistent relation %s", zt_source_of(left), zt_source_of(rel), zt_source_of(right), rel.as.string); return false; } bin_rel = zt_find_binary_relation(rel.as.string); switch (bin_rel) { case ZT_REL_EQ: if (left.as.pointer == right.as.pointer) { return true; } break; case ZT_REL_NE: if (left.as.pointer != right.as.pointer) { return true; } break; default: zt_logf(test->stream, test->location, "assertion %s %s %s uses unsupported relation", zt_source_of(left), zt_source_of(rel), zt_source_of(right)); return false; } zt_logf(test->stream, test->location, "assertion %s %s %s failed because %p %s %p", zt_source_of(left), rel.as.string, zt_source_of(right), left.as.pointer, zt_binary_relation_as_text(zt_invert_binary_relation(bin_rel)), right.as.pointer); return false; } static zt_verifier zt_verifier_for_pointer_relation(void) { zt_verifier verifier; memset(&verifier, 0, sizeof verifier); verifier.func.args3 = zt_verify_pointer_relation; verifier.nargs = 3; verifier.arg_infos[0].kind = ZT_POINTER; verifier.arg_infos[0].kind_mismatch_msg = "left hand side is not a pointer"; verifier.arg_infos[1].kind = ZT_STRING; verifier.arg_infos[1].kind_mismatch_msg = "relation is not a string"; verifier.arg_infos[2].kind = ZT_POINTER; verifier.arg_infos[2].kind_mismatch_msg = "right hand side is not a pointer"; return verifier; } zt_claim zt_cmp_ptr(zt_location location, zt_value left, zt_value rel, zt_value right) { zt_claim claim; memset(&claim, 0, sizeof claim); claim.location = location; claim.make_verifier = zt_verifier_for_pointer_relation; claim.args[0] = left; claim.args[1] = rel; claim.args[2] = right; return claim; } libzt_0.3.1/zt.h0000664000175000017500000001506213675422322012251 0ustar zygazyga/* Copyright 2019-2020 Zygmunt Krynicki. * * This file is part of libzt. * * Libzt is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License. * * Libzt 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with Libzt. If not, see . */ #pragma once #ifdef __cplusplus extern "C" { #endif #include #include #include #include #define ZT_MAJOR_VERSION 0 #define ZT_MINOR_VERSION 3 struct zt_test; typedef struct zt_test* zt_t; struct zt_visitor_vtab; typedef struct zt_visitor { void* id; const struct zt_visitor_vtab* vtab; } zt_visitor; typedef void (*zt_test_case_func)(zt_t); typedef void (*zt_test_suite_func)(zt_visitor); int zt_main(int argc, char** argv, char** envp, zt_test_suite_func tsuite); void zt_visit_test_suite(zt_visitor v, zt_test_suite_func func, const char* name); void zt_visit_test_case(zt_visitor v, zt_test_case_func func, const char* name); #define ZT_VISIT_TEST_SUITE(v, tsuite) zt_visit_test_suite(v, tsuite, #tsuite) #define ZT_VISIT_TEST_CASE(v, tcase) zt_visit_test_case(v, tcase, #tcase) typedef enum zt_value_kind { ZT_NOTHING, ZT_BOOLEAN, ZT_RUNE, /* Rune is a more practical character type. */ ZT_INTEGER, /* Deprecated. Promoted to ZT_INTMAX */ ZT_UNSIGNED, /* Deprecated. Promoted to ZT_UINTMAX */ ZT_STRING, ZT_POINTER, ZT_INTMAX, ZT_UINTMAX } zt_value_kind; typedef struct zt_value { union { bool boolean; int rune; int integer; unsigned unsigned_integer; const char* string; const void* pointer; intmax_t intmax; uintmax_t uintmax; } as; const char* source; zt_value_kind kind; } zt_value; static inline zt_value zt_pack_nothing(void) { zt_value v; zt_value_kind kind = ZT_NOTHING; v.source = NULL; v.kind = kind; return v; } static inline zt_value zt_pack_boolean(bool value, const char* source) { zt_value v; v.as.boolean = value; v.source = source; v.kind = ZT_BOOLEAN; return v; } zt_value zt_pack_rune(int value, const char* source); static inline zt_value zt_pack_integer(intmax_t value, const char* source) { zt_value v; v.as.intmax = value; v.source = source; v.kind = ZT_INTMAX; return v; } static inline zt_value zt_pack_unsigned(uintmax_t value, const char* source) { zt_value v; v.source = source; v.as.uintmax = value; v.kind = ZT_UINTMAX; return v; } static inline zt_value zt_pack_string(const char* value, const char* source) { zt_value v; v.as.string = value; v.source = source; v.kind = ZT_STRING; return v; } static inline zt_value zt_pack_pointer(const void* value, const char* source) { zt_value v; v.as.pointer = value; v.source = source; v.kind = ZT_POINTER; return v; } typedef struct zt_location { const char* fname; int lineno; } zt_location; static inline zt_location zt_location_at(const char* fname, int lineno) { zt_location loc; loc.fname = fname; loc.lineno = lineno; return loc; } #define ZT_CURRENT_LOCATION() zt_location_at(__FILE__, __LINE__) struct zt_verifier; typedef struct zt_claim { struct zt_verifier (*make_verifier)(void); zt_value args[3]; zt_location location; } zt_claim; void zt_check(zt_t test, zt_claim claim); void zt_assert(zt_t test, zt_claim claim); zt_claim zt_true(zt_location location, zt_value value); zt_claim zt_false(zt_location location, zt_value value); zt_claim zt_cmp_bool(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_cmp_rune(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_cmp_int(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_cmp_ptr(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_cmp_uint(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_cmp_cstr(zt_location location, zt_value left, zt_value rel, zt_value right); zt_claim zt_null(zt_location location, zt_value value); zt_claim zt_not_null(zt_location location, zt_value value); #define ZT_TRUE(value) \ zt_true( \ ZT_CURRENT_LOCATION(), \ zt_pack_boolean((value), #value)) #define ZT_FALSE(value) \ zt_false( \ ZT_CURRENT_LOCATION(), \ zt_pack_boolean((value), #value)) #define ZT_CMP_BOOL(left, rel, right) \ zt_cmp_bool( \ ZT_CURRENT_LOCATION(), \ zt_pack_boolean((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_boolean((right), #right)) #define ZT_CMP_RUNE(left, rel, right) \ zt_cmp_rune( \ ZT_CURRENT_LOCATION(), \ zt_pack_rune((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_rune((right), #right)) #define ZT_CMP_INT(left, rel, right) \ zt_cmp_int( \ ZT_CURRENT_LOCATION(), \ zt_pack_integer((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_integer((right), #right)) #define ZT_CMP_UINT(left, rel, right) \ zt_cmp_uint( \ ZT_CURRENT_LOCATION(), \ zt_pack_unsigned((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_unsigned((right), #right)) #define ZT_CMP_CSTR(left, rel, right) \ zt_cmp_cstr( \ ZT_CURRENT_LOCATION(), \ zt_pack_string((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_string((right), #right)) #define ZT_CMP_PTR(left, rel, right) \ zt_cmp_ptr( \ ZT_CURRENT_LOCATION(), \ zt_pack_pointer((left), #left), \ zt_pack_string(#rel, #rel), \ zt_pack_pointer((right), #right)) #define ZT_NULL(value) \ zt_null( \ ZT_CURRENT_LOCATION(), \ zt_pack_pointer((value), #value)) #define ZT_NOT_NULL(value) \ zt_not_null( \ ZT_CURRENT_LOCATION(), \ zt_pack_pointer((value), #value)) #ifdef __cplusplus } #endif