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