package delivery import ( "crypto/sha256" "encoding/hex" "strings" "testing" ) func sha256Of(s string) string { h := sha256.Sum256([]byte(s)); return hex.EncodeToString(h[:]) } // A module whose every artifact names its paths takes its tree from its manifest and those paths alone (novox/hq ADR // 0499 clause 2): a change outside them leaves the value equal, a change to a named path or to the manifest changes it, // and the order the paths are given in changes nothing. func TestTheNamedTreeIsOfTheManifestAndTheNamedPathsAlone(t *testing.T) { manifest := sha256Of(`{"module":"mesh-sdk"}`) paths := map[string]string{"src": strings.Repeat("a", 40), "package.json": strings.Repeat("b", 40)} v, err := NamedTree(manifest, paths) if err != nil { t.Fatal(err) } if !strings.HasPrefix(v, NamedTreePrefix) || !isHex64(strings.TrimPrefix(v, NamedTreePrefix)) { t.Fatalf("the value %q is not %s and 64 hex digits", v, NamedTreePrefix) } // A change outside the named paths is no input at all: the same inputs give the same value, in any map order. again, _ := NamedTree(manifest, map[string]string{"package.json": strings.Repeat("b", 40), "src": strings.Repeat("a", 40)}) if again != v { t.Fatalf("the same inputs gave %q and %q", v, again) } changed, _ := NamedTree(manifest, map[string]string{"src": strings.Repeat("c", 40), "package.json": strings.Repeat("b", 40)}) if changed == v { t.Fatal("a changed named path left the value equal") } otherManifest, _ := NamedTree(sha256Of(`{"module":"mesh-sdk","version":"2"}`), paths) if otherManifest == v { t.Fatal("a changed manifest left the value equal") } renamed, _ := NamedTree(manifest, map[string]string{"lib": strings.Repeat("a", 40), "package.json": strings.Repeat("b", 40)}) if renamed == v { t.Fatal("a path named differently with the same object left the value equal") } // The lines are fixed, so every computation of it agrees: pinned here. want := "named:" + sha256Of("manifest "+manifest+"\npath package.json "+strings.Repeat("b", 40)+"\npath src "+strings.Repeat("a", 40)) if v != want { t.Fatalf("NamedTree = %q, want %q", v, want) } } func TestTheNamedTreeRefusesWhatItCannotPin(t *testing.T) { manifest := sha256Of("{}") for _, c := range []struct { manifest string paths map[string]string says string }{ {manifest, nil, "names no path"}, {manifest, map[string]string{"src": ""}, `the named path "src" has no git object`}, {"abc", map[string]string{"src": "x"}, "not a manifest digest"}, {manifest, map[string]string{"src/../x": "x"}, "is not a clean path"}, {manifest, map[string]string{"": "x"}, "is not a clean path"}, {manifest, map[string]string{"/src": "x"}, "is not a clean path"}, } { if _, err := NamedTree(c.manifest, c.paths); err == nil || !strings.Contains(err.Error(), c.says) { t.Errorf("NamedTree(%q, %v) = %v, wanted a refusal saying %q", c.manifest, c.paths, err, c.says) } } }