blob: 8c1c436230dc0f52489a2c2e313dd0a4290849b2 [file] [log] [blame]
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +02001// 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
15package rust
16
17import (
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020018 "encoding/json"
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020019 "io/ioutil"
20 "path/filepath"
Thiébaud Weksteena6351ca2020-09-29 09:53:21 +020021 "strings"
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020022 "testing"
23
24 "android/soong/android"
25 "android/soong/cc"
26)
27
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020028// testProjectJson run the generation of rust-project.json. It returns the raw
29// content of the generated file.
30func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020031 cc.GatherRequiredFilesForTest(fs)
32
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020033 env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020034 config := android.TestArchConfig(buildDir, env, bp, fs)
35 ctx := CreateTestContext()
36 ctx.Register(config)
37 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
38 android.FailIfErrored(t, errs)
39 _, errs = ctx.PrepareBuildActions(config)
40 android.FailIfErrored(t, errs)
41
42 // The JSON file is generated via WriteFileToOutputDir. Therefore, it
43 // won't appear in the Output of the TestingSingleton. Manually verify
44 // it exists.
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020045 content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName))
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020046 if err != nil {
47 t.Errorf("rust-project.json has not been generated")
48 }
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020049 return content
50}
51
52// validateJsonCrates validates that content follows the basic structure of
53// rust-project.json. It returns the crates attribute if the validation
54// succeeded.
55// It uses an empty interface instead of relying on a defined structure to
56// avoid a strong dependency on our implementation.
57func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} {
58 var content interface{}
59 err := json.Unmarshal(rawContent, &content)
60 if err != nil {
61 t.Errorf("Unable to parse the rust-project.json as JSON: %v", err)
62 }
63 root, ok := content.(map[string]interface{})
64 if !ok {
65 t.Errorf("Unexpected JSON format: %v", content)
66 }
67 if _, ok = root["crates"]; !ok {
68 t.Errorf("No crates attribute in rust-project.json: %v", root)
69 }
70 crates, ok := root["crates"].([]interface{})
71 if !ok {
72 t.Errorf("Unexpected crates format: %v", root["crates"])
73 }
74 return crates
75}
76
77func TestProjectJsonDep(t *testing.T) {
78 bp := `
79 rust_library {
80 name: "liba",
81 srcs: ["a/src/lib.rs"],
82 crate_name: "a"
83 }
84 rust_library {
85 name: "libb",
86 srcs: ["b/src/lib.rs"],
87 crate_name: "b",
88 rlibs: ["liba"],
89 }
90 ` + GatherRequiredDepsForTest()
91 fs := map[string][]byte{
92 "a/src/lib.rs": nil,
93 "b/src/lib.rs": nil,
94 }
95 jsonContent := testProjectJson(t, bp, fs)
96 validateJsonCrates(t, jsonContent)
97}
98
99func TestProjectJsonBindGen(t *testing.T) {
100 bp := `
101 rust_library {
102 name: "liba",
103 srcs: ["src/lib.rs"],
Thiébaud Weksteena6351ca2020-09-29 09:53:21 +0200104 rlibs: ["libbindings1"],
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +0200105 crate_name: "a"
106 }
107 rust_bindgen {
Thiébaud Weksteena6351ca2020-09-29 09:53:21 +0200108 name: "libbindings1",
109 crate_name: "bindings1",
110 source_stem: "bindings1",
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +0200111 host_supported: true,
112 wrapper_src: "src/any.h",
113 }
Thiébaud Weksteena6351ca2020-09-29 09:53:21 +0200114 rust_library_host {
115 name: "libb",
116 srcs: ["src/lib.rs"],
117 rustlibs: ["libbindings2"],
118 crate_name: "b"
119 }
120 rust_bindgen_host {
121 name: "libbindings2",
122 crate_name: "bindings2",
123 source_stem: "bindings2",
124 wrapper_src: "src/any.h",
125 }
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +0200126 ` + GatherRequiredDepsForTest()
127 fs := map[string][]byte{
128 "src/lib.rs": nil,
129 }
130 jsonContent := testProjectJson(t, bp, fs)
Thiébaud Weksteena6351ca2020-09-29 09:53:21 +0200131 crates := validateJsonCrates(t, jsonContent)
132 for _, c := range crates {
133 crate, ok := c.(map[string]interface{})
134 if !ok {
135 t.Fatalf("Unexpected type for crate: %v", c)
136 }
137 rootModule, ok := crate["root_module"].(string)
138 if !ok {
139 t.Fatalf("Unexpected type for root_module: %v", crate["root_module"])
140 }
141 if strings.Contains(rootModule, "libbindings1") && !strings.Contains(rootModule, "android_arm64") {
142 t.Errorf("The source for libbindings1 does not contain android_arm64, got %v", rootModule)
143 }
144 if strings.Contains(rootModule, "libbindings2") && !strings.Contains(rootModule, "linux_glibc") {
145 t.Errorf("The source for libbindings2 does not contain linux_glibc, got %v", rootModule)
146 }
147 }
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +0200148}
Thiébaud Weksteen2f628ba2020-08-05 14:27:32 +0200149
150func TestProjectJsonMultiVersion(t *testing.T) {
151 bp := `
152 rust_library {
153 name: "liba1",
154 srcs: ["a1/src/lib.rs"],
155 crate_name: "a"
156 }
157 rust_library {
158 name: "liba2",
159 srcs: ["a2/src/lib.rs"],
160 crate_name: "a",
161 }
162 rust_library {
163 name: "libb",
164 srcs: ["b/src/lib.rs"],
165 crate_name: "b",
166 rustlibs: ["liba1", "liba2"],
167 }
168 ` + GatherRequiredDepsForTest()
169 fs := map[string][]byte{
170 "a1/src/lib.rs": nil,
171 "a2/src/lib.rs": nil,
172 "b/src/lib.rs": nil,
173 }
174 jsonContent := testProjectJson(t, bp, fs)
175 crates := validateJsonCrates(t, jsonContent)
176 for _, crate := range crates {
177 c := crate.(map[string]interface{})
178 if c["root_module"] == "b/src/lib.rs" {
179 deps, ok := c["deps"].([]interface{})
180 if !ok {
181 t.Errorf("Unexpected format for deps: %v", c["deps"])
182 }
183 aCount := 0
184 for _, dep := range deps {
185 d, ok := dep.(map[string]interface{})
186 if !ok {
187 t.Errorf("Unexpected format for dep: %v", dep)
188 }
189 if d["name"] == "a" {
190 aCount++
191 }
192 }
193 if aCount != 2 {
194 t.Errorf("Unexpected number of liba dependencies want %v, got %v: %v", 2, aCount, deps)
195 }
196 return
197 }
198 }
199 t.Errorf("libb crate has not been found: %v", crates)
200}