package util import ( "bytes" "crypto/sha256" "crypto/sha512" "encoding/hex" "hash" "testing" "github.com/theupdateframework/go-tuf/data" . "gopkg.in/check.v1" ) // Hook up gocheck into the "go test" runner. func Test(t *testing.T) { TestingT(t) } type UtilSuite struct{} var _ = Suite(&UtilSuite{}) func (UtilSuite) TestGenerateTargetFileMetaDefault(c *C) { // default is sha512 r := bytes.NewReader([]byte("foo")) meta, err := GenerateTargetFileMeta(r) c.Assert(err, IsNil) c.Assert(meta.Length, Equals, int64(3)) hashes := meta.Hashes c.Assert(hashes, HasLen, 1) hash, ok := hashes["sha512"] if !ok { c.Fatal("missing sha512 hash") } c.Assert(hash.String(), DeepEquals, "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7") } func (UtilSuite) TestGenerateTargetFileMetaExplicit(c *C) { r := bytes.NewReader([]byte("foo")) meta, err := GenerateTargetFileMeta(r, "sha256", "sha512") c.Assert(err, IsNil) c.Assert(meta.Length, Equals, int64(3)) hashes := meta.Hashes c.Assert(hashes, HasLen, 2) for name, val := range map[string]string{ "sha256": "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", "sha512": "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7", } { hash, ok := hashes[name] if !ok { c.Fatalf("missing %s hash", name) } c.Assert(hash.String(), DeepEquals, val) } } func makeHashes(c *C, hashes map[string]string) data.Hashes { h := make(map[string]data.HexBytes, len(hashes)) for typ, hash := range hashes { v, err := hex.DecodeString(hash) c.Assert(err, IsNil) h[typ] = v } return h } type testMetaFile struct { name string actual data.FileMeta expected data.FileMeta err func(testMetaFile) error } func testMetaFileCases(c *C) []testMetaFile { fileMeta := func(c *C, length int64, hashes map[string]string) data.FileMeta { return data.FileMeta{ Length: length, Hashes: makeHashes(c, hashes), } } return []testMetaFile{ { name: "wrong length", actual: data.FileMeta{Length: 1}, expected: data.FileMeta{Length: 2}, err: func(testMetaFile) error { return ErrWrongLength{Actual: 1, Expected: 2} }, }, { name: "wrong sha512 hash", actual: fileMeta(c, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(c, 10, map[string]string{"sha512": "222222"}), err: func(t testMetaFile) error { return ErrWrongHash{"sha512", t.expected.Hashes["sha512"], t.actual.Hashes["sha512"]} }, }, { name: "intersecting hashes", actual: fileMeta(c, 10, map[string]string{"sha512": "111111", "md5": "222222"}), expected: fileMeta(c, 10, map[string]string{"sha512": "111111", "sha256": "333333"}), err: func(testMetaFile) error { return nil }, }, { name: "no common hashes", actual: fileMeta(c, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(c, 10, map[string]string{"sha256": "222222", "md5": "333333"}), err: func(t testMetaFile) error { return ErrNoCommonHash{t.expected.Hashes, t.actual.Hashes} }, }, } } func (UtilSuite) TestSnapshotFileMetaEqual(c *C) { type test struct { name string actual data.SnapshotFileMeta expected data.SnapshotFileMeta err func(test) error } fileMeta := func(version int64, length int64, hashes map[string]string) data.SnapshotFileMeta { return data.SnapshotFileMeta{ Length: length, Hashes: makeHashes(c, hashes), Version: version, } } tests := []test{ { name: "same version", actual: fileMeta(1, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(1, 10, map[string]string{"sha512": "111111"}), err: func(test) error { return nil }, }, { name: "wrong version", actual: fileMeta(0, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(1, 10, map[string]string{"sha512": "111111"}), err: func(test) error { return ErrWrongVersion{Expected: 1, Actual: 0} }, }, { name: "wrong version", actual: fileMeta(1, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(0, 10, map[string]string{"sha512": "111111"}), err: func(test) error { return ErrWrongVersion{Expected: 0, Actual: 1} }, }, { name: "wrong version", actual: fileMeta(1, 10, map[string]string{"sha512": "111111"}), expected: fileMeta(2, 10, map[string]string{"sha512": "111111"}), err: func(test) error { return ErrWrongVersion{Expected: 2, Actual: 1} }, }, } for _, t := range tests { c.Assert(SnapshotFileMetaEqual(t.actual, t.expected), DeepEquals, t.err(t), Commentf("name = %s", t.name)) } for _, t := range testMetaFileCases(c) { actual := data.SnapshotFileMeta{Length: t.actual.Length, Hashes: t.actual.Hashes} expected := data.SnapshotFileMeta{Length: t.expected.Length, Hashes: t.expected.Hashes} c.Assert(SnapshotFileMetaEqual(actual, expected), DeepEquals, t.err(t), Commentf("name = %s %d %d", t.name, t.actual.Length, t.expected.Length)) c.Assert(FileMetaEqual(t.actual, t.expected), DeepEquals, t.err(t), Commentf("name = %s", t.name)) } } func (UtilSuite) TestNormalizeTarget(c *C) { for before, after := range map[string]string{ "": "", "foo.txt": "foo.txt", "/bar.txt": "bar.txt", "foo//bar.txt": "foo/bar.txt", "/with/./a/dot": "with/a/dot", "/with/double/../dot": "with/dot", } { c.Assert(NormalizeTarget(before), Equals, after) } } func (UtilSuite) TestHashedPaths(c *C) { hexBytes := func(s string) data.HexBytes { v, err := hex.DecodeString(s) c.Assert(err, IsNil) return v } hashes := data.Hashes{ "sha512": hexBytes("abc123"), "sha256": hexBytes("def456"), } paths := HashedPaths("foo/bar.txt", hashes) // cannot use DeepEquals as the returned order is non-deterministic c.Assert(paths, HasLen, 2) expected := map[string]struct{}{"foo/abc123.bar.txt": {}, "foo/def456.bar.txt": {}} for _, path := range paths { if _, ok := expected[path]; !ok { c.Fatalf("unexpected path: %s", path) } delete(expected, path) } } func (UtilSuite) TestVersionEqual(c *C) { c.Assert(VersionEqual(1, 1), IsNil) c.Assert(VersionEqual(1, 3), Equals, ErrWrongVersion{3, 1}) } func makeHash(b []byte, alg string) []byte { var h hash.Hash switch alg { case "sha256": h = sha256.New() case "sha512": h = sha512.New() } h.Write(b) return h.Sum(nil) } func (UtilSuite) TestBytesMatchLenAndHashes(c *C) { type test struct { name string bytes []byte length int64 hashes data.Hashes err func(test) error } b := []byte{82, 253, 252, 7, 33, 130, 101, 79, 22, 63, 95, 15, 154, 98, 29, 114} bhashes := data.Hashes{ "sha512": makeHash(b, "sha512"), "sha256": makeHash(b, "sha256"), } tests := []test{ { name: "correct len and hashes", bytes: b, length: 16, hashes: bhashes, err: func(test) error { return nil }, }, { name: "incorrect len", bytes: b, length: 32, hashes: bhashes, err: func(test) error { return ErrWrongLength{32, 16} }, }, { name: "incorrect hashes sha512", bytes: b, length: 16, hashes: data.Hashes{ "sha512": makeHash(b, "sha256"), }, err: func(test) error { return ErrWrongHash{"sha512", bhashes["sha256"], bhashes["sha512"]} }, }, { name: "incorrect hashes sha256", bytes: b, length: 16, hashes: data.Hashes{ "sha256": makeHash(b, "sha512"), }, err: func(test) error { return ErrWrongHash{"sha256", bhashes["sha512"], bhashes["sha256"]} }, }, { name: "incorrect len and hashes", bytes: b, length: 32, hashes: data.Hashes{ "sha512": makeHash(b, "sha256"), "sha256": makeHash(b, "sha512"), }, err: func(test) error { return ErrWrongLength{32, 16} }, }, } for _, t := range tests { c.Assert(BytesMatchLenAndHashes(t.bytes, t.length, t.hashes), DeepEquals, t.err(t), Commentf("name = %s", t.name)) } }