python_library_conversion_test.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. package bp2build
  2. import (
  3. "fmt"
  4. "strings"
  5. "testing"
  6. "android/soong/android"
  7. "android/soong/python"
  8. )
  9. // TODO(alexmarquez): Should be lifted into a generic Bp2Build file
  10. type PythonLibBp2Build func(ctx android.TopDownMutatorContext)
  11. type pythonLibBp2BuildTestCase struct {
  12. description string
  13. filesystem map[string]string
  14. blueprint string
  15. expectedBazelTargets []testBazelTarget
  16. dir string
  17. expectedError error
  18. }
  19. func convertPythonLibTestCaseToBp2build_Host(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
  20. for i := range tc.expectedBazelTargets {
  21. tc.expectedBazelTargets[i].attrs["target_compatible_with"] = `select({
  22. "//build/bazel/platforms/os:android": ["@platforms//:incompatible"],
  23. "//conditions:default": [],
  24. })`
  25. }
  26. return convertPythonLibTestCaseToBp2build(tc)
  27. }
  28. func convertPythonLibTestCaseToBp2build(tc pythonLibBp2BuildTestCase) Bp2buildTestCase {
  29. var bp2BuildTargets []string
  30. for _, t := range tc.expectedBazelTargets {
  31. bp2BuildTargets = append(bp2BuildTargets, MakeBazelTarget(t.typ, t.name, t.attrs))
  32. }
  33. // Copy the filesystem so that we can change stuff in it later without it
  34. // affecting the original pythonLibBp2BuildTestCase
  35. filesystemCopy := make(map[string]string)
  36. for k, v := range tc.filesystem {
  37. filesystemCopy[k] = v
  38. }
  39. return Bp2buildTestCase{
  40. Description: tc.description,
  41. Filesystem: filesystemCopy,
  42. Blueprint: tc.blueprint,
  43. ExpectedBazelTargets: bp2BuildTargets,
  44. Dir: tc.dir,
  45. ExpectedErr: tc.expectedError,
  46. }
  47. }
  48. func runPythonLibraryTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
  49. t.Helper()
  50. testCase := convertPythonLibTestCaseToBp2build(tc)
  51. testCase.Description = fmt.Sprintf(testCase.Description, "python_library")
  52. testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library")
  53. for name, contents := range testCase.Filesystem {
  54. if strings.HasSuffix(name, "Android.bp") {
  55. testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library")
  56. }
  57. }
  58. testCase.ModuleTypeUnderTest = "python_library"
  59. testCase.ModuleTypeUnderTestFactory = python.PythonLibraryFactory
  60. RunBp2BuildTestCaseSimple(t, testCase)
  61. }
  62. func runPythonLibraryHostTestCase(t *testing.T, tc pythonLibBp2BuildTestCase) {
  63. t.Helper()
  64. testCase := convertPythonLibTestCaseToBp2build_Host(tc)
  65. testCase.Description = fmt.Sprintf(testCase.Description, "python_library_host")
  66. testCase.Blueprint = fmt.Sprintf(testCase.Blueprint, "python_library_host")
  67. for name, contents := range testCase.Filesystem {
  68. if strings.HasSuffix(name, "Android.bp") {
  69. testCase.Filesystem[name] = fmt.Sprintf(contents, "python_library_host")
  70. }
  71. }
  72. testCase.ModuleTypeUnderTest = "python_library_host"
  73. testCase.ModuleTypeUnderTestFactory = python.PythonLibraryHostFactory
  74. RunBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
  75. ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
  76. },
  77. testCase)
  78. }
  79. func runPythonLibraryTestCases(t *testing.T, tc pythonLibBp2BuildTestCase) {
  80. t.Helper()
  81. runPythonLibraryTestCase(t, tc)
  82. runPythonLibraryHostTestCase(t, tc)
  83. }
  84. func TestSimplePythonLib(t *testing.T) {
  85. testCases := []pythonLibBp2BuildTestCase{
  86. {
  87. description: "simple %s converts to a native py_library",
  88. filesystem: map[string]string{
  89. "a.py": "",
  90. "b/c.py": "",
  91. "b/d.py": "",
  92. "b/e.py": "",
  93. "files/data.txt": "",
  94. },
  95. blueprint: `%s {
  96. name: "foo",
  97. srcs: ["**/*.py"],
  98. exclude_srcs: ["b/e.py"],
  99. data: ["files/data.txt",],
  100. libs: ["bar"],
  101. bazel_module: { bp2build_available: true },
  102. }
  103. python_library {
  104. name: "bar",
  105. srcs: ["b/e.py"],
  106. bazel_module: { bp2build_available: false },
  107. }`,
  108. expectedBazelTargets: []testBazelTarget{
  109. {
  110. typ: "py_library",
  111. name: "foo",
  112. attrs: AttrNameToString{
  113. "data": `["files/data.txt"]`,
  114. "deps": `[":bar"]`,
  115. "srcs": `[
  116. "a.py",
  117. "b/c.py",
  118. "b/d.py",
  119. ]`,
  120. "srcs_version": `"PY3"`,
  121. "imports": `["."]`,
  122. },
  123. },
  124. },
  125. },
  126. {
  127. description: "py2 %s converts to a native py_library",
  128. blueprint: `%s {
  129. name: "foo",
  130. srcs: ["a.py"],
  131. version: {
  132. py2: {
  133. enabled: true,
  134. },
  135. py3: {
  136. enabled: false,
  137. },
  138. },
  139. bazel_module: { bp2build_available: true },
  140. }`,
  141. expectedBazelTargets: []testBazelTarget{
  142. {
  143. typ: "py_library",
  144. name: "foo",
  145. attrs: AttrNameToString{
  146. "srcs": `["a.py"]`,
  147. "srcs_version": `"PY2"`,
  148. "imports": `["."]`,
  149. },
  150. },
  151. },
  152. },
  153. {
  154. description: "py3 %s converts to a native py_library",
  155. blueprint: `%s {
  156. name: "foo",
  157. srcs: ["a.py"],
  158. version: {
  159. py2: {
  160. enabled: false,
  161. },
  162. py3: {
  163. enabled: true,
  164. },
  165. },
  166. bazel_module: { bp2build_available: true },
  167. }`,
  168. expectedBazelTargets: []testBazelTarget{
  169. {
  170. typ: "py_library",
  171. name: "foo",
  172. attrs: AttrNameToString{
  173. "srcs": `["a.py"]`,
  174. "srcs_version": `"PY3"`,
  175. "imports": `["."]`,
  176. },
  177. },
  178. },
  179. },
  180. {
  181. description: "py2&3 %s converts to a native py_library",
  182. blueprint: `%s {
  183. name: "foo",
  184. srcs: ["a.py"],
  185. version: {
  186. py2: {
  187. enabled: true,
  188. },
  189. py3: {
  190. enabled: true,
  191. },
  192. },
  193. bazel_module: { bp2build_available: true },
  194. }`,
  195. expectedBazelTargets: []testBazelTarget{
  196. {
  197. // srcs_version is PY2ANDPY3 by default.
  198. typ: "py_library",
  199. name: "foo",
  200. attrs: AttrNameToString{
  201. "srcs": `["a.py"]`,
  202. "imports": `["."]`,
  203. },
  204. },
  205. },
  206. },
  207. {
  208. description: "%s: pkg_path in a subdirectory of the same name converts correctly",
  209. dir: "mylib/subpackage",
  210. filesystem: map[string]string{
  211. "mylib/subpackage/a.py": "",
  212. "mylib/subpackage/Android.bp": `%s {
  213. name: "foo",
  214. srcs: ["a.py"],
  215. pkg_path: "mylib/subpackage",
  216. bazel_module: { bp2build_available: true },
  217. }`,
  218. },
  219. blueprint: `%s {name: "bar"}`,
  220. expectedBazelTargets: []testBazelTarget{
  221. {
  222. // srcs_version is PY2ANDPY3 by default.
  223. typ: "py_library",
  224. name: "foo",
  225. attrs: AttrNameToString{
  226. "srcs": `["a.py"]`,
  227. "imports": `["../.."]`,
  228. "srcs_version": `"PY3"`,
  229. },
  230. },
  231. },
  232. },
  233. {
  234. description: "%s: pkg_path in a subdirectory of a different name fails",
  235. dir: "mylib/subpackage",
  236. filesystem: map[string]string{
  237. "mylib/subpackage/a.py": "",
  238. "mylib/subpackage/Android.bp": `%s {
  239. name: "foo",
  240. srcs: ["a.py"],
  241. pkg_path: "mylib/subpackage2",
  242. bazel_module: { bp2build_available: true },
  243. }`,
  244. },
  245. blueprint: `%s {name: "bar"}`,
  246. expectedError: fmt.Errorf("Currently, bp2build only supports pkg_paths that are the same as the folders the Android.bp file is in."),
  247. },
  248. }
  249. for _, tc := range testCases {
  250. t.Run(tc.description, func(t *testing.T) {
  251. runPythonLibraryTestCases(t, tc)
  252. })
  253. }
  254. }
  255. func TestPythonArchVariance(t *testing.T) {
  256. runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
  257. description: "test %s arch variants",
  258. filesystem: map[string]string{
  259. "dir/arm.py": "",
  260. "dir/x86.py": "",
  261. },
  262. blueprint: `%s {
  263. name: "foo",
  264. arch: {
  265. arm: {
  266. srcs: ["arm.py"],
  267. },
  268. x86: {
  269. srcs: ["x86.py"],
  270. },
  271. },
  272. }`,
  273. expectedBazelTargets: []testBazelTarget{
  274. {
  275. typ: "py_library",
  276. name: "foo",
  277. attrs: AttrNameToString{
  278. "srcs": `select({
  279. "//build/bazel/platforms/arch:arm": ["arm.py"],
  280. "//build/bazel/platforms/arch:x86": ["x86.py"],
  281. "//conditions:default": [],
  282. })`,
  283. "srcs_version": `"PY3"`,
  284. "imports": `["."]`,
  285. },
  286. },
  287. },
  288. })
  289. }
  290. func TestPythonLibraryWithProtobufs(t *testing.T) {
  291. runPythonLibraryTestCases(t, pythonLibBp2BuildTestCase{
  292. description: "test %s protobuf",
  293. filesystem: map[string]string{
  294. "dir/mylib.py": "",
  295. "dir/myproto.proto": "",
  296. },
  297. blueprint: `%s {
  298. name: "foo",
  299. srcs: [
  300. "dir/mylib.py",
  301. "dir/myproto.proto",
  302. ],
  303. }`,
  304. expectedBazelTargets: []testBazelTarget{
  305. {
  306. typ: "proto_library",
  307. name: "foo_proto",
  308. attrs: AttrNameToString{
  309. "srcs": `["dir/myproto.proto"]`,
  310. },
  311. },
  312. {
  313. typ: "py_proto_library",
  314. name: "foo_py_proto",
  315. attrs: AttrNameToString{
  316. "deps": `[":foo_proto"]`,
  317. },
  318. },
  319. {
  320. typ: "py_library",
  321. name: "foo",
  322. attrs: AttrNameToString{
  323. "srcs": `["dir/mylib.py"]`,
  324. "srcs_version": `"PY3"`,
  325. "imports": `["."]`,
  326. "deps": `[":foo_py_proto"]`,
  327. },
  328. },
  329. },
  330. })
  331. }