1// Copyright 2020 The Android Open Source Project 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 ( 18 "strings" 19 "testing" 20 21 "android/soong/android" 22) 23 24func TestRustProtobuf3(t *testing.T) { 25 ctx := testRust(t, ` 26 rust_protobuf { 27 name: "librust_proto", 28 protos: ["buf.proto", "proto.proto"], 29 crate_name: "rust_proto", 30 source_stem: "buf", 31 shared_libs: ["libfoo_shared"], 32 static_libs: ["libfoo_static"], 33 } 34 cc_library_shared { 35 name: "libfoo_shared", 36 export_include_dirs: ["shared_include"], 37 } 38 cc_library_static { 39 name: "libfoo_static", 40 export_include_dirs: ["static_include"], 41 } 42 `) 43 // Check that libprotobuf is added as a dependency. 44 librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) 45 if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) { 46 t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)") 47 } 48 49 // Make sure the correct plugin is being used. 50 librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs") 51 cmd := librust_proto_out.RuleParams.Command 52 if w := "protoc-gen-rust"; !strings.Contains(cmd, w) { 53 t.Errorf("expected %q in %q", w, cmd) 54 } 55 56 // Check exported include directories 57 if w := "-Ishared_include"; !strings.Contains(cmd, w) { 58 t.Errorf("expected %q in %q", w, cmd) 59 } 60 if w := "-Istatic_include"; !strings.Contains(cmd, w) { 61 t.Errorf("expected %q in %q", w, cmd) 62 } 63 64 // Check proto.rs, the second protobuf, is listed as an output 65 librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs() 66 if android.InList("proto.rs", librust_proto_outputs) { 67 t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ", 68 librust_proto_outputs) 69 } 70} 71 72func TestRustProtobufInclude(t *testing.T) { 73 ctx := testRust(t, ` 74 rust_protobuf { 75 name: "librust_proto", 76 protos: ["proto.proto"], 77 crate_name: "rust_proto", 78 source_stem: "proto", 79 rustlibs: ["librust_exported_proto", "libfoo"], 80 } 81 rust_protobuf { 82 name: "librust_exported_proto", 83 protos: ["proto.proto"], 84 crate_name: "rust_exported_proto", 85 source_stem: "exported_proto", 86 exported_include_dirs: ["proto"] 87 } 88 rust_library { 89 name: "libfoo", 90 crate_name: "foo", 91 srcs: ["foo.rs"], 92 } 93 `) 94 // Check that librust_exported_proto is added as additional crate to generate source. 95 librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Module().(*Module).sourceProvider.(*protobufDecorator) 96 if !android.InList("rust_exported_proto", librust_proto.additionalCrates) { 97 t.Errorf("librust_proto should have librust_exported_proto included as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates) 98 } 99 100 // Make sure the default crates aren't being included. 101 if android.InList("std", librust_proto.additionalCrates) { 102 t.Errorf("librust_proto should not have included libstd as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates) 103 } 104 if android.InList("protobuf", librust_proto.additionalCrates) { 105 t.Errorf("librust_proto should not have included libprotobuf as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates) 106 } 107 108 // And make sure that non-protobuf crates aren't getting included either. 109 if android.InList("foo", librust_proto.additionalCrates) { 110 t.Errorf("librust_proto should not have included libfoo as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates) 111 } 112 113 // Check librust_proto args includes -Iproto 114 librust_proto_rule := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("proto.rs") 115 cmd := librust_proto_rule.RuleParams.Command 116 if w := "-Iproto"; !strings.Contains(cmd, w) { 117 t.Errorf("expected %q in %q", w, cmd) 118 } 119 120} 121 122func TestRustGrpc(t *testing.T) { 123 ctx := testRust(t, ` 124 rust_protobuf { 125 name: "librust_grpcio", 126 protos: ["buf.proto"], 127 grpc_protos: ["foo.proto", "proto.proto"], 128 crate_name: "rust_grpcio", 129 source_stem: "buf", 130 } 131 `) 132 133 // Check that libprotobuf is added as a dependency. 134 librust_grpcio_module := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_dylib").Module().(*Module) 135 136 // Check that libgrpcio is added as a dependency. 137 if !android.InList("libgrpcio", librust_grpcio_module.Properties.AndroidMkDylibs) { 138 t.Errorf("libgrpcio dependency missing for rust_grpcio (dependency missing from AndroidMkDylibs)") 139 } 140 141 // Check that libfutures is added as a dependency. 142 if !android.InList("libfutures", librust_grpcio_module.Properties.AndroidMkDylibs) { 143 t.Errorf("libfutures dependency missing for rust_grpcio (dependency missing from AndroidMkDylibs)") 144 } 145 146 // Make sure the correct plugin is being used. 147 librust_grpcio_out := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").Output("foo_grpc.rs") 148 cmd := librust_grpcio_out.RuleParams.Command 149 if w := "protoc-gen-grpc"; !strings.Contains(cmd, w) { 150 t.Errorf("expected %q in %q", w, cmd) 151 } 152 153 // Check that we're including the exported directory from libprotobuf-cpp-full 154 if w := "-I" + rustDefaultsDir + "libprotobuf-cpp-full-includes"; !strings.Contains(cmd, w) { 155 t.Errorf("expected %q in %q", w, cmd) 156 } 157 158 // Check proto.rs, the second protobuf, is listed as an output 159 librust_grpcio_outputs := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").AllOutputs() 160 if android.InList("proto_grpc.rs", librust_grpcio_outputs) { 161 t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto_grpc.rs' in list, got: %#v ", 162 librust_grpcio_outputs) 163 } 164} 165 166func TestRustProtoErrors(t *testing.T) { 167 testRustError(t, "A proto can only be added once to either grpc_protos or protos.*", ` 168 rust_protobuf { 169 name: "librust_grpcio", 170 protos: ["buf.proto"], 171 grpc_protos: ["buf.proto"], 172 crate_name: "rust_grpcio", 173 source_stem: "buf", 174 } 175 `) 176 177 testRustError(t, "proto filenames must be unique across 'protos' and 'grpc_protos'.*", ` 178 rust_protobuf { 179 name: "librust_grpcio", 180 protos: ["buf.proto"], 181 grpc_protos: ["proto/buf.proto"], 182 crate_name: "rust_grpcio", 183 source_stem: "buf", 184 } 185 `) 186} 187