1
1
Fork 0
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:
John Ericson 2024-10-10 14:56:26 -04:00
parent 1cd48008f0
commit e65510da56
270 changed files with 158 additions and 168 deletions

View file

@ -0,0 +1 @@
../../.version

View file

@ -0,0 +1 @@
../../build-utils-meson

View 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

View 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')

View 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;
};
})

View 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);
});
}
};
}

View 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

View 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>())
);
}
}

View 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();
};
}

View 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!";
}
};
}

View 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);
}
}

View 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)
}

View file

@ -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

View file

@ -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;
};
}