1 #include <gtest/gtest.h>
2 #include <wasmtime/component.hh>
3
4 using namespace wasmtime::component;
5 using wasmtime::Config;
6 using wasmtime::Engine;
7 using wasmtime::ExternType;
8 using wasmtime::Result;
9 using wasmtime::Span;
10 using wasmtime::Store;
11
TEST(types,empty_component)12 TEST(types, empty_component) {
13 Engine engine;
14
15 auto component = Component::compile(engine, R"(
16 (component)
17 )")
18 .unwrap()
19 .type();
20
21 EXPECT_EQ(component.import_count(engine), 0);
22 EXPECT_EQ(component.export_count(engine), 0);
23 }
24
TEST(types,component_resource)25 TEST(types, component_resource) {
26 Engine engine;
27
28 auto component = Component::compile(engine, R"(
29 (component
30 (import "x" (type $t (sub resource)))
31 (export "x" (type $t))
32 )
33 )")
34 .unwrap()
35 .type();
36
37 EXPECT_EQ(component.import_count(engine), 1);
38 auto ty = component.import_get(engine, "x")->resource();
39 auto i = *component.import_nth(engine, 0);
40 EXPECT_EQ(i.first, "x");
41 EXPECT_EQ(ty, i.second.resource());
42
43 EXPECT_EQ(component.export_count(engine), 1);
44
45 EXPECT_EQ(component.export_get(engine, "x")->resource(), ty);
46 auto e = *component.import_nth(engine, 0);
47 EXPECT_EQ(e.first, "x");
48 EXPECT_EQ(ty, e.second.resource());
49 }
50
TEST(types,component_instance)51 TEST(types, component_instance) {
52 Engine engine;
53
54 auto component = Component::compile(engine, R"(
55 (component
56 (import "x" (instance $a (export "t" (type (sub resource)))))
57 (export "x" (instance $a))
58 )
59 )")
60 .unwrap()
61 .type();
62
63 auto ty = component.import_get(engine, "x")->component_instance();
64 EXPECT_EQ(ty.export_count(engine), 1);
65 auto resource_ty = ty.export_get(engine, "t")->resource();
66 EXPECT_EQ(resource_ty, ty.export_nth(engine, 0)->second.resource());
67 EXPECT_EQ("t", ty.export_nth(engine, 0)->first);
68
69 auto ty2 = component.export_get(engine, "x")->component_instance();
70 EXPECT_EQ(resource_ty, ty2.export_get(engine, "t")->resource());
71 }
72
TEST(types,component_func)73 TEST(types, component_func) {
74 Engine engine;
75
76 auto component = Component::compile(engine, R"(
77 (component
78 (import "x" (func))
79 )
80 )")
81 .unwrap()
82 .type();
83
84 auto ty = component.import_get(engine, "x")->component_func();
85 EXPECT_EQ(ty.param_count(), 0);
86 EXPECT_FALSE(ty.result());
87
88 component = Component::compile(engine, R"(
89 (component
90 (import "x" (func (param "x" u32) (result string)))
91 )
92 )")
93 .unwrap()
94 .type();
95
96 ty = component.import_get(engine, "x")->component_func();
97 EXPECT_EQ(ty.param_count(), 1);
98 EXPECT_EQ(ty.param_nth(0)->first, "x");
99 EXPECT_TRUE(ty.param_nth(0)->second.is_u32());
100 EXPECT_EQ(ty.param_nth(0)->second, ValType::new_u32());
101
102 EXPECT_TRUE(ty.result()->is_string());
103 EXPECT_EQ(*ty.result(), ValType::new_string());
104 }
105
TEST(types,module_type)106 TEST(types, module_type) {
107 Engine engine;
108
109 auto component = Component::compile(engine, R"(
110 (component
111 (import "x" (core module))
112 )
113 )")
114 .unwrap();
115 auto cty = component.type();
116
117 auto ty = cty.import_get(engine, "x")->module();
118 EXPECT_EQ(ty.import_count(engine), 0);
119 EXPECT_EQ(ty.export_count(engine), 0);
120
121 component = Component::compile(engine, R"(
122 (component
123 (import "x" (core module
124 (import "" "" (func))
125 (export "x" (global (mut i32)))
126 ))
127 )
128 )")
129 .unwrap();
130 cty = component.type();
131
132 ty = cty.import_get(engine, "x")->module();
133 EXPECT_EQ(ty.import_count(engine), 1);
134 auto import = *ty.import_nth(engine, 0);
135 EXPECT_EQ(import.ref().module(), "");
136 EXPECT_EQ(import.ref().name(), "");
137
138 auto import_item_ty = ExternType::from_import(import.ref());
139 auto func_ty = std::get<wasmtime::FuncType::Ref>(import_item_ty);
140 EXPECT_EQ(func_ty.params().size(), 0);
141 EXPECT_EQ(func_ty.results().size(), 0);
142
143 auto export_ty = ty.export_nth(engine, 0);
144 EXPECT_EQ(export_ty->ref().name(), "x");
145 auto export_item_ty = ExternType::from_export(export_ty->ref());
146 auto global_ty = std::get<wasmtime::GlobalType::Ref>(export_item_ty);
147 EXPECT_EQ(global_ty.content().kind(), wasmtime::ValKind::I32);
148 EXPECT_TRUE(global_ty.is_mutable());
149 }
150
result(const char * wat)151 static ValType result(const char *wat) {
152 Engine engine;
153 auto component = Component::compile(engine, wat).unwrap();
154 return *component.type().import_get(engine, "f")->component_func().result();
155 }
156
TEST(types,valtype_primitives)157 TEST(types, valtype_primitives) {
158 EXPECT_TRUE(
159 result("(component (import \"f\" (func (result bool))))").is_bool());
160 EXPECT_TRUE(result("(component (import \"f\" (func (result u8))))").is_u8());
161 EXPECT_TRUE(
162 result("(component (import \"f\" (func (result u16))))").is_u16());
163 EXPECT_TRUE(
164 result("(component (import \"f\" (func (result u32))))").is_u32());
165 EXPECT_TRUE(
166 result("(component (import \"f\" (func (result u64))))").is_u64());
167 EXPECT_TRUE(result("(component (import \"f\" (func (result s8))))").is_s8());
168 EXPECT_TRUE(
169 result("(component (import \"f\" (func (result s16))))").is_s16());
170 EXPECT_TRUE(
171 result("(component (import \"f\" (func (result s32))))").is_s32());
172 EXPECT_TRUE(
173 result("(component (import \"f\" (func (result s64))))").is_s64());
174 EXPECT_TRUE(
175 result("(component (import \"f\" (func (result f32))))").is_f32());
176 EXPECT_TRUE(
177 result("(component (import \"f\" (func (result f64))))").is_f64());
178 EXPECT_TRUE(
179 result("(component (import \"f\" (func (result char))))").is_char());
180 EXPECT_TRUE(
181 result("(component (import \"f\" (func (result string))))").is_string());
182 }
183
TEST(types,valtype_list)184 TEST(types, valtype_list) {
185 auto ty = result("(component (import \"f\" (func (result (list u8)))))");
186 EXPECT_TRUE(ty.is_list());
187 auto elem = ty.list().element();
188 EXPECT_TRUE(elem.is_u8());
189 }
190
TEST(types,valtype_map)191 TEST(types, valtype_map) {
192 Config config;
193 config.wasm_component_model_map(true);
194 Engine engine(std::move(config));
195 auto component =
196 Component::compile(
197 engine, "(component (import \"f\" (func (result (map u32 string)))))")
198 .unwrap();
199 auto ty =
200 *component.type().import_get(engine, "f")->component_func().result();
201 EXPECT_TRUE(ty.is_map());
202 auto map_ty = ty.map();
203 EXPECT_TRUE(map_ty.key().is_u32());
204 EXPECT_TRUE(map_ty.value().is_string());
205 }
206
TEST(types,valtype_record)207 TEST(types, valtype_record) {
208 auto ty = result(R"(
209 (component
210 (type $t' (record (field "a" u8) (field "b" u16)))
211 (import "t" (type $t (eq $t')))
212 (import "f" (func (result $t)))
213 )
214 )");
215 EXPECT_TRUE(ty.is_record());
216 EXPECT_EQ(ty.record().field_count(), 2);
217 auto [name, field_ty] = *ty.record().field_nth(0);
218 EXPECT_EQ(name, "a");
219 EXPECT_TRUE(field_ty.is_u8());
220 auto [name2, field_ty2] = *ty.record().field_nth(1);
221 EXPECT_EQ(name2, "b");
222 EXPECT_TRUE(field_ty2.is_u16());
223 }
224
TEST(types,valtype_tuple)225 TEST(types, valtype_tuple) {
226 auto ty = result("(component (import \"f\" (func (result (tuple u16 u8)))))");
227 EXPECT_TRUE(ty.is_tuple());
228 EXPECT_EQ(ty.tuple().types_count(), 2);
229 EXPECT_TRUE(ty.tuple().types_nth(0)->is_u16());
230 EXPECT_TRUE(ty.tuple().types_nth(1)->is_u8());
231 }
232
TEST(types,valtype_variant)233 TEST(types, valtype_variant) {
234 auto ty = result(R"(
235 (component
236 (type $t' (variant (case "a") (case "b" u16)))
237 (import "t" (type $t (eq $t')))
238 (import "f" (func (result $t)))
239 )
240 )");
241 EXPECT_TRUE(ty.is_variant());
242 EXPECT_EQ(ty.variant().case_count(), 2);
243 auto [name, case_ty] = *ty.variant().case_nth(0);
244 EXPECT_EQ(name, "a");
245 EXPECT_FALSE(case_ty.has_value());
246 auto [name2, case_ty2] = *ty.variant().case_nth(1);
247 EXPECT_EQ(name2, "b");
248 EXPECT_TRUE(case_ty2->is_u16());
249 }
250
TEST(types,valtype_enum)251 TEST(types, valtype_enum) {
252 auto ty = result(R"(
253 (component
254 (type $t' (enum "a" "b" "c"))
255 (import "t" (type $t (eq $t')))
256 (import "f" (func (result $t)))
257 )
258 )");
259 EXPECT_TRUE(ty.is_enum());
260 auto enum_ = ty.enum_();
261 EXPECT_EQ(enum_.names_count(), 3);
262 EXPECT_EQ(enum_.names_nth(0), "a");
263 EXPECT_EQ(enum_.names_nth(1), "b");
264 EXPECT_EQ(enum_.names_nth(2), "c");
265 }
266
TEST(types,valtype_flags)267 TEST(types, valtype_flags) {
268 auto ty = result(R"(
269 (component
270 (type $t' (flags "a" "b" "c"))
271 (import "t" (type $t (eq $t')))
272 (import "f" (func (result $t)))
273 )
274 )");
275 EXPECT_TRUE(ty.is_flags());
276 auto flags = ty.flags();
277 EXPECT_EQ(flags.names_count(), 3);
278 EXPECT_EQ(flags.names_nth(0), "a");
279 EXPECT_EQ(flags.names_nth(1), "b");
280 EXPECT_EQ(flags.names_nth(2), "c");
281 }
282
TEST(types,valtype_option)283 TEST(types, valtype_option) {
284 auto ty = result(R"(
285 (component (import "f" (func (result (option u8)))))
286 )");
287 EXPECT_TRUE(ty.is_option());
288 EXPECT_TRUE(ty.option().ty().is_u8());
289 }
290
TEST(types,valtype_result)291 TEST(types, valtype_result) {
292 auto ty = result(R"(
293 (component (import "f" (func (result (result u8)))))
294 )");
295 EXPECT_TRUE(ty.is_result());
296 EXPECT_TRUE(ty.result().ok()->is_u8());
297 EXPECT_FALSE(ty.result().err().has_value());
298
299 ty = result(R"(
300 (component (import "f" (func (result (result (error u8))))))
301 )");
302 EXPECT_TRUE(ty.is_result());
303 EXPECT_FALSE(ty.result().ok().has_value());
304 EXPECT_TRUE(ty.result().err()->is_u8());
305
306 ty = result(R"(
307 (component (import "f" (func (result (result)))))
308 )");
309 EXPECT_TRUE(ty.is_result());
310 EXPECT_FALSE(ty.result().ok().has_value());
311 EXPECT_FALSE(ty.result().err().has_value());
312 }
313
TEST(types,func_result)314 TEST(types, func_result) {
315 Engine engine;
316 auto wat = R"(
317 (component
318 (core module $m
319 (func (export "f1"))
320 (func (export "f2") (param i32) (result i32) unreachable)
321 )
322 (core instance $i (instantiate $m))
323 (func (export "f1") (canon lift (core func $i "f1")))
324 (func (export "f2") (param "x" u32) (result u32)
325 (canon lift (core func $i "f2")))
326 )
327 )";
328 auto component = Component::compile(engine, wat).unwrap();
329 Store store(engine);
330 auto instance = Linker(engine).instantiate(store, component).unwrap();
331 auto f1_index = *instance.get_export_index(store, nullptr, "f1");
332 auto f2_index = *instance.get_export_index(store, nullptr, "f2");
333 auto f1 = *instance.get_func(store, f1_index);
334 auto f2 = *instance.get_func(store, f2_index);
335
336 EXPECT_FALSE(f1.type(store).async());
337 EXPECT_EQ(f1.type(store).param_count(), 0);
338 EXPECT_FALSE(f1.type(store).result().has_value());
339
340 const auto &ty = f2.type(store);
341 EXPECT_EQ(ty.param_count(), 1);
342 const auto [name, param_ty] = *ty.param_nth(0);
343 EXPECT_EQ(name, "x");
344 EXPECT_TRUE(param_ty.is_u32());
345 auto result = ty.result();
346 ASSERT_TRUE(result.has_value());
347 EXPECT_TRUE(result->is_u32());
348 }
349