// Copyright 2022 Google Inc. All rights reserved. // // 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 main import ( "io/ioutil" "os" "path/filepath" "strings" "testing" "android/soong/cmd/symbols_map/symbols_map_proto" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" ) func Test_mergeProtos(t *testing.T) { type testFile struct { filename string contents *symbols_map_proto.Mapping missing bool } tests := []struct { name string inputs []testFile stripPrefix string writeIfChanged bool ignoreMissingFiles bool error string output *symbols_map_proto.Mappings }{ { name: "empty", output: &symbols_map_proto.Mappings{}, }, { name: "merge", inputs: []testFile{ { filename: "foo", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, }, { filename: "bar", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("bar"), Location: proto.String("symbols/bar"), Type: symbols_map_proto.Mapping_R8.Enum(), }, }, }, output: &symbols_map_proto.Mappings{ Mappings: []*symbols_map_proto.Mapping{ { Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, { Identifier: proto.String("bar"), Location: proto.String("symbols/bar"), Type: symbols_map_proto.Mapping_R8.Enum(), }, }, }, }, { name: "strip prefix", inputs: []testFile{ { filename: "foo", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, }, { filename: "bar", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("bar"), Location: proto.String("symbols/bar"), Type: symbols_map_proto.Mapping_R8.Enum(), }, }, }, stripPrefix: "symbols/", output: &symbols_map_proto.Mappings{ Mappings: []*symbols_map_proto.Mapping{ { Identifier: proto.String("foo"), Location: proto.String("foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, { Identifier: proto.String("bar"), Location: proto.String("bar"), Type: symbols_map_proto.Mapping_R8.Enum(), }, }, }, }, { name: "missing", inputs: []testFile{ { filename: "foo", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, }, { filename: "bar", missing: true, }, }, error: "no such file or directory", }, { name: "ignore missing", inputs: []testFile{ { filename: "foo", contents: &symbols_map_proto.Mapping{ Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, }, { filename: "bar", missing: true, }, }, ignoreMissingFiles: true, output: &symbols_map_proto.Mappings{ Mappings: []*symbols_map_proto.Mapping{ { Identifier: proto.String("foo"), Location: proto.String("symbols/foo"), Type: symbols_map_proto.Mapping_ELF.Enum(), }, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir, err := os.MkdirTemp("", "test_mergeProtos") if err != nil { t.Fatalf("failed to create temporary directory: %s", err) } defer os.RemoveAll(dir) var inputs []string for _, in := range tt.inputs { path := filepath.Join(dir, in.filename) inputs = append(inputs, path) if !in.missing { err := writeTextProto(path, in.contents, false) if err != nil { t.Fatalf("failed to create input file %s: %s", path, err) } } } output := filepath.Join(dir, "out") err = mergeProtos(output, inputs, tt.stripPrefix, tt.writeIfChanged, tt.ignoreMissingFiles) if err != nil { if tt.error != "" { if !strings.Contains(err.Error(), tt.error) { t.Fatalf("expected error %q, got %s", tt.error, err.Error()) } } else { t.Fatalf("unexpected error %q", err) } } else if tt.error != "" { t.Fatalf("missing error %q", tt.error) } else { data, err := ioutil.ReadFile(output) if err != nil { t.Fatalf("failed to read output file %s: %s", output, err) } var got symbols_map_proto.Mappings err = prototext.Unmarshal(data, &got) if err != nil { t.Fatalf("failed to unmarshal textproto %s: %s", output, err) } if !proto.Equal(tt.output, &got) { t.Fatalf("expected output %q, got %q", tt.output.String(), got.String()) } } }) } }