python_test.go 8.5 KB

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