// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package buildid import ( "bytes" "crypto/sha256" "internal/obscuretestdata" "io/ioutil" "os" "reflect" "strings" "testing" ) const ( expectedID = "abcdefghijklmnopqrstuvwxyz.1234567890123456789012345678901234567890123456789012345678901234" newID = "bcdefghijklmnopqrstuvwxyza.2345678901234567890123456789012345678901234567890123456789012341" ) func TestReadFile(t *testing.T) { f, err := ioutil.TempFile("", "buildid-test-") if err != nil { t.Fatal(err) } tmp := f.Name() defer os.Remove(tmp) f.Close() // Use obscured files to prevent Appleā€™s notarization service from // mistaking them as candidates for notarization and rejecting the entire // toolchain. // See golang.org/issue/34986 var files = []string{ "p.a.base64", "a.elf.base64", "a.macho.base64", "a.pe.base64", } for _, name := range files { f, err := obscuretestdata.DecodeToTempFile("testdata/" + name) if err != nil { t.Errorf("obscuretestdata.DecodeToTempFile(testdata/%s): %v", name, err) continue } defer os.Remove(f) id, err := ReadFile(f) if id != expectedID || err != nil { t.Errorf("ReadFile(testdata/%s) = %q, %v, want %q, nil", f, id, err, expectedID) } old := readSize readSize = 2048 id, err = ReadFile(f) readSize = old if id != expectedID || err != nil { t.Errorf("ReadFile(%s) [readSize=2k] = %q, %v, want %q, nil", f, id, err, expectedID) } data, err := ioutil.ReadFile(f) if err != nil { t.Fatal(err) } m, _, err := FindAndHash(bytes.NewReader(data), expectedID, 1024) if err != nil { t.Errorf("FindAndHash(%s): %v", f, err) continue } if err := ioutil.WriteFile(tmp, data, 0666); err != nil { t.Error(err) continue } tf, err := os.OpenFile(tmp, os.O_WRONLY, 0) if err != nil { t.Error(err) continue } err = Rewrite(tf, m, newID) err2 := tf.Close() if err != nil { t.Errorf("Rewrite(%s): %v", f, err) continue } if err2 != nil { t.Fatal(err2) } id, err = ReadFile(tmp) if id != newID || err != nil { t.Errorf("ReadFile(%s after Rewrite) = %q, %v, want %q, nil", f, id, err, newID) } } } func TestFindAndHash(t *testing.T) { buf := make([]byte, 64) buf2 := make([]byte, 64) id := make([]byte, 8) zero := make([]byte, 8) for i := range id { id[i] = byte(i) } numError := 0 errorf := func(msg string, args ...interface{}) { t.Errorf(msg, args...) if numError++; numError > 20 { t.Logf("stopping after too many errors") t.FailNow() } } for bufSize := len(id); bufSize <= len(buf); bufSize++ { for j := range buf { for k := 0; k < 2*len(id) && j+k < len(buf); k++ { for i := range buf { buf[i] = 1 } copy(buf[j:], id) copy(buf[j+k:], id) var m []int64 if j+len(id) <= j+k { m = append(m, int64(j)) } if j+k+len(id) <= len(buf) { m = append(m, int64(j+k)) } copy(buf2, buf) for _, p := range m { copy(buf2[p:], zero) } h := sha256.Sum256(buf2) matches, hash, err := FindAndHash(bytes.NewReader(buf), string(id), bufSize) if err != nil { errorf("bufSize=%d j=%d k=%d: findAndHash: %v", bufSize, j, k, err) continue } if !reflect.DeepEqual(matches, m) { errorf("bufSize=%d j=%d k=%d: findAndHash: matches=%v, want %v", bufSize, j, k, matches, m) continue } if hash != h { errorf("bufSize=%d j=%d k=%d: findAndHash: matches correct, but hash=%x, want %x", bufSize, j, k, hash, h) } } } } } func TestExcludedReader(t *testing.T) { const s = "0123456789abcdefghijklmn" tests := []struct { start, end int64 // excluded range results []string // expected results of reads }{ {12, 15, []string{"0123456789", "ab\x00\x00\x00fghij", "klmn"}}, // within one read {8, 21, []string{"01234567\x00\x00", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00lmn"}}, // across multiple reads {10, 20, []string{"0123456789", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "klmn"}}, // a whole read {0, 5, []string{"\x00\x00\x00\x00\x0056789", "abcdefghij", "klmn"}}, // start {12, 24, []string{"0123456789", "ab\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x00\x00\x00"}}, // end } p := make([]byte, 10) for _, test := range tests { r := &excludedReader{strings.NewReader(s), 0, test.start, test.end} for _, res := range test.results { n, err := r.Read(p) if err != nil { t.Errorf("read failed: %v", err) } if n != len(res) { t.Errorf("unexpected number of bytes read: want %d, got %d", len(res), n) } if string(p[:n]) != res { t.Errorf("unexpected bytes: want %q, got %q", res, p[:n]) } } } }