1// 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 81func TestTestOnlyInTeamsProto(t *testing.T) { 82 t.Parallel() 83 ctx := android.GroupFixturePreparers( 84 android.PrepareForTestWithTeamBuildComponents, 85 prepareForCcTest, 86 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { 87 ctx.RegisterParallelSingletonType("all_teams", android.AllTeamsFactory) 88 ctx.RegisterModuleType("cc_test_host", TestHostFactory) 89 90 }), 91 ).RunTestWithBp(t, ` 92 package { default_team: "someteam"} 93 94 // These should be test-only 95 cc_fuzz { name: "cc-fuzz" } 96 cc_test { name: "cc-test", gtest:false } 97 cc_benchmark { name: "cc-benchmark" } 98 cc_library { name: "cc-library-forced", 99 test_only: true } 100 cc_test_library {name: "cc-test-library", gtest: false} 101 cc_test_host {name: "cc-test-host", gtest: false} 102 103 // These should not be. 104 cc_genrule { name: "cc_genrule", cmd: "echo foo", out: ["out"] } 105 cc_library { name: "cc_library" } 106 cc_library_static { name: "cc_static" } 107 cc_library_shared { name: "cc_library_shared" } 108 109 cc_object { name: "cc-object" } 110 team { 111 name: "someteam", 112 trendy_team_id: "cool_team", 113 } 114 `) 115 116 var teams *team_proto.AllTeams 117 teams = getTeamProtoOutput(t, ctx) 118 119 // map of module name -> trendy team name. 120 actualTrueModules := []string{} 121 for _, teamProto := range teams.Teams { 122 if Bool(teamProto.TestOnly) { 123 actualTrueModules = append(actualTrueModules, teamProto.GetTargetName()) 124 } 125 } 126 expectedTestOnlyModules := []string{ 127 "cc-test", 128 "cc-library-forced", 129 "cc-fuzz", 130 "cc-benchmark", 131 "cc-test-library", 132 "cc-test-host", 133 } 134 135 notEqual, left, right := android.ListSetDifference(expectedTestOnlyModules, actualTrueModules) 136 if notEqual { 137 t.Errorf("test-only: Expected but not found: %v, Found but not expected: %v", left, right) 138 } 139} 140 141// Don't allow setting test-only on things that are always tests or never tests. 142func TestInvalidTestOnlyTargets(t *testing.T) { 143 testCases := []string{ 144 ` cc_test { name: "cc-test", test_only: true, gtest: false, srcs: ["foo.cc"], } `, 145 ` cc_binary { name: "cc-binary", test_only: true, srcs: ["foo.cc"], } `, 146 ` cc_test_library {name: "cc-test-library", test_only: true, gtest: false} `, 147 ` cc_test_host {name: "cc-test-host", test_only: true, gtest: false} `, 148 ` cc_defaults {name: "cc-defaults", test_only: true} `, 149 } 150 151 for i, bp := range testCases { 152 ctx := android.GroupFixturePreparers( 153 prepareForCcTest, 154 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { 155 ctx.RegisterModuleType("cc_test_host", TestHostFactory) 156 })). 157 ExtendWithErrorHandler(android.FixtureIgnoreErrors). 158 RunTestWithBp(t, bp) 159 if len(ctx.Errs) == 0 { 160 t.Errorf("Expected err setting test_only in testcase #%d", i) 161 } 162 if len(ctx.Errs) > 1 { 163 t.Errorf("Too many errs: [%s] %v", bp, ctx.Errs) 164 } 165 166 if len(ctx.Errs) == 1 { 167 if !strings.Contains(ctx.Errs[0].Error(), "unrecognized property \"test_only\"") { 168 t.Errorf("ERR: %s bad bp: %s", ctx.Errs[0], bp) 169 } 170 } 171 } 172} 173 174func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams { 175 teams := new(team_proto.AllTeams) 176 config := ctx.SingletonForTests("all_teams") 177 allOutputs := config.AllOutputs() 178 179 protoPath := allOutputs[0] 180 181 out := config.MaybeOutput(protoPath) 182 outProto := []byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, out)) 183 if err := proto.Unmarshal(outProto, teams); err != nil { 184 log.Fatalln("Failed to parse teams proto:", err) 185 } 186 return teams 187} 188