Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/java/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 25 kB image not shown  

Quelle  kotlin_test.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2017 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package java

import (
 "slices"
 "strconv"
 "strings"
 "testing"

 "android/soong/android"
)

func TestKotlin(t *testing.T) {
 t.Parallel()
 bp := `
  java_library {
   name: "foo",
   srcs: ["a.java", "b.kt"],
   static_libs: ["quz"],
  }

  java_library {
   name: "bar",
   srcs: ["b.kt"],
   libs: ["foo"],
   static_libs: ["baz"],
  }

  java_library {
   name: "baz",
   srcs: ["c.java"],
   static_libs: ["quz"],
  }

  java_library {
   name: "quz",
   srcs: ["d.kt"],
  }`

 kotlinStdlibTurbineJars := []string{
  "out/soong/.intermediates/default/java/kotlin-stdlib/android_common/turbine/kotlin-stdlib.jar",
  "out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/turbine/kotlin-stdlib-jdk7.jar",
  "out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/turbine/kotlin-stdlib-jdk8.jar",
  "out/soong/.intermediates/default/java/kotlin-annotations/android_common/turbine/kotlin-annotations.jar",
 }

 kotlinStdlibJavacJars := []string{
  "out/soong/.intermediates/default/java/kotlin-stdlib/android_common/javac/kotlin-stdlib.jar",
  "out/soong/.intermediates/default/java/kotlin-stdlib-jdk7/android_common/javac/kotlin-stdlib-jdk7.jar",
  "out/soong/.intermediates/default/java/kotlin-stdlib-jdk8/android_common/javac/kotlin-stdlib-jdk8.jar",
  "out/soong/.intermediates/default/java/kotlin-annotations/android_common/javac/kotlin-annotations.jar",
 }

 bootclasspathTurbineJars := []string{
  "out/soong/.intermediates/default/java/stable.core.platform.api.stubs/android_common/turbine/stable.core.platform.api.stubs.jar",
  "out/soong/.intermediates/default/java/core-lambda-stubs/android_common/turbine/core-lambda-stubs.jar",
 }

 frameworkTurbineJars := []string{
  "out/soong/.intermediates/default/java/ext/android_common/turbine/ext.jar",
  "out/soong/.intermediates/default/java/framework/android_common/turbine/framework.jar",
 }

 testCases := []struct {
  name string

  preparer android.FixturePreparer

  fooKotlincInputs        []string
  fooJavacInputs          []string
  fooKotlincClasspath     []string
  fooJavacClasspath       []string
  fooCombinedInputs       []string
  fooHeaderCombinedInputs []string

  barKotlincInputs        []string
  barKotlincClasspath     []string
  barCombinedInputs       []string
  barHeaderCombinedInputs []string
 }{
  {
   name:             "transitive classpath",
   preparer:         android.NullFixturePreparer,
   fooKotlincInputs: []string{"a.java", "b.kt"},
   fooJavacInputs:   []string{"a.java"},
   fooKotlincClasspath: slices.Concat(
    bootclasspathTurbineJars,
    frameworkTurbineJars,
    []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
    kotlinStdlibTurbineJars,
   ),
   fooJavacClasspath: slices.Concat(
    []string{"out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar"},
    frameworkTurbineJars,
    []string{"out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar"},
    kotlinStdlibTurbineJars,
   ),
   fooCombinedInputs: slices.Concat(
    []string{
     "out/soong/.intermediates/foo/android_common/kotlin/foo.jar",
     "out/soong/.intermediates/foo/android_common/javac/foo.jar",
     "out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
    },
    kotlinStdlibJavacJars,
   ),
   fooHeaderCombinedInputs: slices.Concat(
    []string{
     "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
     "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
     "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
    },
    kotlinStdlibTurbineJars,
   ),

   barKotlincInputs: []string{"b.kt"},
   barKotlincClasspath: slices.Concat(
    bootclasspathTurbineJars,
    frameworkTurbineJars,
    []string{
     "out/soong/.intermediates/foo/android_common/turbine/foo.jar",
     "out/soong/.intermediates/foo/android_common/kotlin_headers/foo.jar",
     "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
    },
    kotlinStdlibTurbineJars,
    []string{"out/soong/.intermediates/baz/android_common/turbine/baz.jar"},
   ),
   barCombinedInputs: slices.Concat(
    []string{
     "out/soong/.intermediates/bar/android_common/kotlin/bar.jar",
     "out/soong/.intermediates/baz/android_common/javac/baz.jar",
     "out/soong/.intermediates/quz/android_common/kotlin/quz.jar",
    },
    kotlinStdlibJavacJars,
   ),
   barHeaderCombinedInputs: slices.Concat(
    []string{
     "out/soong/.intermediates/bar/android_common/kotlin_headers/bar.jar",
     "out/soong/.intermediates/baz/android_common/turbine/baz.jar",
     "out/soong/.intermediates/quz/android_common/kotlin_headers/quz.jar",
    },
    kotlinStdlibTurbineJars,
   ),
  },
 }

 for _, tt := range testCases {
  t.Run(tt.name, func(t *testing.T) {
   t.Parallel()
   result := android.GroupFixturePreparers(
    PrepareForTestWithJavaDefaultModules,
    tt.preparer,
   ).RunTestWithBp(t, bp)
   foo := result.ModuleForTests(t, "foo", "android_common")
   fooKotlinc := foo.Rule("kotlinc")
   android.AssertPathsRelativeToTopEquals(t, "foo kotlinc inputs", tt.fooKotlincInputs, fooKotlinc.Inputs)

   fooKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, foo.Output("kotlinc/classpath.rsp"))
   android.AssertStringPathsRelativeToTopEquals(t, "foo kotlinc classpath", result.Config, tt.fooKotlincClasspath, strings.Fields(fooKotlincClasspath))

   fooJavac := foo.Rule("javac")
   android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs)

   fooJavacClasspath := fooJavac.Args["classpath"]
   android.AssertStringPathsRelativeToTopEquals(t, "foo javac classpath", result.Config, tt.fooJavacClasspath,
    strings.Split(strings.TrimPrefix(fooJavacClasspath, "-classpath "), ":"))

   fooCombinedJar := foo.Output("combined/foo.jar")
   android.AssertPathsRelativeToTopEquals(t, "foo combined inputs", tt.fooCombinedInputs, fooCombinedJar.Inputs)

   fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar")
   android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs)

   bar := result.ModuleForTests(t, "bar", "android_common")
   barKotlinc := bar.Rule("kotlinc")
   android.AssertPathsRelativeToTopEquals(t, "bar kotlinc inputs", tt.barKotlincInputs, barKotlinc.Inputs)

   barKotlincClasspath := android.ContentFromFileRuleForTests(t, result.TestContext, bar.Output("kotlinc/classpath.rsp"))
   android.AssertStringPathsRelativeToTopEquals(t, "bar kotlinc classpath", result.Config, tt.barKotlincClasspath, strings.Fields(barKotlincClasspath))

   barCombinedJar := bar.Output("combined/bar.jar")
   android.AssertPathsRelativeToTopEquals(t, "bar combined inputs", tt.barCombinedInputs, barCombinedJar.Inputs)

   barCombinedHeaderJar := bar.Output("turbine-combined/bar.jar")
   android.AssertPathsRelativeToTopEquals(t, "bar header combined inputs", tt.barHeaderCombinedInputs, barCombinedHeaderJar.Inputs)
  })
 }
}

