| // Copyright 2017 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| package serializer |
| |
| import ( |
| "archive/tar" |
| "bytes" |
| "compress/gzip" |
| "fmt" |
| "io" |
| "log" |
| "os" |
| "reflect" |
| "sort" |
| "strings" |
| "testing" |
| |
| "github.com/google/licenseclassifier" |
| "github.com/google/licenseclassifier/stringclassifier/searchset" |
| ) |
| |
| var ( |
| apache20Header, mit []byte |
| normApache, normMIT string |
| ) |
| |
| func TestMain(m *testing.M) { |
| var err error |
| apache20Header, err = licenseclassifier.ReadLicenseFile("Apache-2.0.header.txt") |
| if err != nil { |
| log.Fatalf("error reading contents of Apache-2.0.header.txt: %v", err) |
| } |
| normApache = normalize(string(apache20Header)) |
| |
| mit, err = licenseclassifier.ReadLicenseFile("MIT.txt") |
| if err != nil { |
| log.Fatalf("error reading contents of MIT.txt: %v", err) |
| } |
| normMIT = normalize(string(mit)) |
| |
| os.Exit(m.Run()) |
| } |
| |
| type entry struct { |
| name string |
| size int64 |
| contents string |
| } |
| |
| func TestSerializer_ArchiveLicense(t *testing.T) { |
| tests := []struct { |
| description string |
| licenses []string |
| want []entry |
| }{ |
| { |
| description: "Archiving Apache 2.0 header", |
| licenses: []string{"Apache-2.0.header.txt"}, |
| want: []entry{ |
| { |
| name: "Apache-2.0.header.txt", |
| size: int64(len(normApache)), |
| contents: normApache, |
| }, |
| }, |
| }, |
| { |
| description: "Archiving Apache 2.0 header + MIT", |
| licenses: []string{"Apache-2.0.header.txt", "MIT.txt"}, |
| want: []entry{ |
| { |
| name: "Apache-2.0.header.txt", |
| size: int64(len(normApache)), |
| contents: normApache, |
| }, |
| { |
| name: "MIT.txt", |
| size: int64(len(normMIT)), |
| contents: normMIT, |
| }, |
| }, |
| }, |
| } |
| |
| for _, tt := range tests { |
| var writer bytes.Buffer |
| if err := ArchiveLicenses(tt.licenses, &writer); err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot archive license: %v", tt.description, err) |
| continue |
| } |
| |
| reader := bytes.NewReader(writer.Bytes()) |
| gr, err := gzip.NewReader(reader) |
| if err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot create gzip reader: %v", tt.description, err) |
| continue |
| } |
| |
| tr := tar.NewReader(gr) |
| for i := 0; ; i++ { |
| hdr, err := tr.Next() |
| if err == io.EOF { |
| break |
| } |
| if err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot read header: %v", tt.description, err) |
| break |
| } |
| |
| if i >= len(tt.want)+1 { |
| t.Errorf("ArchiveLicenses(%q): too many files in tar, %d want %d", tt.description, i, len(tt.want)) |
| break |
| } |
| |
| if hdr.Name != tt.want[i].name { |
| t.Errorf("ArchiveLicenses(%q) = %+v, want %+v", tt.description, hdr.Name, tt.want[i].name) |
| } |
| if hdr.Size != tt.want[i].size { |
| t.Errorf("ArchiveLicenses(%q) = %v, want %v", tt.description, hdr.Size, tt.want[i].size) |
| } |
| |
| var b bytes.Buffer |
| if _, err = io.Copy(&b, tr); err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot read contents: %v", tt.description, err) |
| break |
| } |
| |
| if got, want := b.String(), tt.want[i].contents; got != want { |
| t.Errorf("ArchiveLicenses(%q) = got\n%s\nwant:\n%s", tt.description, got, want) |
| } |
| |
| hdr, err = tr.Next() |
| if err != nil { |
| t.Errorf("ArchiveLicenses(%q): no hash file found in archive: %v", tt.description, err) |
| break |
| } |
| |
| if hdr.Name != strings.TrimSuffix(tt.want[i].name, "txt")+"hash" { |
| t.Errorf("ArchiveLicenses(%q) = %+v, want %+v", tt.description, hdr.Name, strings.TrimSuffix(tt.want[i].name, "txt")+"hash") |
| } |
| |
| b.Reset() |
| if _, err = io.Copy(&b, tr); err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot read contents: %v", tt.description, err) |
| break |
| } |
| |
| var got searchset.SearchSet |
| if err := searchset.Deserialize(&b, &got); err != nil { |
| t.Errorf("ArchiveLicenses(%q): cannot deserialize search set: %v", tt.description, err) |
| break |
| } |
| |
| want := searchset.New(tt.want[i].contents, searchset.DefaultGranularity) |
| if err := compareSearchSets(want, &got); err != nil { |
| t.Errorf("ArchiveLicenses(%q): search sets not equal: %v", tt.description, err) |
| break |
| } |
| } |
| } |
| } |
| |
| type sortUInt32 []uint32 |
| |
| func (s sortUInt32) Len() int { return len(s) } |
| func (s sortUInt32) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
| func (s sortUInt32) Less(i, j int) bool { return s[i] < s[j] } |
| |
| func compareSearchSets(x, y *searchset.SearchSet) error { |
| // Check to see that the tokens are equal. |
| if len(x.Tokens) != len(y.Tokens) { |
| return fmt.Errorf("Lengths differ = %d vs %d", len(x.Tokens), len(y.Tokens)) |
| } |
| for i := 0; i < len(x.Tokens); i++ { |
| if x.Tokens[i].Text != y.Tokens[i].Text { |
| return fmt.Errorf("Token values at %d differ = %q vs %q", i, x.Tokens[i].Text, y.Tokens[i].Text) |
| } |
| if x.Tokens[i].Offset != y.Tokens[i].Offset { |
| return fmt.Errorf("Token offsets at %d differ = %d vs %d", i, x.Tokens[i].Offset, y.Tokens[i].Offset) |
| } |
| } |
| |
| // Now check that the hash maps are equal. |
| var xKeys []uint32 |
| for k := range x.Hashes { |
| xKeys = append(xKeys, k) |
| } |
| var yKeys []uint32 |
| for k := range y.Hashes { |
| yKeys = append(yKeys, k) |
| } |
| |
| if len(xKeys) != len(yKeys) { |
| return fmt.Errorf("Lengths of hashes differ = %d vs %d", len(xKeys), len(yKeys)) |
| } |
| |
| sort.Sort(sortUInt32(xKeys)) |
| sort.Sort(sortUInt32(yKeys)) |
| |
| for i := 0; i < len(xKeys); i++ { |
| if xKeys[i] != yKeys[i] { |
| return fmt.Errorf("Hash keys differ = %d vs %d", xKeys[i], yKeys[i]) |
| } |
| if !reflect.DeepEqual(x.Hashes[xKeys[i]], y.Hashes[yKeys[i]]) { |
| return fmt.Errorf("Hash values differ = %v vs %v", x.Hashes[xKeys[i]], y.Hashes[yKeys[i]]) |
| } |
| } |
| |
| return nil |
| } |
| |
| func normalize(s string) string { |
| for _, n := range licenseclassifier.Normalizers { |
| s = n(s) |
| } |
| return s |
| } |