mirror of
https://github.com/NixOS/nix.git
synced 2025-11-14 06:22:42 +01:00
Move unit tests to the location Meson expects them to be
Everything that is a separate subproject should live in the subprojects
directory.
Progress on #2503
This reverts commit 451f8a8c19.
This commit is contained in:
parent
1cd48008f0
commit
e65510da56
270 changed files with 158 additions and 168 deletions
1
src/libutil-test-support/.version
Symbolic link
1
src/libutil-test-support/.version
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../.version
|
||||
1
src/libutil-test-support/build-utils-meson
Symbolic link
1
src/libutil-test-support/build-utils-meson
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
../../build-utils-meson
|
||||
19
src/libutil-test-support/local.mk
Normal file
19
src/libutil-test-support/local.mk
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
libraries += libutil-test-support
|
||||
|
||||
libutil-test-support_NAME = libnixutil-test-support
|
||||
|
||||
libutil-test-support_DIR := $(d)
|
||||
|
||||
ifeq ($(INSTALL_UNIT_TESTS), yes)
|
||||
libutil-test-support_INSTALL_DIR := $(checklibdir)
|
||||
else
|
||||
libutil-test-support_INSTALL_DIR :=
|
||||
endif
|
||||
|
||||
libutil-test-support_SOURCES := $(wildcard $(d)/tests/*.cc)
|
||||
|
||||
libutil-test-support_CXXFLAGS += $(libutil-tests_EXTRA_INCLUDES)
|
||||
|
||||
libutil-test-support_LIBS = libutil
|
||||
|
||||
libutil-test-support_LDFLAGS := $(THREAD_LDFLAGS) -lrapidcheck
|
||||
73
src/libutil-test-support/meson.build
Normal file
73
src/libutil-test-support/meson.build
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
project('nix-util-test-support', 'cpp',
|
||||
version : files('.version'),
|
||||
default_options : [
|
||||
'cpp_std=c++2a',
|
||||
# TODO(Qyriad): increase the warning level
|
||||
'warning_level=1',
|
||||
'debug=true',
|
||||
'optimization=2',
|
||||
'errorlogs=true', # Please print logs for tests that fail
|
||||
],
|
||||
meson_version : '>= 1.1',
|
||||
license : 'LGPL-2.1-or-later',
|
||||
)
|
||||
|
||||
cxx = meson.get_compiler('cpp')
|
||||
|
||||
subdir('build-utils-meson/deps-lists')
|
||||
|
||||
deps_private_maybe_subproject = [
|
||||
]
|
||||
deps_public_maybe_subproject = [
|
||||
dependency('nix-util'),
|
||||
]
|
||||
subdir('build-utils-meson/subprojects')
|
||||
|
||||
subdir('build-utils-meson/threads')
|
||||
|
||||
rapidcheck = dependency('rapidcheck')
|
||||
deps_public += rapidcheck
|
||||
|
||||
add_project_arguments(
|
||||
# TODO(Qyriad): Yes this is how the autoconf+Make system did it.
|
||||
# It would be nice for our headers to be idempotent instead.
|
||||
'-include', 'config-util.hh',
|
||||
language : 'cpp',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/diagnostics')
|
||||
|
||||
sources = files(
|
||||
'tests/hash.cc',
|
||||
'tests/string_callback.cc',
|
||||
)
|
||||
|
||||
include_dirs = [include_directories('.')]
|
||||
|
||||
headers = files(
|
||||
'tests/characterization.hh',
|
||||
'tests/gtest-with-params.hh',
|
||||
'tests/hash.hh',
|
||||
'tests/nix_api_util.hh',
|
||||
'tests/string_callback.hh',
|
||||
)
|
||||
|
||||
subdir('build-utils-meson/export-all-symbols')
|
||||
|
||||
this_library = library(
|
||||
'nix-util-test-support',
|
||||
sources,
|
||||
dependencies : deps_public + deps_private + deps_other,
|
||||
include_directories : include_dirs,
|
||||
# TODO: Remove `-lrapidcheck` when https://github.com/emil-e/rapidcheck/pull/326
|
||||
# is available. See also ../libutil/build.meson
|
||||
link_args: linker_export_flags + ['-lrapidcheck'],
|
||||
prelink : true, # For C++ static initializers
|
||||
install : true,
|
||||
)
|
||||
|
||||
install_headers(headers, subdir : 'nix', preserve_path : true)
|
||||
|
||||
libraries_private = []
|
||||
|
||||
subdir('build-utils-meson/export')
|
||||
58
src/libutil-test-support/package.nix
Normal file
58
src/libutil-test-support/package.nix
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
{ lib
|
||||
, stdenv
|
||||
, mkMesonLibrary
|
||||
|
||||
, nix-util
|
||||
|
||||
, rapidcheck
|
||||
|
||||
# Configuration Options
|
||||
|
||||
, version
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (lib) fileset;
|
||||
in
|
||||
|
||||
mkMesonLibrary (finalAttrs: {
|
||||
pname = "nix-util-test-support";
|
||||
inherit version;
|
||||
|
||||
workDir = ./.;
|
||||
fileset = fileset.unions [
|
||||
../../build-utils-meson
|
||||
./build-utils-meson
|
||||
../../.version
|
||||
./.version
|
||||
./meson.build
|
||||
# ./meson.options
|
||||
(fileset.fileFilter (file: file.hasExt "cc") ./.)
|
||||
(fileset.fileFilter (file: file.hasExt "hh") ./.)
|
||||
];
|
||||
|
||||
propagatedBuildInputs = [
|
||||
nix-util
|
||||
rapidcheck
|
||||
];
|
||||
|
||||
preConfigure =
|
||||
# "Inline" .version so it's not a symlink, and includes the suffix.
|
||||
# Do the meson utils, without modification.
|
||||
''
|
||||
chmod u+w ./.version
|
||||
echo ${version} > ../../.version
|
||||
'';
|
||||
|
||||
mesonFlags = [
|
||||
];
|
||||
|
||||
env = lib.optionalAttrs (stdenv.isLinux && !(stdenv.hostPlatform.isStatic && stdenv.system == "aarch64-linux")) {
|
||||
LDFLAGS = "-fuse-ld=gold";
|
||||
};
|
||||
|
||||
meta = {
|
||||
platforms = lib.platforms.unix ++ lib.platforms.windows;
|
||||
};
|
||||
|
||||
})
|
||||
109
src/libutil-test-support/tests/characterization.hh
Normal file
109
src/libutil-test-support/tests/characterization.hh
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "types.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "file-system.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
/**
|
||||
* The path to the unit test data directory. See the contributing guide
|
||||
* in the manual for further details.
|
||||
*/
|
||||
static inline std::filesystem::path getUnitTestData() {
|
||||
return getEnv("_NIX_TEST_UNIT_DATA").value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether we should update "golden masters" instead of running tests
|
||||
* against them. See the contributing guide in the manual for further
|
||||
* details.
|
||||
*/
|
||||
static inline bool testAccept() {
|
||||
return getEnv("_NIX_TEST_ACCEPT") == "1";
|
||||
}
|
||||
|
||||
/**
|
||||
* Mixin class for writing characterization tests
|
||||
*/
|
||||
class CharacterizationTest : public virtual ::testing::Test
|
||||
{
|
||||
protected:
|
||||
/**
|
||||
* While the "golden master" for this characterization test is
|
||||
* located. It should not be shared with any other test.
|
||||
*/
|
||||
virtual std::filesystem::path goldenMaster(PathView testStem) const = 0;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Golden test for reading
|
||||
*
|
||||
* @param test hook that takes the contents of the file and does the
|
||||
* actual work
|
||||
*/
|
||||
void readTest(PathView testStem, auto && test)
|
||||
{
|
||||
auto file = goldenMaster(testStem);
|
||||
|
||||
if (testAccept())
|
||||
{
|
||||
GTEST_SKIP()
|
||||
<< "Cannot read golden master "
|
||||
<< file
|
||||
<< "because another test is also updating it";
|
||||
}
|
||||
else
|
||||
{
|
||||
test(readFile(file));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Golden test for writing
|
||||
*
|
||||
* @param test hook that produces contents of the file and does the
|
||||
* actual work
|
||||
*/
|
||||
void writeTest(
|
||||
PathView testStem, auto && test, auto && readFile2, auto && writeFile2)
|
||||
{
|
||||
auto file = goldenMaster(testStem);
|
||||
|
||||
auto got = test();
|
||||
|
||||
if (testAccept())
|
||||
{
|
||||
std::filesystem::create_directories(file.parent_path());
|
||||
writeFile2(file, got);
|
||||
GTEST_SKIP()
|
||||
<< "Updating golden master "
|
||||
<< file;
|
||||
}
|
||||
else
|
||||
{
|
||||
decltype(got) expected = readFile2(file);
|
||||
ASSERT_EQ(got, expected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialize to `std::string`
|
||||
*/
|
||||
void writeTest(PathView testStem, auto && test)
|
||||
{
|
||||
writeTest(
|
||||
testStem, test,
|
||||
[](const std::filesystem::path & f) -> std::string {
|
||||
return readFile(f);
|
||||
},
|
||||
[](const std::filesystem::path & f, const std::string & c) {
|
||||
return writeFile(f, c);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
54
src/libutil-test-support/tests/gtest-with-params.hh
Normal file
54
src/libutil-test-support/tests/gtest-with-params.hh
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
// SPDX-FileCopyrightText: 2014 Emil Eriksson
|
||||
//
|
||||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
//
|
||||
// The lion's share of this code is copy pasted directly out of RapidCheck
|
||||
// headers, so the copyright is set accordingly.
|
||||
/**
|
||||
* @file Implements the ability to run a RapidCheck test under gtest with changed
|
||||
* test parameters such as the number of tests to run. This is useful for
|
||||
* running very large numbers of the extremely cheap property tests.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <rapidcheck/gtest.h>
|
||||
#include <rapidcheck/gen/Arbitrary.hpp>
|
||||
|
||||
namespace rc::detail {
|
||||
|
||||
using MakeTestParams = TestParams (*)();
|
||||
|
||||
template<typename Testable>
|
||||
void checkGTestWith(Testable && testable, MakeTestParams makeTestParams)
|
||||
{
|
||||
const auto testInfo = ::testing::UnitTest::GetInstance()->current_test_info();
|
||||
detail::TestMetadata metadata;
|
||||
metadata.id = std::string(testInfo->test_case_name()) + "/" + std::string(testInfo->name());
|
||||
metadata.description = std::string(testInfo->name());
|
||||
|
||||
const auto result = checkTestable(std::forward<Testable>(testable), metadata, makeTestParams());
|
||||
|
||||
if (result.template is<detail::SuccessResult>()) {
|
||||
const auto success = result.template get<detail::SuccessResult>();
|
||||
if (!success.distribution.empty()) {
|
||||
printResultMessage(result, std::cout);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
} else {
|
||||
std::ostringstream ss;
|
||||
printResultMessage(result, ss);
|
||||
FAIL() << ss.str() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define RC_GTEST_PROP_WITH_PARAMS(TestCase, Name, MakeParams, ArgList) \
|
||||
void rapidCheck_propImpl_##TestCase##_##Name ArgList; \
|
||||
\
|
||||
TEST(TestCase, Name) \
|
||||
{ \
|
||||
::rc::detail::checkGTestWith(&rapidCheck_propImpl_##TestCase##_##Name, MakeParams); \
|
||||
} \
|
||||
\
|
||||
void rapidCheck_propImpl_##TestCase##_##Name ArgList
|
||||
27
src/libutil-test-support/tests/hash.cc
Normal file
27
src/libutil-test-support/tests/hash.cc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include <regex>
|
||||
|
||||
#include <rapidcheck.h>
|
||||
|
||||
#include "hash.hh"
|
||||
|
||||
#include "tests/hash.hh"
|
||||
|
||||
namespace rc {
|
||||
using namespace nix;
|
||||
|
||||
Gen<Hash> Arbitrary<Hash>::arbitrary()
|
||||
{
|
||||
Hash prototype(HashAlgorithm::SHA1);
|
||||
return
|
||||
gen::apply(
|
||||
[](const std::vector<uint8_t> & v) {
|
||||
Hash hash(HashAlgorithm::SHA1);
|
||||
assert(v.size() == hash.hashSize);
|
||||
std::copy(v.begin(), v.end(), hash.hash);
|
||||
return hash;
|
||||
},
|
||||
gen::container<std::vector<uint8_t>>(prototype.hashSize, gen::arbitrary<uint8_t>())
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/libutil-test-support/tests/hash.hh
Normal file
16
src/libutil-test-support/tests/hash.hh
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
///@file
|
||||
|
||||
#include <rapidcheck/gen/Arbitrary.h>
|
||||
|
||||
#include <hash.hh>
|
||||
|
||||
namespace rc {
|
||||
using namespace nix;
|
||||
|
||||
template<>
|
||||
struct Arbitrary<Hash> {
|
||||
static Gen<Hash> arbitrary();
|
||||
};
|
||||
|
||||
}
|
||||
48
src/libutil-test-support/tests/nix_api_util.hh
Normal file
48
src/libutil-test-support/tests/nix_api_util.hh
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
///@file
|
||||
#include "nix_api_util.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
class nix_api_util_context : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
|
||||
nix_api_util_context()
|
||||
{
|
||||
ctx = nix_c_context_create();
|
||||
nix_libutil_init(ctx);
|
||||
};
|
||||
|
||||
~nix_api_util_context() override
|
||||
{
|
||||
nix_c_context_free(ctx);
|
||||
ctx = nullptr;
|
||||
}
|
||||
|
||||
nix_c_context * ctx;
|
||||
|
||||
inline void assert_ctx_ok()
|
||||
{
|
||||
|
||||
if (nix_err_code(ctx) == NIX_OK) {
|
||||
return;
|
||||
}
|
||||
unsigned int n;
|
||||
const char * p = nix_err_msg(nullptr, ctx, &n);
|
||||
std::string msg(p, n);
|
||||
FAIL() << "nix_err_code(ctx) != NIX_OK, message: " << msg;
|
||||
}
|
||||
|
||||
inline void assert_ctx_err()
|
||||
{
|
||||
if (nix_err_code(ctx) != NIX_OK) {
|
||||
return;
|
||||
}
|
||||
FAIL() << "Got NIX_OK, but expected an error!";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
11
src/libutil-test-support/tests/string_callback.cc
Normal file
11
src/libutil-test-support/tests/string_callback.cc
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "string_callback.hh"
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, void * user_data)
|
||||
{
|
||||
auto user_data_casted = reinterpret_cast<std::string *>(user_data);
|
||||
*user_data_casted = std::string(start);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/libutil-test-support/tests/string_callback.hh
Normal file
15
src/libutil-test-support/tests/string_callback.hh
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, void * user_data);
|
||||
|
||||
inline void * observe_string_cb_data(std::string & out)
|
||||
{
|
||||
return (void *) &out;
|
||||
};
|
||||
|
||||
#define OBSERVE_STRING(str) nix::testing::observe_string_cb, nix::testing::observe_string_cb_data(str)
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
#include <iostream>
|
||||
#include "tracing-file-system-object-sink.hh"
|
||||
|
||||
namespace nix::test {
|
||||
|
||||
void TracingFileSystemObjectSink::createDirectory(const CanonPath & path)
|
||||
{
|
||||
std::cerr << "createDirectory(" << path << ")\n";
|
||||
sink.createDirectory(path);
|
||||
}
|
||||
|
||||
void TracingFileSystemObjectSink::createRegularFile(
|
||||
const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn)
|
||||
{
|
||||
std::cerr << "createRegularFile(" << path << ")\n";
|
||||
sink.createRegularFile(path, [&](CreateRegularFileSink & crf) {
|
||||
// We could wrap this and trace about the chunks of data and such
|
||||
fn(crf);
|
||||
});
|
||||
}
|
||||
|
||||
void TracingFileSystemObjectSink::createSymlink(const CanonPath & path, const std::string & target)
|
||||
{
|
||||
std::cerr << "createSymlink(" << path << ", target: " << target << ")\n";
|
||||
sink.createSymlink(path, target);
|
||||
}
|
||||
|
||||
void TracingExtendedFileSystemObjectSink::createHardlink(const CanonPath & path, const CanonPath & target)
|
||||
{
|
||||
std::cerr << "createHardlink(" << path << ", target: " << target << ")\n";
|
||||
sink.createHardlink(path, target);
|
||||
}
|
||||
|
||||
} // namespace nix::test
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
#include "fs-sink.hh"
|
||||
|
||||
namespace nix::test {
|
||||
|
||||
/**
|
||||
* A `FileSystemObjectSink` that traces calls, writing to stderr.
|
||||
*/
|
||||
class TracingFileSystemObjectSink : public virtual FileSystemObjectSink
|
||||
{
|
||||
FileSystemObjectSink & sink;
|
||||
public:
|
||||
TracingFileSystemObjectSink(FileSystemObjectSink & sink)
|
||||
: sink(sink)
|
||||
{
|
||||
}
|
||||
|
||||
void createDirectory(const CanonPath & path) override;
|
||||
|
||||
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn) override;
|
||||
|
||||
void createSymlink(const CanonPath & path, const std::string & target) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* A `ExtendedFileSystemObjectSink` that traces calls, writing to stderr.
|
||||
*/
|
||||
class TracingExtendedFileSystemObjectSink : public TracingFileSystemObjectSink, public ExtendedFileSystemObjectSink
|
||||
{
|
||||
ExtendedFileSystemObjectSink & sink;
|
||||
public:
|
||||
TracingExtendedFileSystemObjectSink(ExtendedFileSystemObjectSink & sink)
|
||||
: TracingFileSystemObjectSink(sink)
|
||||
, sink(sink)
|
||||
{
|
||||
}
|
||||
|
||||
void createHardlink(const CanonPath & path, const CanonPath & target) override;
|
||||
};
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue