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