forked from lix-project/lix
Create EvalState::coerceToDerivedPath
This gives us some round trips to test. `EvalState::coerceToDerivedPathUnchecked` is a factored out helper just for unit testing.
This commit is contained in:
parent
8e1a990268
commit
5a23b80b0a
|
@ -2318,6 +2318,80 @@ StorePath EvalState::coerceToStorePath(const PosIdx pos, Value & v, NixStringCon
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::pair<DerivedPath, std::string_view> EvalState::coerceToDerivedPathUnchecked(const PosIdx pos, Value & v, std::string_view errorCtx)
|
||||||
|
{
|
||||||
|
NixStringContext context;
|
||||||
|
auto s = forceString(v, context, pos, errorCtx);
|
||||||
|
auto csize = context.size();
|
||||||
|
if (csize != 1)
|
||||||
|
error(
|
||||||
|
"string '%s' has %d entries in its context. It should only have exactly one entry",
|
||||||
|
s, csize)
|
||||||
|
.withTrace(pos, errorCtx).debugThrow<EvalError>();
|
||||||
|
auto derivedPath = std::visit(overloaded {
|
||||||
|
[&](NixStringContextElem::Opaque && o) -> DerivedPath {
|
||||||
|
return DerivedPath::Opaque {
|
||||||
|
.path = std::move(o.path),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
[&](NixStringContextElem::DrvDeep &&) -> DerivedPath {
|
||||||
|
error(
|
||||||
|
"string '%s' has a context which refers to a complete source and binary closure. This is not supported at this time",
|
||||||
|
s).withTrace(pos, errorCtx).debugThrow<EvalError>();
|
||||||
|
},
|
||||||
|
[&](NixStringContextElem::Built && b) -> DerivedPath {
|
||||||
|
return DerivedPath::Built {
|
||||||
|
.drvPath = std::move(b.drvPath),
|
||||||
|
.outputs = OutputsSpec::Names { std::move(b.output) },
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}, ((NixStringContextElem &&) *context.begin()).raw());
|
||||||
|
return {
|
||||||
|
std::move(derivedPath),
|
||||||
|
std::move(s),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DerivedPath EvalState::coerceToDerivedPath(const PosIdx pos, Value & v, std::string_view errorCtx)
|
||||||
|
{
|
||||||
|
auto [derivedPath, s_] = coerceToDerivedPathUnchecked(pos, v, errorCtx);
|
||||||
|
auto s = s_;
|
||||||
|
std::visit(overloaded {
|
||||||
|
[&](const DerivedPath::Opaque & o) {
|
||||||
|
auto sExpected = store->printStorePath(o.path);
|
||||||
|
if (s != sExpected)
|
||||||
|
error(
|
||||||
|
"path string '%s' has context with the different path '%s'",
|
||||||
|
s, sExpected)
|
||||||
|
.withTrace(pos, errorCtx).debugThrow<EvalError>();
|
||||||
|
},
|
||||||
|
[&](const DerivedPath::Built & b) {
|
||||||
|
// TODO need derived path with single output to make this
|
||||||
|
// total. Will add as part of RFC 92 work and then this is
|
||||||
|
// cleaned up.
|
||||||
|
auto output = *std::get<OutputsSpec::Names>(b.outputs).begin();
|
||||||
|
|
||||||
|
auto drv = store->readDerivation(b.drvPath);
|
||||||
|
auto i = drv.outputs.find(output);
|
||||||
|
if (i == drv.outputs.end())
|
||||||
|
throw Error("derivation '%s' does not have output '%s'", store->printStorePath(b.drvPath), output);
|
||||||
|
auto optOutputPath = i->second.path(*store, drv.name, output);
|
||||||
|
// This is testing for the case of CA derivations
|
||||||
|
auto sExpected = optOutputPath
|
||||||
|
? store->printStorePath(*optOutputPath)
|
||||||
|
: downstreamPlaceholder(*store, b.drvPath, output);
|
||||||
|
if (s != sExpected)
|
||||||
|
error(
|
||||||
|
"string '%s' has context with the output '%s' from derivation '%s', but the string is not the right placeholder for this derivation output. It should be '%s'",
|
||||||
|
s, output, store->printStorePath(b.drvPath), sExpected)
|
||||||
|
.withTrace(pos, errorCtx).debugThrow<EvalError>();
|
||||||
|
}
|
||||||
|
}, derivedPath.raw());
|
||||||
|
return derivedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_view errorCtx)
|
||||||
{
|
{
|
||||||
forceValue(v1, noPos);
|
forceValue(v1, noPos);
|
||||||
|
|
|
@ -21,6 +21,7 @@ namespace nix {
|
||||||
class Store;
|
class Store;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
class StorePath;
|
class StorePath;
|
||||||
|
struct DerivedPath;
|
||||||
enum RepairFlag : bool;
|
enum RepairFlag : bool;
|
||||||
|
|
||||||
|
|
||||||
|
@ -473,6 +474,28 @@ public:
|
||||||
*/
|
*/
|
||||||
StorePath coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx);
|
StorePath coerceToStorePath(const PosIdx pos, Value & v, NixStringContext & context, std::string_view errorCtx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part of `coerceToDerivedPath()` without any store IO which is exposed for unit testing only.
|
||||||
|
*/
|
||||||
|
std::pair<DerivedPath, std::string_view> coerceToDerivedPathUnchecked(const PosIdx pos, Value & v, std::string_view errorCtx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Coerce to `DerivedPath`.
|
||||||
|
*
|
||||||
|
* Must be a string which is either a literal store path or a
|
||||||
|
* "placeholder (see `downstreamPlaceholder()`).
|
||||||
|
*
|
||||||
|
* Even more importantly, the string context must be exactly one
|
||||||
|
* element, which is either a `NixStringContextElem::Opaque` or
|
||||||
|
* `NixStringContextElem::Built`. (`NixStringContextEleme::DrvDeep`
|
||||||
|
* is not permitted).
|
||||||
|
*
|
||||||
|
* The string is parsed based on the context --- the context is the
|
||||||
|
* source of truth, and ultimately tells us what we want, and then
|
||||||
|
* we ensure the string corresponds to it.
|
||||||
|
*/
|
||||||
|
DerivedPath coerceToDerivedPath(const PosIdx pos, Value & v, std::string_view errorCtx);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
65
src/libexpr/tests/derived-path.cc
Normal file
65
src/libexpr/tests/derived-path.cc
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <rapidcheck/gtest.h>
|
||||||
|
|
||||||
|
#include "tests/derived-path.hh"
|
||||||
|
#include "tests/libexpr.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
// Testing of trivial expressions
|
||||||
|
class DerivedPathExpressionTest : public LibExprTest {};
|
||||||
|
|
||||||
|
// FIXME: `RC_GTEST_FIXTURE_PROP` isn't calling `SetUpTestSuite` because it is
|
||||||
|
// no a real fixture.
|
||||||
|
//
|
||||||
|
// See https://github.com/emil-e/rapidcheck/blob/master/doc/gtest.md#rc_gtest_fixture_propfixture-name-args
|
||||||
|
TEST_F(DerivedPathExpressionTest, force_init)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RC_GTEST_FIXTURE_PROP(
|
||||||
|
DerivedPathExpressionTest,
|
||||||
|
prop_opaque_path_round_trip,
|
||||||
|
(const DerivedPath::Opaque & o))
|
||||||
|
{
|
||||||
|
auto * v = state.allocValue();
|
||||||
|
state.mkStorePathString(o.path, *v);
|
||||||
|
auto d = state.coerceToDerivedPath(noPos, *v, "");
|
||||||
|
RC_ASSERT(DerivedPath { o } == d);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO use DerivedPath::Built for parameter once it supports a single output
|
||||||
|
// path only.
|
||||||
|
|
||||||
|
RC_GTEST_FIXTURE_PROP(
|
||||||
|
DerivedPathExpressionTest,
|
||||||
|
prop_built_path_placeholder_round_trip,
|
||||||
|
(const StorePath & drvPath, const StorePathName & outputName))
|
||||||
|
{
|
||||||
|
auto * v = state.allocValue();
|
||||||
|
state.mkOutputString(*v, drvPath, outputName.name, std::nullopt);
|
||||||
|
auto [d, _] = state.coerceToDerivedPathUnchecked(noPos, *v, "");
|
||||||
|
DerivedPath::Built b {
|
||||||
|
.drvPath = drvPath,
|
||||||
|
.outputs = OutputsSpec::Names { outputName.name },
|
||||||
|
};
|
||||||
|
RC_ASSERT(DerivedPath { b } == d);
|
||||||
|
}
|
||||||
|
|
||||||
|
RC_GTEST_FIXTURE_PROP(
|
||||||
|
DerivedPathExpressionTest,
|
||||||
|
prop_built_path_out_path_round_trip,
|
||||||
|
(const StorePath & drvPath, const StorePathName & outputName, const StorePath & outPath))
|
||||||
|
{
|
||||||
|
auto * v = state.allocValue();
|
||||||
|
state.mkOutputString(*v, drvPath, outputName.name, outPath);
|
||||||
|
auto [d, _] = state.coerceToDerivedPathUnchecked(noPos, *v, "");
|
||||||
|
DerivedPath::Built b {
|
||||||
|
.drvPath = drvPath,
|
||||||
|
.outputs = OutputsSpec::Names { outputName.name },
|
||||||
|
};
|
||||||
|
RC_ASSERT(DerivedPath { b } == d);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace nix */
|
Loading…
Reference in a new issue