1 #include "utils.h"
2 
3 #include <gtest/gtest.h>
4 #include <wasmtime.h>
5 
6 #include <array>
7 #include <format>
8 #include <optional>
9 #include <span>
10 #include <variant>
11 
12 static std::string echo_component(std::string_view type, std::string_view func,
13                                   std::string_view host_params) {
14   return std::format(
15       R"END(
16 (component
17 	(type $Foo' {})
18 	(import "foo" (type $Foo (eq $Foo')))
19 	(import "do" (func $do (param "a" $Foo) (result $Foo)))
20 	(core module $libc
21 		(memory (export "memory") 1)
22 		{}
23 	)
24 	(core instance $libc (instantiate $libc))
25 	(core func $do_lower (canon lower (func $do) (memory $libc "memory") (realloc (func $libc "realloc"))))
26 
27 	(core module $doer
28 		(import "host" "do" (func $do {}))
29 		(import "libc" "memory" (memory 1))
30 		(import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
31 
32 		(func (export "call")
33 			{})
34 	)
35 	(core instance $doer (instantiate $doer
36 		(with "host" (instance (export "do" (func $do_lower))))
37 		(with "libc" (instance $libc))
38 	))
39 
40 	(func $call
41 		(param "a" $Foo)
42 		(result $Foo)
43 		(canon lift
44 			(core func $doer "call")
45 			(memory $libc "memory")
46 			(realloc (func $libc "realloc")))
47 	)
48 
49 	(export "call" (func $call))
50 )
51 		  )END",
52       type, REALLOC_AND_FREE, host_params, func);
53 }
54 
55 struct Context {
56   wasm_engine_t *engine;
57   wasmtime_store_t *store;
58   wasmtime_context_t *context;
59   wasmtime_component_t *component;
60   wasmtime_component_instance_t instance;
61   wasmtime_component_func_t func;
62 };
63 
64 static Context create(std::string_view type, std::string_view body,
65                       std::string_view host_params,
66                       wasmtime_component_func_callback_t callback) {
67   auto component_text = echo_component(type, body, host_params);
68   const auto engine = wasm_engine_new();
69   EXPECT_NE(engine, nullptr);
70 
71   const auto store = wasmtime_store_new(engine, nullptr, nullptr);
72   const auto context = wasmtime_store_context(store);
73 
74   wasmtime_component_t *component = nullptr;
75 
76   auto err = wasmtime_component_new(
77       engine, reinterpret_cast<const uint8_t *>(component_text.data()),
78       component_text.size(), &component);
79 
80   CHECK_ERR(err);
81 
82   auto f = wasmtime_component_get_export_index(component, nullptr, "call",
83                                                strlen("call"));
84 
85   EXPECT_NE(f, nullptr);
86 
87   const auto linker = wasmtime_component_linker_new(engine);
88   const auto root = wasmtime_component_linker_root(linker);
89 
90   wasmtime_component_linker_instance_add_func(root, "do", strlen("do"),
91                                               callback, nullptr, nullptr);
92 
93   wasmtime_component_linker_instance_delete(root);
94 
95   wasmtime_component_instance_t instance = {};
96   err = wasmtime_component_linker_instantiate(linker, context, component,
97                                               &instance);
98   CHECK_ERR(err);
99 
100   wasmtime_component_linker_delete(linker);
101 
102   wasmtime_component_func_t func = {};
103   const auto found =
104       wasmtime_component_instance_get_func(&instance, context, f, &func);
105   EXPECT_TRUE(found);
106   EXPECT_NE(func.store_id, 0);
107 
108   wasmtime_component_export_index_delete(f);
109 
110   return Context{
111       .engine = engine,
112       .store = store,
113       .context = context,
114       .component = component,
115       .instance = instance,
116       .func = func,
117   };
118 }
119 
120 static void destroy(Context &ctx) {
121   wasmtime_component_delete(ctx.component);
122   wasmtime_store_delete(ctx.store);
123   wasm_engine_delete(ctx.engine);
124 }
125 
126 TEST(component, value_record) {
127   static const auto check = [](const wasmtime_component_val_t &val, uint64_t x,
128                                uint64_t y) {
129     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_RECORD);
130 
131     EXPECT_EQ(val.of.record.size, 2);
132     const auto entries = val.of.record.data;
133 
134     EXPECT_EQ((std::string_view{entries[0].name.data, entries[0].name.size}),
135               "x");
136     EXPECT_EQ(entries[0].val.kind, WASMTIME_COMPONENT_U64);
137     EXPECT_EQ(entries[0].val.of.u64, x);
138 
139     EXPECT_EQ((std::string_view{entries[1].name.data, entries[1].name.size}),
140               "y");
141     EXPECT_EQ(entries[1].val.kind, WASMTIME_COMPONENT_U64);
142     EXPECT_EQ(entries[1].val.of.u64, y);
143   };
144 
145   static const auto make = [](uint64_t x,
146                               uint64_t y) -> wasmtime_component_val_t {
147     auto ret = wasmtime_component_val_t{
148         .kind = WASMTIME_COMPONENT_RECORD,
149     };
150 
151     wasmtime_component_valrecord_new_uninit(&ret.of.record, 2);
152 
153     const auto entries = ret.of.record.data;
154     wasm_name_new_from_string(&entries[0].name, "x");
155     entries[0].val.kind = WASMTIME_COMPONENT_U64;
156     entries[0].val.of.u64 = x;
157     wasm_name_new_from_string(&entries[1].name, "y");
158     entries[1].val.kind = WASMTIME_COMPONENT_U64;
159     entries[1].val.of.u64 = y;
160 
161     return ret;
162   };
163 
164   auto ctx = create(
165       R"((record (field "x" u64) (field "y" u64)))", R"(
166 (param $x i64)
167 (param $y i64)
168 (result i32)
169 (local $res i32)
170 local.get $x
171 local.get $y
172 (call $realloc
173 	(i32.const 0)
174 	(i32.const 0)
175 	(i32.const 4)
176 	(i32.const 16))
177 local.tee $res
178 call $do
179 local.get $res
180 	  )",
181       "(param i64 i64 i32)",
182       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
183           size_t args_len, wasmtime_component_val_t *rets,
184           size_t rets_len) -> wasmtime_error_t * {
185         EXPECT_EQ(args_len, 1);
186         check(args[0], 1, 2);
187 
188         EXPECT_EQ(rets_len, 1);
189         rets[0] = make(3, 4);
190 
191         return nullptr;
192       });
193 
194   auto arg = make(1, 2);
195   auto res = wasmtime_component_val_t{};
196 
197   auto err =
198       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
199   CHECK_ERR(err);
200 
201   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
202   CHECK_ERR(err);
203 
204   check(res, 3, 4);
205 
206   wasmtime_component_val_delete(&arg);
207   wasmtime_component_val_delete(&res);
208 
209   destroy(ctx);
210 }
211 
212 TEST(component, value_string) {
213   static const auto check = [](const wasmtime_component_val_t &val,
214                                std::string_view text) {
215     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_STRING);
216     EXPECT_EQ((std::string_view{val.of.string.data, val.of.string.size}), text);
217   };
218 
219   static const auto make =
220       [](std::string_view text) -> wasmtime_component_val_t {
221     auto str = wasm_name_t{};
222     wasm_name_new_from_string(&str, text.data());
223 
224     return wasmtime_component_val_t{
225         .kind = WASMTIME_COMPONENT_STRING,
226         .of = {.string = str},
227     };
228   };
229 
230   auto ctx = create(
231       R"(string)", R"(
232 (param $x i32)
233 (param $y i32)
234 (result i32)
235 (local $res i32)
236 local.get $x
237 local.get $y
238 (call $realloc
239 	(i32.const 0)
240 	(i32.const 0)
241 	(i32.const 4)
242 	(i32.const 8))
243 local.tee $res
244 call $do
245 local.get $res
246 	  )",
247       "(param i32 i32 i32)",
248       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
249           size_t args_len, wasmtime_component_val_t *rets,
250           size_t rets_len) -> wasmtime_error_t * {
251         EXPECT_EQ(args_len, 1);
252         check(args[0], "hello from A!");
253 
254         EXPECT_EQ(rets_len, 1);
255         rets[0] = make("hello from B!");
256 
257         return nullptr;
258       });
259 
260   auto arg = make("hello from A!");
261   auto res = wasmtime_component_val_t{};
262 
263   auto err =
264       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
265   CHECK_ERR(err);
266 
267   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
268   CHECK_ERR(err);
269 
270   check(res, "hello from B!");
271 
272   wasmtime_component_val_delete(&arg);
273   wasmtime_component_val_delete(&res);
274 
275   destroy(ctx);
276 }
277 
278 TEST(component, value_list) {
279   static const auto check = [](const wasmtime_component_val_t &val,
280                                std::vector<uint32_t> data) {
281     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_LIST);
282     auto vals = std::span{val.of.list.data, val.of.list.size};
283     EXPECT_EQ(vals.size(), data.size());
284     for (auto i = 0; i < data.size(); i++) {
285       EXPECT_EQ(vals[i].kind, WASMTIME_COMPONENT_U32);
286       EXPECT_EQ(vals[i].of.u32, data[i]);
287     }
288   };
289 
290   static const auto make =
291       [](std::vector<uint32_t> data) -> wasmtime_component_val_t {
292     auto ret = wasmtime_component_val_t{
293         .kind = WASMTIME_COMPONENT_LIST,
294     };
295 
296     wasmtime_component_vallist_new_uninit(&ret.of.list, data.size());
297 
298     for (auto i = 0; i < data.size(); i++) {
299       ret.of.list.data[i] = wasmtime_component_val_t{
300           .kind = WASMTIME_COMPONENT_U32,
301           .of = {.u32 = data[i]},
302       };
303     }
304 
305     return ret;
306   };
307 
308   auto ctx = create(
309       R"((list u32))", R"(
310 (param $x i32)
311 (param $y i32)
312 (result i32)
313 (local $res i32)
314 local.get $x
315 local.get $y
316 (call $realloc
317 	(i32.const 0)
318 	(i32.const 0)
319 	(i32.const 4)
320 	(i32.const 8))
321 local.tee $res
322 call $do
323 local.get $res
324 	  )",
325       "(param i32 i32 i32)",
326       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
327           size_t args_len, wasmtime_component_val_t *rets,
328           size_t rets_len) -> wasmtime_error_t * {
329         EXPECT_EQ(args_len, 1);
330         check(args[0], {1, 2, 3});
331 
332         EXPECT_EQ(rets_len, 1);
333         rets[0] = make({4, 5, 6, 7});
334 
335         return nullptr;
336       });
337 
338   auto arg = make({1, 2, 3});
339   auto res = wasmtime_component_val_t{};
340 
341   auto err =
342       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
343   CHECK_ERR(err);
344 
345   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
346   CHECK_ERR(err);
347 
348   check(res, {4, 5, 6, 7});
349 
350   wasmtime_component_val_delete(&arg);
351   wasmtime_component_val_delete(&res);
352 
353   destroy(ctx);
354 }
355 
356 TEST(component, value_tuple) {
357   static const auto check = [](const wasmtime_component_val_t &val,
358                                std::vector<uint32_t> data) {
359     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_TUPLE);
360     auto vals = std::span{val.of.tuple.data, val.of.tuple.size};
361     EXPECT_EQ(vals.size(), data.size());
362     for (auto i = 0; i < data.size(); i++) {
363       EXPECT_EQ(vals[i].kind, WASMTIME_COMPONENT_U32);
364       EXPECT_EQ(vals[i].of.u32, data[i]);
365     }
366   };
367 
368   static const auto make =
369       [](std::vector<uint32_t> data) -> wasmtime_component_val_t {
370     auto ret = wasmtime_component_val_t{
371         .kind = WASMTIME_COMPONENT_TUPLE,
372     };
373 
374     wasmtime_component_valtuple_new_uninit(&ret.of.tuple, data.size());
375 
376     for (auto i = 0; i < data.size(); i++) {
377       ret.of.list.data[i] = wasmtime_component_val_t{
378           .kind = WASMTIME_COMPONENT_U32,
379           .of = {.u32 = data[i]},
380       };
381     }
382 
383     return ret;
384   };
385 
386   auto ctx = create(
387       R"((tuple u32 u32 u32))", R"(
388 (param $x i32)
389 (param $y i32)
390 (param $z i32)
391 (result i32)
392 (local $res i32)
393 local.get $x
394 local.get $y
395 local.get $z
396 (call $realloc
397 	(i32.const 0)
398 	(i32.const 0)
399 	(i32.const 4)
400 	(i32.const 12))
401 local.tee $res
402 call $do
403 local.get $res
404 	  )",
405       "(param i32 i32 i32 i32)",
406       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
407           size_t args_len, wasmtime_component_val_t *rets,
408           size_t rets_len) -> wasmtime_error_t * {
409         EXPECT_EQ(args_len, 1);
410         check(args[0], {1, 2, 3});
411 
412         EXPECT_EQ(rets_len, 1);
413         rets[0] = make({4, 5, 6});
414 
415         return nullptr;
416       });
417 
418   auto arg = make({1, 2, 3});
419   auto res = wasmtime_component_val_t{};
420 
421   auto err =
422       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
423   CHECK_ERR(err);
424 
425   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
426   CHECK_ERR(err);
427 
428   check(res, {4, 5, 6});
429 
430   wasmtime_component_val_delete(&arg);
431   wasmtime_component_val_delete(&res);
432 
433   destroy(ctx);
434 }
435 
436 TEST(component, value_variant) {
437   static const auto check_aa = [](const wasmtime_component_val_t &val,
438                                   uint32_t value) {
439     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_VARIANT);
440     EXPECT_EQ((std::string_view{val.of.variant.discriminant.data,
441                                 val.of.variant.discriminant.size}),
442               "aa");
443 
444     EXPECT_NE(val.of.variant.val, nullptr);
445 
446     EXPECT_EQ(val.of.variant.val->kind, WASMTIME_COMPONENT_U32);
447     EXPECT_EQ(val.of.variant.val->of.u32, value);
448   };
449 
450   static const auto check_bb = [](const wasmtime_component_val_t &val,
451                                   std::string_view value) {
452     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_VARIANT);
453     EXPECT_EQ((std::string_view{val.of.variant.discriminant.data,
454                                 val.of.variant.discriminant.size}),
455               "bb");
456 
457     EXPECT_NE(val.of.variant.val, nullptr);
458 
459     EXPECT_EQ(val.of.variant.val->kind, WASMTIME_COMPONENT_STRING);
460     EXPECT_EQ((std::string_view{val.of.variant.val->of.string.data,
461                                 val.of.variant.val->of.string.size}),
462               value);
463   };
464 
465   static const auto make_aa = [](uint32_t value) -> wasmtime_component_val_t {
466     auto ret = wasmtime_component_val_t{
467         .kind = WASMTIME_COMPONENT_VARIANT,
468     };
469 
470     wasm_name_new_from_string(&ret.of.variant.discriminant, "aa");
471 
472     ret.of.variant.val = wasmtime_component_val_new();
473     ret.of.variant.val->kind = WASMTIME_COMPONENT_U32;
474     ret.of.variant.val->of.u32 = value;
475 
476     return ret;
477   };
478 
479   static const auto make_bb =
480       [](std::string_view value) -> wasmtime_component_val_t {
481     auto ret = wasmtime_component_val_t{
482         .kind = WASMTIME_COMPONENT_VARIANT,
483     };
484 
485     wasm_name_new_from_string(&ret.of.variant.discriminant, "bb");
486 
487     ret.of.variant.val = wasmtime_component_val_new();
488     ret.of.variant.val->kind = WASMTIME_COMPONENT_STRING;
489     wasm_name_new(&ret.of.variant.val->of.string, value.size(), value.data());
490 
491     return ret;
492   };
493 
494   auto ctx = create(
495       R"(
496 (variant
497 	(case "aa" u32)
498 	(case "bb" string)
499 )
500 	  )",
501       R"(
502 (param $x i32)
503 (param $y i32)
504 (param $z i32)
505 (result i32)
506 (local $res i32)
507 local.get $x
508 local.get $y
509 local.get $z
510 (call $realloc
511 	(i32.const 0)
512 	(i32.const 0)
513 	(i32.const 4)
514 	(i32.const 12))
515 local.tee $res
516 call $do
517 local.get $res
518 	  )",
519       "(param i32 i32 i32 i32)",
520       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
521           size_t args_len, wasmtime_component_val_t *rets,
522           size_t rets_len) -> wasmtime_error_t * {
523         EXPECT_EQ(args_len, 1);
524         check_aa(args[0], 123);
525 
526         EXPECT_EQ(rets_len, 1);
527         rets[0] = make_bb("textt");
528 
529         return nullptr;
530       });
531 
532   auto arg = make_aa(123);
533   auto res = wasmtime_component_val_t{};
534 
535   auto err =
536       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
537   CHECK_ERR(err);
538 
539   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
540   CHECK_ERR(err);
541 
542   check_bb(res, "textt");
543 
544   wasmtime_component_val_delete(&arg);
545   wasmtime_component_val_delete(&res);
546 
547   destroy(ctx);
548 }
549 
550 TEST(component, value_enum) {
551   static const auto check = [](const wasmtime_component_val_t &val,
552                                std::string_view text) {
553     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_ENUM);
554     EXPECT_EQ(
555         (std::string_view{val.of.enumeration.data, val.of.enumeration.size}),
556         text);
557   };
558 
559   static const auto make =
560       [](std::string_view text) -> wasmtime_component_val_t {
561     auto ret = wasmtime_component_val_t{
562         .kind = WASMTIME_COMPONENT_ENUM,
563     };
564 
565     wasm_name_new(&ret.of.enumeration, text.size(), text.data());
566 
567     return ret;
568   };
569 
570   auto ctx = create(
571       R"((enum "aa" "bb"))", R"(
572 (param $x i32)
573 (result i32)
574 local.get $x
575 call $do
576 	  )",
577       "(param i32) (result i32)",
578       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
579           size_t args_len, wasmtime_component_val_t *rets,
580           size_t rets_len) -> wasmtime_error_t * {
581         EXPECT_EQ(args_len, 1);
582         check(args[0], "aa");
583 
584         EXPECT_EQ(rets_len, 1);
585         rets[0] = make("bb");
586 
587         return nullptr;
588       });
589 
590   auto arg = make("aa");
591   auto res = wasmtime_component_val_t{};
592 
593   auto err =
594       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
595   CHECK_ERR(err);
596 
597   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
598   CHECK_ERR(err);
599 
600   check(res, "bb");
601 
602   wasmtime_component_val_delete(&arg);
603   wasmtime_component_val_delete(&res);
604 
605   destroy(ctx);
606 }
607 
608 TEST(component, value_option) {
609   static const auto check = [](const wasmtime_component_val_t &val,
610                                std::optional<uint32_t> value) {
611     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_OPTION);
612 
613     if (value.has_value()) {
614       EXPECT_NE(val.of.option, nullptr);
615       EXPECT_EQ(val.of.option->kind, WASMTIME_COMPONENT_U32);
616       EXPECT_EQ(val.of.option->of.u32, *value);
617     } else {
618       EXPECT_EQ(val.of.option, nullptr);
619     }
620   };
621 
622   static const auto make =
623       [](std::optional<uint32_t> value) -> wasmtime_component_val_t {
624     auto ret = wasmtime_component_val_t{
625         .kind = WASMTIME_COMPONENT_OPTION,
626         .of = {.option = nullptr},
627     };
628 
629     if (value.has_value()) {
630       ret.of.option = wasmtime_component_val_new();
631       *ret.of.option = wasmtime_component_val_t{
632           .kind = WASMTIME_COMPONENT_U32,
633           .of = {.u32 = *value},
634       };
635     }
636 
637     return ret;
638   };
639 
640   auto ctx = create(
641       R"((option u32))", R"(
642 (param $x i32)
643 (param $y i32)
644 (result i32)
645 (local $res i32)
646 local.get $x
647 local.get $y
648 (call $realloc
649 	(i32.const 0)
650 	(i32.const 0)
651 	(i32.const 4)
652 	(i32.const 8))
653 local.tee $res
654 call $do
655 local.get $res
656 	  )",
657       "(param i32 i32 i32)",
658       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
659           size_t args_len, wasmtime_component_val_t *rets,
660           size_t rets_len) -> wasmtime_error_t * {
661         EXPECT_EQ(args_len, 1);
662         check(args[0], 123);
663 
664         EXPECT_EQ(rets_len, 1);
665         rets[0] = make({});
666 
667         return nullptr;
668       });
669 
670   auto arg = make(123);
671   auto res = wasmtime_component_val_t{};
672 
673   auto err =
674       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
675   CHECK_ERR(err);
676 
677   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
678   CHECK_ERR(err);
679 
680   check(res, {});
681 
682   wasmtime_component_val_delete(&arg);
683   wasmtime_component_val_delete(&res);
684 
685   destroy(ctx);
686 }
687 
688 TEST(component, value_result) {
689   static const auto check = [](const wasmtime_component_val_t &val,
690                                bool expected_is_ok, uint32_t expected_value) {
691     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_RESULT);
692 
693     EXPECT_EQ(val.of.result.is_ok, expected_is_ok);
694     EXPECT_NE(val.of.result.val, nullptr);
695 
696     EXPECT_EQ(val.of.result.val->kind, WASMTIME_COMPONENT_U32);
697     EXPECT_EQ(val.of.result.val->of.u32, expected_value);
698   };
699 
700   static const auto make = [](bool is_ok,
701                               uint32_t value) -> wasmtime_component_val_t {
702     auto ret = wasmtime_component_val_t{
703         .kind = WASMTIME_COMPONENT_RESULT,
704     };
705 
706     const auto inner = wasmtime_component_val_new();
707     inner->kind = WASMTIME_COMPONENT_U32;
708     inner->of.u32 = value;
709 
710     ret.of.result = {
711         .is_ok = is_ok,
712         .val = inner,
713     };
714 
715     return ret;
716   };
717 
718   auto ctx = create(
719       R"((result u32 (error u32)))", R"(
720 (param $x i32)
721 (param $y i32)
722 (result i32)
723 (local $res i32)
724 local.get $x
725 local.get $y
726 (call $realloc
727 	(i32.const 0)
728 	(i32.const 0)
729 	(i32.const 4)
730 	(i32.const 8))
731 local.tee $res
732 call $do
733 local.get $res
734 	  )",
735       "(param i32 i32 i32)",
736       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
737           size_t args_len, wasmtime_component_val_t *rets,
738           size_t rets_len) -> wasmtime_error_t * {
739         EXPECT_EQ(args_len, 1);
740         check(args[0], true, 123);
741 
742         EXPECT_EQ(rets_len, 1);
743         rets[0] = make(false, 456);
744 
745         return nullptr;
746       });
747 
748   auto arg = make(true, 123);
749   auto res = wasmtime_component_val_t{};
750 
751   auto err =
752       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
753   CHECK_ERR(err);
754 
755   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
756   CHECK_ERR(err);
757 
758   check(res, false, 456);
759 
760   wasmtime_component_val_delete(&arg);
761   wasmtime_component_val_delete(&res);
762 
763   destroy(ctx);
764 }
765 
766 TEST(component, value_flags) {
767   static const auto check = [](const wasmtime_component_val_t &val,
768                                std::vector<std::string> data) {
769     EXPECT_EQ(val.kind, WASMTIME_COMPONENT_FLAGS);
770     auto flags = std::span{val.of.flags.data, val.of.flags.size};
771     EXPECT_EQ(flags.size(), data.size());
772     for (auto i = 0; i < data.size(); i++) {
773       EXPECT_EQ((std::string_view{flags[i].data, flags[i].size}), data[i]);
774     }
775   };
776 
777   static const auto make =
778       [](std::vector<std::string> data) -> wasmtime_component_val_t {
779     auto ret = wasmtime_component_val_t{
780         .kind = WASMTIME_COMPONENT_FLAGS,
781     };
782 
783     wasmtime_component_valflags_new_uninit(&ret.of.flags, data.size());
784 
785     for (auto i = 0; i < data.size(); i++) {
786       wasm_name_new(&ret.of.flags.data[i], data[i].size(), data[i].data());
787     }
788 
789     return ret;
790   };
791 
792   auto ctx = create(
793       R"((flags "aa" "bb"))", R"(
794 (param $x i32)
795 (result i32)
796 local.get $x
797 call $do
798 	  )",
799       "(param i32) (result i32)",
800       +[](void *, wasmtime_context_t *, const wasmtime_component_val_t *args,
801           size_t args_len, wasmtime_component_val_t *rets,
802           size_t rets_len) -> wasmtime_error_t * {
803         EXPECT_EQ(args_len, 1);
804         check(args[0], {"aa"});
805 
806         EXPECT_EQ(rets_len, 1);
807         rets[0] = make({"aa", "bb"});
808 
809         return nullptr;
810       });
811 
812   auto arg = make({"aa"});
813   auto res = wasmtime_component_val_t{};
814 
815   auto err =
816       wasmtime_component_func_call(&ctx.func, ctx.context, &arg, 1, &res, 1);
817   CHECK_ERR(err);
818 
819   err = wasmtime_component_func_post_return(&ctx.func, ctx.context);
820   CHECK_ERR(err);
821 
822   check(res, {"aa", "bb"});
823 
824   wasmtime_component_val_delete(&arg);
825   wasmtime_component_val_delete(&res);
826 
827   destroy(ctx);
828 }
829 
830 TEST(component, value_list_inner) {
831   {
832     auto x = wasmtime_component_val_t{
833         .kind = WASMTIME_COMPONENT_LIST,
834     };
835     wasmtime_component_vallist_new_empty(&x.of.list);
836     EXPECT_EQ(x.of.list.data, nullptr);
837     EXPECT_EQ(x.of.list.size, 0);
838 
839     wasmtime_component_vallist_new_uninit(&x.of.list, 1);
840     EXPECT_NE(x.of.list.data, nullptr);
841     EXPECT_EQ(x.of.list.size, 1);
842 
843     wasmtime_component_vallist_delete(&x.of.list);
844 
845     auto items = std::array{
846         wasmtime_component_val_t{
847             .kind = WASMTIME_COMPONENT_U32,
848             .of = {.u32 = 123},
849         },
850     };
851 
852     wasmtime_component_vallist_new(&x.of.list, items.size(), items.data());
853     EXPECT_NE(x.of.list.data, nullptr);
854     EXPECT_EQ(x.of.list.size, 1);
855 
856     EXPECT_EQ(x.of.list.data[0].kind, WASMTIME_COMPONENT_U32);
857     EXPECT_EQ(x.of.list.data[0].of.u32, 123);
858 
859     auto clone = wasmtime_component_val_t{
860         .kind = WASMTIME_COMPONENT_LIST,
861     };
862 
863     wasmtime_component_vallist_copy(&clone.of.list, &x.of.list);
864     wasmtime_component_vallist_delete(&x.of.list);
865 
866     EXPECT_NE(clone.of.list.data, nullptr);
867     EXPECT_EQ(clone.of.list.size, 1);
868 
869     EXPECT_EQ(clone.of.list.data[0].kind, WASMTIME_COMPONENT_U32);
870     EXPECT_EQ(clone.of.list.data[0].of.u32, 123);
871 
872     wasmtime_component_vallist_delete(&clone.of.list);
873   }
874 }
875