modules_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. // Copyright 2020 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 soongconfig
  15. import (
  16. "reflect"
  17. "testing"
  18. "github.com/google/blueprint/proptools"
  19. )
  20. func Test_CanonicalizeToProperty(t *testing.T) {
  21. tests := []struct {
  22. name string
  23. arg string
  24. want string
  25. }{
  26. {
  27. name: "lowercase",
  28. arg: "board",
  29. want: "board",
  30. },
  31. {
  32. name: "uppercase",
  33. arg: "BOARD",
  34. want: "BOARD",
  35. },
  36. {
  37. name: "numbers",
  38. arg: "BOARD123",
  39. want: "BOARD123",
  40. },
  41. {
  42. name: "underscore",
  43. arg: "TARGET_BOARD",
  44. want: "TARGET_BOARD",
  45. },
  46. {
  47. name: "dash",
  48. arg: "TARGET-BOARD",
  49. want: "TARGET_BOARD",
  50. },
  51. {
  52. name: "unicode",
  53. arg: "boardλ",
  54. want: "board_",
  55. },
  56. }
  57. for _, tt := range tests {
  58. t.Run(tt.name, func(t *testing.T) {
  59. if got := CanonicalizeToProperty(tt.arg); got != tt.want {
  60. t.Errorf("canonicalizeToProperty() = %v, want %v", got, tt.want)
  61. }
  62. })
  63. }
  64. }
  65. func Test_typeForPropertyFromPropertyStruct(t *testing.T) {
  66. tests := []struct {
  67. name string
  68. ps interface{}
  69. property string
  70. want string
  71. }{
  72. {
  73. name: "string",
  74. ps: struct {
  75. A string
  76. }{},
  77. property: "a",
  78. want: "string",
  79. },
  80. {
  81. name: "list",
  82. ps: struct {
  83. A []string
  84. }{},
  85. property: "a",
  86. want: "[]string",
  87. },
  88. {
  89. name: "missing",
  90. ps: struct {
  91. A []string
  92. }{},
  93. property: "b",
  94. want: "",
  95. },
  96. {
  97. name: "nested",
  98. ps: struct {
  99. A struct {
  100. B string
  101. }
  102. }{},
  103. property: "a.b",
  104. want: "string",
  105. },
  106. {
  107. name: "missing nested",
  108. ps: struct {
  109. A struct {
  110. B string
  111. }
  112. }{},
  113. property: "a.c",
  114. want: "",
  115. },
  116. {
  117. name: "not a struct",
  118. ps: struct {
  119. A string
  120. }{},
  121. property: "a.b",
  122. want: "",
  123. },
  124. {
  125. name: "nested pointer",
  126. ps: struct {
  127. A *struct {
  128. B string
  129. }
  130. }{},
  131. property: "a.b",
  132. want: "string",
  133. },
  134. {
  135. name: "nested interface",
  136. ps: struct {
  137. A interface{}
  138. }{
  139. A: struct {
  140. B string
  141. }{},
  142. },
  143. property: "a.b",
  144. want: "string",
  145. },
  146. {
  147. name: "nested interface pointer",
  148. ps: struct {
  149. A interface{}
  150. }{
  151. A: &struct {
  152. B string
  153. }{},
  154. },
  155. property: "a.b",
  156. want: "string",
  157. },
  158. {
  159. name: "nested interface nil pointer",
  160. ps: struct {
  161. A interface{}
  162. }{
  163. A: (*struct {
  164. B string
  165. })(nil),
  166. },
  167. property: "a.b",
  168. want: "string",
  169. },
  170. }
  171. for _, tt := range tests {
  172. t.Run(tt.name, func(t *testing.T) {
  173. typ := typeForPropertyFromPropertyStruct(tt.ps, tt.property)
  174. got := ""
  175. if typ != nil {
  176. got = typ.String()
  177. }
  178. if got != tt.want {
  179. t.Errorf("typeForPropertyFromPropertyStruct() = %v, want %v", got, tt.want)
  180. }
  181. })
  182. }
  183. }
  184. func Test_createAffectablePropertiesType(t *testing.T) {
  185. tests := []struct {
  186. name string
  187. affectableProperties []string
  188. factoryProps interface{}
  189. want string
  190. }{
  191. {
  192. name: "string",
  193. affectableProperties: []string{"cflags"},
  194. factoryProps: struct {
  195. Cflags string
  196. }{},
  197. want: "*struct { Cflags string }",
  198. },
  199. {
  200. name: "list",
  201. affectableProperties: []string{"cflags"},
  202. factoryProps: struct {
  203. Cflags []string
  204. }{},
  205. want: "*struct { Cflags []string }",
  206. },
  207. {
  208. name: "string pointer",
  209. affectableProperties: []string{"cflags"},
  210. factoryProps: struct {
  211. Cflags *string
  212. }{},
  213. want: "*struct { Cflags *string }",
  214. },
  215. {
  216. name: "subset",
  217. affectableProperties: []string{"cflags"},
  218. factoryProps: struct {
  219. Cflags string
  220. Ldflags string
  221. }{},
  222. want: "*struct { Cflags string }",
  223. },
  224. {
  225. name: "none",
  226. affectableProperties: []string{"cflags"},
  227. factoryProps: struct {
  228. Ldflags string
  229. }{},
  230. want: "",
  231. },
  232. {
  233. name: "nested",
  234. affectableProperties: []string{"multilib.lib32.cflags"},
  235. factoryProps: struct {
  236. Multilib struct {
  237. Lib32 struct {
  238. Cflags string
  239. }
  240. }
  241. }{},
  242. want: "*struct { Multilib struct { Lib32 struct { Cflags string } } }",
  243. },
  244. {
  245. name: "complex",
  246. affectableProperties: []string{
  247. "cflags",
  248. "multilib.lib32.cflags",
  249. "multilib.lib32.ldflags",
  250. "multilib.lib64.cflags",
  251. "multilib.lib64.ldflags",
  252. "zflags",
  253. },
  254. factoryProps: struct {
  255. Cflags string
  256. Multilib struct {
  257. Lib32 struct {
  258. Cflags string
  259. Ldflags string
  260. }
  261. Lib64 struct {
  262. Cflags string
  263. Ldflags string
  264. }
  265. }
  266. Zflags string
  267. }{},
  268. want: "*struct { Cflags string; Multilib struct { Lib32 struct { Cflags string; Ldflags string }; Lib64 struct { Cflags string; Ldflags string } }; Zflags string }",
  269. },
  270. }
  271. for _, tt := range tests {
  272. t.Run(tt.name, func(t *testing.T) {
  273. typ := createAffectablePropertiesType(tt.affectableProperties, []interface{}{tt.factoryProps})
  274. got := ""
  275. if typ != nil {
  276. got = typ.String()
  277. }
  278. if !reflect.DeepEqual(got, tt.want) {
  279. t.Errorf("createAffectablePropertiesType() = %v, want %v", got, tt.want)
  280. }
  281. })
  282. }
  283. }
  284. type properties struct {
  285. A *string
  286. B bool
  287. }
  288. type boolVarProps struct {
  289. A *string
  290. B bool
  291. Conditions_default *properties
  292. }
  293. type soongConfigVars struct {
  294. Bool_var interface{}
  295. }
  296. type stringSoongConfigVars struct {
  297. String_var interface{}
  298. }
  299. func Test_PropertiesToApply(t *testing.T) {
  300. mt, _ := newModuleType(&ModuleTypeProperties{
  301. Module_type: "foo",
  302. Config_namespace: "bar",
  303. Bool_variables: []string{"bool_var"},
  304. Properties: []string{"a", "b"},
  305. })
  306. boolVarPositive := &properties{
  307. A: proptools.StringPtr("A"),
  308. B: true,
  309. }
  310. conditionsDefault := &properties{
  311. A: proptools.StringPtr("default"),
  312. B: false,
  313. }
  314. actualProps := &struct {
  315. Soong_config_variables soongConfigVars
  316. }{
  317. Soong_config_variables: soongConfigVars{
  318. Bool_var: &boolVarProps{
  319. A: boolVarPositive.A,
  320. B: boolVarPositive.B,
  321. Conditions_default: conditionsDefault,
  322. },
  323. },
  324. }
  325. props := reflect.ValueOf(actualProps)
  326. testCases := []struct {
  327. name string
  328. config SoongConfig
  329. wantProps []interface{}
  330. }{
  331. {
  332. name: "no_vendor_config",
  333. config: Config(map[string]string{}),
  334. wantProps: []interface{}{conditionsDefault},
  335. },
  336. {
  337. name: "vendor_config_false",
  338. config: Config(map[string]string{"bool_var": "n"}),
  339. wantProps: []interface{}{conditionsDefault},
  340. },
  341. {
  342. name: "bool_var_true",
  343. config: Config(map[string]string{"bool_var": "y"}),
  344. wantProps: []interface{}{boolVarPositive},
  345. },
  346. }
  347. for _, tc := range testCases {
  348. gotProps, err := PropertiesToApply(mt, props, tc.config)
  349. if err != nil {
  350. t.Errorf("%s: Unexpected error in PropertiesToApply: %s", tc.name, err)
  351. }
  352. if !reflect.DeepEqual(gotProps, tc.wantProps) {
  353. t.Errorf("%s: Expected %s, got %s", tc.name, tc.wantProps, gotProps)
  354. }
  355. }
  356. }
  357. func Test_PropertiesToApply_String_Error(t *testing.T) {
  358. mt, _ := newModuleType(&ModuleTypeProperties{
  359. Module_type: "foo",
  360. Config_namespace: "bar",
  361. Variables: []string{"string_var"},
  362. Properties: []string{"a", "b"},
  363. })
  364. mt.Variables = append(mt.Variables, &stringVariable{
  365. baseVariable: baseVariable{
  366. variable: "string_var",
  367. },
  368. values: []string{"a", "b", "c"},
  369. })
  370. stringVarPositive := &properties{
  371. A: proptools.StringPtr("A"),
  372. B: true,
  373. }
  374. conditionsDefault := &properties{
  375. A: proptools.StringPtr("default"),
  376. B: false,
  377. }
  378. actualProps := &struct {
  379. Soong_config_variables stringSoongConfigVars
  380. }{
  381. Soong_config_variables: stringSoongConfigVars{
  382. String_var: &boolVarProps{
  383. A: stringVarPositive.A,
  384. B: stringVarPositive.B,
  385. Conditions_default: conditionsDefault,
  386. },
  387. },
  388. }
  389. props := reflect.ValueOf(actualProps)
  390. _, err := PropertiesToApply(mt, props, Config(map[string]string{
  391. "string_var": "x",
  392. }))
  393. expected := `Soong config property "string_var" must be one of [a b c], found "x"`
  394. if err == nil {
  395. t.Fatalf("Expected an error, got nil")
  396. } else if err.Error() != expected {
  397. t.Fatalf("Error message was not correct, expected %q, got %q", expected, err.Error())
  398. }
  399. }
  400. func Test_Bp2BuildSoongConfigDefinitionsAddVars(t *testing.T) {
  401. testCases := []struct {
  402. desc string
  403. defs []*SoongConfigDefinition
  404. expected Bp2BuildSoongConfigDefinitions
  405. }{
  406. {
  407. desc: "non-overlapping",
  408. defs: []*SoongConfigDefinition{
  409. &SoongConfigDefinition{
  410. ModuleTypes: map[string]*ModuleType{
  411. "a": &ModuleType{
  412. ConfigNamespace: "foo",
  413. Variables: []soongConfigVariable{
  414. &stringVariable{
  415. baseVariable: baseVariable{"string_var"},
  416. values: []string{"a", "b", "c"},
  417. },
  418. },
  419. },
  420. },
  421. },
  422. &SoongConfigDefinition{
  423. ModuleTypes: map[string]*ModuleType{
  424. "b": &ModuleType{
  425. ConfigNamespace: "foo",
  426. Variables: []soongConfigVariable{
  427. &stringVariable{
  428. baseVariable: baseVariable{"string_var"},
  429. values: []string{"a", "b", "c"},
  430. },
  431. &boolVariable{baseVariable: baseVariable{"bool_var"}},
  432. &valueVariable{baseVariable: baseVariable{"variable_var"}},
  433. },
  434. },
  435. },
  436. },
  437. },
  438. expected: Bp2BuildSoongConfigDefinitions{
  439. StringVars: map[string]map[string]bool{
  440. "foo__string_var": map[string]bool{"a": true, "b": true, "c": true},
  441. },
  442. BoolVars: map[string]bool{"foo__bool_var": true},
  443. ValueVars: map[string]bool{"foo__variable_var": true},
  444. },
  445. },
  446. {
  447. desc: "overlapping",
  448. defs: []*SoongConfigDefinition{
  449. &SoongConfigDefinition{
  450. ModuleTypes: map[string]*ModuleType{
  451. "a": &ModuleType{
  452. ConfigNamespace: "foo",
  453. Variables: []soongConfigVariable{
  454. &stringVariable{
  455. baseVariable: baseVariable{"string_var"},
  456. values: []string{"a", "b", "c"},
  457. },
  458. },
  459. },
  460. },
  461. },
  462. &SoongConfigDefinition{
  463. ModuleTypes: map[string]*ModuleType{
  464. "b": &ModuleType{
  465. ConfigNamespace: "foo",
  466. Variables: []soongConfigVariable{
  467. &stringVariable{
  468. baseVariable: baseVariable{"string_var"},
  469. values: []string{"b", "c", "d"},
  470. },
  471. &boolVariable{baseVariable: baseVariable{"bool_var"}},
  472. &valueVariable{baseVariable: baseVariable{"variable_var"}},
  473. },
  474. },
  475. },
  476. },
  477. },
  478. expected: Bp2BuildSoongConfigDefinitions{
  479. StringVars: map[string]map[string]bool{
  480. "foo__string_var": map[string]bool{"a": true, "b": true, "c": true, "d": true},
  481. },
  482. BoolVars: map[string]bool{"foo__bool_var": true},
  483. ValueVars: map[string]bool{"foo__variable_var": true},
  484. },
  485. },
  486. }
  487. for _, tc := range testCases {
  488. t.Run(tc.desc, func(t *testing.T) {
  489. actual := &Bp2BuildSoongConfigDefinitions{}
  490. for _, d := range tc.defs {
  491. func(def *SoongConfigDefinition) {
  492. actual.AddVars(def)
  493. }(d)
  494. }
  495. if !reflect.DeepEqual(*actual, tc.expected) {
  496. t.Errorf("Expected %#v, got %#v", tc.expected, *actual)
  497. }
  498. })
  499. }
  500. }
  501. func Test_Bp2BuildSoongConfigDefinitions(t *testing.T) {
  502. testCases := []struct {
  503. desc string
  504. defs Bp2BuildSoongConfigDefinitions
  505. expected string
  506. }{
  507. {
  508. desc: "all empty",
  509. defs: Bp2BuildSoongConfigDefinitions{},
  510. expected: `soong_config_bool_variables = {}
  511. soong_config_value_variables = {}
  512. soong_config_string_variables = {}`}, {
  513. desc: "only bool",
  514. defs: Bp2BuildSoongConfigDefinitions{
  515. BoolVars: map[string]bool{
  516. "bool_var": true,
  517. },
  518. },
  519. expected: `soong_config_bool_variables = {
  520. "bool_var": True,
  521. }
  522. soong_config_value_variables = {}
  523. soong_config_string_variables = {}`}, {
  524. desc: "only value vars",
  525. defs: Bp2BuildSoongConfigDefinitions{
  526. ValueVars: map[string]bool{
  527. "value_var": true,
  528. },
  529. },
  530. expected: `soong_config_bool_variables = {}
  531. soong_config_value_variables = {
  532. "value_var": True,
  533. }
  534. soong_config_string_variables = {}`}, {
  535. desc: "only string vars",
  536. defs: Bp2BuildSoongConfigDefinitions{
  537. StringVars: map[string]map[string]bool{
  538. "string_var": map[string]bool{
  539. "choice1": true,
  540. "choice2": true,
  541. "choice3": true,
  542. },
  543. },
  544. },
  545. expected: `soong_config_bool_variables = {}
  546. soong_config_value_variables = {}
  547. soong_config_string_variables = {
  548. "string_var": [
  549. "choice1",
  550. "choice2",
  551. "choice3",
  552. ],
  553. }`}, {
  554. desc: "all vars",
  555. defs: Bp2BuildSoongConfigDefinitions{
  556. BoolVars: map[string]bool{
  557. "bool_var_one": true,
  558. },
  559. ValueVars: map[string]bool{
  560. "value_var_one": true,
  561. "value_var_two": true,
  562. },
  563. StringVars: map[string]map[string]bool{
  564. "string_var_one": map[string]bool{
  565. "choice1": true,
  566. "choice2": true,
  567. "choice3": true,
  568. },
  569. "string_var_two": map[string]bool{
  570. "foo": true,
  571. "bar": true,
  572. },
  573. },
  574. },
  575. expected: `soong_config_bool_variables = {
  576. "bool_var_one": True,
  577. }
  578. soong_config_value_variables = {
  579. "value_var_one": True,
  580. "value_var_two": True,
  581. }
  582. soong_config_string_variables = {
  583. "string_var_one": [
  584. "choice1",
  585. "choice2",
  586. "choice3",
  587. ],
  588. "string_var_two": [
  589. "bar",
  590. "foo",
  591. ],
  592. }`},
  593. }
  594. for _, test := range testCases {
  595. t.Run(test.desc, func(t *testing.T) {
  596. actual := test.defs.String()
  597. if actual != test.expected {
  598. t.Errorf("Expected:\n%s\nbut got:\n%s", test.expected, actual)
  599. }
  600. })
  601. }
  602. }