func TestSortKotlincFlags(t *testing.T) {
 t.Parallel()

 t.Run("Successful sorting of kotlincFlags", func(t *testing.T) {
  t.Parallel()
  bp := `
   java_library {
    name: "Foo",
    srcs: ["Foo.kt"],
    kotlincflags: ["-Ja", "-Xb", "-JCz", "-JCy", "-JCx", "-Xd"]
   }
  `
  result := android.GroupFixturePreparers(
   PrepareForTestWithJavaDefaultModules,
  ).RunTestWithBp(t, bp)

  module := result.ModuleForTests(t, "Foo", "android_common")
  kotlincRule := module.Rule("kotlinc")
  expectedFlags := "-Ja -JCz -JCy -JCx -Xb -Xd"

  kotlincFlags := kotlincRule.Args["kotlincFlags"]
  if !strings.Contains(kotlincFlags, expectedFlags) {
   t.Errorf("kotlincFlags expected to have -J flags sorted first:\n  Flags: %s\n  Expected: %s", kotlincFlags, expectedFlags)
  }
 })

}

func TestKapt(t *testing.T) {
 t.Parallel()
 bp := `
  java_library {
   name: "foo",
   srcs: ["a.java", "b.kt"],
   plugins: ["bar", "baz"],
   errorprone: {
    extra_check_modules: ["my_check"],
   },
  }

  java_plugin {
   name: "bar",
   processor_class: "com.bar",
   srcs: ["b.java"],
  }

  java_plugin {
   name: "baz",
   processor_class: "com.baz",
   srcs: ["b.java"],
  }

  java_plugin {
   name: "my_check",
   srcs: ["b.java"],
  }
 `
 t.Run("", func(t *testing.T) {
  t.Parallel()
  ctx, _ := testJava(t, bp)

  buildOS := ctx.Config().BuildOS.String()

  foo := ctx.ModuleForTests(t, "foo", "android_common")
  kaptStubs := foo.Rule("kapt")
  turbineApt := foo.Description("turbine apt")
  kotlinc := foo.Rule("kotlinc")
  javac := foo.Rule("javac")

  bar := ctx.ModuleForTests(t, "bar", buildOS+"_common").Rule("javac").Output.String()
  baz := ctx.ModuleForTests(t, "baz", buildOS+"_common").Rule("javac").Output.String()

  // Test that the kotlin and java sources are passed to kapt and kotlinc
  if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" {
   t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kaptStubs.Inputs)
  }
  if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
   t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
  }

  // Test that only the java sources are passed to turbine-apt and javac
  if len(turbineApt.Inputs) != 1 || turbineApt.Inputs[0].String() != "a.java" {
   t.Errorf(`foo turbine apt inputs %v != ["a.java"]`, turbineApt.Inputs)
  }
  if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
   t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
  }

  // Test that the kapt stubs jar is a dependency of turbine-apt
  if !inList(kaptStubs.Output.String(), turbineApt.Implicits.Strings()) {
   t.Errorf("expected %q in turbine-apt implicits %v", kaptStubs.Output.String(), kotlinc.Implicits.Strings())
  }

  // Test that the turbine-apt srcjar is a dependency of kotlinc and javac rules
  if !inList(turbineApt.Output.String(), kotlinc.Implicits.Strings()) {
   t.Errorf("expected %q in kotlinc implicits %v", turbineApt.Output.String(), kotlinc.Implicits.Strings())
  }
  if !inList(turbineApt.Output.String(), javac.Implicits.Strings()) {
   t.Errorf("expected %q in javac implicits %v", turbineApt.Output.String(), javac.Implicits.Strings())
  }

  // Test that the turbine-apt srcjar is extracted by the kotlinc and javac rules
  if kotlinc.Args["srcJars"] != turbineApt.Output.String() {
   t.Errorf("expected %q in kotlinc srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
  }
  if javac.Args["srcJars"] != turbineApt.Output.String() {
   t.Errorf("expected %q in javac srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
  }

  // Test that the processors are passed to kapt
  expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
   " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
  if kaptStubs.Args["kaptProcessorPath"] != expectedProcessorPath {
   t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kaptStubs.Args["kaptProcessorPath"])
  }
  expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
  if kaptStubs.Args["kaptProcessor"] != expectedProcessor {
   t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kaptStubs.Args["kaptProcessor"])
  }

  // Test that the processors are passed to turbine-apt
  expectedProcessorPath = "--processorpath " + bar + " " + baz
  if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessorPath) {
   t.Errorf("expected turbine-apt processorpath %q, got %q", expectedProcessorPath, turbineApt.Args["turbineFlags"])
  }
  expectedProcessor = "--processors com.bar com.baz"
  if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessor) {
   t.Errorf("expected turbine-apt processor %q, got %q", expectedProcessor, turbineApt.Args["turbineFlags"])
  }

  // Test that the processors are not passed to javac
  if javac.Args["processorpath"] != "" {
   t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
  }
  if javac.Args["processor"] != "-proc:none" {
   t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
  }
 })

 t.Run("errorprone", func(t *testing.T) {
  t.Parallel()
  env := map[string]string{
   "RUN_ERROR_PRONE": "true",
  }

  result := android.GroupFixturePreparers(
   PrepareForTestWithJavaDefaultModules,
   android.FixtureMergeEnv(env),
  ).RunTestWithBp(t, bp)

  buildOS := result.Config.BuildOS.String()

  kapt := result.ModuleForTests(t, "foo", "android_common").Rule("kapt")
  javac := result.ModuleForTests(t, "foo", "android_common").Description("javac")
  errorprone := result.ModuleForTests(t, "foo", "android_common").Description("errorprone")

  bar := result.ModuleForTests(t, "bar", buildOS+"_common").Description("javac").Output.String()
  baz := result.ModuleForTests(t, "baz", buildOS+"_common").Description("javac").Output.String()
  myCheck := result.ModuleForTests(t, "my_check", buildOS+"_common").Description("javac").Output.String()

  // Test that the errorprone plugins are not passed to kapt
  expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
   " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
  if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
   t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
  }
  expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
  if kapt.Args["kaptProcessor"] != expectedProcessor {
   t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
  }

  // Test that the errorprone plugins are not passed to javac
  if javac.Args["processorpath"] != "" {
   t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
  }
  if javac.Args["processor"] != "-proc:none" {
   t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
  }

  // Test that the errorprone plugins are passed to errorprone
  errorProneJar := "out/soong/.intermediates/external/error_prone/error_prone_plugin/" + buildOS + "_common/combined/error_prone_plugin.jar"
  expectedProcessorPath = "-processorpath " + errorProneJar + ":" + myCheck
  if errorprone.Args["processorpath"] != expectedProcessorPath {
   t.Errorf("expected processorpath %q, got %q", expectedProcessorPath, errorprone.Args["processorpath"])
  }
  if errorprone.Args["processor"] != "-proc:none" {
   t.Errorf("expected processor '-proc:none', got %q", errorprone.Args["processor"])
  }
 })
}

