diff --git a/.gitignore b/.gitignore index ab9977f..db97466 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,8 @@ /m4/libtool.m4 /m4/lt*.m4 /missing +/tests/package.m4 +/tests/testsuite Makefile.in # The build tree diff --git a/INSTALL.md b/INSTALL.md index 651038a..a97b610 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -51,7 +51,6 @@ Requirements Optionally: - GNU Texinfo, for building the user manual - - DejaGNU, for running tests Installation diff --git a/configure.ac b/configure.ac index a38e055..1d5a09d 100644 --- a/configure.ac +++ b/configure.ac @@ -12,8 +12,10 @@ AC_INIT([bookmarkfs], [0.1.0], [bug-bookmarkfs@nongnu.org]) AC_CONFIG_SRCDIR([bookmarkfs.pc.in]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_TESTDIR([tests]) AM_INIT_AUTOMAKE([1.14 foreign no-installinfo no-installman]) AM_EXTRA_RECURSIVE_TARGETS([install-man]) +AM_MISSING_PROG([AUTOM4TE], [autom4te]) PKG_PROG_PKG_CONFIG([0.27]) LT_PREREQ([2.4.3]) LT_INIT([disable-static dlopen]) @@ -236,7 +238,7 @@ AC_CONFIG_FILES([ Makefile doc/Makefile src/Makefile - tests/Makefile + tests/Makefile tests/atlocal bookmarkfs.pc ]) AC_OUTPUT diff --git a/tests/Makefile.am b/tests/Makefile.am index b628b66..4994068 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -6,4 +6,42 @@ # this notice are preserved. This file is offered as-is, without any warranty. # -AUTOMAKE_OPTIONS = dejagnu +EXTRA_DIST = package.m4 testsuite.at $(TESTSUITE) $(TESTSUITE_AT_) + +TESTSUITE_AT_ = lib_hash.at lib_prng.at + +# Helper programs for testing + +check_PROGRAMS = check-bookmarkfs-util + +check_bookmarkfs_util_CPPFLAGS = -I$(top_srcdir)/src +check_bookmarkfs_util_LDADD = $(top_builddir)/src/libbookmarkfs_util.la +check_bookmarkfs_util_SOURCES = check_lib.c + +# Autotest setup + +AUTOTEST = $(AUTOM4TE) --language=autotest +TESTSUITE = $(srcdir)/testsuite + +$(srcdir)/package.m4: $(top_srcdir)/configure.ac + { \ + echo '# Signature of the current package.'; \ + echo 'm4_define([AT_PACKAGE_NAME], [@PACKAGE_NAME@])'; \ + echo 'm4_define([AT_PACKAGE_TARNAME], [@PACKAGE_TARNAME@])'; \ + echo 'm4_define([AT_PACKAGE_VERSION], [@PACKAGE_VERSION@])'; \ + echo 'm4_define([AT_PACKAGE_STRING], [@PACKAGE_STRING@])'; \ + echo 'm4_define([AT_PACKAGE_BUGREPORT], [@PACKAGE_BUGREPORT@])'; \ + } >'$(srcdir)/package.m4' + +$(TESTSUITE): $(srcdir)/testsuite.at $(srcdir)/package.m4 $(TESTSUITE_AT_) + $(AUTOTEST) -I '$(srcdir)' -o $@.tmp $@.at + mv $@.tmp $@ + +check-local: atconfig atlocal $(TESTSUITE) + $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) + +installcheck-local: atconfig atlocal $(TESTSUITE) + $(SHELL) '$(TESTSUITE)' $(TESTSUITEFLAGS) AUTOTEST_PATH='$(bindir)' + +clean-local: + test ! -f '$(TESTSUITE)' || $(SHELL) '$(TESTSUITE)' --clean diff --git a/tests/atlocal.in b/tests/atlocal.in new file mode 100644 index 0000000..c8f2eb3 --- /dev/null +++ b/tests/atlocal.in @@ -0,0 +1,17 @@ +# +# Copyright (C) 2025 CismonX +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty, provided the copyright notice and +# this notice are preserved. This file is offered as-is, without any warranty. +# + +rand_u64_hex() { + echo $(od -vAn -N8 -tx8 /dev/urandom | tr -d ' ') +} + +rand_base64() { + # The `base64` utility is not specified by POSIX, + # but present in GNU Coreutils, BusyBox and FreeBSD base system. + echo $(head -c$1 /dev/urandom | base64 -w0) +} diff --git a/tests/check_lib.c b/tests/check_lib.c new file mode 100644 index 0000000..715eef8 --- /dev/null +++ b/tests/check_lib.c @@ -0,0 +1,143 @@ +/** + * bookmarkfs/tests/check_lib.c + * ---- + * + * Copyright (C) 2025 CismonX + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#include "frontend_util.h" +#include "hash.h" +#include "prng.h" + +// Forward declaration start +static int dispatch_subcmds (int, char *[]); +static size_t hash_cb (void *, void const **); +static int subcmd_hash (int, char *[]); +static int subcmd_prng (int, char *[]); +// Forward declaration end + +static int +dispatch_subcmds ( + int argc, + char *argv[] +) { + if (--argc < 1) { + return -1; + } + char const *cmd = *(++argv); + + int status = -1; + if (0 == strcmp("hash", cmd)) { + status = subcmd_hash(argc, argv); + } else if (0 == strcmp("prng", cmd)) { + status = subcmd_prng(argc, argv); + } + return status; +} + +static size_t +hash_cb ( + void *UNUSED_VAR(user_data), + void const **buf_ptr +) { + static char buf[4096]; + + *buf_ptr = buf; + return fread(buf, 1, sizeof(buf), stdin); +} + +static int +subcmd_hash ( + int argc, + char *argv[] +) { + unsigned long long seed = 0; + + getopt_foreach(argc, argv, ":s:") { + case 's': + seed = strtoull(optarg, NULL, 16); + break; + + default: + return -1; + } + + hash_seed(seed); + printf("%016" PRIx64 "\n", hash_digestcb(hash_cb, NULL)); + return 0; +} + +static int +subcmd_prng ( + int argc, + char *argv[] +) { + static uint64_t seed[4]; + int cnt = 0; + int n = 0; + + getopt_foreach(argc, argv, ":s:n:") { + case 's': + cnt = sscanf(optarg, + "%16" SCNx64 "%16" SCNx64 "%16" SCNx64 "%16" SCNx64, + &seed[0], &seed[1], &seed[2], &seed[3]); + if (cnt != 4) { + return -1; + } + break; + + case 'n': + n = atoi(optarg); + break; + + default: + return -1; + } + + if (0 != prng_seed(cnt == 0 ? NULL : seed)) { + return -1; + } + for (; n > 0; --n) { + printf("%016" PRIx64 "\n", prng_rand()); + } + return 0; +} + +int +main ( + int argc, + char *argv[] +) { + int status = EXIT_FAILURE; + if (0 != dispatch_subcmds(argc, argv)) { + goto end; + } + status = EXIT_SUCCESS; + + end: + return status; +} diff --git a/tests/lib_hash.at b/tests/lib_hash.at new file mode 100644 index 0000000..1457b68 --- /dev/null +++ b/tests/lib_hash.at @@ -0,0 +1,31 @@ +dnl +dnl Copyright (C) 2025 CismonX +dnl +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty, +dnl provided the copyright notice and this notice are preserved. +dnl This file is offered as-is, without any warranty. +dnl + +AT_SETUP([util lib: hash function]) +AT_KEYWORDS([lib hash]) + +AT_CHECK([ + calc_digest() { + echo "$2" | check-bookmarkfs-util hash -s$1 + } + + seed=$(rand_u64_hex) + input=$(rand_base64 300) + + hash_1=$(calc_digest $seed $input) + hash_2=$(calc_digest $seed $input) + hash_3=$(calc_digest $seed $input) + + # Given the same seed and input, the digest should be consistent. + if test "$hash_1" != "$hash_2" -o "$hash_2" != "$hash_3"; then + exit 99 + fi +], , [ignore]) + +AT_CLEANUP diff --git a/tests/lib_prng.at b/tests/lib_prng.at new file mode 100644 index 0000000..9453e49 --- /dev/null +++ b/tests/lib_prng.at @@ -0,0 +1,37 @@ +dnl +dnl Copyright (C) 2025 CismonX +dnl +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty, +dnl provided the copyright notice and this notice are preserved. +dnl This file is offered as-is, without any warranty. +dnl + +AT_SETUP([util lib: prng]) +AT_KEYWORDS([lib prng]) + +AT_CHECK([ + gen_prng() { + check-bookmarkfs-util prng -s$1 -n$2 + } + + seed=$(rand_u64_hex)$(rand_u64_hex)$(rand_u64_hex)$(rand_u64_hex) + count=32 + + prng_1=$(gen_prng $seed $count) + prng_2=$(gen_prng $seed $count) + prng_3=$(gen_prng $seed $count) + + # Given the same seed, the results should be consistent. + if test "$prng_1" != "$prng_2" -o "$prng_2" != "$prng_3"; then + exit 99 + fi + + # Bad PRNG if we're getting duplicates too soon. + uniq_count=$(echo "$prng_1" | sort | uniq | wc -l) + if test $uniq_count -ne $count; then + exit 99 + fi +], , [ignore]) + +AT_CLEANUP diff --git a/tests/testsuite.at b/tests/testsuite.at new file mode 100644 index 0000000..1e3d3a8 --- /dev/null +++ b/tests/testsuite.at @@ -0,0 +1,14 @@ +dnl +dnl Copyright (C) 2025 CismonX +dnl +dnl Copying and distribution of this file, with or without modification, +dnl are permitted in any medium without royalty, +dnl provided the copyright notice and this notice are preserved. +dnl This file is offered as-is, without any warranty. +dnl + +AT_INIT + +AT_BANNER([The Utility Library]) +m4_include([lib_hash.at]) +m4_include([lib_prng.at])