python_test.go 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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 python
  15. import (
  16. "fmt"
  17. "os"
  18. "path/filepath"
  19. "testing"
  20. "android/soong/android"
  21. "android/soong/cc"
  22. )
  23. type pyModule struct {
  24. name string
  25. actualVersion string
  26. pyRunfiles []string
  27. srcsZip string
  28. depsSrcsZips []string
  29. }
  30. var (
  31. buildNamePrefix = "soong_python_test"
  32. // We allow maching almost anything before the actual variant so that the os/arch variant
  33. // is matched.
  34. moduleVariantErrTemplate = `%s: module %q variant "[a-zA-Z0-9_]*%s": `
  35. pkgPathErrTemplate = moduleVariantErrTemplate +
  36. "pkg_path: %q must be a relative path contained in par file."
  37. badIdentifierErrTemplate = moduleVariantErrTemplate +
  38. "srcs: the path %q contains invalid subpath %q."
  39. dupRunfileErrTemplate = moduleVariantErrTemplate +
  40. "found two files to be placed at the same location within zip %q." +
  41. " First file: in module %s at path %q." +
  42. " Second file: in module %s at path %q."
  43. noSrcFileErr = moduleVariantErrTemplate + "doesn't have any source files!"
  44. badSrcFileExtErr = moduleVariantErrTemplate + "srcs: found non (.py|.proto) file: %q!"
  45. badDataFileExtErr = moduleVariantErrTemplate + "data: found (.py|.proto) file: %q!"
  46. bpFile = "Android.bp"
  47. data = []struct {
  48. desc string
  49. mockFiles android.MockFS
  50. errors []string
  51. expectedBinaries []pyModule
  52. }{
  53. {
  54. desc: "module without any src files",
  55. mockFiles: map[string][]byte{
  56. filepath.Join("dir", bpFile): []byte(
  57. `python_library_host {
  58. name: "lib1",
  59. }`,
  60. ),
  61. },
  62. errors: []string{
  63. fmt.Sprintf(noSrcFileErr,
  64. "dir/Android.bp:1:1", "lib1", "PY3"),
  65. },
  66. },
  67. {
  68. desc: "module with bad src file ext",
  69. mockFiles: map[string][]byte{
  70. filepath.Join("dir", bpFile): []byte(
  71. `python_library_host {
  72. name: "lib1",
  73. srcs: [
  74. "file1.exe",
  75. ],
  76. }`,
  77. ),
  78. "dir/file1.exe": nil,
  79. },
  80. errors: []string{
  81. fmt.Sprintf(badSrcFileExtErr,
  82. "dir/Android.bp:3:11", "lib1", "PY3", "dir/file1.exe"),
  83. },
  84. },
  85. {
  86. desc: "module with bad data file ext",
  87. mockFiles: map[string][]byte{
  88. filepath.Join("dir", bpFile): []byte(
  89. `python_library_host {
  90. name: "lib1",
  91. srcs: [
  92. "file1.py",
  93. ],
  94. data: [
  95. "file2.py",
  96. ],
  97. }`,
  98. ),
  99. "dir/file1.py": nil,
  100. "dir/file2.py": nil,
  101. },
  102. errors: []string{
  103. fmt.Sprintf(badDataFileExtErr,
  104. "dir/Android.bp:6:11", "lib1", "PY3", "dir/file2.py"),
  105. },
  106. },
  107. {
  108. desc: "module with bad pkg_path format",
  109. mockFiles: map[string][]byte{
  110. filepath.Join("dir", bpFile): []byte(
  111. `python_library_host {
  112. name: "lib1",
  113. pkg_path: "a/c/../../",
  114. srcs: [
  115. "file1.py",
  116. ],
  117. }
  118. python_library_host {
  119. name: "lib2",
  120. pkg_path: "a/c/../../../",
  121. srcs: [
  122. "file1.py",
  123. ],
  124. }
  125. python_library_host {
  126. name: "lib3",
  127. pkg_path: "/a/c/../../",
  128. srcs: [
  129. "file1.py",
  130. ],
  131. }`,
  132. ),
  133. "dir/file1.py": nil,
  134. },
  135. errors: []string{
  136. fmt.Sprintf(pkgPathErrTemplate,
  137. "dir/Android.bp:11:15", "lib2", "PY3", "a/c/../../../"),
  138. fmt.Sprintf(pkgPathErrTemplate,
  139. "dir/Android.bp:19:15", "lib3", "PY3", "/a/c/../../"),
  140. },
  141. },
  142. {
  143. desc: "module with bad runfile src path format",
  144. mockFiles: map[string][]byte{
  145. filepath.Join("dir", bpFile): []byte(
  146. `python_library_host {
  147. name: "lib1",
  148. pkg_path: "a/b/c/",
  149. srcs: [
  150. ".file1.py",
  151. "123/file1.py",
  152. "-e/f/file1.py",
  153. ],
  154. }`,
  155. ),
  156. "dir/.file1.py": nil,
  157. "dir/123/file1.py": nil,
  158. "dir/-e/f/file1.py": nil,
  159. },
  160. errors: []string{
  161. fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
  162. "lib1", "PY3", "a/b/c/-e/f/file1.py", "-e"),
  163. fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
  164. "lib1", "PY3", "a/b/c/.file1.py", ".file1"),
  165. fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11",
  166. "lib1", "PY3", "a/b/c/123/file1.py", "123"),
  167. },
  168. },
  169. {
  170. desc: "module with duplicate runfile path",
  171. mockFiles: map[string][]byte{
  172. filepath.Join("dir", bpFile): []byte(
  173. `python_library_host {
  174. name: "lib1",
  175. pkg_path: "a/b/",
  176. srcs: [
  177. "c/file1.py",
  178. ],
  179. }
  180. python_library_host {
  181. name: "lib2",
  182. pkg_path: "a/b/c/",
  183. srcs: [
  184. "file1.py",
  185. ],
  186. libs: [
  187. "lib1",
  188. ],
  189. }
  190. python_binary_host {
  191. name: "bin",
  192. pkg_path: "e/",
  193. srcs: [
  194. "bin.py",
  195. ],
  196. libs: [
  197. "lib2",
  198. ],
  199. }
  200. `,
  201. ),
  202. "dir/c/file1.py": nil,
  203. "dir/file1.py": nil,
  204. "dir/bin.py": nil,
  205. },
  206. errors: []string{
  207. fmt.Sprintf(dupRunfileErrTemplate, "dir/Android.bp:20:6",
  208. "bin", "PY3", "a/b/c/file1.py", "bin", "dir/file1.py",
  209. "lib1", "dir/c/file1.py"),
  210. },
  211. },
  212. {
  213. desc: "module for testing dependencies",
  214. mockFiles: map[string][]byte{
  215. filepath.Join("dir", bpFile): []byte(
  216. `python_defaults {
  217. name: "default_lib",
  218. srcs: [
  219. "default.py",
  220. ],
  221. version: {
  222. py2: {
  223. enabled: true,
  224. srcs: [
  225. "default_py2.py",
  226. ],
  227. },
  228. py3: {
  229. enabled: false,
  230. srcs: [
  231. "default_py3.py",
  232. ],
  233. },
  234. },
  235. }
  236. python_library_host {
  237. name: "lib5",
  238. pkg_path: "a/b/",
  239. srcs: [
  240. "file1.py",
  241. ],
  242. version: {
  243. py2: {
  244. enabled: true,
  245. },
  246. py3: {
  247. enabled: true,
  248. },
  249. },
  250. }
  251. python_library_host {
  252. name: "lib6",
  253. pkg_path: "c/d/",
  254. srcs: [
  255. "file2.py",
  256. ],
  257. libs: [
  258. "lib5",
  259. ],
  260. }
  261. python_binary_host {
  262. name: "bin",
  263. defaults: ["default_lib"],
  264. pkg_path: "e/",
  265. srcs: [
  266. "bin.py",
  267. ],
  268. libs: [
  269. "lib5",
  270. ],
  271. version: {
  272. py3: {
  273. enabled: true,
  274. srcs: [
  275. "file4.py",
  276. ],
  277. libs: [
  278. "lib6",
  279. ],
  280. },
  281. },
  282. }`,
  283. ),
  284. filepath.Join("dir", "default.py"): nil,
  285. filepath.Join("dir", "default_py2.py"): nil,
  286. filepath.Join("dir", "default_py3.py"): nil,
  287. filepath.Join("dir", "file1.py"): nil,
  288. filepath.Join("dir", "file2.py"): nil,
  289. filepath.Join("dir", "bin.py"): nil,
  290. filepath.Join("dir", "file4.py"): nil,
  291. },
  292. expectedBinaries: []pyModule{
  293. {
  294. name: "bin",
  295. actualVersion: "PY3",
  296. pyRunfiles: []string{
  297. "e/default.py",
  298. "e/bin.py",
  299. "e/default_py3.py",
  300. "e/file4.py",
  301. },
  302. srcsZip: "out/soong/.intermediates/dir/bin/PY3/bin.py.srcszip",
  303. },
  304. },
  305. },
  306. }
  307. )
  308. func TestPythonModule(t *testing.T) {
  309. for _, d := range data {
  310. if d.desc != "module with duplicate runfile path" {
  311. continue
  312. }
  313. d.mockFiles[filepath.Join("common", bpFile)] = []byte(`
  314. python_library {
  315. name: "py3-stdlib",
  316. host_supported: true,
  317. }
  318. cc_binary {
  319. name: "py3-launcher",
  320. host_supported: true,
  321. }
  322. `)
  323. t.Run(d.desc, func(t *testing.T) {
  324. result := android.GroupFixturePreparers(
  325. android.PrepareForTestWithDefaults,
  326. android.PrepareForTestWithArchMutator,
  327. android.PrepareForTestWithAllowMissingDependencies,
  328. cc.PrepareForTestWithCcDefaultModules,
  329. PrepareForTestWithPythonBuildComponents,
  330. d.mockFiles.AddToFixture(),
  331. ).ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(d.errors)).
  332. RunTest(t)
  333. if len(result.Errs) > 0 {
  334. return
  335. }
  336. for _, e := range d.expectedBinaries {
  337. t.Run(e.name, func(t *testing.T) {
  338. expectModule(t, result.TestContext, e.name, e.actualVersion, e.srcsZip, e.pyRunfiles)
  339. })
  340. }
  341. })
  342. }
  343. }
  344. func expectModule(t *testing.T, ctx *android.TestContext, name, variant, expectedSrcsZip string, expectedPyRunfiles []string) {
  345. module := ctx.ModuleForTests(name, variant)
  346. base, baseOk := module.Module().(*PythonLibraryModule)
  347. if !baseOk {
  348. t.Fatalf("%s is not Python module!", name)
  349. }
  350. actualPyRunfiles := []string{}
  351. for _, path := range base.srcsPathMappings {
  352. actualPyRunfiles = append(actualPyRunfiles, path.dest)
  353. }
  354. android.AssertDeepEquals(t, "pyRunfiles", expectedPyRunfiles, actualPyRunfiles)
  355. android.AssertPathRelativeToTopEquals(t, "srcsZip", expectedSrcsZip, base.srcsZip)
  356. }
  357. func TestMain(m *testing.M) {
  358. os.Exit(m.Run())
  359. }