From c217f098f0a41af48d510150d13fd8b97fd8df88 Mon Sep 17 00:00:00 2001 From: Yingchi Long Date: Tue, 9 Apr 2024 00:05:56 +0800 Subject: [PATCH] libnixt: add Value library (#389) --- libnixt/include/nixt/Value.h | 12 +++++++++ libnixt/lib/Value.cpp | 41 ++++++++++++++++++++++++++++++ libnixt/meson.build | 2 ++ libnixt/test/ASTReader.cpp | 10 +++----- libnixt/test/StateTest.h | 13 ++++++++++ libnixt/test/Value.cpp | 48 ++++++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 7 deletions(-) create mode 100644 libnixt/include/nixt/Value.h create mode 100644 libnixt/lib/Value.cpp create mode 100644 libnixt/test/StateTest.h create mode 100644 libnixt/test/Value.cpp diff --git a/libnixt/include/nixt/Value.h b/libnixt/include/nixt/Value.h new file mode 100644 index 000000000..f5be62bc7 --- /dev/null +++ b/libnixt/include/nixt/Value.h @@ -0,0 +1,12 @@ +#include + +namespace nixt { + +bool isOption(nix::EvalState &State, nix::Value &V); + +bool isDerivation(nix::EvalState &State, nix::Value &V); + +std::string attrPathStr(nix::EvalState &State, nix::Value &V, + const std::string &AttrPath); + +} // namespace nixt diff --git a/libnixt/lib/Value.cpp b/libnixt/lib/Value.cpp new file mode 100644 index 000000000..3227cab94 --- /dev/null +++ b/libnixt/lib/Value.cpp @@ -0,0 +1,41 @@ +#include "nixt/Value.h" + +#include + +using namespace nixt; + +bool nixt::isOption(nix::EvalState &State, nix::Value &V) { + State.forceValue(V, nix::noPos); + if (V.type() != nix::ValueType::nAttrs) + return false; + + // https://github.com/NixOS/nixpkgs/blob/58ca986543b591a8269cbce3328293ca8d64480f/lib/options.nix#L89 + try { + auto S = attrPathStr(State, V, "_type"); + return S == "option"; + } catch (nix::AttrPathNotFound &Error) { + return false; + } +}; + +bool nixt::isDerivation(nix::EvalState &State, nix::Value &V) { + State.forceValue(V, nix::noPos); + if (V.type() != nix::ValueType::nAttrs) + return false; + + try { + // Derivations has a special attribute "type" == "derivation" + auto S = attrPathStr(State, V, "type"); + return S == "derivation"; + } catch (nix::AttrPathNotFound &Error) { + return false; + } +} + +std::string nixt::attrPathStr(nix::EvalState &State, nix::Value &V, + const std::string &AttrPath) { + auto &AutoArgs = *State.allocBindings(0); + auto [VPath, Pos] = nix::findAlongAttrPath(State, AttrPath, AutoArgs, V); + State.forceValue(*VPath, Pos); + return std::string(State.forceStringNoCtx(*VPath, nix::noPos, "")); +} diff --git a/libnixt/meson.build b/libnixt/meson.build index 6b3460257..8d573d448 100644 --- a/libnixt/meson.build +++ b/libnixt/meson.build @@ -13,6 +13,7 @@ libnixt = library('nixt', 'lib/HookExpr.cpp', 'lib/Kinds.cpp', 'lib/ParentMap.cpp', + 'lib/Value.cpp', include_directories: libnixdInc, dependencies: libnixtDeps, install: true @@ -37,6 +38,7 @@ libnixt_test_exe = executable( 'test/ASTReader.cpp', 'test/InitEval.cpp', 'test/Kinds.cpp', + 'test/Value.cpp', dependencies: [ gtest_main, nixt ] ) diff --git a/libnixt/test/ASTReader.cpp b/libnixt/test/ASTReader.cpp index b062dad90..36bd06d5f 100644 --- a/libnixt/test/ASTReader.cpp +++ b/libnixt/test/ASTReader.cpp @@ -1,6 +1,5 @@ -#include - #include "ReaderData/ReaderData.h" +#include "StateTest.h" #include "nixt/Deserialize.h" #include "nixt/InitEval.h" @@ -12,16 +11,13 @@ using namespace nixt; namespace { -struct ReaderTest : testing::Test { - std::unique_ptr State; +struct ReaderTest : StateTest { nix::Pos::Origin O = nix::Pos::none_tag{}; DeserializeContext Ctx; ValueMap VMap; EnvMap EMap; PtrPool Pool; - ReaderTest() - : State(new nix::EvalState{{}, nix::openStore("dummy://")}), - Ctx(getDeserializeContext(*State, ".", O)) {} + ReaderTest() : Ctx(getDeserializeContext(*State, ".", O)) {} }; TEST_F(ReaderTest, AllGrammars) { diff --git a/libnixt/test/StateTest.h b/libnixt/test/StateTest.h new file mode 100644 index 000000000..9f702c161 --- /dev/null +++ b/libnixt/test/StateTest.h @@ -0,0 +1,13 @@ +#include + +#include +#include + +namespace nixt { + +struct StateTest : testing::Test { + std::unique_ptr State; + StateTest() : State(new nix::EvalState{{}, nix::openStore("dummy://")}) {} +}; + +} // namespace nixt diff --git a/libnixt/test/Value.cpp b/libnixt/test/Value.cpp new file mode 100644 index 000000000..592f97165 --- /dev/null +++ b/libnixt/test/Value.cpp @@ -0,0 +1,48 @@ +#include "StateTest.h" + +#include "nixt/Value.h" + +using namespace nixt; + +namespace { + +struct ValueTest : StateTest { + nix::SourcePath cwd() { return State->rootPath(nix::CanonPath::fromCwd()); } +}; + +TEST_F(ValueTest, IsOption_neg) { + nix::Expr *AST = State->parseExprFromString("1", cwd()); + nix::Value V; + State->eval(AST, V); + + ASSERT_FALSE(isOption(*State, V)); +} + +TEST_F(ValueTest, IsOption_pos) { + nix::Expr *AST = + State->parseExprFromString(R"({ _type = "option"; })", cwd()); + nix::Value V; + State->eval(AST, V); + + ASSERT_TRUE(isOption(*State, V)); +} + +TEST_F(ValueTest, IsDerivation_neg) { + nix::Expr *AST = + State->parseExprFromString(R"({ _type = "option"; })", cwd()); + nix::Value V; + State->eval(AST, V); + + ASSERT_FALSE(isDerivation(*State, V)); +} + +TEST_F(ValueTest, IsDerivation_pos) { + nix::Expr *AST = + State->parseExprFromString(R"({ type = "derivation"; })", cwd()); + nix::Value V; + State->eval(AST, V); + + ASSERT_TRUE(isDerivation(*State, V)); +} + +} // namespace