1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-07 01:21:00 +01:00

Merge pull request #13904 from NixOS/c-ffi-improvements

C ffi improvements
This commit is contained in:
Jörg Thalheim 2025-09-03 23:10:27 +02:00 committed by GitHub
commit 81e068ab8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 210 additions and 141 deletions

View file

@ -40,6 +40,8 @@ static T * unsafe_new_with_self(F && init)
return new (p) T(init(static_cast<T *>(p)));
}
extern "C" {
nix_err nix_libexpr_init(nix_c_context * context)
{
if (context)
@ -287,3 +289,5 @@ void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * o
GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
#endif
}
} // extern "C"

View file

@ -8,6 +8,8 @@
#include "nix_api_value.h"
#include "nix/expr/search-path.hh"
extern "C" {
struct nix_eval_state_builder
{
nix::ref<nix::Store> store;
@ -61,4 +63,6 @@ struct nix_realised_string
std::vector<StorePath> storePaths;
};
} // extern "C"
#endif // NIX_API_EXPR_INTERNAL_H

View file

@ -14,6 +14,8 @@
#include <nlohmann/json.hpp>
extern "C" {
void nix_set_string_return(nix_string_return * str, const char * c)
{
str->str = c;
@ -40,6 +42,8 @@ nix_err nix_external_add_string_context(nix_c_context * context, nix_string_cont
NIXC_CATCH_ERRS
}
} // extern "C"
class NixCExternalValue : public nix::ExternalValueBase
{
NixCExternalValueDesc & desc;
@ -170,6 +174,8 @@ public:
virtual ~NixCExternalValue() override {};
};
extern "C" {
ExternalValue * nix_create_external_value(nix_c_context * context, NixCExternalValueDesc * desc, void * v)
{
if (context)
@ -198,3 +204,5 @@ void * nix_get_external_value_content(nix_c_context * context, ExternalValue * b
}
NIXC_CATCH_ERRS_NULL
}
} // extern "C"

View file

@ -111,6 +111,8 @@ static void nix_c_primop_wrapper(
v = vTmp;
}
extern "C" {
PrimOp * nix_alloc_primop(
nix_c_context * context,
PrimOpFun fun,
@ -651,3 +653,5 @@ const StorePath * nix_realised_string_get_store_path(nix_realised_string * s, si
{
return &s->storePaths[i];
}
} // extern "C"

View file

@ -55,6 +55,7 @@ sources = files(
'nix_api_expr.cc',
'nix_api_external.cc',
'nix_api_value.cc',
'nix_api_value_internal.cc',
'primops.cc',
'search-path.cc',
'trivial.cc',

View file

@ -1,7 +1,5 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
@ -151,8 +149,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_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")));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("cannot coerce"));
}
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
@ -168,8 +166,8 @@ TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build)
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")));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("failed with exit code 1"));
}
TEST_F(nix_api_expr_test, nix_expr_realise_context)
@ -381,12 +379,11 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_no_return)
nix_value * result = nix_alloc_value(ctx, state);
assert_ctx_ok();
nix_value_call(ctx, state, primopValue, three, result);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
ctx->last_err,
testing::Optional(
testing::HasSubstr("Implementation error in custom function: return value was not initialized")));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badNoReturn")));
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("Implementation error in custom function: return value was not initialized"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badNoReturn"));
}
static void primop_bad_return_thunk(
@ -419,12 +416,11 @@ TEST_F(nix_api_expr_test, nix_expr_primop_bad_return_thunk)
assert_ctx_ok();
NIX_VALUE_CALL(ctx, state, result, primopValue, toString, four);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
ctx->last_err,
testing::Optional(
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk")));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badReturnThunk")));
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("Implementation error in custom function: return value must not be a thunk"));
ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badReturnThunk"));
}
TEST_F(nix_api_expr_test, nix_value_call_multi_no_args)

View file

@ -1,9 +1,6 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
#include "nix_api_value.h"
#include "nix_api_external.h"
@ -39,7 +36,7 @@ private:
std::string type_string = "nix-external<MyExternalValueDesc( ";
type_string += std::to_string(obj->_x);
type_string += " )>";
res->str = &*type_string.begin();
nix_set_string_return(res, &*type_string.begin());
}
};

