From e1ffe56793be79dfea203121ecafff3d0baa29ba Mon Sep 17 00:00:00 2001 From: Qyriad Date: Thu, 21 Mar 2024 15:38:11 -0600 Subject: [PATCH] meson: implement unit tests Unit tests can be run with `meson test -C build --suite check`. `--suite check` is optional, as right now that's the only test suite, but when functional tests are added those will be in a separate suite. Change-Id: I7f22f1cde4b489b3cdb5f9a36a544f0c409fcc1f --- meson.build | 30 +++++- meson.options | 12 +++ package.nix | 4 + tests/unit/meson.build | 207 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 251 insertions(+), 2 deletions(-) create mode 100644 tests/unit/meson.build diff --git a/meson.build b/meson.build index 73c13582b..66a30f716 100644 --- a/meson.build +++ b/meson.build @@ -16,6 +16,8 @@ # that become part of the final Nix command (things like `src/nix-build/*.cc`). # # Finally, src/nix/meson.build defines the Nix command itself, relying on all prior meson files. +# +# Unit tests are setup in tests/unit/meson.build, under the test suite "check". project('lix', 'cpp', version : run_command('bash', '-c', 'echo -n $(cat ./.version)$VERSION_SUFFIX', check : true).stdout().strip(), @@ -56,6 +58,20 @@ foreach optname : path_opts endif endforeach + +enable_tests = get_option('enable-tests') + +tests_args = [] + +if get_option('tests-color') + tests_args += '--gtest_color=yes' +endif + +if get_option('tests-brief') + tests_args += '--gtest_brief=1' +endif + + cxx = meson.get_compiler('cpp') host_system = host_machine.cpu_family() + '-' + host_machine.system() @@ -170,10 +186,17 @@ deps += editline lowdown = dependency('lowdown', version : '>=0.9.0', required : true) deps += lowdown -rapidcheck = dependency('rapidcheck', required : false) +# HACK(Qyriad): rapidcheck's pkg-config doesn't include the libs lol +rapidcheck_meson = dependency('rapidcheck', required : enable_tests) +rapidcheck = declare_dependency(dependencies : rapidcheck_meson, link_args : ['-lrapidcheck']) deps += rapidcheck -gtest = dependency('gtest', required : false) +gtest = [ + dependency('gtest', required : enable_tests), + dependency('gtest_main', required : enable_tests), + dependency('gmock', required : enable_tests), + dependency('gmock_main', required : enable_tests), +] deps += gtest # @@ -285,3 +308,6 @@ if cxx.get_linker_id() in ['ld.bfd', 'ld.gold'] endif subdir('src') +if enable_tests + subdir('tests/unit') +endif diff --git a/meson.options b/meson.options index 50b1d8553..4e8323689 100644 --- a/meson.options +++ b/meson.options @@ -19,6 +19,18 @@ option('sandbox-shell', type : 'string', value : 'busybox', description : 'path to a statically-linked shell to use as /bin/sh in sandboxes (usually busybox)', ) +option('enable-tests', type : 'boolean', value : true, + description : 'whether to enable tests or not (requires rapidcheck and gtest)', +) + +option('tests-color', type : 'boolean', value : true, + description : 'set to false to disable color output in gtest', +) + +option('tests-brief', type : 'boolean', value : false, + description : 'set to true for shorter tests output', +) + option('store-dir', type : 'string', value : '/nix/store', description : 'path of the Nix store', ) diff --git a/package.nix b/package.nix index 4b4c35731..1392bbe62 100644 --- a/package.nix +++ b/package.nix @@ -251,6 +251,10 @@ in stdenv.mkDerivation (finalAttrs: { doCheck = true; + mesonCheckFlags = lib.optionals (buildWithMeson || forDevShell) [ + "--suite=check" + ]; + installFlags = "sysconfdir=$(out)/etc"; postInstall = lib.optionalString (!finalAttrs.dontBuild) '' diff --git a/tests/unit/meson.build b/tests/unit/meson.build new file mode 100644 index 000000000..a2e882098 --- /dev/null +++ b/tests/unit/meson.build @@ -0,0 +1,207 @@ +# NOTE(Qyriad): This file is one big slab of boilerplate. +# Lix's current unit test organization is scattered and entagled. +# Each of the test-support libraries could theoretically be a somewhat self-contained +# subdir(), but literally nothing else can. Each of the tests have dependencies on other +# test support libraries, and so do their support libraries. +# Each of the tests have dependencies on their own andother test support libraries, +# and so do their support libraries, and they have entangled dependencies on Lix's mainline +# lib* targets as well. +# The only boilerplate reduction I really could do here is throw everything in big nested dictionaries +# and dynamically generate and refer to targets based on abstracted specs, but without user-defined +# functions, the result would be way less readable than just a bit of copypasta. +# It's only ~200 lines; better to just refactor the tests themselves which we'll want to do anyway. + +libutil_test_support_sources = files( + 'libutil-support/tests/cli-literate-parser.cc', + 'libutil-support/tests/hash.cc', + 'libutil-support/tests/terminal-code-eater.cc', +) +libutil_test_support = library( + 'nixutil-test-support', + libutil_test_support_sources, + dependencies : [ + liblixutil, + # TODO(Qyriad): libutil tests really should not depend on libexpr... + liblixexpr, + rapidcheck, + boehm, + ], + include_directories : include_directories('libutil-support', '../../src'), +) +liblixutil_test_support = declare_dependency( + include_directories : include_directories('libutil-support'), + link_with : libutil_test_support, +) + +libutil_tests_sources = files( + 'libutil/canon-path.cc', + 'libutil/chunked-vector.cc', + 'libutil/closure.cc', + 'libutil/compression.cc', + 'libutil/config.cc', + 'libutil/git.cc', + 'libutil/hash.cc', + 'libutil/hilite.cc', + 'libutil/json-utils.cc', + 'libutil/logging.cc', + 'libutil/lru-cache.cc', + 'libutil/pool.cc', + 'libutil/references.cc', + 'libutil/suggestions.cc', + 'libutil/tests.cc', + 'libutil/url.cc', + 'libutil/xml-writer.cc', +) + +libutil_tester = executable( + 'libnixutil-tests', + libutil_tests_sources, + dependencies : [ + rapidcheck, + gtest, + boehm, + liblixutil, + liblixexpr, + liblixutil_test_support, + ], +) + +test( + 'libutil-unit-tests', + libutil_tester, + args : tests_args, + env : { + '_NIX_TEST_UNIT_DATA': meson.project_source_root() / 'tests/unit/libutil/data', + }, + suite : 'check', + protocol : 'gtest', + verbose : true, +) + +libstore_test_support_sources = files( + 'libstore-support/tests/derived-path.cc', + 'libstore-support/tests/outputs-spec.cc', + 'libstore-support/tests/path.cc', +) + +libstore_test_support = library( + 'nixstore-test-support', + libstore_test_support_sources, + dependencies : [ + liblixutil_test_support, + liblixutil, + liblixstore, + rapidcheck, + boehm, + ], + include_directories : include_directories( + 'libstore-support', + ), +) +liblixstore_test_support = declare_dependency( + include_directories : include_directories('libstore-support'), + link_with : libstore_test_support, +) + +libstore_tests_sources = files( + 'libstore/common-protocol.cc', + 'libstore/derivation.cc', + 'libstore/derived-path.cc', + 'libstore/downstream-placeholder.cc', + 'libstore/machines.cc', + 'libstore/nar-info-disk-cache.cc', + 'libstore/outputs-spec.cc', + 'libstore/path.cc', + 'libstore/references.cc', + 'libstore/serve-protocol.cc', + 'libstore/worker-protocol.cc', +) + +libstore_tester = executable( + 'libnixstore-tests', + libstore_tests_sources, + dependencies : [ + liblixstore_test_support, + liblixutil_test_support, + liblixstore, + liblixutil, + rapidcheck, + gtest, + ], +) + +test( + 'libstore-unit-tests', + libstore_tester, + args : tests_args, + env : { + '_NIX_TEST_UNIT_DATA': meson.project_source_root() / 'tests/unit/libstore/data', + }, + suite : 'check', + workdir : meson.project_source_root(), + protocol : 'gtest', + verbose : true, +) + +libexpr_test_support_sources = files( + 'libexpr-support/tests/value/context.cc', +) + +libexpr_test_support = library( + 'nixexpr-test-support', + libexpr_test_support_sources, + dependencies : [ + liblixstore_test_support, + liblixstore, + liblixutil, + liblixexpr, + rapidcheck, + ], + include_directories : include_directories( + 'libexpr-support', + ), +) +liblixexpr_test_support = declare_dependency( + include_directories : include_directories('libexpr-support'), + link_with : libexpr_test_support, +) + +libexpr_tests_sources = files( + 'libexpr/derived-path.cc', + 'libexpr/error_traces.cc', + 'libexpr/flakeref.cc', + 'libexpr/json.cc', + 'libexpr/primops.cc', + 'libexpr/search-path.cc', + 'libexpr/trivial.cc', + 'libexpr/value/context.cc', + 'libexpr/value/print.cc', +) + +libexpr_tester = executable( + 'libnixexpr-tests', + libexpr_tests_sources, + dependencies : [ + liblixexpr_test_support, + liblixstore_test_support, + liblixstore, + liblixutil, + liblixexpr, + liblixfetchers, + rapidcheck, + boehm, + gtest, + ], +) + +test( + 'libexpr-unit-tests', + libexpr_tester, + args : tests_args, + env : { + '_NIX_TEST_UNIT_DATA': meson.project_source_root() / 'tests/unit/libexpr/data', + }, + suite : 'check', + protocol : 'gtest', + verbose : true, +)