blob: 85219404a294cc2e223cfbc72a4424fc2c5e6ce9 [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"
21 "testing"
22
23 "android/soong/android"
24 "android/soong/cc"
25)
26
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020027// testProjectJson run the generation of rust-project.json. It returns the raw
28// content of the generated file.
29func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020030 cc.GatherRequiredFilesForTest(fs)
31
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020032 env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020033 config := android.TestArchConfig(buildDir, env, bp, fs)
34 ctx := CreateTestContext()
35 ctx.Register(config)
36 _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
37 android.FailIfErrored(t, errs)
38 _, errs = ctx.PrepareBuildActions(config)
39 android.FailIfErrored(t, errs)
40
41 // The JSON file is generated via WriteFileToOutputDir. Therefore, it
42 // won't appear in the Output of the TestingSingleton. Manually verify
43 // it exists.
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020044 content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName))
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +020045 if err != nil {
46 t.Errorf("rust-project.json has not been generated")
47 }
Thiébaud Weksteen83ee52f2020-08-05 09:29:23 +020048 return content
49}
50
51// validateJsonCrates validates that content follows the basic structure of
52// rust-project.json. It returns the crates attribute if the validation
53// succeeded.
54// It uses an empty interface instead of relying on a defined structure to
55// avoid a strong dependency on our implementation.
56func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} {
57 var content interface{}
58 err := json.Unmarshal(rawContent, &content)
59 if err != nil {
60 t.Errorf("Unable to parse the rust-project.json as JSON: %v", err)
61 }
62 root, ok := content.(map[string]interface{})
63 if !ok {
64 t.Errorf("Unexpected JSON format: %v", content)
65 }
66 if _, ok = root["crates"]; !ok {
67 t.Errorf("No crates attribute in rust-project.json: %v", root)
68 }
69 crates, ok := root["crates"].([]interface{})
70 if !ok {
71 t.Errorf("Unexpected crates format: %v", root["crates"])
72 }
73 return crates
74}
75
76func TestProjectJsonDep(t *testing.T) {
77 bp := `
78 rust_library {
79 name: "liba",
80 srcs: ["a/src/lib.rs"],
81 crate_name: "a"
82 }
83 rust_library {
84 name: "libb",
85 srcs: ["b/src/lib.rs"],
86 crate_name: "b",
87 rlibs: ["liba"],
88 }
89 ` + GatherRequiredDepsForTest()
90 fs := map[string][]byte{
91 "a/src/lib.rs": nil,
92 "b/src/lib.rs": nil,
93 }
94 jsonContent := testProjectJson(t, bp, fs)
95 validateJsonCrates(t, jsonContent)
96}
97
98func TestProjectJsonBindGen(t *testing.T) {
99 bp := `
100 rust_library {
101 name: "liba",
102 srcs: ["src/lib.rs"],
103 rlibs: ["libbindings"],
104 crate_name: "a"
105 }
106 rust_bindgen {
107 name: "libbindings",
108 crate_name: "bindings",
109 source_stem: "bindings",
110 host_supported: true,
111 wrapper_src: "src/any.h",
112 }
113 ` + GatherRequiredDepsForTest()
114 fs := map[string][]byte{
115 "src/lib.rs": nil,
116 }
117 jsonContent := testProjectJson(t, bp, fs)
118 validateJsonCrates(t, jsonContent)
Thiébaud Weksteene4d12a02020-06-05 11:09:27 +0200119}
Thiébaud Weksteen2f628ba2020-08-05 14:27:32 +0200120
121func TestProjectJsonMultiVersion(t *testing.T) {
122 bp := `
123 rust_library {
124 name: "liba1",
125 srcs: ["a1/src/lib.rs"],
126 crate_name: "a"
127 }
128 rust_library {
129 name: "liba2",
130 srcs: ["a2/src/lib.rs"],
131 crate_name: "a",
132 }
133 rust_library {
134 name: "libb",
135 srcs: ["b/src/lib.rs"],
136 crate_name: "b",
137 rustlibs: ["liba1", "liba2"],
138 }
139 ` + GatherRequiredDepsForTest()
140 fs := map[string][]byte{
141 "a1/src/lib.rs": nil,
142 "a2/src/lib.rs": nil,
143 "b/src/lib.rs": nil,
144 }
145 jsonContent := testProjectJson(t, bp, fs)
146 crates := validateJsonCrates(t, jsonContent)
147 for _, crate := range crates {
148 c := crate.(map[string]interface{})
149 if c["root_module"] == "b/src/lib.rs" {
150 deps, ok := c["deps"].([]interface{})
151 if !ok {
152 t.Errorf("Unexpected format for deps: %v", c["deps"])
153 }
154 aCount := 0
155 for _, dep := range deps {
156 d, ok := dep.(map[string]interface{})
157 if !ok {
158 t.Errorf("Unexpected format for dep: %v", dep)
159 }
160 if d["name"] == "a" {
161 aCount++
162 }
163 }
164 if aCount != 2 {
165 t.Errorf("Unexpected number of liba dependencies want %v, got %v: %v", 2, aCount, deps)
166 }
167 return
168 }
169 }
170 t.Errorf("libb crate has not been found: %v", crates)
171}