package narinfo import ( "strings" "testing" "github.com/google/go-cmp/cmp" ) func TestRoundtripHash(t *testing.T) { tcs := []struct { base16 string base32 string base64 string sriBase64 string }{{ base16: "sha256:1fbeb031b3b03845e290a26b3727815f92b261f45ba68c082885f7950f2a8bc7", base32: "sha256:1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz", base64: "sha256:H76wMbOwOEXikKJrNyeBX5KyYfRbpowIKIX3lQ8qi8c=", sriBase64: "sha256-H76wMbOwOEXikKJrNyeBX5KyYfRbpowIKIX3lQ8qi8c=", }, { base16: "sha256:42b0ead11a3146dcac102d56b63809ac405fe8d196a7748f7b6176ab44162879", base32: "sha256:0y982r2anxk1gf7p99wns7l5yh5c14wbcmid22ndqiii3b8ymc22", base64: "sha256:QrDq0RoxRtysEC1WtjgJrEBf6NGWp3SPe2F2q0QWKHk=", sriBase64: "sha256-QrDq0RoxRtysEC1WtjgJrEBf6NGWp3SPe2F2q0QWKHk=", }} for _, tc := range tcs { base16Got, err := hashFromString(tc.base16) if err != nil { t.Errorf("hashFromString(%q): %v", tc.base16, err) } base32Got, err := hashFromString(tc.base32) if err != nil { t.Errorf("hashFromString(%q): %v", tc.base32, err) } base64Got, err := hashFromString(tc.base64) if err != nil { t.Errorf("hashFromString(%q): %v", tc.base64, err) } sriBase64Got, err := hashFromString(tc.sriBase64) if err != nil { t.Errorf("hashFromString(%q): %v", tc.sriBase64, err) } if diff := cmp.Diff(base16Got, base32Got); diff != "" { t.Errorf("hashFromString diff (-base16 +base32):\n%v", diff) } if diff := cmp.Diff(base16Got, base64Got); diff != "" { t.Errorf("hashFromString diff (-base16 +base64):\n%v", diff) } sriBase64Got.IsSRI = false if diff := cmp.Diff(base16Got, sriBase64Got); diff != "" { t.Errorf("hashFromString diff (-base16 +sriBase64):\n%v", diff) } sriBase64Got.IsSRI = true if base16Got.String() != tc.base32 { t.Errorf("base16Got.String() = %q; want %q", base16Got.String(), tc.base32) } if base32Got.String() != tc.base32 { t.Errorf("base32Got.String() = %q; want %q", base32Got.String(), tc.base32) } if base64Got.String() != tc.base32 { t.Errorf("base64Got.String() = %q; want %q", base64Got.String(), tc.base32) } if sriBase64Got.String() != tc.sriBase64 { t.Errorf("sriBase64Got.String() = %q; want %q", sriBase64Got.String(), tc.sriBase64) } } } func TestParseNarInfo(t *testing.T) { tcs := []struct { name string input string wantErr bool want *NarInfo wantStr string }{{ name: "empty", input: "", wantErr: true, }, { name: "bare minimum narinfo", input: `StorePath: /nix/store/27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10 URL: nar/1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz.nar.bz2 NarHash: sha256:0y982r2anxk1gf7p99wns7l5yh5c14wbcmid22ndqiii3b8ymc22 NarSize: 206152 `, want: &NarInfo{ StorePath: "/nix/store/27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10", URL: "nar/1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz.nar.bz2", Compression: CompressionBzip2, NarHash: Hash{ Algorithm: HashSha256, Hash: []byte{ 0x42, 0xb0, 0xea, 0xd1, 0x1a, 0x31, 0x46, 0xdc, 0xac, 0x10, 0x2d, 0x56, 0xb6, 0x38, 0x09, 0xac, 0x40, 0x5f, 0xe8, 0xd1, 0x96, 0xa7, 0x74, 0x8f, 0x7b, 0x61, 0x76, 0xab, 0x44, 0x16, 0x28, 0x79, }, }, NarSize: 206152, }, wantStr: `StorePath: /nix/store/27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10 URL: nar/1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz.nar.bz2 Compression: bzip2 NarHash: sha256:0y982r2anxk1gf7p99wns7l5yh5c14wbcmid22ndqiii3b8ymc22 NarSize: 206152 `, }, { name: "hello NAR", input: `StorePath: /nix/store/27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10 URL: nar/1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz.nar.xz Compression: xz FileHash: sha256:1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz FileSize: 41180 NarHash: sha256:0y982r2anxk1gf7p99wns7l5yh5c14wbcmid22ndqiii3b8ymc22 NarSize: 206152 References: 27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10 j5p0j1w27aqdzncpw73k95byvhh5prw2-glibc-2.33-47 Deriver: s1n7mahd61zgxk2w4b1q1ani0nzqfl47-hello-2.10.drv Sig: cache.nixos.org-1:jdYq19bNeGQ7rqzMcJu6IQeSNmAgLVrZUbnVc6KOXw8aTevoZcMNOdDS8s+puPq4BDC1+A2jvH0aUgc9lkBzCw== `, want: &NarInfo{ StorePath: "/nix/store/27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10", URL: "nar/1iwb587rbxw55048r9jvyihv54jzh4kkfsx2j3i4af5hncqv1ghz.nar.xz", Compression: CompressionXz, FileHash: Hash{ Algorithm: HashSha256, Hash: []byte{ 0x1f, 0xbe, 0xb0, 0x31, 0xb3, 0xb0, 0x38, 0x45, 0xe2, 0x90, 0xa2, 0x6b, 0x37, 0x27, 0x81, 0x5f, 0x92, 0xb2, 0x61, 0xf4, 0x5b, 0xa6, 0x8c, 0x08, 0x28, 0x85, 0xf7, 0x95, 0x0f, 0x2a, 0x8b, 0xc7, }, }, FileSize: 41180, NarHash: Hash{ Algorithm: HashSha256, Hash: []byte{ 0x42, 0xb0, 0xea, 0xd1, 0x1a, 0x31, 0x46, 0xdc, 0xac, 0x10, 0x2d, 0x56, 0xb6, 0x38, 0x09, 0xac, 0x40, 0x5f, 0xe8, 0xd1, 0x96, 0xa7, 0x74, 0x8f, 0x7b, 0x61, 0x76, 0xab, 0x44, 0x16, 0x28, 0x79, }, }, NarSize: 206152, References: []string{ "27albyvzh5j455fhm53q1wn697f6nzkh-hello-2.10", "j5p0j1w27aqdzncpw73k95byvhh5prw2-glibc-2.33-47", }, Deriver: "s1n7mahd61zgxk2w4b1q1ani0nzqfl47-hello-2.10.drv", Sig: map[string][]uint8{ "cache.nixos.org-1": []uint8{ 0x8d, 0xd6, 0x2a, 0xd7, 0xd6, 0xcd, 0x78, 0x64, 0x3b, 0xae, 0xac, 0xcc, 0x70, 0x9b, 0xba, 0x21, 0x07, 0x92, 0x36, 0x60, 0x20, 0x2d, 0x5a, 0xd9, 0x51, 0xb9, 0xd5, 0x73, 0xa2, 0x8e, 0x5f, 0x0f, 0x1a, 0x4d, 0xeb, 0xe8, 0x65, 0xc3, 0x0d, 0x39, 0xd0, 0xd2, 0xf2, 0xcf, 0xa9, 0xb8, 0xfa, 0xb8, 0x04, 0x30, 0xb5, 0xf8, 0x0d, 0xa3, 0xbc, 0x7d, 0x1a, 0x52, 0x07, 0x3d, 0x96, 0x40, 0x73, 0x0b, }, }, }, }} for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { got, err := ParseNarInfo(strings.NewReader(tc.input)) if !tc.wantErr && err != nil { t.Fatalf("ParseNarInfo: %v", err) } else if tc.wantErr && err == nil { t.Fatal("ParseNarInfo didn't return error (expected one)") } if diff := cmp.Diff(tc.want, got); diff != "" { t.Errorf("ParseNarInfo mismatch (-want +got):\n%s", diff) } if got != nil { wantStr := tc.wantStr if wantStr == "" { wantStr = tc.input } if got.String() != wantStr { t.Errorf("roundtrip: got.String() = \n%v\n\nwant:\n%v", got.String(), wantStr) } } }) } }