func TestKaptEncodeFlags(t *testing.T) {
 t.Parallel()
 // Compares the kaptEncodeFlags against the results of the example implementation at
 // https://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding
 tests := []struct {
  in  [][2]string
  out string
 }{
  {
   // empty input
   in:  [][2]string{},
   out: "rO0ABXcEAAAAAA==",
  },
  {
   // common input
   in: [][2]string{
    {"-source", "1.8"},
    {"-target", "1.8"},
   },
   out: "rO0ABXcgAAAAAgAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjg=",
  },
  {
   // input that serializes to a 255 byte block
   in: [][2]string{
    {"-source", "1.8"},
    {"-target", "1.8"},
    {"a", strings.Repeat("b", 218)},
   },
   out: "rO0ABXf/AAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA2mJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi",
  },
  {
   // input that serializes to a 256 byte block
   in: [][2]string{
    {"-source", "1.8"},
    {"-target", "1.8"},
    {"a", strings.Repeat("b", 219)},
   },
   out: "rO0ABXoAAAEAAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA22JiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYg==",
  },
  {
   // input that serializes to a 257 byte block
   in: [][2]string{
    {"-source", "1.8"},
    {"-target", "1.8"},
    {"a", strings.Repeat("b", 220)},
   },
   out: "rO0ABXoAAAEBAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA3GJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=",
  },
 }

 for i, test := range tests {
  t.Run(strconv.Itoa(i), func(t *testing.T) {
   t.Parallel()
   got := kaptEncodeFlags(test.in)
   if got != test.out {
    t.Errorf("\nwant %q\n got %q", test.out, got)
   }
  })
 }
}

