kotlin_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  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. package java
  15. import (
  16. "strconv"
  17. "strings"
  18. "testing"
  19. "android/soong/android"
  20. )
  21. func TestKotlin(t *testing.T) {
  22. ctx, _ := testJava(t, `
  23. java_library {
  24. name: "foo",
  25. srcs: ["a.java", "b.kt"],
  26. }
  27. java_library {
  28. name: "bar",
  29. srcs: ["b.kt"],
  30. libs: ["foo"],
  31. static_libs: ["baz"],
  32. }
  33. java_library {
  34. name: "baz",
  35. srcs: ["c.java"],
  36. }
  37. `)
  38. kotlinStdlib := ctx.ModuleForTests("kotlin-stdlib", "android_common").
  39. Output("turbine-combined/kotlin-stdlib.jar").Output
  40. kotlinStdlibJdk7 := ctx.ModuleForTests("kotlin-stdlib-jdk7", "android_common").
  41. Output("turbine-combined/kotlin-stdlib-jdk7.jar").Output
  42. kotlinStdlibJdk8 := ctx.ModuleForTests("kotlin-stdlib-jdk8", "android_common").
  43. Output("turbine-combined/kotlin-stdlib-jdk8.jar").Output
  44. kotlinAnnotations := ctx.ModuleForTests("kotlin-annotations", "android_common").
  45. Output("turbine-combined/kotlin-annotations.jar").Output
  46. fooKotlinc := ctx.ModuleForTests("foo", "android_common").Rule("kotlinc")
  47. fooJavac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
  48. fooJar := ctx.ModuleForTests("foo", "android_common").Output("combined/foo.jar")
  49. fooHeaderJar := ctx.ModuleForTests("foo", "android_common").Output("turbine-combined/foo.jar")
  50. fooKotlincClasses := fooKotlinc.Output
  51. fooKotlincHeaderClasses := fooKotlinc.ImplicitOutput
  52. if len(fooKotlinc.Inputs) != 2 || fooKotlinc.Inputs[0].String() != "a.java" ||
  53. fooKotlinc.Inputs[1].String() != "b.kt" {
  54. t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, fooKotlinc.Inputs)
  55. }
  56. if len(fooJavac.Inputs) != 1 || fooJavac.Inputs[0].String() != "a.java" {
  57. t.Errorf(`foo inputs %v != ["a.java"]`, fooJavac.Inputs)
  58. }
  59. if !strings.Contains(fooJavac.Args["classpath"], fooKotlincHeaderClasses.String()) {
  60. t.Errorf("foo classpath %v does not contain %q",
  61. fooJavac.Args["classpath"], fooKotlincHeaderClasses.String())
  62. }
  63. if !inList(fooKotlincClasses.String(), fooJar.Inputs.Strings()) {
  64. t.Errorf("foo jar inputs %v does not contain %q",
  65. fooJar.Inputs.Strings(), fooKotlincClasses.String())
  66. }
  67. if !inList(kotlinStdlib.String(), fooJar.Inputs.Strings()) {
  68. t.Errorf("foo jar inputs %v does not contain %v",
  69. fooJar.Inputs.Strings(), kotlinStdlib.String())
  70. }
  71. if !inList(kotlinStdlibJdk7.String(), fooJar.Inputs.Strings()) {
  72. t.Errorf("foo jar inputs %v does not contain %v",
  73. fooJar.Inputs.Strings(), kotlinStdlibJdk7.String())
  74. }
  75. if !inList(kotlinStdlibJdk8.String(), fooJar.Inputs.Strings()) {
  76. t.Errorf("foo jar inputs %v does not contain %v",
  77. fooJar.Inputs.Strings(), kotlinStdlibJdk8.String())
  78. }
  79. if !inList(kotlinAnnotations.String(), fooJar.Inputs.Strings()) {
  80. t.Errorf("foo jar inputs %v does not contain %v",
  81. fooJar.Inputs.Strings(), kotlinAnnotations.String())
  82. }
  83. if !inList(fooKotlincHeaderClasses.String(), fooHeaderJar.Inputs.Strings()) {
  84. t.Errorf("foo header jar inputs %v does not contain %q",
  85. fooHeaderJar.Inputs.Strings(), fooKotlincHeaderClasses.String())
  86. }
  87. bazHeaderJar := ctx.ModuleForTests("baz", "android_common").Output("turbine-combined/baz.jar")
  88. barKotlinc := ctx.ModuleForTests("bar", "android_common").Rule("kotlinc")
  89. if len(barKotlinc.Inputs) != 1 || barKotlinc.Inputs[0].String() != "b.kt" {
  90. t.Errorf(`bar kotlinc inputs %v != ["b.kt"]`, barKotlinc.Inputs)
  91. }
  92. if !inList(fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
  93. t.Errorf(`expected %q in bar implicits %v`,
  94. fooHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
  95. }
  96. if !inList(bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings()) {
  97. t.Errorf(`expected %q in bar implicits %v`,
  98. bazHeaderJar.Output.String(), barKotlinc.Implicits.Strings())
  99. }
  100. }
  101. func TestKapt(t *testing.T) {
  102. bp := `
  103. java_library {
  104. name: "foo",
  105. srcs: ["a.java", "b.kt"],
  106. plugins: ["bar", "baz"],
  107. errorprone: {
  108. extra_check_modules: ["my_check"],
  109. },
  110. }
  111. java_plugin {
  112. name: "bar",
  113. processor_class: "com.bar",
  114. srcs: ["b.java"],
  115. }
  116. java_plugin {
  117. name: "baz",
  118. processor_class: "com.baz",
  119. srcs: ["b.java"],
  120. }
  121. java_plugin {
  122. name: "my_check",
  123. srcs: ["b.java"],
  124. }
  125. `
  126. t.Run("", func(t *testing.T) {
  127. ctx, _ := testJava(t, bp)
  128. buildOS := ctx.Config().BuildOS.String()
  129. foo := ctx.ModuleForTests("foo", "android_common")
  130. kaptStubs := foo.Rule("kapt")
  131. turbineApt := foo.Description("turbine apt")
  132. kotlinc := foo.Rule("kotlinc")
  133. javac := foo.Rule("javac")
  134. bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
  135. baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String()
  136. // Test that the kotlin and java sources are passed to kapt and kotlinc
  137. if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" {
  138. t.Errorf(`foo kapt inputs %v != ["a.java", "b.kt"]`, kaptStubs.Inputs)
  139. }
  140. if len(kotlinc.Inputs) != 2 || kotlinc.Inputs[0].String() != "a.java" || kotlinc.Inputs[1].String() != "b.kt" {
  141. t.Errorf(`foo kotlinc inputs %v != ["a.java", "b.kt"]`, kotlinc.Inputs)
  142. }
  143. // Test that only the java sources are passed to turbine-apt and javac
  144. if len(turbineApt.Inputs) != 1 || turbineApt.Inputs[0].String() != "a.java" {
  145. t.Errorf(`foo turbine apt inputs %v != ["a.java"]`, turbineApt.Inputs)
  146. }
  147. if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" {
  148. t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs)
  149. }
  150. // Test that the kapt stubs jar is a dependency of turbine-apt
  151. if !inList(kaptStubs.Output.String(), turbineApt.Implicits.Strings()) {
  152. t.Errorf("expected %q in turbine-apt implicits %v", kaptStubs.Output.String(), kotlinc.Implicits.Strings())
  153. }
  154. // Test that the turbine-apt srcjar is a dependency of kotlinc and javac rules
  155. if !inList(turbineApt.Output.String(), kotlinc.Implicits.Strings()) {
  156. t.Errorf("expected %q in kotlinc implicits %v", turbineApt.Output.String(), kotlinc.Implicits.Strings())
  157. }
  158. if !inList(turbineApt.Output.String(), javac.Implicits.Strings()) {
  159. t.Errorf("expected %q in javac implicits %v", turbineApt.Output.String(), javac.Implicits.Strings())
  160. }
  161. // Test that the turbine-apt srcjar is extracted by the kotlinc and javac rules
  162. if kotlinc.Args["srcJars"] != turbineApt.Output.String() {
  163. t.Errorf("expected %q in kotlinc srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
  164. }
  165. if javac.Args["srcJars"] != turbineApt.Output.String() {
  166. t.Errorf("expected %q in javac srcjars %v", turbineApt.Output.String(), kotlinc.Args["srcJars"])
  167. }
  168. // Test that the processors are passed to kapt
  169. expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
  170. " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
  171. if kaptStubs.Args["kaptProcessorPath"] != expectedProcessorPath {
  172. t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kaptStubs.Args["kaptProcessorPath"])
  173. }
  174. expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
  175. if kaptStubs.Args["kaptProcessor"] != expectedProcessor {
  176. t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kaptStubs.Args["kaptProcessor"])
  177. }
  178. // Test that the processors are passed to turbine-apt
  179. expectedProcessorPath = "--processorpath " + bar + " " + baz
  180. if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessorPath) {
  181. t.Errorf("expected turbine-apt processorpath %q, got %q", expectedProcessorPath, turbineApt.Args["turbineFlags"])
  182. }
  183. expectedProcessor = "--processors com.bar com.baz"
  184. if !strings.Contains(turbineApt.Args["turbineFlags"], expectedProcessor) {
  185. t.Errorf("expected turbine-apt processor %q, got %q", expectedProcessor, turbineApt.Args["turbineFlags"])
  186. }
  187. // Test that the processors are not passed to javac
  188. if javac.Args["processorpath"] != "" {
  189. t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
  190. }
  191. if javac.Args["processor"] != "-proc:none" {
  192. t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
  193. }
  194. })
  195. t.Run("errorprone", func(t *testing.T) {
  196. env := map[string]string{
  197. "RUN_ERROR_PRONE": "true",
  198. }
  199. result := android.GroupFixturePreparers(
  200. PrepareForTestWithJavaDefaultModules,
  201. android.FixtureMergeEnv(env),
  202. ).RunTestWithBp(t, bp)
  203. buildOS := result.Config.BuildOS.String()
  204. kapt := result.ModuleForTests("foo", "android_common").Rule("kapt")
  205. javac := result.ModuleForTests("foo", "android_common").Description("javac")
  206. errorprone := result.ModuleForTests("foo", "android_common").Description("errorprone")
  207. bar := result.ModuleForTests("bar", buildOS+"_common").Description("javac").Output.String()
  208. baz := result.ModuleForTests("baz", buildOS+"_common").Description("javac").Output.String()
  209. myCheck := result.ModuleForTests("my_check", buildOS+"_common").Description("javac").Output.String()
  210. // Test that the errorprone plugins are not passed to kapt
  211. expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar +
  212. " -P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + baz
  213. if kapt.Args["kaptProcessorPath"] != expectedProcessorPath {
  214. t.Errorf("expected kaptProcessorPath %q, got %q", expectedProcessorPath, kapt.Args["kaptProcessorPath"])
  215. }
  216. expectedProcessor := "-P plugin:org.jetbrains.kotlin.kapt3:processors=com.bar -P plugin:org.jetbrains.kotlin.kapt3:processors=com.baz"
  217. if kapt.Args["kaptProcessor"] != expectedProcessor {
  218. t.Errorf("expected kaptProcessor %q, got %q", expectedProcessor, kapt.Args["kaptProcessor"])
  219. }
  220. // Test that the errorprone plugins are not passed to javac
  221. if javac.Args["processorpath"] != "" {
  222. t.Errorf("expected processorPath '', got %q", javac.Args["processorpath"])
  223. }
  224. if javac.Args["processor"] != "-proc:none" {
  225. t.Errorf("expected processor '-proc:none', got %q", javac.Args["processor"])
  226. }
  227. // Test that the errorprone plugins are passed to errorprone
  228. expectedProcessorPath = "-processorpath " + myCheck
  229. if errorprone.Args["processorpath"] != expectedProcessorPath {
  230. t.Errorf("expected processorpath %q, got %q", expectedProcessorPath, errorprone.Args["processorpath"])
  231. }
  232. if errorprone.Args["processor"] != "-proc:none" {
  233. t.Errorf("expected processor '-proc:none', got %q", errorprone.Args["processor"])
  234. }
  235. })
  236. }
  237. func TestKaptEncodeFlags(t *testing.T) {
  238. // Compares the kaptEncodeFlags against the results of the example implementation at
  239. // https://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding
  240. tests := []struct {
  241. in [][2]string
  242. out string
  243. }{
  244. {
  245. // empty input
  246. in: [][2]string{},
  247. out: "rO0ABXcEAAAAAA==",
  248. },
  249. {
  250. // common input
  251. in: [][2]string{
  252. {"-source", "1.8"},
  253. {"-target", "1.8"},
  254. },
  255. out: "rO0ABXcgAAAAAgAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjg=",
  256. },
  257. {
  258. // input that serializes to a 255 byte block
  259. in: [][2]string{
  260. {"-source", "1.8"},
  261. {"-target", "1.8"},
  262. {"a", strings.Repeat("b", 218)},
  263. },
  264. out: "rO0ABXf/AAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA2mJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJi",
  265. },
  266. {
  267. // input that serializes to a 256 byte block
  268. in: [][2]string{
  269. {"-source", "1.8"},
  270. {"-target", "1.8"},
  271. {"a", strings.Repeat("b", 219)},
  272. },
  273. out: "rO0ABXoAAAEAAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA22JiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYg==",
  274. },
  275. {
  276. // input that serializes to a 257 byte block
  277. in: [][2]string{
  278. {"-source", "1.8"},
  279. {"-target", "1.8"},
  280. {"a", strings.Repeat("b", 220)},
  281. },
  282. out: "rO0ABXoAAAEBAAAAAwAHLXNvdXJjZQADMS44AActdGFyZ2V0AAMxLjgAAWEA3GJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmI=",
  283. },
  284. }
  285. for i, test := range tests {
  286. t.Run(strconv.Itoa(i), func(t *testing.T) {
  287. got := kaptEncodeFlags(test.in)
  288. if got != test.out {
  289. t.Errorf("\nwant %q\n got %q", test.out, got)
  290. }
  291. })
  292. }
  293. }
  294. func TestKotlinCompose(t *testing.T) {
  295. result := android.GroupFixturePreparers(
  296. PrepareForTestWithJavaDefaultModules,
  297. ).RunTestWithBp(t, `
  298. java_library {
  299. name: "androidx.compose.runtime_runtime",
  300. }
  301. java_library_host {
  302. name: "androidx.compose.compiler_compiler-hosted",
  303. }
  304. java_library {
  305. name: "withcompose",
  306. srcs: ["a.kt"],
  307. plugins: ["plugin"],
  308. static_libs: ["androidx.compose.runtime_runtime"],
  309. }
  310. java_library {
  311. name: "nocompose",
  312. srcs: ["a.kt"],
  313. }
  314. java_plugin {
  315. name: "plugin",
  316. }
  317. `)
  318. buildOS := result.Config.BuildOS.String()
  319. composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted", buildOS+"_common").Rule("combineJar").Output
  320. withCompose := result.ModuleForTests("withcompose", "android_common")
  321. noCompose := result.ModuleForTests("nocompose", "android_common")
  322. android.AssertStringListContains(t, "missing compose compiler dependency",
  323. withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
  324. android.AssertStringDoesContain(t, "missing compose compiler plugin",
  325. withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
  326. android.AssertStringListContains(t, "missing kapt compose compiler dependency",
  327. withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String())
  328. android.AssertStringListDoesNotContain(t, "unexpected compose compiler dependency",
  329. noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String())
  330. android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin",
  331. noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String())
  332. }