aboutsummaryrefslogtreecommitdiffstats
path: root/tests/jq.sh
blob: a62d6cbf2c9f60a058bdb0586310955b9ce42e10 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#! /bin/sh
# Runs populate's jq programs for flakes over lock files in the shapes
# different versions of Nix write, without VMs.
#
# usage: jq.sh DIR
#
# DIR contains the programs as selected.jq, selfIsRemote.jq, and
# selfLocked.jq.
set -efu

programs=$1
failed=0

# usage: expect WHAT ACTUAL EXPECTED
expect() {
  if test "$2" != "$3"; then
    printf 'FAIL: %s\n  expected: %s\n  got:      %s\n' "$1" "$3" "$2" >&2
    failed=1
  fi
}

# usage: expect_error WHAT ACTUAL MESSAGE
expect_error() {
  case $2 in
    *"$3"*) ;;
    *)
      printf 'FAIL: %s\n  expected an error: %s\n  got: %s\n' "$1" "$3" "$2" >&2
      failed=1
      ;;
  esac
}

# usage: selection METADATA INPUT
selection() {
  printf '%s\n' "$1" |
    timeout 10 jq -c --argjson input "$2" --from-file "$programs"/selected.jq 2>&1 ||
    :
}

# A flake with an input dep, which has an input inner following the flake's
# input inner, and an input sub, a flake in a subdirectory, written as
# attribute dir or as query parameter dir of the URL.
metadata() {
  cat <<JSON
{
  "locked": { "type": "path", "path": "/src/top", "narHash": "sha256-top" },
  "path": "/nix/store/top-source",
  "locks": {
    "root": "root",
    "version": 7,
    "nodes": {
      "root": { "inputs": { "dep": "dep", "inner": "inner", "sub": "sub" } },
      "dep": {
        "inputs": { "inner": [ "inner" ] },
        "locked": { "type": "tarball", "url": "http://x/dep.tar.gz", "narHash": "sha256-dep" }
      },
      "inner": {
        "locked": { "type": "tarball", "url": "http://x/inner.tar.gz", "narHash": "sha256-inner" }
      },
      "sub": {
        "locked": $1,
        "original": $2
      }
    }
  }
}
JSON
}
attribute=$(metadata \
  '{ "type": "tarball", "url": "http://x/mono.tar.gz", "dir": "sub", "narHash": "sha256-mono" }' \
  '{ "type": "tarball", "url": "http://x/mono.tar.gz", "dir": "sub" }')
url=$(metadata \
  '{ "type": "tarball", "url": "http://x/mono.tar.gz?dir=sub", "narHash": "sha256-mono" }' \
  '{ "type": "tarball", "url": "http://x/mono.tar.gz?dir=sub" }')

mono='{"self":false,"locked":{"type":"tarball","url":"http://x/mono.tar.gz","narHash":"sha256-mono"},"subdir":"sub"}'
expect "subdirectory as attribute" "$(selection "$attribute" '["sub"]')" "$mono"
expect "subdirectory in the URL" "$(selection "$url" '["sub"]')" "$mono"
expect "the flake itself" "$(selection "$attribute" '[]')" \
  '{"self":true,"locked":null,"subdir":""}'
expect "name through follows" "$(selection "$attribute" '["dep","inner"]')" \
  '{"self":false,"locked":{"type":"tarball","url":"http://x/inner.tar.gz","narHash":"sha256-inner"},"subdir":""}'
expect_error "missing input" "$(selection "$attribute" '["nope"]')" "no input nope"

# An empty follows path removes an input.
removed=$(printf '%s\n' "$attribute" | jq -c '.locks.nodes.dep.inputs.inner = []')
expect_error "removed input" "$(selection "$removed" '["dep","inner"]')" "no input inner"

# Inputs following each other.
cyclic=$(printf '%s\n' "$attribute" | jq -c '
  .locks.nodes.dep.inputs.inner = ["inner", "x"]
  | .locks.nodes.inner.inputs = { x: ["dep", "inner"] }
')
expect_error "cyclic follows" "$(selection "$cyclic" '["dep","inner"]')" "follows nest too deep"

# An input given by a path relative to the flake, which is in subdirectory
# sub itself.
relative=$(printf '%s\n' "$attribute" | jq -c '
  .locked.dir = "sub"
  | .locks.nodes.root.inputs.lib = "lib"
  | .locks.nodes.lib = { locked: { type: "path", path: "./lib" }, parent: [] }
')
expect "relative path" "$(selection "$relative" '["lib"]')" \
  '{"self":true,"locked":null,"subdir":"sub/lib"}'

# usage: remote LOCKED
remote() {
  printf '{ "locked": %s }\n' "$1" |
    jq --from-file "$programs"/selfIsRemote.jq
}
expect "path" "$(remote '{ "type": "path", "path": "/src" }')" false
expect "local Git" "$(remote '{ "type": "git", "url": "file:///src" }')" false
expect "remote Git" "$(remote '{ "type": "git", "url": "https://x/y" }')" true
expect "GitHub" "$(remote '{ "type": "github", "owner": "o", "repo": "r" }')" true

expect "locked reference of the flake itself" "$(
  printf '%s\n' '{ "locked": { "__final": true, "type": "tarball", "url": "http://x/mono.tar.gz?dir=sub", "narHash": "sha256-mono" } }' |
    jq -c --argjson selected '{"self":true,"locked":null,"subdir":"sub"}' \
      --from-file "$programs"/selfLocked.jq
)" "$mono"

exit "$failed"