xref: /aosp_15_r20/build/make/tools/compliance/readgraph_test.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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