View file

@ -1,10 +1,7 @@
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
#include "nix_api_expr_internal.h"
#include "nix/expr/tests/nix_api_expr.hh"
#include "nix/util/tests/string_callback.hh"
@ -16,14 +13,6 @@
namespace nixC {
TEST_F(nix_api_expr_test, as_nix_value_ptr)
{
// nix_alloc_value casts nix::Value to nix_value
// It should be obvious from the decl that that works, but if it doesn't,
// the whole implementation would be utterly broken.
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
}
TEST_F(nix_api_expr_test, nix_value_get_int_invalid)
{
ASSERT_EQ(0, nix_get_int(ctx, nullptr));
@ -320,8 +309,10 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_error)
// Evaluate it
nix_value_force(ctx, state, v);
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("attempt to call something which is not a function but"));
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("attempt to call something which is not a function but"));
// Clean up
nix_gc_decref(ctx, some_string);
@ -380,7 +371,9 @@ TEST_F(nix_api_expr_test, nix_value_init_apply_lazy_arg)
// nix_get_attr_byname isn't lazy (it could have been) so it will throw the exception
nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo");
ASSERT_EQ(nullptr, foo);
ASSERT_THAT(ctx->last_err.value(), testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("error message for test case nix_value_init_apply_lazy_arg"));
// Clean up
nix_gc_decref(ctx, f);

View file

@ -0,0 +1,25 @@
#include "nix_api_store.h"
#include "nix_api_util.h"
#include "nix_api_expr.h"
#include "nix_api_value.h"
#include "nix_api_expr_internal.h"
#include "nix/expr/tests/nix_api_expr.hh"
#include "nix/util/tests/string_callback.hh"
#include <gmock/gmock.h>
#include <cstddef>
#include <cstdlib>
#include <gtest/gtest.h>
namespace nixC {
TEST_F(nix_api_expr_test, as_nix_value_ptr)
{
// nix_alloc_value casts nix::Value to nix_value
// It should be obvious from the decl that that works, but if it doesn't,
// the whole implementation would be utterly broken.
ASSERT_EQ(sizeof(nix::Value), sizeof(nix_value));
}
} // namespace nixC

View file

@ -2,6 +2,8 @@
#include "nix_api_fetchers_internal.hh"
#include "nix_api_util_internal.h"
extern "C" {
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context)
{
try {
@ -17,3 +19,5 @@ void nix_fetchers_settings_free(nix_fetchers_settings * settings)
{
delete settings;
}
} // extern "C"

View file

@ -10,6 +10,8 @@
#include "nix/flake/flake.hh"
extern "C" {
nix_flake_settings * nix_flake_settings_new(nix_c_context * context)
{
nix_clear_err(context);
@ -203,3 +205,5 @@ nix_value * nix_locked_flake_get_output_attrs(
}
NIXC_CATCH_ERRS_NULL
}
} // extern "C"

View file

@ -5,6 +5,8 @@
#include "nix/main/plugin.hh"
extern "C" {
nix_err nix_init_plugins(nix_c_context * context)
{
if (context)
@ -14,3 +16,5 @@ nix_err nix_init_plugins(nix_c_context * context)
}
NIXC_CATCH_ERRS
}
} // extern "C"

View file