func TestKsp(t *testing.T) {
 t.Parallel()
 bp := `
  java_library {
   name: "foo",
   srcs: ["a.java", "b.kt"],
   enable_ksp: true,
   annotation_processor_flags: ["a=b", "c=d"],
   plugins: ["bar", "baz"],
   errorprone: {
    extra_check_modules: ["my_check"],
   },
  }

  java_plugin {
   name: "bar",
   processor_class: "com.bar",
   srcs: ["b.java"],
  }

  java_plugin {
   name: "baz",
   processor_class: "com.baz",
   srcs: ["b.java"],
  }

  java_plugin {
   name: "my_check",
   srcs: ["b.java"],
  }`
 t.Run("", func(t *testing.T) {
  t.Parallel()
  ctx, _ := testJava(t, bp)

  buildOS := ctx.Config().BuildOS.String()

  foo := ctx.ModuleForTests(t, "foo", "android_common")
  kspStubs := foo.Rule("ksp")
  kotlinc := foo.Rule("kotlinc")
  javac := foo.Rule("javac")

  bar := ctx.ModuleForTests(t, "bar", buildOS+"_common").Rule("javac").Output.String()
  baz := ctx.ModuleForTests(t, "baz", buildOS+"_common").Rule("javac").Output.String()

  // Test that the kotlin and java sources are passed to ksp and kotlinc
  if len(kspStubs.Inputs) != 2 || kspStubs.Inputs[0].String() != "a.java" || kspStubs.Inputs[1].String() != "b.kt" {
   t.Errorf(`foo ksp inputs %v != ["a.java", "b.kt"]`, kspStubs.Inputs)
  }
  if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
   t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
  }

  // Test that only the java sources are passed to javac
  if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
   t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
  }

  // Test that the processors are passed to ksp
  expectedProcessorPath := bar + " " + baz
  if kspStubs.Args["kspProcessorPath"] != expectedProcessorPath {
   t.Errorf("expected kspProcessorPath %q, got %q", expectedProcessorPath, kspStubs.Args["kspProcessorPath"])
  }
  expectedProcessorOptions := "a=b:c=d"
  if kspStubs.Args["processorOptions"] != expectedProcessorOptions {
   t.Errorf("expected processorOptions %q, got %q", expectedProcessorOptions, kspStubs.Args["processorOptions"])
  }

  // Test that the processors are not passed to javac
  if javac.Args["processorpath"] != "" {
   t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
  }
  if javac.Args["processor"] != "-proc:none" {
   t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
  }
 })
}

