blob: c14f34ecbefbd9cbfb1255722de07dc14fe40bcf [file] [log] [blame]
Ronald Braunsteina115e262024-04-09 18:07:38 -07001// Copyright 2024 Google Inc. All rights reserved.
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 cc
16
17import (
18 "android/soong/android"
19 "android/soong/android/team_proto"
20 "log"
21 "strings"
22 "testing"
23
24 "github.com/google/blueprint"
25 "google.golang.org/protobuf/proto"
26)
27
28func TestTestOnlyProvider(t *testing.T) {
29 t.Parallel()
30 ctx := android.GroupFixturePreparers(
31 prepareForCcTest,
32 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
33 ctx.RegisterModuleType("cc_test_host", TestHostFactory)
34 }),
35 ).RunTestWithBp(t, `
36 // These should be test-only
37 cc_fuzz { name: "cc-fuzz" }
38 cc_test { name: "cc-test", gtest:false }
39 cc_benchmark { name: "cc-benchmark" }
40 cc_library { name: "cc-library-forced",
41 test_only: true }
42 cc_test_library {name: "cc-test-library", gtest: false}
43 cc_test_host {name: "cc-test-host", gtest: false}
44
45 // These should not be.
46 cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] }
47 cc_library { name: "cc_library" }
48 cc_library { name: "cc_library_false", test_only: false }
49 cc_library_static { name: "cc_static" }
50 cc_library_shared { name: "cc_library_shared" }
51
52 cc_object { name: "cc-object" }
53 `)
54
55 // Visit all modules and ensure only the ones that should
56 // marked as test-only are marked as test-only.
57
58 actualTestOnly := []string{}
59 ctx.VisitAllModules(func(m blueprint.Module) {
60 if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
61 if provider.TestOnly {
62 actualTestOnly = append(actualTestOnly, m.Name())
63 }
64 }
65 })
66 expectedTestOnlyModules := []string{
67 "cc-test",
68 "cc-library-forced",
69 "cc-fuzz",
70 "cc-benchmark",
71 "cc-test-library",
72 "cc-test-host",
73 }
74
75 notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTestOnly)
76 if notEqual {
77 t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
78 }
79}
80
Ronald Braunstein6a08d492024-04-15 12:55:30 -070081func TestTestOnlyValueWithTestPerSrcProp(t *testing.T) {
82 t.Parallel()
83 ctx := android.GroupFixturePreparers(
84 prepareForCcTest,
85 ).RunTestWithBp(t, `
86 // These should be test-only
87 cc_test { name: "cc-test",
88 gtest: false,
89 test_per_src: true,
90 srcs: ["foo_test.cpp"],
91 test_options: { unit_test: false, },
92 }
93 `)
94
95 // Ensure all variation of test-per-src tests are marked test-only.
96 ctx.VisitAllModules(func(m blueprint.Module) {
97 testOnly := false
98 if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok {
99 if provider.TestOnly {
100 testOnly = true
101 }
102 }
103 if module, ok := m.(*Module); ok {
104 if testModule, ok := module.installer.(*testBinary); ok {
105 if !testOnly && *testModule.Properties.Test_per_src {
106 t.Errorf("%v is not test-only but should be", m)
107 }
108 }
109 }
110 })
111}
112
Ronald Braunsteina115e262024-04-09 18:07:38 -0700113func TestTestOnlyInTeamsProto(t *testing.T) {
114 t.Parallel()
115 ctx := android.GroupFixturePreparers(
116 android.PrepareForTestWithTeamBuildComponents,
117 prepareForCcTest,
118 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
119 ctx.RegisterParallelSingletonType("all_teams", android.AllTeamsFactory)
120 ctx.RegisterModuleType("cc_test_host", TestHostFactory)
121
122 }),
123 ).RunTestWithBp(t, `
124 package { default_team: "someteam"}
125
126 // These should be test-only
127 cc_fuzz { name: "cc-fuzz" }
128 cc_test { name: "cc-test", gtest:false }
129 cc_benchmark { name: "cc-benchmark" }
130 cc_library { name: "cc-library-forced",
131 test_only: true }
132 cc_test_library {name: "cc-test-library", gtest: false}
133 cc_test_host {name: "cc-test-host", gtest: false}
134
135 // These should not be.
136 cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] }
137 cc_library { name: "cc_library" }
138 cc_library_static { name: "cc_static" }
139 cc_library_shared { name: "cc_library_shared" }
140
141 cc_object { name: "cc-object" }
142 team {
143 name: "someteam",
144 trendy_team_id: "cool_team",
145 }
146 `)
147
148 var teams *team_proto.AllTeams
149 teams = getTeamProtoOutput(t, ctx)
150
151 // map of module name -> trendy team name.
152 actualTrueModules := []string{}
153 for _, teamProto := range teams.Teams {
154 if Bool(teamProto.TestOnly) {
155 actualTrueModules = append(actualTrueModules, teamProto.GetTargetName())
156 }
157 }
158 expectedTestOnlyModules := []string{
159 "cc-test",
160 "cc-library-forced",
161 "cc-fuzz",
162 "cc-benchmark",
163 "cc-test-library",
164 "cc-test-host",
165 }
166
167 notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTrueModules)
168 if notEqual {
169 t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right)
170 }
171}
172
173// Don't allow setting test-only on things that are always tests or never tests.
174func TestInvalidTestOnlyTargets(t *testing.T) {
175 testCases := []string{
176 ` cc_test { name: "cc-test", test_only: true, gtest: false, srcs: ["foo.cc"], } `,
177 ` cc_binary { name: "cc-binary", test_only: true, srcs: ["foo.cc"], } `,
178 ` cc_test_library {name: "cc-test-library", test_only: true, gtest: false} `,
179 ` cc_test_host {name: "cc-test-host", test_only: true, gtest: false} `,
180 ` cc_defaults {name: "cc-defaults", test_only: true} `,
181 }
182
183 for i, bp := range testCases {
184 ctx := android.GroupFixturePreparers(
185 prepareForCcTest,
186 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
187 ctx.RegisterModuleType("cc_test_host", TestHostFactory)
188 })).
189 ExtendWithErrorHandler(android.FixtureIgnoreErrors).
190 RunTestWithBp(t, bp)
191 if len(ctx.Errs) == 0 {
192 t.Errorf("Expected err setting test_only in testcase #%d", i)
193 }
194 if len(ctx.Errs) > 1 {
195 t.Errorf("Too many errs: [%s] %v", bp, ctx.Errs)
196 }
197
198 if len(ctx.Errs) == 1 {
199 if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") {
200 t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp)
201 }
202 }
203 }
204}
205
206func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams {
207 teams := new(team_proto.AllTeams)
208 config := ctx.SingletonForTests("all_teams")
209 allOutputs := config.AllOutputs()
210
211 protoPath := allOutputs[0]
212
213 out := config.MaybeOutput(protoPath)
214 outProto := []byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, out))
215 if err := proto.Unmarshal(outProto, teams); err != nil {
216 log.Fatalln("Failed to parse teams proto:", err)
217 }
218 return teams
219}