xref: /aosp_15_r20/build/soong/java/kotlin_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2017 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 java
16
17import (
18	"slices"
19	"strconv"
20	"strings"
21	"testing"
22
23	"android/soong/android"
24)
25
26func TestKotlin(t *testing.T) {
27	bp := `
28		java_library {
29			name: "foo",
30			srcs: ["a.java", "b.kt"],
31			static_libs: ["quz"],
32		}
33
34		java_library {
35			name: "bar",
36			srcs: ["b.kt"],
37			libs: ["foo"],
38			static_libs: ["baz"],
39		}
40
41		java_library {
42			name: "baz",
43			srcs: ["c.java"],
44			static_libs: ["quz"],
45		}
46
47		java_library {
48			name: "quz",
49			srcs: ["d.kt"],
50		}`
51
52	kotlinStdlibTurbineCombinedJars := []string{
53		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine-combined/kotlin-stdlib.jar",
54		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine-combined/kotlin-stdlib-jdk7.jar",
55		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine-combined/kotlin-stdlib-jdk8.jar",
56		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine-combined/kotlin-annotations.jar",
57	}
58
59	kotlinStdlibTurbineJars := []string{
60		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar",
61		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar",
62		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar",
63		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar",
64	}
65
66	kotlinStdlibJavacJars := []string{
67		"out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
68		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
69		"out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/javac/kotlin-stdlib-jdk8.jar",
70		"out/soong/.intermediates/default/java/kotlin-annotations/android_common/javac/kotlin-annotations.jar",
71	}
72
73	bootclasspathTurbineCombinedJars := []string{
74		"out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine-combined/stable.core.platform.api.stubs.jar",
75		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine-combined/core-lambda-stubs.jar",
76	}
77
78	bootclasspathTurbineJars := []string{
79		"out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar",
80		"out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar",
81	}
82
83	frameworkTurbineCombinedJars := []string{
84		"out/soong/.intermediates/default/java/ext/android_common/turbine-combined/ext.jar",
85		"out/soong/.intermediates/default/java/framework/android_common/turbine-combined/framework.jar",
86	}
87
88	frameworkTurbineJars := []string{
89		"out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
90		"out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
91	}
92
93	testCases := []struct {
94		name string
95
96		preparer android.FixturePreparer
97
98		fooKotlincInputs        []string
99		fooJavacInputs          []string
100		fooKotlincClasspath     []string
101		fooJavacClasspath       []string
102		fooCombinedInputs       []string
103		fooHeaderCombinedInputs []string
104
105		barKotlincInputs        []string
106		barKotlincClasspath     []string
107		barCombinedInputs       []string
108		barHeaderCombinedInputs []string
109	}{
110		{
111			name:             "normal",
112			preparer:         android.NullFixturePreparer,
113			fooKotlincInputs: []string{"a.java", "b.kt"},
114			fooJavacInputs:   []string{"a.java"},
115			fooKotlincClasspath: slices.Concat(
116				bootclasspathTurbineCombinedJars,
117				frameworkTurbineCombinedJars,
118				[]string{"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar"},
119				kotlinStdlibTurbineCombinedJars,
120			),
121			fooJavacClasspath: slices.Concat(
122				[]string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
123				frameworkTurbineCombinedJars,
124				[]string{"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar"},
125				kotlinStdlibTurbineCombinedJars,
126			),
127			fooCombinedInputs: slices.Concat(
128				[]string{
129					"out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
130					"out/soong/.intermediates/foo/android_common/javac/foo.jar",
131					"out/soong/.intermediates/quz/android_common/combined/quz.jar",
132				},
133				kotlinStdlibJavacJars,
134			),
135			fooHeaderCombinedInputs: slices.Concat(
136				[]string{
137					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
138					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
139					"out/soong/.intermediates/quz/android_common/turbine-combined/quz.jar",
140				},
141				kotlinStdlibTurbineCombinedJars,
142			),
143
144			barKotlincInputs: []string{"b.kt"},
145			barKotlincClasspath: slices.Concat(
146				bootclasspathTurbineCombinedJars,
147				frameworkTurbineCombinedJars,
148				[]string{
149					"out/soong/.intermediates/foo/android_common/turbine-combined/foo.jar",
150					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
151				},
152				kotlinStdlibTurbineCombinedJars,
153			),
154			barCombinedInputs: slices.Concat(
155				[]string{
156					"out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
157					"out/soong/.intermediates/baz/android_common/combined/baz.jar",
158				},
159				kotlinStdlibJavacJars,
160				[]string{},
161			),
162			barHeaderCombinedInputs: slices.Concat(
163				[]string{
164					"out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
165					"out/soong/.intermediates/baz/android_common/turbine-combined/baz.jar",
166				},
167				kotlinStdlibTurbineCombinedJars,
168			),
169		},
170		{
171			name:             "transitive classpath",
172			preparer:         PrepareForTestWithTransitiveClasspathEnabled,
173			fooKotlincInputs: []string{"a.java", "b.kt"},
174			fooJavacInputs:   []string{"a.java"},
175			fooKotlincClasspath: slices.Concat(
176				bootclasspathTurbineJars,
177				frameworkTurbineJars,
178				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
179				kotlinStdlibTurbineJars,
180			),
181			fooJavacClasspath: slices.Concat(
182				[]string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
183				frameworkTurbineJars,
184				[]string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
185				kotlinStdlibTurbineJars,
186			),
187			fooCombinedInputs: slices.Concat(
188				[]string{
189					"out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
190					"out/soong/.intermediates/foo/android_common/javac/foo.jar",
191					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
192				},
193				kotlinStdlibJavacJars,
194			),
195			fooHeaderCombinedInputs: slices.Concat(
196				[]string{
197					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
198					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
199					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
200				},
201				kotlinStdlibTurbineJars,
202			),
203
204			barKotlincInputs: []string{"b.kt"},
205			barKotlincClasspath: slices.Concat(
206				bootclasspathTurbineJars,
207				frameworkTurbineJars,
208				[]string{
209					"out/soong/.intermediates/foo/android_common/turbine/foo.jar",
210					"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
211					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
212				},
213				kotlinStdlibTurbineJars,
214				[]string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"},
215			),
216			barCombinedInputs: slices.Concat(
217				[]string{
218					"out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
219					"out/soong/.intermediates/baz/android_common/javac/baz.jar",
220					"out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
221				},
222				kotlinStdlibJavacJars,
223			),
224			barHeaderCombinedInputs: slices.Concat(
225				[]string{
226					"out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
227					"out/soong/.intermediates/baz/android_common/turbine/baz.jar",
228					"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
229				},
230				kotlinStdlibTurbineJars,
231			),
232		},
233	}
234
235	for _, tt := range testCases {
236		t.Run(tt.name, func(t *testing.T) {
237			result := android.GroupFixturePreparers(
238				PrepareForTestWithJavaDefaultModules,
239				tt.preparer,
240			).RunTestWithBp(t, bp)
241			foo := result.ModuleForTests("foo", "android_common")
242			fooKotlinc := foo.Rule("kotlinc")
243			android.AssertPathsRelativeToTopEquals(t, "foo kotlinc inputs", tt.fooKotlincInputs, fooKotlinc.Inputs)
244
245			fooKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, foo.Output("kotlinc/classpath.rsp"))
246			android.AssertStringPathsRelativeToTopEquals(t, "foo kotlinc classpath", result.Config, tt.fooKotlincClasspath, strings.Fields(fooKotlincClasspath))
247
248			fooJavac := foo.Rule("javac")
249			android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)
250
251			fooJavacClasspath := fooJavac.Args["classpath"]
252			android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
253				strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))
254
255			fooCombinedJar := foo.Output("combined/foo.jar")
256			android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)
257
258			fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
259			android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)
260
261			bar := result.ModuleForTests("bar", "android_common")
262			barKotlinc := bar.Rule("kotlinc")
263			android.AssertPathsRelativeToTopEquals(t, "bar kotlinc inputs", tt.barKotlincInputs, barKotlinc.Inputs)
264
265			barKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, bar.Output("kotlinc/classpath.rsp"))
266			android.AssertStringPathsRelativeToTopEquals(t, "bar kotlinc classpath", result.Config, tt.barKotlincClasspath, strings.Fields(barKotlincClasspath))
267
268			barCombinedJar := bar.Output("combined/bar.jar")
269			android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)
270
271			barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
272			android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
273		})
274	}
275}
276
277func TestKapt(t *testing.T) {
278	bp := `
279		java_library {
280			name: "foo",
281			srcs: ["a.java", "b.kt"],
282			plugins: ["bar", "baz"],
283			errorprone: {
284				extra_check_modules: ["my_check"],
285			},
286		}
287
288		java_plugin {
289			name: "bar",
290			processor_class: "com.bar",
291			srcs: ["b.java"],
292		}
293
294		java_plugin {
295			name: "baz",
296			processor_class: "com.baz",
297			srcs: ["b.java"],
298		}
299
300		java_plugin {
301			name: "my_check",
302			srcs: ["b.java"],
303		}
304	`
305	t.Run("", func(t *testing.T) {
306		ctx, _ := testJava(t, bp)
307
308		buildOS := ctx.Config().BuildOS.String()
309
310		foo := ctx.ModuleForTests("foo", "android_common")
311		kaptStubs := foo.Rule("kapt")
312		turbineApt := foo.Description("turbine apt")
313		kotlinc := foo.Rule("kotlinc")
314		javac := foo.Rule("javac")
315
316		bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
317		baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
318
319		// Test that the kotlin and java sources are passed to kapt and kotlinc
320		if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" {
321			t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kaptStubs.Inputs)
322		}
323		if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
324			t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
325		}
326
327		// Test that only the java sources are passed to turbine-apt and javac
328		if len(turbineApt.Inputs) != 1 || turbineApt.Inputs[0].String() != "a.java" {
329			t.Errorf(`foo turbine apt inputs %v != ["a.java"]`, turbineApt.Inputs)
330		}
331		if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
332			t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
333		}
334
335		// Test that the kapt stubs jar is a dependency of turbine-apt
336		if !inList(kaptStubs.Output.String(), turbineApt.Implicits.Strings()) {
337			t.Errorf("expected %q in turbine-apt implicits %v", kaptStubs.Output.String(), kotlinc.Implicits.Strings())
338		}
339
340		// Test that the turbine-apt srcjar is a dependency of kotlinc and javac rules
341		if !inList(turbineApt.Output.String(), kotlinc.Implicits.Strings()) {
342			t.Errorf("expected %q in kotlinc implicits %v", turbineApt.Output.String(), kotlinc.Implicits.Strings())
343		}
344		if !inList(turbineApt.Output.String(), javac.Implicits.Strings()) {
345			t.Errorf("expected %q in javac implicits %v", turbineApt.Output.String(), javac.Implicits.Strings())
346		}
347
348		// Test that the turbine-apt srcjar is extracted by the kotlinc and javac rules
349		if kotlinc.Args["srcJars"] != turbineApt.Output.String() {
350			t.Errorf("expected %q in kotlinc srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
351		}
352		if javac.Args["srcJars"] != turbineApt.Output.String() {
353			t.Errorf("expected %q in javac srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
354		}
355
356		// Test that the processors are passed to kapt
357		expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
358			" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
359		if kaptStubs.Args["kaptProcessorPath"] != expectedProcessorPath {
360			t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kaptStubs.Args["kaptProcessorPath"])
361		}
362		expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
363		if kaptStubs.Args["kaptProcessor"] != expectedProcessor {
364			t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kaptStubs.Args["kaptProcessor"])
365		}
366
367		// Test that the processors are passed to turbine-apt
368		expectedProcessorPath = "--processorpath " + bar + " " + baz
369		if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessorPath) {
370			t.Errorf("expected turbine-apt processorpath %q, got %q", expectedProcessorPath, turbineApt.Args["turbineFlags"])
371		}
372		expectedProcessor = "--processors com.bar com.baz"
373		if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessor) {
374			t.Errorf("expected turbine-apt processor %q, got %q", expectedProcessor, turbineApt.Args["turbineFlags"])
375		}
376
377		// Test that the processors are not passed to javac
378		if javac.Args["processorpath"] != "" {
379			t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
380		}
381		if javac.Args["processor"] != "-proc:none" {
382			t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
383		}
384	})
385
386	t.Run("errorprone", func(t *testing.T) {
387		env := map[string]string{
388			"RUN_ERROR_PRONE": "true",
389		}
390
391		result := android.GroupFixturePreparers(
392			PrepareForTestWithJavaDefaultModules,
393			android.FixtureMergeEnv(env),
394		).RunTestWithBp(t, bp)
395
396		buildOS := result.Config.BuildOS.String()
397
398		kapt := result.ModuleForTests("foo", "android_common").Rule("kapt")
399		javac := result.ModuleForTests("foo", "android_common").Description("javac")
400		errorprone := result.ModuleForTests("foo", "android_common").Description("errorprone")
401
402		bar := result.ModuleForTests("bar", buildOS+"_common").Description("javac").Output.String()
403		baz := result.ModuleForTests("baz", buildOS+"_common").Description("javac").Output.String()
404		myCheck := result.ModuleForTests("my_check", buildOS+"_common").Description("javac").Output.String()
405
406		// Test that the errorprone plugins are not passed to kapt
407		expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
408			" -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
409		if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
410			t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
411		}
412		expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
413		if kapt.Args["kaptProcessor"] != expectedProcessor {
414			t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
415		}
416
417		// Test that the errorprone plugins are not passed to javac
418		if javac.Args["processorpath"] != "" {
419			t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
420		}
421		if javac.Args["processor"] != "-proc:none" {
422			t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
423		}
424
425		// Test that the errorprone plugins are passed to errorprone
426		expectedProcessorPath = "-processorpath " + myCheck
427		if errorprone.Args["processorpath"] != expectedProcessorPath {
428			t.Errorf("expected processorpath %q, got %q", expectedProcessorPath, errorprone.Args["processorpath"])
429		}
430		if errorprone.Args["processor"] != "-proc:none" {
431			t.Errorf("expected processor '-proc:none', got %q", errorprone.Args["processor"])
432		}
433	})
434}
435
436func TestKaptEncodeFlags(t *testing.T) {
437	// Compares the kaptEncodeFlags against the results of the example implementation at
438	// https://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding
439	tests := []struct {
440		in  [][2]string
441		out string
442	}{
443		{
444			// empty input
445			in:  [][2]string{},
446			out: "rO0ABXcEAAAAAA==",
447		},
448		{
449			// common input
450			in: [][2]string{
451				{"-source", "1.8"},
452				{"-target", "1.8"},
453			},
454			out: "rO0ABXcgAAAAAgAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjg=",
455		},
456		{
457			// input that serializes to a 255 byte block
458			in: [][2]string{
459				{"-source", "1.8"},
460				{"-target", "1.8"},
461				{"a", strings.Repeat("b", 218)},
462			},
463			out: "rO0ABXf/AAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA2mJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi",
464		},
465		{
466			// input that serializes to a 256 byte block
467			in: [][2]string{
468				{"-source", "1.8"},
469				{"-target", "1.8"},
470				{"a", strings.Repeat("b", 219)},
471			},
472			out: "rO0ABXoAAAEAAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA22JiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYg==",
473		},
474		{
475			// input that serializes to a 257 byte block
476			in: [][2]string{
477				{"-source", "1.8"},
478				{"-target", "1.8"},
479				{"a", strings.Repeat("b", 220)},
480			},
481			out: "rO0ABXoAAAEBAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA3GJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=",
482		},
483	}
484
485	for i, test := range tests {
486		t.Run(strconv.Itoa(i), func(t *testing.T) {
487			got := kaptEncodeFlags(test.in)
488			if got != test.out {
489				t.Errorf("\nwant %q\n got %q", test.out, got)
490			}
491		})
492	}
493}
494
495func TestKotlinCompose(t *testing.T) {
496	result := android.GroupFixturePreparers(
497		PrepareForTestWithJavaDefaultModules,
498	).RunTestWithBp(t, `
499		java_library {
500			name: "androidx.compose.runtime_runtime",
501		}
502
503		kotlin_plugin {
504			name: "androidx.compose.compiler_compiler-hosted-plugin",
505		}
506
507		java_library {
508			name: "withcompose",
509			srcs: ["a.kt"],
510			plugins: ["plugin"],
511			static_libs: ["androidx.compose.runtime_runtime"],
512		}
513
514		java_library {
515			name: "nocompose",
516			srcs: ["a.kt"],
517		}
518
519		java_plugin {
520			name: "plugin",
521		}
522	`)
523
524	buildOS := result.Config.BuildOS.String()
525
526	composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted-plugin", buildOS+"_common").Rule("combineJar").Output
527	withCompose := result.ModuleForTests("withcompose", "android_common")
528	noCompose := result.ModuleForTests("nocompose", "android_common")
529
530	android.AssertStringListContains(t, "missing compose compiler dependency",
531		withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
532
533	android.AssertStringDoesContain(t, "missing compose compiler plugin",
534		withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
535
536	android.AssertStringListContains(t, "missing kapt compose compiler dependency",
537		withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String())
538
539	android.AssertStringListDoesNotContain(t, "unexpected compose compiler dependency",
540		noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
541
542	android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
543		noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
544}
545
546func TestKotlinPlugin(t *testing.T) {
547	result := android.GroupFixturePreparers(
548		PrepareForTestWithJavaDefaultModules,
549	).RunTestWithBp(t, `
550		kotlin_plugin {
551			name: "kotlin_plugin",
552		}
553
554		java_library {
555			name: "with_kotlin_plugin",
556			srcs: ["a.kt"],
557			plugins: ["plugin"],
558			kotlin_plugins: ["kotlin_plugin"],
559		}
560
561		java_library {
562			name: "no_kotlin_plugin",
563			srcs: ["a.kt"],
564		}
565
566		java_plugin {
567			name: "plugin",
568		}
569	`)
570
571	buildOS := result.Config.BuildOS.String()
572
573	kotlinPlugin := result.ModuleForTests("kotlin_plugin", buildOS+"_common").Rule("combineJar").Output
574	withKotlinPlugin := result.ModuleForTests("with_kotlin_plugin", "android_common")
575	noKotlinPlugin := result.ModuleForTests("no_kotlin_plugin", "android_common")
576
577	android.AssertStringListContains(t, "missing plugin compiler dependency",
578		withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())
579
580	android.AssertStringDoesContain(t, "missing kotlin plugin",
581		withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String())
582
583	android.AssertStringListContains(t, "missing kapt kotlin plugin dependency",
584		withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String())
585
586	android.AssertStringListDoesNotContain(t, "unexpected kotlin plugin dependency",
587		noKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())
588
589	android.AssertStringDoesNotContain(t, "unexpected kotlin plugin",
590		noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String())
591}
592