func TestKotlinCompose(t *testing.T) {
 t.Parallel()
 result := android.GroupFixturePreparers(
  PrepareForTestWithJavaDefaultModules,
 ).RunTestWithBp(t, `
  java_library {
   name: "androidx.compose.runtime_runtime",
  }

  kotlin_plugin {
   name: "kotlin-compose-compiler-plugin",
  }

  java_library {
   name: "withcompose",
   srcs: ["a.kt"],
   plugins: ["plugin"],
   static_libs: ["androidx.compose.runtime_runtime"],
  }

  java_library {
   name: "nocompose",
   srcs: ["a.kt"],
  }

  java_plugin {
   name: "plugin",
  }
 `)

 buildOS := result.Config.BuildOS.String()

 composeCompiler := result.ModuleForTests(t, "kotlin-compose-compiler-plugin", buildOS+"_common").Rule("combineJar").Output
 withCompose := result.ModuleForTests(t, "withcompose", "android_common")
 noCompose := result.ModuleForTests(t, "nocompose", "android_common")

 android.AssertStringListContains(t, "missing compose compiler dependency",
  withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())

 android.AssertStringDoesContain(t, "missing compose compiler plugin",
  withCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String())

 android.AssertStringListContains(t, "missing kapt compose compiler dependency",
  withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String())

 android.AssertStringListDoesNotContain(t, "unexpected compose compiler dependency",
  noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())

 android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
  noCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String())
}

