1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-07 09:31:01 +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))); return new (p) T(init(static_cast<T *>(p)));
} }
extern "C" {
nix_err nix_libexpr_init(nix_c_context * context) nix_err nix_libexpr_init(nix_c_context * context)
{ {
if (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); GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
#endif #endif
} }
} // extern "C"

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,5 @@
#include "nix_api_store.h" #include "nix_api_store.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h" #include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h" #include "nix_api_expr.h"
#include "nix_api_value.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(); assert_ctx_ok();
auto r = nix_string_realise(ctx, state, value, false); auto r = nix_string_realise(ctx, state, value, false);
ASSERT_EQ(nullptr, r); ASSERT_EQ(nullptr, r);
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("cannot coerce"))); ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("cannot coerce"));
} }
TEST_F(nix_api_expr_test, nix_expr_realise_context_bad_build) 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(); assert_ctx_ok();
auto r = nix_string_realise(ctx, state, value, false); auto r = nix_string_realise(ctx, state, value, false);
ASSERT_EQ(nullptr, r); ASSERT_EQ(nullptr, r);
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("failed with exit code 1"))); 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) 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); nix_value * result = nix_alloc_value(ctx, state);
assert_ctx_ok(); assert_ctx_ok();
nix_value_call(ctx, state, primopValue, three, result); 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( ASSERT_THAT(
ctx->last_err, nix_err_msg(nullptr, ctx, nullptr),
testing::Optional( testing::HasSubstr("Implementation error in custom function: return value was not initialized"));
testing::HasSubstr("Implementation error in custom function: return value was not initialized"))); ASSERT_THAT(nix_err_msg(nullptr, ctx, nullptr), testing::HasSubstr("badNoReturn"));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badNoReturn")));
} }
static void primop_bad_return_thunk( 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(); assert_ctx_ok();
NIX_VALUE_CALL(ctx, state, result, primopValue, toString, four); 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( ASSERT_THAT(
ctx->last_err, nix_err_msg(nullptr, ctx, nullptr),
testing::Optional( testing::HasSubstr("Implementation error in custom function: return value must not be a thunk"));
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"));
ASSERT_THAT(ctx->last_err, testing::Optional(testing::HasSubstr("badReturnThunk")));
} }
TEST_F(nix_api_expr_test, nix_value_call_multi_no_args) 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.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h" #include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h" #include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
#include "nix_api_value.h" #include "nix_api_value.h"
#include "nix_api_external.h" #include "nix_api_external.h"
@ -39,7 +36,7 @@ private:
std::string type_string = "nix-external<MyExternalValueDesc( "; std::string type_string = "nix-external<MyExternalValueDesc( ";
type_string += std::to_string(obj->_x); type_string += std::to_string(obj->_x);
type_string += " )>"; 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.h"
#include "nix_api_store_internal.h"
#include "nix_api_util.h" #include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_expr.h" #include "nix_api_expr.h"
#include "nix_api_value.h" #include "nix_api_value.h"
#include "nix_api_expr_internal.h"
#include "nix/expr/tests/nix_api_expr.hh" #include "nix/expr/tests/nix_api_expr.hh"
#include "nix/util/tests/string_callback.hh" #include "nix/util/tests/string_callback.hh"
@ -16,14 +13,6 @@
namespace nixC { 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) TEST_F(nix_api_expr_test, nix_value_get_int_invalid)
{ {
ASSERT_EQ(0, nix_get_int(ctx, nullptr)); 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 // Evaluate it
nix_value_force(ctx, state, v); nix_value_force(ctx, state, v);
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.value(), testing::HasSubstr("attempt to call something which is not a function but")); ASSERT_THAT(
nix_err_msg(nullptr, ctx, nullptr),
testing::HasSubstr("attempt to call something which is not a function but"));
// Clean up // Clean up
nix_gc_decref(ctx, some_string); 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_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"); nix_value * foo = nix_get_attr_byname(ctx, r, state, "foo");
ASSERT_EQ(nullptr, 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 // Clean up
nix_gc_decref(ctx, f); 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_fetchers_internal.hh"
#include "nix_api_util_internal.h" #include "nix_api_util_internal.h"
extern "C" {
nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context) nix_fetchers_settings * nix_fetchers_settings_new(nix_c_context * context)
{ {
try { try {
@ -17,3 +19,5 @@ void nix_fetchers_settings_free(nix_fetchers_settings * settings)
{ {
delete settings; delete settings;
} }
} // extern "C"

View file

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

View file

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

View file

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

View file

@ -148,7 +148,7 @@ void nix_store_path_free(StorePath * p);
* @param[in] path Path to check * @param[in] path Path to check
* @return true or false, error info in context * @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 * @brief Get the physical location of a store path
@ -190,7 +190,7 @@ nix_err nix_store_realise(
Store * store, Store * store,
StorePath * path, StorePath * path,
void * userdata, 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. * @brief get the version of a nix store.

View file

@ -2,6 +2,8 @@
#define NIX_API_STORE_INTERNAL_H #define NIX_API_STORE_INTERNAL_H
#include "nix/store/store-api.hh" #include "nix/store/store-api.hh"
extern "C" {
struct Store struct Store
{ {
nix::ref<nix::Store> ptr; nix::ref<nix::Store> ptr;
@ -12,4 +14,6 @@ struct StorePath
nix::StorePath path; nix::StorePath path;
}; };
} // extern "C"
#endif #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 // Register benchmarks for actual test derivation files if they exist
BENCHMARK_CAPTURE( BENCHMARK_CAPTURE(
BM_ParseRealDerivationFile, BM_ParseRealDerivationFile, hello, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/hello.drv");
hello,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv");
BENCHMARK_CAPTURE( BENCHMARK_CAPTURE(
BM_ParseRealDerivationFile, BM_ParseRealDerivationFile, firefox, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/firefox.drv");
firefox,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv");
BENCHMARK_CAPTURE( BENCHMARK_CAPTURE(
BM_UnparseRealDerivationFile, BM_UnparseRealDerivationFile, hello, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/hello.drv");
hello,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/hello.drv");
BENCHMARK_CAPTURE( BENCHMARK_CAPTURE(
BM_UnparseRealDerivationFile, BM_UnparseRealDerivationFile, firefox, getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value() + "/derivation/firefox.drv");
firefox,
getEnvNonEmpty("_NIX_TEST_UNIT_DATA").value_or(NIX_UNIT_TEST_DATA) + "/derivation/firefox.drv");

View file

@ -130,10 +130,13 @@ if get_option('benchmarks')
link_args : linker_export_flags, link_args : linker_export_flags,
install : true, install : true,
cpp_pch : do_pch ? [ 'pch/precompiled-headers.hh' ] : [], 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 endif

View file

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

View file

@ -9,6 +9,8 @@
#include "nix_api_util_config.h" #include "nix_api_util_config.h"
extern "C" {
nix_c_context * nix_c_context_create() nix_c_context * nix_c_context_create()
{ {
return new nix_c_context(); 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); callback(str.c_str(), str.size(), user_data);
return NIX_OK; return NIX_OK;
} }
} // extern "C"

View file

@ -7,6 +7,8 @@
#include "nix/util/error.hh" #include "nix/util/error.hh"
#include "nix_api_util.h" #include "nix_api_util.h"
extern "C" {
struct nix_c_context struct nix_c_context
{ {
nix_err last_err_code = NIX_OK; 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) #define NIXC_CATCH_ERRS_NULL NIXC_CATCH_ERRS_RES(nullptr)
} // extern "C"
#endif // NIX_API_UTIL_INTERNAL_H #endif // NIX_API_UTIL_INTERNAL_H

View file

@ -54,4 +54,12 @@ protected:
#define assert_ctx_err() assert_ctx_err(__FILE__, __LINE__) #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 } // namespace nixC

View file

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

View file

@ -1,7 +1,6 @@
#include "nix/util/config-global.hh" #include "nix/util/config-global.hh"
#include "nix/util/args.hh" #include "nix/util/args.hh"
#include "nix_api_util.h" #include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix/util/tests/nix_api_util.hh" #include "nix/util/tests/nix_api_util.hh"
#include "nix/util/tests/string_callback.hh" #include "nix/util/tests/string_callback.hh"
@ -13,41 +12,6 @@
namespace nixC { 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) TEST(nix_api_util, nix_version_get)
{ {
ASSERT_EQ(std::string(nix_version_get()), PACKAGE_VERSION); ASSERT_EQ(std::string(nix_version_get()), PACKAGE_VERSION);
@ -61,17 +25,9 @@ struct MySettings : nix::Config
MySettings mySettings; MySettings mySettings;
static nix::GlobalConfig::Register rs(&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) 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; std::string setting_value;
nix_err result = nix_setting_get(ctx, "invalid-key", OBSERVE_STRING(setting_value)); nix_err result = nix_setting_get(ctx, "invalid-key", OBSERVE_STRING(setting_value));
ASSERT_EQ(result, NIX_ERR_KEY); 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()); 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) TEST_F(nix_api_util_context, nix_err_code)
{ {
ASSERT_EQ(nix_err_code(ctx), NIX_OK); 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