@ -10,6 +10,8 @@
#include "nix/store/globals.hh"
extern "C" {
nix_err nix_libstore_init(nix_c_context * context)
{
if (context)
@ -91,7 +93,7 @@ nix_store_get_version(nix_c_context * context, Store * store, nix_get_string_cal
NIXC_CATCH_ERRS
}
bool nix_store_is_valid_path(nix_c_context * context, Store * store, StorePath * path)
bool nix_store_is_valid_path(nix_c_context * context, Store * store, const StorePath * path)
{
if (context)
context->last_err_code = NIX_OK;
@ -129,7 +131,7 @@ nix_err nix_store_realise(
Store * store,
StorePath * path,
void * userdata,
void (*callback)(void * userdata, const char *, const char *))
void (*callback)(void * userdata, const char *, const StorePath *))
{
if (context)
context->last_err_code = NIX_OK;
@ -144,8 +146,8 @@ nix_err nix_store_realise(
if (callback) {
for (const auto & result : results) {
for (const auto & [outputName, realisation] : result.builtOutputs) {
auto op = store->ptr->printStorePath(realisation.outPath);
callback(userdata, outputName.c_str(), op.c_str());
StorePath p{realisation.outPath};
callback(userdata, outputName.c_str(), &p);
}
}
}
@ -180,3 +182,5 @@ nix_err nix_store_copy_closure(nix_c_context * context, Store * srcStore, Store
}
NIXC_CATCH_ERRS
}
} // extern "C"

View file

@ -148,7 +148,7 @@ void nix_store_path_free(StorePath * p);
* @param[in] path Path to check
* @return true or false, error info in context
*/
bool nix_store_is_valid_path(nix_c_context * context, Store * store, StorePath * path);
bool nix_store_is_valid_path(nix_c_context * context, Store * store, const StorePath * path);
/**
* @brief Get the physical location of a store path
@ -190,7 +190,7 @@ nix_err nix_store_realise(
Store * store,
StorePath * path,
void * userdata,
void (*callback)(void * userdata, const char * outname, const char * out));
void (*callback)(void * userdata, const char * outname, const StorePath * out));
/**
* @brief get the version of a nix store.

View file

@ -2,6 +2,8 @@
#define NIX_API_STORE_INTERNAL_H
#include "nix/store/store-api.hh"
extern "C" {
struct Store
{
nix::ref<nix::Store> ptr;
@ -12,4 +14,6 @@ struct StorePath
nix::StorePath path;
};
} // extern "C"
#endif

View file

@ -51,18 +51,10 @@ static void BM_UnparseRealDerivationFile(benchmark::State & state, const std::st
// Register benchmarks for actual test derivation files if they exist
BENCHMARK_CAPTURE(
BM_ParseRealDerivationFile,
hello,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv");
BM_ParseRealDerivationFile, hello, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/hello.drv");
BENCHMARK_CAPTURE(
BM_ParseRealDerivationFile,
firefox,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv");
BM_ParseRealDerivationFile, firefox, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/firefox.drv");
BENCHMARK_CAPTURE(
BM_UnparseRealDerivationFile,
hello,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv");
BM_UnparseRealDerivationFile, hello, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/hello.drv");
BENCHMARK_CAPTURE(
BM_UnparseRealDerivationFile,
firefox,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv");
BM_UnparseRealDerivationFile, firefox, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/firefox.drv");

View file

@ -130,10 +130,13 @@ if get_option('benchmarks')
link_args : linker_export_flags,
install : true,
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [],
cpp_args : [
'-DNIX_UNIT_TEST_DATA="' + meson.current_source_dir() + '/data"',
],
)
benchmark('nix-store-benchmarks', benchmark_exe)
benchmark(
'nix-store-benchmarks',
benchmark_exe,
env : {
'_NIX_TEST_UNIT_DATA' : meson.current_source_dir() / 'data',
},
)
endif

View file

@ -1,7 +1,5 @@
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix/store/tests/nix_api_store.hh"
#include "nix/util/tests/string_callback.hh"
@ -65,7 +63,7 @@ TEST_F(nix_api_store_test, nix_store_get_storedir)
TEST_F(nix_api_store_test, InvalidPathFails)
{
nix_store_parse_path(ctx, store, "invalid-path");
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
}
TEST_F(nix_api_store_test, ReturnsValidStorePath)
@ -80,7 +78,7 @@ TEST_F(nix_api_store_test, ReturnsValidStorePath)
TEST_F(nix_api_store_test, SetsLastErrCodeToNixOk)
{
StorePath * path = nix_store_parse_path(ctx, store, (nixStoreDir + PATH_SUFFIX).c_str());
ASSERT_EQ(ctx->last_err_code, NIX_OK);
ASSERT_EQ(nix_err_code(ctx), NIX_OK);
nix_store_path_free(path);
}
@ -103,7 +101,7 @@ TEST_F(nix_api_util_context, nix_store_open_dummy)
{
nix_libstore_init(ctx);
Store * store = nix_store_open(ctx, "dummy://", nullptr);
ASSERT_EQ(NIX_OK, ctx->last_err_code);
ASSERT_EQ(NIX_OK, nix_err_code(ctx));
ASSERT_STREQ("dummy://", store->ptr->config.getReference().render(/*withParams=*/true).c_str());
std::string str;
@ -117,7 +115,7 @@ TEST_F(nix_api_util_context, nix_store_open_invalid)
{
nix_libstore_init(ctx);
Store * store = nix_store_open(ctx, "invalid://", nullptr);
ASSERT_EQ(NIX_ERR_NIX_ERROR, ctx->last_err_code);
ASSERT_EQ(NIX_ERR_NIX_ERROR, nix_err_code(ctx));
ASSERT_EQ(nullptr, store);
nix_store_free(store);
}

