mirror of
https://github.com/NixOS/nix
synced 2025-07-07 22:33:57 +02:00
Merge remote-tracking branch 'origin/master' into detsys-main
This commit is contained in:
commit
042c2ae3ac
222 changed files with 3295 additions and 1254 deletions
|
@ -63,7 +63,7 @@ function characterisationTestExit() {
|
|||
echo ''
|
||||
echo 'You can rerun this test with:'
|
||||
echo ''
|
||||
echo " _NIX_TEST_ACCEPT=1 make tests/functional/${TEST_NAME}.test"
|
||||
echo " _NIX_TEST_ACCEPT=1 make tests/functional/${TEST_NAME}.sh.test"
|
||||
echo ''
|
||||
echo 'to regenerate the files containing the expected output,'
|
||||
echo 'and then view the git diff to decide whether a change is'
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
source common.sh
|
||||
source characterisation/framework.sh
|
||||
|
||||
testDir="$PWD"
|
||||
cd "$TEST_ROOT"
|
||||
|
@ -73,21 +74,31 @@ testReplResponseGeneral () {
|
|||
local grepMode commands expectedResponse response
|
||||
grepMode="$1"; shift
|
||||
commands="$1"; shift
|
||||
expectedResponse="$1"; shift
|
||||
response="$(nix repl "$@" <<< "$commands" | stripColors)"
|
||||
echo "$response" | grepQuiet "$grepMode" -s "$expectedResponse" \
|
||||
|| fail "repl command set:
|
||||
# Expected response can contain newlines.
|
||||
# grep can't handle multiline patterns, so replace newlines with TEST_NEWLINE
|
||||
# in both expectedResponse and response.
|
||||
# awk ORS always adds a trailing record separator, so we strip it with sed.
|
||||
expectedResponse="$(printf '%s' "$1" | awk 1 ORS=TEST_NEWLINE | sed 's/TEST_NEWLINE$//')"; shift
|
||||
# We don't need to strip trailing record separator here, since extra data is ok.
|
||||
response="$(nix repl "$@" <<< "$commands" 2>&1 | stripColors | awk 1 ORS=TEST_NEWLINE)"
|
||||
printf '%s' "$response" | grepQuiet "$grepMode" -s "$expectedResponse" \
|
||||
|| fail "$(echo "repl command set:
|
||||
|
||||
$commands
|
||||
|
||||
does not respond with:
|
||||
|
||||
---
|
||||
$expectedResponse
|
||||
---
|
||||
|
||||
but with:
|
||||
|
||||
---
|
||||
$response
|
||||
"
|
||||
---
|
||||
|
||||
" | sed 's/TEST_NEWLINE/\n/g')"
|
||||
}
|
||||
|
||||
testReplResponse () {
|
||||
|
@ -189,7 +200,7 @@ testReplResponseNoRegex '
|
|||
let x = { y = { a = 1; }; inherit x; }; in x
|
||||
' \
|
||||
'{
|
||||
x = { ... };
|
||||
x = «repeated»;
|
||||
y = { ... };
|
||||
}
|
||||
'
|
||||
|
@ -241,6 +252,45 @@ testReplResponseNoRegex '
|
|||
' \
|
||||
'{
|
||||
x = «repeated»;
|
||||
y = { a = 1 };
|
||||
y = { a = 1; };
|
||||
}
|
||||
'
|
||||
|
||||
# TODO: move init to characterisation/framework.sh
|
||||
badDiff=0
|
||||
badExitCode=0
|
||||
|
||||
nixVersion="$(nix eval --impure --raw --expr 'builtins.nixVersion' --extra-experimental-features nix-command)"
|
||||
|
||||
runRepl () {
|
||||
|
||||
# That is right, we are also filtering out the testdir _without underscores_.
|
||||
# This is crazy, but without it, GHA will fail to run the tests, showing paths
|
||||
# _with_ underscores in the set -x log, but _without_ underscores in the
|
||||
# supposed nix repl output. I have looked in a number of places, but I cannot
|
||||
# find a mechanism that could cause this to happen.
|
||||
local testDirNoUnderscores
|
||||
testDirNoUnderscores="${testDir//_/}"
|
||||
|
||||
# TODO: pass arguments to nix repl; see lang.sh
|
||||
nix repl 2>&1 \
|
||||
| stripColors \
|
||||
| sed \
|
||||
-e "s@$testDir@/path/to/tests/functional@g" \
|
||||
-e "s@$testDirNoUnderscores@/path/to/tests/functional@g" \
|
||||
-e "s@$nixVersion@<nix version>@g" \
|
||||
-e "s@Added [0-9]* variables@Added <number omitted> variables@g" \
|
||||
| grep -vF $'warning: you don\'t have Internet access; disabling some network-dependent features' \
|
||||
;
|
||||
}
|
||||
|
||||
for test in $(cd "$testDir/repl"; echo *.in); do
|
||||
test="$(basename "$test" .in)"
|
||||
in="$testDir/repl/$test.in"
|
||||
actual="$testDir/repl/$test.actual"
|
||||
expected="$testDir/repl/$test.expected"
|
||||
(cd "$testDir/repl"; set +x; runRepl 2>&1) < "$in" > "$actual"
|
||||
diffAndAcceptInner "$test" "$actual" "$expected"
|
||||
done
|
||||
|
||||
characterisationTestExit
|
||||
|
|
0
tests/functional/repl/characterisation/empty
Normal file
0
tests/functional/repl/characterisation/empty
Normal file
24
tests/functional/repl/doc-comment-curried-args.expected
Normal file
24
tests/functional/repl/doc-comment-curried-args.expected
Normal file
|
@ -0,0 +1,24 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function curriedArgs
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:48:5
|
||||
|
||||
A documented function.
|
||||
|
||||
|
||||
"Note that users may not expect this to behave as it currently does"
|
||||
|
||||
Function curriedArgs
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:50:5
|
||||
|
||||
The function returned by applying once
|
||||
|
||||
"This won't produce documentation, because we can't actually document arbitrary values"
|
||||
|
||||
error: value does not have documentation
|
||||
|
||||
|
7
tests/functional/repl/doc-comment-curried-args.in
Normal file
7
tests/functional/repl/doc-comment-curried-args.in
Normal file
|
@ -0,0 +1,7 @@
|
|||
:l doc-comments.nix
|
||||
:doc curriedArgs
|
||||
x = curriedArgs 1
|
||||
"Note that users may not expect this to behave as it currently does"
|
||||
:doc x
|
||||
"This won't produce documentation, because we can't actually document arbitrary values"
|
||||
:doc x 2
|
13
tests/functional/repl/doc-comment-formals.expected
Normal file
13
tests/functional/repl/doc-comment-formals.expected
Normal file
|
@ -0,0 +1,13 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
"Note that this is not yet complete"
|
||||
|
||||
Function documentedFormals
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:57:5
|
||||
|
||||
Finds x
|
||||
|
||||
|
3
tests/functional/repl/doc-comment-formals.in
Normal file
3
tests/functional/repl/doc-comment-formals.in
Normal file
|
@ -0,0 +1,3 @@
|
|||
:l doc-comments.nix
|
||||
"Note that this is not yet complete"
|
||||
:doc documentedFormals
|
8
tests/functional/repl/doc-comment-function.expected
Normal file
8
tests/functional/repl/doc-comment-function.expected
Normal file
|
@ -0,0 +1,8 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Function defined at
|
||||
/path/to/tests/functional/repl/doc-comment-function.nix:2:1
|
||||
|
||||
A doc comment for a file that only contains a function
|
||||
|
||||
|
1
tests/functional/repl/doc-comment-function.in
Normal file
1
tests/functional/repl/doc-comment-function.in
Normal file
|
@ -0,0 +1 @@
|
|||
:doc import ./doc-comment-function.nix
|
3
tests/functional/repl/doc-comment-function.nix
Normal file
3
tests/functional/repl/doc-comment-function.nix
Normal file
|
@ -0,0 +1,3 @@
|
|||
/** A doc comment for a file that only contains a function */
|
||||
{ ... }:
|
||||
{ }
|
60
tests/functional/repl/doc-comments.nix
Normal file
60
tests/functional/repl/doc-comments.nix
Normal file
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
/**
|
||||
Perform *arithmetic* multiplication. It's kind of like repeated **addition**, very neat.
|
||||
|
||||
```nix
|
||||
multiply 2 3
|
||||
=> 6
|
||||
```
|
||||
*/
|
||||
multiply = x: y: x * y;
|
||||
|
||||
/**👈 precisely this wide 👉*/
|
||||
measurement = x: x;
|
||||
|
||||
floatedIn = /** This also works. */
|
||||
x: y: x;
|
||||
|
||||
compact=/**boom*/x: x;
|
||||
|
||||
# https://github.com/NixOS/rfcs/blob/master/rfcs/0145-doc-strings.md#ambiguous-placement
|
||||
/** Ignore!!! */
|
||||
unambiguous =
|
||||
/** Very close */
|
||||
x: x;
|
||||
|
||||
/** Firmly rigid. */
|
||||
constant = true;
|
||||
|
||||
/** Immovably fixed. */
|
||||
lib.version = "9000";
|
||||
|
||||
/** Unchangeably constant. */
|
||||
lib.attr.empty = { };
|
||||
|
||||
lib.attr.undocumented = { };
|
||||
|
||||
nonStrict = /** My syntax is not strict, but I'm strict anyway. */ x: x;
|
||||
strict = /** I don't have to be strict, but I am anyway. */ { ... }: null;
|
||||
# Note that pre and post are the same here. I just had to name them somehow.
|
||||
strictPre = /** Here's one way to do this */ a@{ ... }: a;
|
||||
strictPost = /** Here's another way to do this */ { ... }@a: a;
|
||||
|
||||
# TODO
|
||||
|
||||
/** You won't see this. */
|
||||
curriedArgs =
|
||||
/** A documented function. */
|
||||
x:
|
||||
/** The function returned by applying once */
|
||||
y:
|
||||
/** A function body performing summation of two items */
|
||||
x + y;
|
||||
|
||||
/** Documented formals (but you won't see this comment) */
|
||||
documentedFormals =
|
||||
/** Finds x */
|
||||
{ /** The x attribute */
|
||||
x
|
||||
}: x;
|
||||
}
|
11
tests/functional/repl/doc-compact.expected
Normal file
11
tests/functional/repl/doc-compact.expected
Normal file
|
@ -0,0 +1,11 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function compact
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:18:20
|
||||
|
||||
boom
|
||||
|
||||
|
2
tests/functional/repl/doc-compact.in
Normal file
2
tests/functional/repl/doc-compact.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
:l doc-comments.nix
|
||||
:doc compact
|
102
tests/functional/repl/doc-constant.expected
Normal file
102
tests/functional/repl/doc-constant.expected
Normal file
|
@ -0,0 +1,102 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
error: value does not have documentation
|
||||
|
||||
Attribute version
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:30:3
|
||||
|
||||
Immovably fixed.
|
||||
|
||||
Attribute empty
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:33:3
|
||||
|
||||
Unchangeably constant.
|
||||
|
||||
error:
|
||||
… while evaluating the attribute 'attr.undocument'
|
||||
at /path/to/tests/functional/repl/doc-comments.nix:33:3:
|
||||
32| /** Unchangeably constant. */
|
||||
33| lib.attr.empty = { };
|
||||
| ^
|
||||
34|
|
||||
|
||||
error: attribute 'undocument' missing
|
||||
at «string»:1:1:
|
||||
1| lib.attr.undocument
|
||||
| ^
|
||||
Did you mean undocumented?
|
||||
|
||||
Attribute constant
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:27:3
|
||||
|
||||
Firmly rigid.
|
||||
|
||||
Attribute version
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:30:3
|
||||
|
||||
Immovably fixed.
|
||||
|
||||
Attribute empty
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:33:3
|
||||
|
||||
Unchangeably constant.
|
||||
|
||||
Attribute undocumented
|
||||
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:35:3
|
||||
|
||||
No documentation found.
|
||||
|
||||
error: undefined variable 'missing'
|
||||
at «string»:1:1:
|
||||
1| missing
|
||||
| ^
|
||||
|
||||
error: undefined variable 'constanz'
|
||||
at «string»:1:1:
|
||||
1| constanz
|
||||
| ^
|
||||
|
||||
error: undefined variable 'missing'
|
||||
at «string»:1:1:
|
||||
1| missing.attr
|
||||
| ^
|
||||
|
||||
error: attribute 'missing' missing
|
||||
at «string»:1:1:
|
||||
1| lib.missing
|
||||
| ^
|
||||
|
||||
error: attribute 'missing' missing
|
||||
at «string»:1:1:
|
||||
1| lib.missing.attr
|
||||
| ^
|
||||
|
||||
error:
|
||||
… while evaluating the attribute 'attr.undocumental'
|
||||
at /path/to/tests/functional/repl/doc-comments.nix:33:3:
|
||||
32| /** Unchangeably constant. */
|
||||
33| lib.attr.empty = { };
|
||||
| ^
|
||||
34|
|
||||
|
||||
error: attribute 'undocumental' missing
|
||||
at «string»:1:1:
|
||||
1| lib.attr.undocumental
|
||||
| ^
|
||||
Did you mean undocumented?
|
||||
|
||||
|
15
tests/functional/repl/doc-constant.in
Normal file
15
tests/functional/repl/doc-constant.in
Normal file
|
@ -0,0 +1,15 @@
|
|||
:l doc-comments.nix
|
||||
:doc constant
|
||||
:doc lib.version
|
||||
:doc lib.attr.empty
|
||||
:doc lib.attr.undocument
|
||||
:doc (import ./doc-comments.nix).constant
|
||||
:doc (import ./doc-comments.nix).lib.version
|
||||
:doc (import ./doc-comments.nix).lib.attr.empty
|
||||
:doc (import ./doc-comments.nix).lib.attr.undocumented
|
||||
:doc missing
|
||||
:doc constanz
|
||||
:doc missing.attr
|
||||
:doc lib.missing
|
||||
:doc lib.missing.attr
|
||||
:doc lib.attr.undocumental
|
11
tests/functional/repl/doc-floatedIn.expected
Normal file
11
tests/functional/repl/doc-floatedIn.expected
Normal file
|
@ -0,0 +1,11 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function floatedIn
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:16:5
|
||||
|
||||
This also works.
|
||||
|
||||
|
2
tests/functional/repl/doc-floatedIn.in
Normal file
2
tests/functional/repl/doc-floatedIn.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
:l doc-comments.nix
|
||||
:doc floatedIn
|
29
tests/functional/repl/doc-lambda-flavors.expected
Normal file
29
tests/functional/repl/doc-lambda-flavors.expected
Normal file
|
@ -0,0 +1,29 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function nonStrict
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:37:70
|
||||
|
||||
My syntax is not strict, but I'm strict anyway.
|
||||
|
||||
Function strict
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:38:63
|
||||
|
||||
I don't have to be strict, but I am anyway.
|
||||
|
||||
Function strictPre
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:40:48
|
||||
|
||||
Here's one way to do this
|
||||
|
||||
Function strictPost
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:41:53
|
||||
|
||||
Here's another way to do this
|
||||
|
||||
|
5
tests/functional/repl/doc-lambda-flavors.in
Normal file
5
tests/functional/repl/doc-lambda-flavors.in
Normal file
|
@ -0,0 +1,5 @@
|
|||
:l doc-comments.nix
|
||||
:doc nonStrict
|
||||
:doc strict
|
||||
:doc strictPre
|
||||
:doc strictPost
|
11
tests/functional/repl/doc-measurement.expected
Normal file
11
tests/functional/repl/doc-measurement.expected
Normal file
|
@ -0,0 +1,11 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function measurement
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:13:17
|
||||
|
||||
👈 precisely this wide 👉
|
||||
|
||||
|
2
tests/functional/repl/doc-measurement.in
Normal file
2
tests/functional/repl/doc-measurement.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
:l doc-comments.nix
|
||||
:doc measurement
|
15
tests/functional/repl/doc-multiply.expected
Normal file
15
tests/functional/repl/doc-multiply.expected
Normal file
|
@ -0,0 +1,15 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function multiply
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:10:14
|
||||
|
||||
Perform arithmetic multiplication. It's kind of like
|
||||
repeated addition, very neat.
|
||||
|
||||
| multiply 2 3
|
||||
| => 6
|
||||
|
||||
|
2
tests/functional/repl/doc-multiply.in
Normal file
2
tests/functional/repl/doc-multiply.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
:l doc-comments.nix
|
||||
:doc multiply
|
11
tests/functional/repl/doc-unambiguous.expected
Normal file
11
tests/functional/repl/doc-unambiguous.expected
Normal file
|
@ -0,0 +1,11 @@
|
|||
Nix <nix version>
|
||||
Type :? for help.
|
||||
Added <number omitted> variables.
|
||||
|
||||
Function unambiguous
|
||||
… defined at
|
||||
/path/to/tests/functional/repl/doc-comments.nix:24:5
|
||||
|
||||
Very close
|
||||
|
||||
|
2
tests/functional/repl/doc-unambiguous.in
Normal file
2
tests/functional/repl/doc-unambiguous.in
Normal file
|
@ -0,0 +1,2 @@
|
|||
:l doc-comments.nix
|
||||
:doc unambiguous
|
|
@ -71,3 +71,15 @@ test_tarball() {
|
|||
test_tarball '' cat
|
||||
test_tarball .xz xz
|
||||
test_tarball .gz gzip
|
||||
|
||||
# Test hard links.
|
||||
# All entries in tree.tar.gz refer to the same file, and all have the same inode when unpacked by GNU tar.
|
||||
# We don't preserve the hard links, because that's an optimization we think is not worth the complexity,
|
||||
# so we only make sure that the contents are copied correctly.
|
||||
path="$(nix flake prefetch --json "tarball+file://$(pwd)/tree.tar.gz" | jq -r .storePath)"
|
||||
[[ $(cat "$path/a/b/foo") = bar ]]
|
||||
[[ $(cat "$path/a/b/xyzzy") = bar ]]
|
||||
[[ $(cat "$path/a/yyy") = bar ]]
|
||||
[[ $(cat "$path/a/zzz") = bar ]]
|
||||
[[ $(cat "$path/c/aap") = bar ]]
|
||||
[[ $(cat "$path/fnord") = bar ]]
|
||||
|
|
BIN
tests/functional/tree.tar.gz
Normal file
BIN
tests/functional/tree.tar.gz
Normal file
Binary file not shown.
|
@ -4,12 +4,14 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#include "fetch-settings.hh"
|
||||
#include "value.hh"
|
||||
#include "nixexpr.hh"
|
||||
#include "nixexpr.hh"
|
||||
#include "eval.hh"
|
||||
#include "eval-gc.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "store-api.hh"
|
||||
|
||||
#include "tests/libstore.hh"
|
||||
|
||||
|
@ -24,7 +26,7 @@ namespace nix {
|
|||
protected:
|
||||
LibExprTest()
|
||||
: LibStoreTest()
|
||||
, state({}, store, evalSettings, nullptr)
|
||||
, state({}, store, fetchSettings, evalSettings, nullptr)
|
||||
{
|
||||
evalSettings.nixPath = {};
|
||||
}
|
||||
|
@ -43,6 +45,7 @@ namespace nix {
|
|||
}
|
||||
|
||||
bool readOnlyMode = true;
|
||||
fetchers::Settings fetchSettings{};
|
||||
EvalSettings evalSettings{readOnlyMode};
|
||||
EvalState state;
|
||||
};
|
||||
|
|
112
tests/unit/libfetchers/git-utils.cc
Normal file
112
tests/unit/libfetchers/git-utils.cc
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include "git-utils.hh"
|
||||
#include "file-system.hh"
|
||||
#include "gmock/gmock.h"
|
||||
#include <git2/global.h>
|
||||
#include <git2/repository.h>
|
||||
#include <git2/types.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include "fs-sink.hh"
|
||||
#include "serialise.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
class GitUtilsTest : public ::testing::Test
|
||||
{
|
||||
// We use a single repository for all tests.
|
||||
Path tmpDir;
|
||||
std::unique_ptr<AutoDelete> delTmpDir;
|
||||
|
||||
public:
|
||||
void SetUp() override
|
||||
{
|
||||
tmpDir = createTempDir();
|
||||
delTmpDir = std::make_unique<AutoDelete>(tmpDir, true);
|
||||
|
||||
// Create the repo with libgit2
|
||||
git_libgit2_init();
|
||||
git_repository * repo = nullptr;
|
||||
auto r = git_repository_init(&repo, tmpDir.c_str(), 0);
|
||||
ASSERT_EQ(r, 0);
|
||||
git_repository_free(repo);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
{
|
||||
// Destroy the AutoDelete, triggering removal
|
||||
// not AutoDelete::reset(), which would cancel the deletion.
|
||||
delTmpDir.reset();
|
||||
}
|
||||
|
||||
ref<GitRepo> openRepo()
|
||||
{
|
||||
return GitRepo::openRepo(tmpDir, true, false);
|
||||
}
|
||||
};
|
||||
|
||||
void writeString(CreateRegularFileSink & fileSink, std::string contents, bool executable)
|
||||
{
|
||||
if (executable)
|
||||
fileSink.isExecutable();
|
||||
fileSink.preallocateContents(contents.size());
|
||||
fileSink(contents);
|
||||
}
|
||||
|
||||
TEST_F(GitUtilsTest, sink_basic)
|
||||
{
|
||||
auto repo = openRepo();
|
||||
auto sink = repo->getFileSystemObjectSink();
|
||||
|
||||
// TODO/Question: It seems a little odd that we use the tarball-like convention of requiring a top-level directory
|
||||
// here
|
||||
// The sync method does not document this behavior, should probably renamed because it's not very
|
||||
// general, and I can't imagine that "non-conventional" archives or any other source to be handled by
|
||||
// this sink.
|
||||
|
||||
sink->createDirectory(CanonPath("foo-1.1"));
|
||||
|
||||
sink->createRegularFile(CanonPath("foo-1.1/hello"), [](CreateRegularFileSink & fileSink) {
|
||||
writeString(fileSink, "hello world", false);
|
||||
});
|
||||
sink->createRegularFile(CanonPath("foo-1.1/bye"), [](CreateRegularFileSink & fileSink) {
|
||||
writeString(fileSink, "thanks for all the fish", false);
|
||||
});
|
||||
sink->createSymlink(CanonPath("foo-1.1/bye-link"), "bye");
|
||||
sink->createDirectory(CanonPath("foo-1.1/empty"));
|
||||
sink->createDirectory(CanonPath("foo-1.1/links"));
|
||||
sink->createHardlink(CanonPath("foo-1.1/links/foo"), CanonPath("foo-1.1/hello"));
|
||||
|
||||
// sink->createHardlink("foo-1.1/links/foo-2", CanonPath("foo-1.1/hello"));
|
||||
|
||||
auto result = sink->sync();
|
||||
auto accessor = repo->getAccessor(result, false);
|
||||
auto entries = accessor->readDirectory(CanonPath::root);
|
||||
ASSERT_EQ(entries.size(), 5);
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("hello")), "hello world");
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("bye")), "thanks for all the fish");
|
||||
ASSERT_EQ(accessor->readLink(CanonPath("bye-link")), "bye");
|
||||
ASSERT_EQ(accessor->readDirectory(CanonPath("empty")).size(), 0);
|
||||
ASSERT_EQ(accessor->readFile(CanonPath("links/foo")), "hello world");
|
||||
};
|
||||
|
||||
TEST_F(GitUtilsTest, sink_hardlink)
|
||||
{
|
||||
auto repo = openRepo();
|
||||
auto sink = repo->getFileSystemObjectSink();
|
||||
|
||||
sink->createDirectory(CanonPath("foo-1.1"));
|
||||
|
||||
sink->createRegularFile(CanonPath("foo-1.1/hello"), [](CreateRegularFileSink & fileSink) {
|
||||
writeString(fileSink, "hello world", false);
|
||||
});
|
||||
|
||||
try {
|
||||
sink->createHardlink(CanonPath("foo-1.1/link"), CanonPath("hello"));
|
||||
FAIL() << "Expected an exception";
|
||||
} catch (const nix::Error & e) {
|
||||
ASSERT_THAT(e.msg(), testing::HasSubstr("invalid hard link target"));
|
||||
ASSERT_THAT(e.msg(), testing::HasSubstr("/hello"));
|
||||
ASSERT_THAT(e.msg(), testing::HasSubstr("foo-1.1/link"));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace nix
|
|
@ -29,7 +29,7 @@ libfetchers-tests_LIBS = \
|
|||
libstore-test-support libutil-test-support \
|
||||
libfetchers libstore libutil
|
||||
|
||||
libfetchers-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS)
|
||||
libfetchers-tests_LDFLAGS := -lrapidcheck $(GTEST_LIBS) $(LIBGIT2_LIBS)
|
||||
|
||||
ifdef HOST_WINDOWS
|
||||
# Increase the default reserved stack size to 65 MB so Nix doesn't run out of space
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "fetch-settings.hh"
|
||||
#include "flake/flakeref.hh"
|
||||
|
||||
namespace nix {
|
||||
|
@ -11,8 +12,9 @@ namespace nix {
|
|||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(to_string, doesntReencodeUrl) {
|
||||
fetchers::Settings fetchSettings;
|
||||
auto s = "http://localhost:8181/test/+3d.tar.gz";
|
||||
auto flakeref = parseFlakeRef(s);
|
||||
auto flakeref = parseFlakeRef(fetchSettings, s);
|
||||
auto parsed = flakeref.to_string();
|
||||
auto expected = "http://localhost:8181/test/%2B3d.tar.gz";
|
||||
|
||||
|
|
26
tests/unit/libstore/legacy-ssh-store.cc
Normal file
26
tests/unit/libstore/legacy-ssh-store.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "legacy-ssh-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(LegacySSHStore, constructConfig)
|
||||
{
|
||||
LegacySSHStoreConfig config{
|
||||
"ssh",
|
||||
"localhost",
|
||||
StoreConfig::Params{
|
||||
{
|
||||
"remote-program",
|
||||
// TODO #11106, no more split on space
|
||||
"foo bar",
|
||||
},
|
||||
}};
|
||||
EXPECT_EQ(
|
||||
config.remoteProgram.get(),
|
||||
(Strings{
|
||||
"foo",
|
||||
"bar",
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ sources = files(
|
|||
'derivation.cc',
|
||||
'derived-path.cc',
|
||||
'downstream-placeholder.cc',
|
||||
'legacy-ssh-store.cc',
|
||||
'machines.cc',
|
||||
'nar-info-disk-cache.cc',
|
||||
'nar-info.cc',
|
||||
|
@ -67,6 +68,7 @@ sources = files(
|
|||
'path.cc',
|
||||
'references.cc',
|
||||
'serve-protocol.cc',
|
||||
'ssh-store.cc',
|
||||
'store-reference.cc',
|
||||
'worker-protocol.cc',
|
||||
)
|
||||
|
|
|
@ -26,9 +26,9 @@ static UnkeyedValidPathInfo makeEmpty()
|
|||
};
|
||||
}
|
||||
|
||||
static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo)
|
||||
static ValidPathInfo makeFullKeyed(const Store & store, bool includeImpureInfo)
|
||||
{
|
||||
UnkeyedValidPathInfo info = ValidPathInfo {
|
||||
ValidPathInfo info = ValidPathInfo {
|
||||
store,
|
||||
"foo",
|
||||
FixedOutputInfo {
|
||||
|
@ -57,6 +57,9 @@ static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo
|
|||
}
|
||||
return info;
|
||||
}
|
||||
static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo) {
|
||||
return makeFullKeyed(store, includeImpureInfo);
|
||||
}
|
||||
|
||||
#define JSON_TEST(STEM, OBJ, PURE) \
|
||||
TEST_F(PathInfoTest, PathInfo_ ## STEM ## _from_json) { \
|
||||
|
@ -86,4 +89,13 @@ JSON_TEST(empty_impure, makeEmpty(), true)
|
|||
JSON_TEST(pure, makeFull(*store, false), false)
|
||||
JSON_TEST(impure, makeFull(*store, true), true)
|
||||
|
||||
TEST_F(PathInfoTest, PathInfo_full_shortRefs) {
|
||||
ValidPathInfo it = makeFullKeyed(*store, true);
|
||||
// it.references = unkeyed.references;
|
||||
auto refs = it.shortRefs();
|
||||
ASSERT_EQ(refs.size(), 2);
|
||||
ASSERT_EQ(*refs.begin(), "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar");
|
||||
ASSERT_EQ(*++refs.begin(), "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo");
|
||||
}
|
||||
|
||||
} // namespace nix
|
||||
|
|
26
tests/unit/libstore/ssh-store.cc
Normal file
26
tests/unit/libstore/ssh-store.cc
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "ssh-store.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
TEST(SSHStore, constructConfig)
|
||||
{
|
||||
SSHStoreConfig config{
|
||||
"ssh",
|
||||
"localhost",
|
||||
StoreConfig::Params{
|
||||
{
|
||||
"remote-program",
|
||||
// TODO #11106, no more split on space
|
||||
"foo bar",
|
||||
},
|
||||
}};
|
||||
EXPECT_EQ(
|
||||
config.remoteProgram.get(),
|
||||
(Strings{
|
||||
"foo",
|
||||
"bar",
|
||||
}));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#include <iostream>
|
||||
#include "tracing-file-system-object-sink.hh"
|
||||
|
||||
namespace nix::test {
|
||||
|
||||
void TracingFileSystemObjectSink::createDirectory(const CanonPath & path)
|
||||
{
|
||||
std::cerr << "createDirectory(" << path << ")\n";
|
||||
sink.createDirectory(path);
|
||||
}
|
||||
|
||||
void TracingFileSystemObjectSink::createRegularFile(
|
||||
const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn)
|
||||
{
|
||||
std::cerr << "createRegularFile(" << path << ")\n";
|
||||
sink.createRegularFile(path, [&](CreateRegularFileSink & crf) {
|
||||
// We could wrap this and trace about the chunks of data and such
|
||||
fn(crf);
|
||||
});
|
||||
}
|
||||
|
||||
void TracingFileSystemObjectSink::createSymlink(const CanonPath & path, const std::string & target)
|
||||
{
|
||||
std::cerr << "createSymlink(" << path << ", target: " << target << ")\n";
|
||||
sink.createSymlink(path, target);
|
||||
}
|
||||
|
||||
void TracingExtendedFileSystemObjectSink::createHardlink(const CanonPath & path, const CanonPath & target)
|
||||
{
|
||||
std::cerr << "createHardlink(" << path << ", target: " << target << ")\n";
|
||||
sink.createHardlink(path, target);
|
||||
}
|
||||
|
||||
} // namespace nix::test
|
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
#include "fs-sink.hh"
|
||||
|
||||
namespace nix::test {
|
||||
|
||||
/**
|
||||
* A `FileSystemObjectSink` that traces calls, writing to stderr.
|
||||
*/
|
||||
class TracingFileSystemObjectSink : public virtual FileSystemObjectSink
|
||||
{
|
||||
FileSystemObjectSink & sink;
|
||||
public:
|
||||
TracingFileSystemObjectSink(FileSystemObjectSink & sink)
|
||||
: sink(sink)
|
||||
{
|
||||
}
|
||||
|
||||
void createDirectory(const CanonPath & path) override;
|
||||
|
||||
void createRegularFile(const CanonPath & path, std::function<void(CreateRegularFileSink &)> fn) override;
|
||||
|
||||
void createSymlink(const CanonPath & path, const std::string & target) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* A `ExtendedFileSystemObjectSink` that traces calls, writing to stderr.
|
||||
*/
|
||||
class TracingExtendedFileSystemObjectSink : public TracingFileSystemObjectSink, public ExtendedFileSystemObjectSink
|
||||
{
|
||||
ExtendedFileSystemObjectSink & sink;
|
||||
public:
|
||||
TracingExtendedFileSystemObjectSink(ExtendedFileSystemObjectSink & sink)
|
||||
: TracingFileSystemObjectSink(sink)
|
||||
, sink(sink)
|
||||
{
|
||||
}
|
||||
|
||||
void createHardlink(const CanonPath & path, const CanonPath & target) override;
|
||||
};
|
||||
|
||||
}
|
|
@ -229,7 +229,7 @@ TEST_F(GitTest, both_roundrip) {
|
|||
|
||||
mkSinkHook(CanonPath::root, root.hash, BlobMode::Regular);
|
||||
|
||||
ASSERT_EQ(*files, *files2);
|
||||
ASSERT_EQ(files->root, files2->root);
|
||||
}
|
||||
|
||||
TEST(GitLsRemote, parseSymrefLineWithReference) {
|
||||
|
|
122
tests/unit/libutil/position.cc
Normal file
122
tests/unit/libutil/position.cc
Normal file
|
@ -0,0 +1,122 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "position.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
inline Pos::Origin makeStdin(std::string s)
|
||||
{
|
||||
return Pos::Stdin{make_ref<std::string>(s)};
|
||||
}
|
||||
|
||||
TEST(Position, getSnippetUpTo_0)
|
||||
{
|
||||
Pos::Origin o = makeStdin("");
|
||||
Pos p(1, 1, o);
|
||||
ASSERT_EQ(p.getSnippetUpTo(p), "");
|
||||
}
|
||||
TEST(Position, getSnippetUpTo_1)
|
||||
{
|
||||
Pos::Origin o = makeStdin("x");
|
||||
{
|
||||
// NOTE: line and column are actually 1-based indexes
|
||||
Pos start(0, 0, o);
|
||||
Pos end(99, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(start), "");
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "x");
|
||||
ASSERT_EQ(end.getSnippetUpTo(end), "");
|
||||
ASSERT_EQ(end.getSnippetUpTo(start), std::nullopt);
|
||||
}
|
||||
{
|
||||
// NOTE: line and column are actually 1-based indexes
|
||||
Pos start(0, 99, o);
|
||||
Pos end(99, 0, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(start), "");
|
||||
|
||||
// "x" might be preferable, but we only care about not crashing for invalid inputs
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "");
|
||||
|
||||
ASSERT_EQ(end.getSnippetUpTo(end), "");
|
||||
ASSERT_EQ(end.getSnippetUpTo(start), std::nullopt);
|
||||
}
|
||||
{
|
||||
Pos start(1, 1, o);
|
||||
Pos end(1, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(start), "");
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "x");
|
||||
ASSERT_EQ(end.getSnippetUpTo(end), "");
|
||||
ASSERT_EQ(end.getSnippetUpTo(start), "");
|
||||
}
|
||||
{
|
||||
Pos start(1, 1, o);
|
||||
Pos end(99, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(start), "");
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "x");
|
||||
ASSERT_EQ(end.getSnippetUpTo(end), "");
|
||||
ASSERT_EQ(end.getSnippetUpTo(start), std::nullopt);
|
||||
}
|
||||
}
|
||||
TEST(Position, getSnippetUpTo_2)
|
||||
{
|
||||
Pos::Origin o = makeStdin("asdf\njkl\nqwer");
|
||||
{
|
||||
Pos start(1, 1, o);
|
||||
Pos end(1, 2, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(start), "");
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "a");
|
||||
ASSERT_EQ(end.getSnippetUpTo(end), "");
|
||||
|
||||
// nullopt? I feel like changing the column handling would just make it more fragile
|
||||
ASSERT_EQ(end.getSnippetUpTo(start), "");
|
||||
}
|
||||
{
|
||||
Pos start(1, 2, o);
|
||||
Pos end(1, 3, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "s");
|
||||
}
|
||||
{
|
||||
Pos start(1, 2, o);
|
||||
Pos end(2, 2, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "sdf\nj");
|
||||
}
|
||||
{
|
||||
Pos start(1, 2, o);
|
||||
Pos end(3, 2, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "sdf\njkl\nq");
|
||||
}
|
||||
{
|
||||
Pos start(1, 2, o);
|
||||
Pos end(2, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "sdf\njkl");
|
||||
}
|
||||
{
|
||||
Pos start(1, 4, o);
|
||||
Pos end(2, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "f\njkl");
|
||||
}
|
||||
{
|
||||
Pos start(1, 5, o);
|
||||
Pos end(2, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "\njkl");
|
||||
}
|
||||
{
|
||||
Pos start(1, 6, o); // invalid: starting column past last "line character", ie at the newline
|
||||
Pos end(2, 99, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "\njkl"); // jkl might be acceptable for this invalid start position
|
||||
}
|
||||
{
|
||||
Pos start(1, 1, o);
|
||||
Pos end(2, 0, o); // invalid
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "asdf\n");
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Position, example_1)
|
||||
{
|
||||
Pos::Origin o = makeStdin(" unambiguous = \n /** Very close */\n x: x;\n# ok\n");
|
||||
Pos start(2, 5, o);
|
||||
Pos end(2, 22, o);
|
||||
ASSERT_EQ(start.getSnippetUpTo(end), "/** Very close */");
|
||||
}
|
||||
|
||||
} // namespace nix
|
|
@ -15,7 +15,7 @@ struct RewriteParams {
|
|||
strRewrites.insert(from + "->" + to);
|
||||
return os <<
|
||||
"OriginalString: " << bar.originalString << std::endl <<
|
||||
"Rewrites: " << concatStringsSep(",", strRewrites) << std::endl <<
|
||||
"Rewrites: " << dropEmptyInitThenConcatStringsSep(",", strRewrites) << std::endl <<
|
||||
"Expected result: " << bar.finalString;
|
||||
}
|
||||
};
|
||||
|
|
83
tests/unit/libutil/strings.cc
Normal file
83
tests/unit/libutil/strings.cc
Normal file
|
@ -0,0 +1,83 @@
|
|||
#include <gtest/gtest.h>
|
||||
|
||||
#include "strings.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
using Strings = std::vector<std::string>;
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* concatStringsSep
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(concatStringsSep, empty)
|
||||
{
|
||||
Strings strings;
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, justOne)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "this");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, emptyString)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, emptyStrings)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("");
|
||||
strings.push_back("");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), ",");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, threeEmptyStrings)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("");
|
||||
strings.push_back("");
|
||||
strings.push_back("");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), ",,");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, buildCommaSeparatedString)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
strings.push_back("is");
|
||||
strings.push_back("great");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "this,is,great");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, buildStringWithEmptySeparator)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
strings.push_back("is");
|
||||
strings.push_back("great");
|
||||
|
||||
ASSERT_EQ(concatStringsSep("", strings), "thisisgreat");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, buildSingleString)
|
||||
{
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "this");
|
||||
}
|
||||
|
||||
} // namespace nix
|
|
@ -227,32 +227,32 @@ namespace nix {
|
|||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* concatStringsSep
|
||||
* dropEmptyInitThenConcatStringsSep
|
||||
* --------------------------------------------------------------------------*/
|
||||
|
||||
TEST(concatStringsSep, buildCommaSeparatedString) {
|
||||
TEST(dropEmptyInitThenConcatStringsSep, buildCommaSeparatedString) {
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
strings.push_back("is");
|
||||
strings.push_back("great");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "this,is,great");
|
||||
ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), "this,is,great");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, buildStringWithEmptySeparator) {
|
||||
TEST(dropEmptyInitThenConcatStringsSep, buildStringWithEmptySeparator) {
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
strings.push_back("is");
|
||||
strings.push_back("great");
|
||||
|
||||
ASSERT_EQ(concatStringsSep("", strings), "thisisgreat");
|
||||
ASSERT_EQ(dropEmptyInitThenConcatStringsSep("", strings), "thisisgreat");
|
||||
}
|
||||
|
||||
TEST(concatStringsSep, buildSingleString) {
|
||||
TEST(dropEmptyInitThenConcatStringsSep, buildSingleString) {
|
||||
Strings strings;
|
||||
strings.push_back("this");
|
||||
|
||||
ASSERT_EQ(concatStringsSep(",", strings), "this");
|
||||
ASSERT_EQ(dropEmptyInitThenConcatStringsSep(",", strings), "this");
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue