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
123
124
125
126
127
128
129
130
131
132
from pathlib import Path
from collections.abc import Callable

import pytest

from testlib.fixtures.file_helper import _init_files  # noqa: PLC2701
from testlib.fixtures.file_helper import File, AssetSymlink, with_files, Symlink
from testlib.fixtures.nix import Nix
from testlib.fixtures.snapshot import Snapshot


@pytest.mark.parametrize("algo", ["md5", "sha1", "sha256", "sha512"])
@pytest.mark.parametrize(
    "content",
    ["", "a", "abc", "message_digest", "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"],
)
@pytest.mark.parametrize("format_flag", ["--base16", "--base32", "--sri"])
@pytest.mark.parametrize("classic", [True, False])
def test_hash(
    algo: str,
    content: str,
    format_flag: str,
    classic: bool,
    nix: Nix,
    snapshot: Callable[[str], Snapshot],
    files: Path,
):
    _init_files(
        {
            "vector": File(content),
            "expected_hash.txt": AssetSymlink(
                f"assets/test_hash/{content}_{algo}_{format_flag}_{classic}.out.exp"
            ),
        },
        files,
        Path(__file__).parent,
        nix.env,
    )

    args = [format_flag, "--type", algo, files / "vector"]
    if classic:
        res = nix.nix(["--flat", *args], nix_exe="nix-hash").run().ok()
    else:
        res = nix.nix(["hash", "file", *args], flake=True).run().ok()
    assert snapshot("expected_hash.txt") == res.stdout_s


@with_files({"vector": File("abc")})
def test_hash_classic_defaults_base16(nix: Nix, files: Path):
    res = nix.nix(["--flat", "--type", "sha512", files / "vector"], nix_exe="nix-hash").run().ok()
    assert (
        res.stdout_plain
        == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"
    )


@with_files({"vector": File("abc")})
def test_hash_command_defaults_sri(nix: Nix, files: Path):
    res = nix.nix(["hash", "file", "--type", "sha512", files / "vector"], flake=True).run().ok()
    assert (
        res.stdout_plain
        == "sha512-3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9RU1EI2Q86A4qmslPpUyknw=="
    )


@with_files(
    {
        "hash-part": {
            "hello": File("Hello World\n", 0o644)  # Default perms
        }
    }
)
def test_hash_part(nix: Nix, files: Path):
    res = nix.nix(["--type", "md5", files / "hash-part"], nix_exe="nix-hash").run().ok()
    assert res.stdout_plain == "ea9b55537dd4c7e104515b2ccfaf4100"


@with_files(
    {
        "hash-part": {
            "hello": File("Hello World\n", 0o755)  # chmod +x
        }
    }
)
def test_hash_part_exec_matters(nix: Nix, files: Path):
    res = nix.nix(["--type", "md5", files / "hash-part"], nix_exe="nix-hash").run().ok()
    assert res.stdout_plain == "20f3ffe011d4cfa7d72bfabef7882836"


@with_files({"hash-part": {"hello": File("Hello World\n", 0o744)}})
def test_hash_part_everything_else_doesnt(nix: Nix, files: Path):
    res = nix.nix(["--type", "md5", files / "hash-part"], nix_exe="nix-hash").run().ok()
    assert res.stdout_plain == "20f3ffe011d4cfa7d72bfabef7882836"


@with_files({"hash-part": {"hello": Symlink("x")}})
def test_hash_part_filetype_matters(nix: Nix, files: Path):
    res = nix.nix(["--type", "md5", files / "hash-part"], nix_exe="nix-hash").run().ok()
    assert res.stdout_plain == "f78b733a68f5edbdf9413899339eaa4a"


@pytest.mark.parametrize(
    ("algo", "orig", "b32", "b64"),
    [
        (
            "sha1",
            "800d59cfcd3c05e900cb4e214be48f6b886a08df",
            "vw46m23bizj4n8afrc0fj19wrp7mj3c0",
            "gA1Zz808BekAy04hS+SPa4hqCN8=",
        ),
        (
            "sha256",
            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
            "1b8m03r63zqhnjf7l5wnldhh7c134ap5vpj0850ymkq1iyzicy5s",
            "ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0=",
        ),
        (
            "sha512",
            "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445",
            "12k9jiq29iyqm03swfsgiw5mlqs173qazm3n7daz43infy12pyrcdf30fkk3qwv4yl2ick8yipc2mqnlh48xsvvxl60lbx8vp38yji0",
            "IEqPxt2oLwoM7XvrjgikFlfBbvRosiioJ5vjMacDwzWW/RXBOxsH+aodO+pXeJygMa2Fx6cd1wNU7GMSOMo0RQ==",
        ),
    ],
)
def test_hash_conversion(algo: str, orig: str, b32: str, b64: str, nix: Nix):
    for target_type, exp in zip(
        ["to-base16", "to-base32", "to-base64", "to-sri"], [orig, b32, b64, f"{algo}-{b64}"]
    ):
        res = nix.nix(["--type", algo, f"--{target_type}", orig], nix_exe="nix-hash").run().ok()
        assert res.stdout_plain == exp
        res = nix.nix(["hash", target_type, "--type", algo, orig], flake=True).run().ok()
        assert res.stdout_plain == exp