View file

@ -9,6 +9,8 @@
#include "nix_api_util_config.h"
extern "C" {
nix_c_context * nix_c_context_create()
{
return new nix_c_context();
@ -156,3 +158,5 @@ nix_err call_nix_get_string_callback(const std::string str, nix_get_string_callb
callback(str.c_str(), str.size(), user_data);
return NIX_OK;
}
} // extern "C"

View file

@ -7,6 +7,8 @@
#include "nix/util/error.hh"
#include "nix_api_util.h"
extern "C" {
struct nix_c_context
{
nix_err last_err_code = NIX_OK;
@ -47,4 +49,6 @@ nix_err call_nix_get_string_callback(const std::string str, nix_get_string_callb
}
#define NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_RES(nullptr)
} // extern "C"
#endif // NIX_API_UTIL_INTERNAL_H

View file

@ -54,4 +54,12 @@ protected:
#define assert_ctx_err() assert_ctx_err(__FILE__, __LINE__)
};
static inline auto createOwnedNixContext()
{
return std::unique_ptr<nix_c_context, decltype([](nix_c_context * ctx) {
if (ctx)
nix_c_context_free(ctx);
})>(nix_c_context_create(), {});
}
} // namespace nixC

View file

@ -63,6 +63,7 @@ sources = files(
'lru-cache.cc',
'monitorfdhup.cc',
'nix_api_util.cc',
'nix_api_util_internal.cc',
'pool.cc',
'position.cc',
'processes.cc',

View file

@ -1,7 +1,6 @@
#include "nix/util/config-global.hh"
#include "nix/util/args.hh"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix/util/tests/nix_api_util.hh"
#include "nix/util/tests/string_callback.hh"
@ -13,41 +12,6 @@
namespace nixC {
TEST_F(nix_api_util_context, nix_context_error)
{
std::string err_msg_ref;
try {
throw nix::Error("testing error");
} catch (nix::Error & e) {
err_msg_ref = e.what();
nix_context_error(ctx);
}
ASSERT_EQ(ctx->last_err_code, NIX_ERR_NIX_ERROR);
ASSERT_EQ(ctx->name, "nix::Error");
ASSERT_EQ(*ctx->last_err, err_msg_ref);
ASSERT_EQ(ctx->info->msg.str(), "testing error");
try {
throw std::runtime_error("testing exception");
} catch (std::exception & e) {
err_msg_ref = e.what();
nix_context_error(ctx);
}
ASSERT_EQ(ctx->last_err_code, NIX_ERR_UNKNOWN);
ASSERT_EQ(*ctx->last_err, err_msg_ref);
nix_clear_err(ctx);
ASSERT_EQ(ctx->last_err_code, NIX_OK);
}
TEST_F(nix_api_util_context, nix_set_err_msg)
{
ASSERT_EQ(ctx->last_err_code, NIX_OK);
nix_set_err_msg(ctx, NIX_ERR_UNKNOWN, "unknown test error");
ASSERT_EQ(ctx->last_err_code, NIX_ERR_UNKNOWN);
ASSERT_EQ(*ctx->last_err, "unknown test error");
}
TEST(nix_api_util, nix_version_get)
{
ASSERT_EQ(std::string(nix_version_get()), PACKAGE_VERSION);
@ -61,17 +25,9 @@ struct MySettings : nix::Config
MySettings mySettings;
static nix::GlobalConfig::Register rs(&mySettings);
static auto createOwnedNixContext()
{
return std::unique_ptr<nix_c_context, decltype([](nix_c_context * ctx) {
if (ctx)
nix_c_context_free(ctx);
})>(nix_c_context_create(), {});
}
TEST_F(nix_api_util_context, nix_setting_get)
{
ASSERT_EQ(ctx->last_err_code, NIX_OK);
ASSERT_EQ(nix_err_code(ctx), NIX_OK);
std::string setting_value;
nix_err result = nix_setting_get(ctx, "invalid-key", OBSERVE_STRING(setting_value));
ASSERT_EQ(result, NIX_ERR_KEY);
@ -114,40 +70,6 @@ TEST_F(nix_api_util_context, nix_err_msg)
ASSERT_EQ(sz, err_msg.size());
}
TEST_F(nix_api_util_context, nix_err_info_msg)
{
std::string err_info;
// no 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);
}
auto new_ctx = createOwnedNixContext();
nix_err_info_msg(new_ctx.get(), ctx, OBSERVE_STRING(err_info));
ASSERT_STREQ("testing error", err_info.c_str());
}
TEST_F(nix_api_util_context, nix_err_name)
{
std::string err_name;
// no error
EXPECT_THROW(nix_err_name(NULL, ctx, OBSERVE_STRING(err_name)), nix::Error);
try {
throw nix::Error("testing error");
} catch (...) {
nix_context_error(ctx);
}
auto new_ctx = createOwnedNixContext();
nix_err_name(new_ctx.get(), ctx, OBSERVE_STRING(err_name));
ASSERT_EQ(std::string(err_name), "nix::Error");
}
TEST_F(nix_api_util_context, nix_err_code)
{
ASSERT_EQ(nix_err_code(ctx), NIX_OK);

View file

@ -0,0 +1,85 @@
#include "nix/util/config-global.hh"
#include "nix/util/args.hh"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix/util/tests/nix_api_util.hh"
#include "nix/util/tests/string_callback.hh"
#include <gtest/gtest.h>
#include <memory>
#include "util-tests-config.hh"
namespace nixC {
TEST_F(nix_api_util_context, nix_context_error)
{
std::string err_msg_ref;
try {
throw nix::Error("testing error");
} catch (nix::Error & e) {
err_msg_ref = e.what();
nix_context_error(ctx);
}
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_NIX_ERROR);
ASSERT_EQ(ctx->name, "nix::Error");
ASSERT_EQ(*ctx->last_err, err_msg_ref);
ASSERT_EQ(ctx->info->msg.str(), "testing error");
try {
throw std::runtime_error("testing exception");
} catch (std::exception & e) {
err_msg_ref = e.what();
nix_context_error(ctx);
}
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_UNKNOWN);
ASSERT_EQ(*ctx->last_err, err_msg_ref);
nix_clear_err(ctx);
ASSERT_EQ(nix_err_code(ctx), NIX_OK);
}
TEST_F(nix_api_util_context, nix_set_err_msg)
{
ASSERT_EQ(nix_err_code(ctx), NIX_OK);
nix_set_err_msg(ctx, NIX_ERR_UNKNOWN, "unknown test error");
ASSERT_EQ(nix_err_code(ctx), NIX_ERR_UNKNOWN);
ASSERT_EQ(*ctx->last_err, "unknown test error");
}
TEST_F(nix_api_util_context, nix_err_info_msg)
{
std::string err_info;
// no 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);
}
auto new_ctx = createOwnedNixContext();
nix_err_info_msg(new_ctx.get(), ctx, OBSERVE_STRING(err_info));
ASSERT_STREQ("testing error", err_info.c_str());
}
TEST_F(nix_api_util_context, nix_err_name)
{
std::string err_name;
// no error
EXPECT_THROW(nix_err_name(NULL, ctx, OBSERVE_STRING(err_name)), nix::Error);
try {
throw nix::Error("testing error");
} catch (...) {
nix_context_error(ctx);
}
auto new_ctx = createOwnedNixContext();
nix_err_name(new_ctx.get(), ctx, OBSERVE_STRING(err_name));
ASSERT_EQ(std::string(err_name), "nix::Error");
}
} // namespace nixC