1// Copyright 2021 Google LLC 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package compliance 16 17import ( 18 "bytes" 19 "sort" 20 "strings" 21 "testing" 22 23 "android/soong/tools/compliance/testfs" 24) 25 26func TestReadLicenseGraph(t *testing.T) { 27 tests := []struct { 28 name string 29 fs *testfs.TestFS 30 roots []string 31 expectedError string 32 expectedEdges []edge 33 expectedTargets []string 34 }{ 35 { 36 name: "trivial", 37 fs: &testfs.TestFS{ 38 "app.meta_lic": []byte("package_name: \"Android\"\n"), 39 }, 40 roots: []string{"app.meta_lic"}, 41 expectedEdges: []edge{}, 42 expectedTargets: []string{"app.meta_lic"}, 43 }, 44 { 45 name: "unterminated", 46 fs: &testfs.TestFS{ 47 "app.meta_lic": []byte("package_name: \"Android\n"), 48 }, 49 roots: []string{"app.meta_lic"}, 50 expectedError: `invalid character '\n' in string`, 51 }, 52 { 53 name: "danglingref", 54 fs: &testfs.TestFS{ 55 "app.meta_lic": []byte(AOSP + "deps: {\n file: \"lib.meta_lic\"\n}\n"), 56 }, 57 roots: []string{"app.meta_lic"}, 58 expectedError: `unknown file "lib.meta_lic"`, 59 }, 60 { 61 name: "singleedge", 62 fs: &testfs.TestFS{ 63 "app.meta_lic": []byte(AOSP + "deps: {\n file: \"lib.meta_lic\"\n}\n"), 64 "lib.meta_lic": []byte(AOSP), 65 }, 66 roots: []string{"app.meta_lic"}, 67 expectedEdges: []edge{{"app.meta_lic", "lib.meta_lic"}}, 68 expectedTargets: []string{"app.meta_lic", "lib.meta_lic"}, 69 }, 70 { 71 name: "fullgraph", 72 fs: &testfs.TestFS{ 73 "apex.meta_lic": []byte(AOSP + "deps: {\n file: \"app.meta_lic\"\n}\ndeps: {\n file: \"bin.meta_lic\"\n}\n"), 74 "app.meta_lic": []byte(AOSP), 75 "bin.meta_lic": []byte(AOSP + "deps: {\n file: \"lib.meta_lic\"\n}\n"), 76 "lib.meta_lic": []byte(AOSP), 77 }, 78 roots: []string{"apex.meta_lic"}, 79 expectedEdges: []edge{ 80 {"apex.meta_lic", "app.meta_lic"}, 81 {"apex.meta_lic", "bin.meta_lic"}, 82 {"bin.meta_lic", "lib.meta_lic"}, 83 }, 84 expectedTargets: []string{"apex.meta_lic", "app.meta_lic", "bin.meta_lic", "lib.meta_lic"}, 85 }, 86 } 87 for _, tt := range tests { 88 t.Run(tt.name, func(t *testing.T) { 89 stderr := &bytes.Buffer{} 90 lg, err := ReadLicenseGraph(tt.fs, stderr, tt.roots) 91 if err != nil { 92 if len(tt.expectedError) == 0 { 93 t.Errorf("unexpected error: got %s, want no error", err) 94 } else if !strings.Contains(err.Error(), tt.expectedError) { 95 t.Errorf("unexpected error: got %s, want %q", err, tt.expectedError) 96 } 97 return 98 } 99 if len(tt.expectedError) > 0 { 100 t.Errorf("unexpected success: got no error, want %q err", tt.expectedError) 101 return 102 } 103 if lg == nil { 104 t.Errorf("missing license graph: got nil, want license graph") 105 return 106 } 107 actualEdges := make([]edge, 0) 108 for _, e := range lg.Edges() { 109 actualEdges = append(actualEdges, edge{e.Target().Name(), e.Dependency().Name()}) 110 } 111 sort.Sort(byEdge(tt.expectedEdges)) 112 sort.Sort(byEdge(actualEdges)) 113 t.Logf("actualEdges:") 114 for _, edge := range actualEdges { 115 t.Logf(" %s", edge.String()) 116 } 117 t.Logf("expectedEdges:") 118 for _, edge := range actualEdges { 119 t.Logf(" %s", edge.String()) 120 } 121 if len(tt.expectedEdges) != len(actualEdges) { 122 t.Errorf("len(actualEdges): got %d, want %d", len(actualEdges), len(tt.expectedEdges)) 123 } else { 124 for i := 0; i < len(actualEdges); i++ { 125 if tt.expectedEdges[i] != actualEdges[i] { 126 t.Errorf("actualEdges[%d]: got %s, want %s", i, actualEdges[i], tt.expectedEdges[i]) 127 } 128 } 129 } 130 131 actualTargets := make([]string, 0) 132 for _, t := range lg.Targets() { 133 actualTargets = append(actualTargets, t.Name()) 134 } 135 sort.Strings(tt.expectedTargets) 136 sort.Strings(actualTargets) 137 138 t.Logf("actualTargets: %v", actualTargets) 139 t.Logf("expectedTargets: %v", tt.expectedTargets) 140 141 if len(tt.expectedTargets) != len(actualTargets) { 142 t.Errorf("len(actualTargets): got %d, want %d", len(actualTargets), len(tt.expectedTargets)) 143 } else { 144 for i := 0; i < len(actualTargets); i++ { 145 if tt.expectedTargets[i] != actualTargets[i] { 146 t.Errorf("actualTargets[%d]: got %s, want %s", i, actualTargets[i], tt.expectedTargets[i]) 147 } 148 } 149 } 150 }) 151 } 152} 153