func TestKotlinPlugin(t *testing.T) {
 t.Parallel()
 result := android.GroupFixturePreparers(
  PrepareForTestWithJavaDefaultModules,
 ).RunTestWithBp(t, `
  kotlin_plugin {
   name: "kotlin_plugin",
  }

  java_library {
   name: "with_kotlin_plugin",
   srcs: ["a.kt"],
   plugins: ["plugin"],
   kotlin_plugins: ["kotlin_plugin"],
  }

  java_library {
   name: "no_kotlin_plugin",
   srcs: ["a.kt"],
  }

  java_plugin {
   name: "plugin",
  }
 `)

 buildOS := result.Config.BuildOS.String()

 kotlinPlugin := result.ModuleForTests(t, "kotlin_plugin", buildOS+"_common").Rule("combineJar").Output
 withKotlinPlugin := result.ModuleForTests(t, "with_kotlin_plugin", "android_common")
 noKotlinPlugin := result.ModuleForTests(t, "no_kotlin_plugin", "android_common")

 android.AssertStringListContains(t, "missing plugin compiler dependency",
  withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())

 android.AssertStringDoesContain(t, "missing kotlin plugin",
  withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincPluginFlags"], "-Xplugin="+kotlinPlugin.String())

 android.AssertStringListContains(t, "missing kapt kotlin plugin dependency",
  withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String())

 android.AssertStringListDoesNotContain(t, "unexpected kotlin plugin dependency",
  noKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String())

 android.AssertStringDoesNotContain(t, "unexpected kotlin plugin",
  noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String())
}

func TestKotlinAssociates(t *testing.T) {
 t.Parallel()

 targets := []string{"FooUtils", "FooTest"}
 for _, target := range targets {
  t.Run("Successful associate linking of "+target, func(t *testing.T) {
   t.Parallel()
   bp := `
    java_library {
     name: "Foo",
     srcs: ["Foo.kt"],
    }

    java_library {
     name: "FooUtils",
     srcs: ["FooUtils.kt"],
     libs: ["Foo"],
     associates: ["Foo"],
    }

    java_test {
     name: "FooTest",
     srcs: ["FooTest.kt"],
     static_libs: ["Foo"],
     associates: ["Foo"],
    }
   `
   result := android.GroupFixturePreparers(
    PrepareForTestWithJavaDefaultModules,
   ).RunTestWithBp(t, bp)

   module := result.ModuleForTests(t, target, "android_common")
   kotlincRule := module.Rule("kotlinc")
   expectedFriendPath := "out/soong/.intermediates/Foo/android_common/kotlin_headers/Foo.jar"
   expectedFlag := "-Xfriend-paths=" + expectedFriendPath

   friendPathsArg := kotlincRule.Args["friendPathsArg"]
   if !strings.Contains(friendPathsArg, expectedFlag) {
    t.Errorf("friendPathsArg missing expected friend path:\n  Flags: %s\n  Expected: %s", friendPathsArg, expectedFlag)
   }

   classpathRspFile := module.Output("kotlinc/classpath.rsp")
   classpathContent := android.ContentFromFileRuleForTests(t, result.TestContext, classpathRspFile)
   classpathEntries := strings.Fields(classpathContent)
   android.AssertStringPathRelativeToTopEquals(t, "first classpath entry", result.Config, expectedFriendPath, classpathEntries[0])
  })
 }

 t.Run("Error: Associate not a dependency", func(t *testing.T) {
  t.Parallel()
  bp := `
    java_library {
     name: "Foo",
     srcs: ["Foo.kt"],
    }

    java_library {
     name: "FooUtils",
     srcs: ["FooUtils.kt"],
     associates: ["Foo"],
    }
   `
  android.GroupFixturePreparers(
   PrepareForTestWithJavaDefaultModules,
  ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
   `\QAssociates: associate module 'Foo' must also be listed as a direct dependency\E`,
  )).RunTestWithBp(t, bp)
 })

 t.Run("Error: Associate not a Kotlin module", func(t *testing.T) {
  t.Parallel()
  bp := `
    java_library {
     name: "Foo",
     srcs: ["Foo.java"],
    }

    java_library {
     name: "FooUtils",
     srcs: ["FooUtils.kt"],
     libs: ["Foo"],
     associates: ["Foo"],
    }
   `
  android.GroupFixturePreparers(
   PrepareForTestWithJavaDefaultModules,
  ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
   `\QAssociates: associate module 'Foo' is not a Kotlin module\E`,
  )).RunTestWithBp(t, bp)
 })
}

[Dauer der Verarbeitung: 0.1 Sekunden, vorverarbeitet 2026-06-28]