mirror of
https://github.com/NixOS/nix
synced 2025-07-07 01:51:47 +02:00
Merge pull request #10412 from roberth/c-string-context
C API: Add `nix_string_realise`
This commit is contained in:
commit
5b9cb8b372
16 changed files with 351 additions and 40 deletions
|
@ -34,7 +34,7 @@ libexpr-tests_EXTRA_INCLUDES = \
|
|||
libexpr-tests_CXXFLAGS += $(libexpr-tests_EXTRA_INCLUDES)
|
||||
|
||||
libexpr-tests_LIBS = \
|
||||
libexpr-test-support libstore-test-support libutils-test-support \
|
||||
libexpr-test-support libstore-test-support libutil-test-support \
|
||||
libexpr libexprc libfetchers libstore libstorec libutil libutilc
|
||||
|
||||
libexpr-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) -lgmock
|
||||
|
|
39
tests/unit/libexpr/main.cc
Normal file
39
tests/unit/libexpr/main.cc
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <cstdlib>
|
||||
#include "globals.hh"
|
||||
#include "logging.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
int main (int argc, char **argv) {
|
||||
if (argc > 1 && std::string_view(argv[1]) == "__build-remote") {
|
||||
printError("test-build-remote: not supported in libexpr unit tests");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Disable build hook. We won't be testing remote builds in these unit tests. If we do, fix the above build hook.
|
||||
settings.buildHook = {};
|
||||
|
||||
#if __linux__ // should match the conditional around sandboxBuildDir declaration.
|
||||
|
||||
// When building and testing nix within the host's Nix sandbox, our store dir will be located in the host's sandboxBuildDir, e.g.:
|
||||
// Host
|
||||
// storeDir = /nix/store
|
||||
// sandboxBuildDir = /build
|
||||
// This process
|
||||
// storeDir = /build/foo/bar/store
|
||||
// sandboxBuildDir = /build
|
||||
// However, we have a rule that the store dir must not be inside the storeDir, so we need to pick a different sandboxBuildDir.
|
||||
settings.sandboxBuildDir = "/test-build-dir-instead-of-usual-build-dir";
|
||||
#endif
|
||||
|
||||
#if __APPLE__
|
||||
// Avoid this error, when already running in a sandbox:
|
||||
// sandbox-exec: sandbox_apply: Operation not permitted
|
||||
settings.sandboxMode = smDisabled;
|
||||
setEnv("_NIX_TEST_NO_SANDBOX", "1");
|
||||
#endif
|
||||
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
|
@ -6,7 +6,9 @@
|
|||
#include "nix_api_value.h"
|
||||
|
||||
#include "tests/nix_api_expr.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
@ -73,6 +75,9 @@ TEST_F(nix_api_expr_test, nix_build_drv)
|
|||
std::string pEnd = "-myname.drv";
|
||||
ASSERT_EQ(pEnd, p.substr(p.size() - pEnd.size()));
|
||||
|
||||
// NOTE: .drvPath should be usually be ignored. Output paths are more versatile.
|
||||
// See https://github.com/NixOS/nix/issues/6507
|
||||
// Use e.g. nix_string_realise to realise the output.
|
||||
StorePath * drvStorePath = nix_store_parse_path(ctx, store, drvPath);
|
||||
ASSERT_EQ(true, nix_store_is_valid_path(ctx, store, drvStorePath));
|
||||
|
||||
|
@ -87,14 +92,99 @@ TEST_F(nix_api_expr_test, nix_build_drv)
|
|||
StorePath * outStorePath = nix_store_parse_path(ctx, store, outPath);
|
||||
ASSERT_EQ(false, nix_store_is_valid_path(ctx, store, outStorePath));
|
||||
|
||||
// TODO figure out why fails.
|
||||
// `make libexpr-tests_RUN` works, but `nix build .` enters an infinite loop
|
||||
/* nix_store_realise(ctx, store, drvStorePath, nullptr, nullptr); */
|
||||
/* auto is_valid_path = nix_store_is_valid_path(ctx, store, outStorePath); */
|
||||
/* ASSERT_EQ(true, is_valid_path); */
|
||||
nix_store_realise(ctx, store, drvStorePath, nullptr, nullptr);
|
||||
auto is_valid_path = nix_store_is_valid_path(ctx, store, outStorePath);
|
||||
ASSERT_EQ(true, is_valid_path);
|
||||
|
||||
// Clean up
|
||||
nix_store_path_free(drvStorePath);
|
||||
nix_store_path_free(outStorePath);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_value)
|
||||
{
|
||||
auto expr = "true";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("cannot coerce")));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
|
||||
{
|
||||
auto expr = R"(
|
||||
derivation { name = "letsbuild";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo failing a build for testing purposes; exit 1;" ];
|
||||
}
|
||||
)";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
ASSERT_EQ(nullptr, r);
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
|
||||
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("failed with exit code 1")));
|
||||
}
|
||||
|
||||
TEST_F(nix_api_expr_test, nix_expr_realise_context)
|
||||
{
|
||||
// TODO (ca-derivations): add a content-addressed derivation output, which produces a placeholder
|
||||
auto expr = R"(
|
||||
''
|
||||
a derivation output: ${
|
||||
derivation { name = "letsbuild";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo foo > $out" ];
|
||||
}}
|
||||
a path: ${builtins.toFile "just-a-file" "ooh file good"}
|
||||
a derivation path by itself: ${
|
||||
builtins.unsafeDiscardOutputDependency
|
||||
(derivation {
|
||||
name = "not-actually-built-yet";
|
||||
system = builtins.currentSystem;
|
||||
builder = "/bin/sh";
|
||||
args = [ "-c" "echo foo > $out" ];
|
||||
}).drvPath}
|
||||
''
|
||||
)";
|
||||
nix_expr_eval_from_string(ctx, state, expr, ".", value);
|
||||
assert_ctx_ok();
|
||||
auto r = nix_string_realise(ctx, state, value, false);
|
||||
assert_ctx_ok();
|
||||
ASSERT_NE(nullptr, r);
|
||||
|
||||
auto s = std::string(nix_realised_string_get_buffer_start(r), nix_realised_string_get_buffer_size(r));
|
||||
|
||||
EXPECT_THAT(s, testing::StartsWith("a derivation output:"));
|
||||
EXPECT_THAT(s, testing::HasSubstr("-letsbuild\n"));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("-letsbuild.drv")));
|
||||
EXPECT_THAT(s, testing::HasSubstr("a path:"));
|
||||
EXPECT_THAT(s, testing::HasSubstr("-just-a-file"));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("-just-a-file.drv")));
|
||||
EXPECT_THAT(s, testing::Not(testing::HasSubstr("ooh file good")));
|
||||
EXPECT_THAT(s, testing::HasSubstr("a derivation path by itself:"));
|
||||
EXPECT_THAT(s, testing::EndsWith("-not-actually-built-yet.drv\n"));
|
||||
|
||||
std::vector<std::string> names;
|
||||
size_t n = nix_realised_string_get_store_path_count(r);
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
const StorePath * p = nix_realised_string_get_store_path(r, i);
|
||||
ASSERT_NE(nullptr, p);
|
||||
std::string name;
|
||||
nix_store_path_name(p, OBSERVE_STRING(name));
|
||||
names.push_back(name);
|
||||
}
|
||||
std::sort(names.begin(), names.end());
|
||||
ASSERT_EQ(3, names.size());
|
||||
EXPECT_THAT(names[0], testing::StrEq("just-a-file"));
|
||||
EXPECT_THAT(names[1], testing::StrEq("letsbuild"));
|
||||
EXPECT_THAT(names[2], testing::StrEq("not-actually-built-yet.drv"));
|
||||
|
||||
nix_realised_string_free(r);
|
||||
}
|
||||
|
||||
} // namespace nixC
|
||||
|
|
|
@ -4,14 +4,10 @@
|
|||
#include "nix_api_store_internal.h"
|
||||
|
||||
#include "tests/nix_api_store.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
namespace nixC {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data)
|
||||
{
|
||||
*user_data = std::string(start);
|
||||
}
|
||||
|
||||
std::string PATH_SUFFIX = "/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-name";
|
||||
|
||||
TEST_F(nix_api_util_context, nix_libstore_init)
|
||||
|
@ -23,7 +19,7 @@ TEST_F(nix_api_util_context, nix_libstore_init)
|
|||
TEST_F(nix_api_store_test, nix_store_get_uri)
|
||||
{
|
||||
std::string str;
|
||||
auto ret = nix_store_get_uri(ctx, store, (void *) observe_string_cb, &str);
|
||||
auto ret = nix_store_get_uri(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_EQ(NIX_OK, ret);
|
||||
ASSERT_STREQ("local", str.c_str());
|
||||
}
|
||||
|
@ -56,7 +52,7 @@ TEST_F(nix_api_store_test, DoesNotCrashWhenContextIsNull)
|
|||
TEST_F(nix_api_store_test, get_version)
|
||||
{
|
||||
std::string str;
|
||||
auto ret = nix_store_get_version(ctx, store, (void *) observe_string_cb, &str);
|
||||
auto ret = nix_store_get_version(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_EQ(NIX_OK, ret);
|
||||
ASSERT_STREQ(PACKAGE_VERSION, str.c_str());
|
||||
}
|
||||
|
@ -69,7 +65,7 @@ TEST_F(nix_api_util_context, nix_store_open_dummy)
|
|||
ASSERT_STREQ("dummy", store->ptr->getUri().c_str());
|
||||
|
||||
std::string str;
|
||||
nix_store_get_version(ctx, store, (void *) observe_string_cb, &str);
|
||||
nix_store_get_version(ctx, store, OBSERVE_STRING(str));
|
||||
ASSERT_STREQ("", str.c_str());
|
||||
|
||||
nix_store_free(store);
|
||||
|
|
|
@ -23,5 +23,15 @@ protected:
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
9
tests/unit/libutil-support/tests/string_callback.cc
Normal file
9
tests/unit/libutil-support/tests/string_callback.cc
Normal file
|
@ -0,0 +1,9 @@
|
|||
#include "string_callback.hh"
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data) {
|
||||
*user_data = std::string(start);
|
||||
}
|
||||
|
||||
}
|
12
tests/unit/libutil-support/tests/string_callback.hh
Normal file
12
tests/unit/libutil-support/tests/string_callback.hh
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace nix::testing {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data);
|
||||
inline void * observe_string_cb_data(std::string & out) {
|
||||
return (void *) &out;
|
||||
};
|
||||
#define OBSERVE_STRING(str) (void *)nix::testing::observe_string_cb, nix::testing::observe_string_cb_data(str)
|
||||
|
||||
}
|
|
@ -3,16 +3,12 @@
|
|||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "tests/nix_api_util.hh"
|
||||
#include "tests/string_callback.hh"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace nixC {
|
||||
|
||||
void observe_string_cb(const char * start, unsigned int n, std::string * user_data)
|
||||
{
|
||||
*user_data = std::string(start);
|
||||
}
|
||||
|
||||
TEST_F(nix_api_util_context, nix_context_error)
|
||||
{
|
||||
std::string err_msg_ref;
|
||||
|
@ -62,10 +58,10 @@ TEST_F(nix_api_util_context, nix_setting_get)
|
|||
{
|
||||
ASSERT_EQ(ctx->last_err_code, NIX_OK);
|
||||
std::string setting_value;
|
||||
nix_err result = nix_setting_get(ctx, "invalid-key", (void *) observe_string_cb, &setting_value);
|
||||
nix_err result = nix_setting_get(ctx, "invalid-key", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_ERR_KEY);
|
||||
|
||||
result = nix_setting_get(ctx, "setting-name", (void *) observe_string_cb, &setting_value);
|
||||
result = nix_setting_get(ctx, "setting-name", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_OK);
|
||||
ASSERT_STREQ("empty", setting_value.c_str());
|
||||
}
|
||||
|
@ -79,7 +75,7 @@ TEST_F(nix_api_util_context, nix_setting_set)
|
|||
ASSERT_EQ(result, NIX_OK);
|
||||
|
||||
std::string setting_value;
|
||||
result = nix_setting_get(ctx, "setting-name", (void *) observe_string_cb, &setting_value);
|
||||
result = nix_setting_get(ctx, "setting-name", OBSERVE_STRING(setting_value));
|
||||
ASSERT_EQ(result, NIX_OK);
|
||||
ASSERT_STREQ("new-value", setting_value.c_str());
|
||||
}
|
||||
|
@ -107,14 +103,14 @@ TEST_F(nix_api_util_context, nix_err_info_msg)
|
|||
std::string err_info;
|
||||
|
||||
// no error
|
||||
EXPECT_THROW(nix_err_info_msg(NULL, ctx, (void *) observe_string_cb, &err_info), nix::Error);
|
||||
EXPECT_THROW(nix_err_info_msg(NULL, ctx, OBSERVE_STRING(err_info)), nix::Error);
|
||||
|
||||
try {
|
||||
throw nix::Error("testing error");
|
||||
} catch (...) {
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
nix_err_info_msg(nix_c_context_create(), ctx, (void *) observe_string_cb, &err_info);
|
||||
nix_err_info_msg(nix_c_context_create(), ctx, OBSERVE_STRING(err_info));
|
||||
ASSERT_STREQ("testing error", err_info.c_str());
|
||||
}
|
||||
|
||||
|
@ -123,7 +119,7 @@ TEST_F(nix_api_util_context, nix_err_name)
|
|||
std::string err_name;
|
||||
|
||||
// no error
|
||||
EXPECT_THROW(nix_err_name(NULL, ctx, (void *) observe_string_cb, &err_name), nix::Error);
|
||||
EXPECT_THROW(nix_err_name(NULL, ctx, OBSERVE_STRING(err_name)), nix::Error);
|
||||
|
||||
std::string err_msg_ref;
|
||||
try {
|
||||
|
@ -131,7 +127,7 @@ TEST_F(nix_api_util_context, nix_err_name)
|
|||
} catch (...) {
|
||||
nix_context_error(ctx);
|
||||
}
|
||||
nix_err_name(nix_c_context_create(), ctx, (void *) observe_string_cb, &err_name);
|
||||
nix_err_name(nix_c_context_create(), ctx, OBSERVE_STRING(err_name));
|
||||
ASSERT_EQ(std::string(err_name), "nix::Error");
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue