From 48e3a0bcdd72e3ddfd1f67c85a23eb4bf5c24dac Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 2 Oct 2026 18:01:58 -0400 Subject: [PATCH 1/5] Drive-by function rename I spent some time confused by the fact that obviously non-wasip1 modules were being fed through a function explicitly named for wasip1. --- crates/test/src/c.rs | 2 +- crates/test/src/d.rs | 2 +- crates/test/src/go.rs | 2 +- crates/test/src/lib.rs | 12 +++++++----- crates/test/src/rust.rs | 2 +- crates/test/src/wat.rs | 2 +- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/crates/test/src/c.rs b/crates/test/src/c.rs index 944f833be..647a34064 100644 --- a/crates/test/src/c.rs +++ b/crates/test/src/c.rs @@ -158,7 +158,7 @@ fn compile(runner: &Runner, compile: &Compile<'_>, compiler: PathBuf) -> Result< runner.run_command(&mut cmd)?; runner - .convert_p1_to_component(&output, compile) + .convert_core_module_to_component(&output, compile) .with_context(|| format!("failed to convert {output:?}"))?; Ok(()) } diff --git a/crates/test/src/d.rs b/crates/test/src/d.rs index f11692146..98c791df4 100644 --- a/crates/test/src/d.rs +++ b/crates/test/src/d.rs @@ -145,7 +145,7 @@ fn compile(runner: &Runner, compile: &Compile<'_>, compiler: PathBuf) -> Result< runner.run_command(&mut cmd)?; runner - .convert_p1_to_component(&output, compile) + .convert_core_module_to_component(&output, compile) .with_context(|| format!("failed to convert {output:?}"))?; Ok(()) diff --git a/crates/test/src/go.rs b/crates/test/src/go.rs index 7eb1240c0..535b6918c 100644 --- a/crates/test/src/go.rs +++ b/crates/test/src/go.rs @@ -189,7 +189,7 @@ func main() {} .arg("-ldflags=-checklinkname=0"), )?; - runner.convert_p1_to_component(&output, compile)?; + runner.convert_core_module_to_component(&output, compile)?; Ok(()) } diff --git a/crates/test/src/lib.rs b/crates/test/src/lib.rs index 858631bb7..cc334b80c 100644 --- a/crates/test/src/lib.rs +++ b/crates/test/src/lib.rs @@ -1090,7 +1090,7 @@ status: {}", /// Converts the list of dynamic libraries in `dylibs` into a component and places it /// in the destination specified by `compile`. /// - /// This is similar to `convert_p1_to_component` except usese a + /// This is similar to `convert_core_module_to_component` except uses a /// `wit_component::Linker` instead of a `wit_component::ComponentEncoder`. fn link_dylibs_to_component(&self, dylibs: &[PathBuf], compile: &Compile<'_>) -> Result<()> { let mut linker = wit_component::Linker::default(); @@ -1110,17 +1110,19 @@ status: {}", Ok(()) } - /// Converts the WASIp1 module at `p1` to a component using the information - /// stored within `compile`. + /// Converts the core module at `path` (wasip1 or otherwise) to a component + /// using the information stored within `compile`. Can handle both wasip1 + /// modules and modules built with components in mind (e.g. those built + /// with --skip-wit-component in wasm-component-ld). /// /// Stores the output at `compile.output`. - fn convert_p1_to_component(&self, p1: &Path, compile: &Compile<'_>) -> Result<()> { + fn convert_core_module_to_component(&self, path: &Path, compile: &Compile<'_>) -> Result<()> { let mut resolve = wit_parser::Resolve::default(); let (pkg, _) = resolve .push_path(&compile.component.bindgen.wit_path) .context("failed to load WIT")?; let world = resolve.select_world(&[pkg], Some(&compile.component.bindgen.world))?; - let mut module = fs::read(&p1).context("failed to read wasm file")?; + let mut module = fs::read(&path).context("failed to read wasm file")?; if !has_component_type_sections(&module) { let encoded = wit_component::metadata::encode( diff --git a/crates/test/src/rust.rs b/crates/test/src/rust.rs index e2b3ddf74..5827de997 100644 --- a/crates/test/src/rust.rs +++ b/crates/test/src/rust.rs @@ -321,7 +321,7 @@ path = 'lib.rs' .with_context(|| format!("failed to link {output:?}"))?; } else { runner - .convert_p1_to_component(&output, compile) + .convert_core_module_to_component(&output, compile) .with_context(|| format!("failed to convert {output:?}"))?; } diff --git a/crates/test/src/wat.rs b/crates/test/src/wat.rs index 8278ade8e..ffdacf708 100644 --- a/crates/test/src/wat.rs +++ b/crates/test/src/wat.rs @@ -39,7 +39,7 @@ impl LanguageMethods for Wat { let p1 = compile.output.with_extension("core.wasm"); super::write_if_different(&p1, wasm)?; - runner.convert_p1_to_component(&p1, compile)?; + runner.convert_core_module_to_component(&p1, compile)?; Ok(()) } From 7f6889e3a75150340a4d1b7385eb5605b17252ba Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 2 Oct 2026 18:06:50 -0400 Subject: [PATCH 2/5] Use the dev version of wasmtime in CI --- .github/actions/install-wasi-sdk/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/install-wasi-sdk/action.yml b/.github/actions/install-wasi-sdk/action.yml index bca070a87..3a6227b73 100644 --- a/.github/actions/install-wasi-sdk/action.yml +++ b/.github/actions/install-wasi-sdk/action.yml @@ -38,4 +38,4 @@ runs: - name: Setup `wasmtime` uses: bytecodealliance/actions/wasmtime/setup@v1 with: - version: "48.0.1" + version: "dev" From f4817e874105ba4cd7c7fb5af386a8a815feb260 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 2 Oct 2026 18:50:41 -0400 Subject: [PATCH 3/5] Rust accessor tests --- tests/runtime/accessors/runner.rs | 55 ++++++++++++++++++ tests/runtime/accessors/test.rs | 92 +++++++++++++++++++++++++++++++ tests/runtime/accessors/test.wit | 35 ++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 tests/runtime/accessors/runner.rs create mode 100644 tests/runtime/accessors/test.rs create mode 100644 tests/runtime/accessors/test.wit diff --git a/tests/runtime/accessors/runner.rs b/tests/runtime/accessors/runner.rs new file mode 100644 index 000000000..76466adda --- /dev/null +++ b/tests/runtime/accessors/runner.rs @@ -0,0 +1,55 @@ +//@ wasmtime-flags = '-Wcomponent-model-accessors' + +include!(env!("BINDINGS")); + +use crate::test::accessors::i::*; + +struct Component; + +export!(Component); + +impl Guest for Component { + fn run() { + assert_eq!(counter(), 0); + set_counter(5); + assert_eq!(counter(), 5); + set_counter(u32::MAX); + assert_eq!(counter(), u32::MAX); + + assert_eq!(read_only(), "read only"); + + assert_eq!(bounded(), 0); + assert_eq!(set_bounded(10), Ok(())); + assert_eq!(bounded(), 10); + assert_eq!(set_bounded(101), Err("101 is out of bounds".to_string())); + assert_eq!(bounded(), 10); + + let a = Blob::new(&[1, 2, 3]); + let b = Blob::new(&[4, 5]); + assert_eq!(a.contents(), [1, 2, 3]); + assert_eq!(a.position(), 0); + assert_eq!(b.position(), 0); + a.set_position(2); + assert_eq!(a.position(), 2); + assert_eq!(b.position(), 0); + b.set_position(1); + assert_eq!(a.position(), 2); + assert_eq!(b.position(), 1); + + assert_eq!(a.label(), ""); + assert_eq!(a.set_label("hello"), Ok(())); + assert_eq!(a.label(), "hello"); + assert_eq!(b.label(), ""); + assert_eq!(a.set_label(""), Err("label must not be empty".to_string())); + assert_eq!(a.label(), "hello"); + + assert_eq!(Blob::max_size(), 1024); + assert_eq!(Blob::set_max_size(2048), Ok(())); + assert_eq!(Blob::max_size(), 2048); + assert_eq!( + Blob::set_max_size(0), + Err("max size must be nonzero".to_string()) + ); + assert_eq!(Blob::max_size(), 2048); + } +} diff --git a/tests/runtime/accessors/test.rs b/tests/runtime/accessors/test.rs new file mode 100644 index 000000000..045a2c928 --- /dev/null +++ b/tests/runtime/accessors/test.rs @@ -0,0 +1,92 @@ +include!(env!("BINDINGS")); + +use crate::exports::test::accessors::i::{Guest, GuestBlob}; +use std::cell::{Cell, RefCell}; + +struct Component; + +export!(Component); + +static mut COUNTER: u32 = 0; +static mut BOUNDED: u32 = 0; +static mut MAX_SIZE: u64 = 1024; + +impl Guest for Component { + type Blob = MyBlob; + + fn counter() -> u32 { + unsafe { COUNTER } + } + + fn set_counter(value: u32) { + unsafe { COUNTER = value } + } + + fn read_only() -> String { + "read only".to_string() + } + + fn bounded() -> u32 { + unsafe { BOUNDED } + } + + fn set_bounded(value: u32) -> Result<(), String> { + if value > 100 { + return Err(format!("{value} is out of bounds")); + } + unsafe { BOUNDED = value } + Ok(()) + } +} + +struct MyBlob { + contents: Vec, + position: Cell, + label: RefCell, +} + +impl GuestBlob for MyBlob { + fn new(init: Vec) -> MyBlob { + MyBlob { + contents: init, + position: Cell::new(0), + label: RefCell::new(String::new()), + } + } + + fn contents(&self) -> Vec { + self.contents.clone() + } + + fn position(&self) -> u64 { + self.position.get() + } + + fn set_position(&self, value: u64) { + self.position.set(value); + } + + fn label(&self) -> String { + self.label.borrow().clone() + } + + fn set_label(&self, value: String) -> Result<(), String> { + if value.is_empty() { + return Err("label must not be empty".to_string()); + } + *self.label.borrow_mut() = value; + Ok(()) + } + + fn max_size() -> u64 { + unsafe { MAX_SIZE } + } + + fn set_max_size(value: u64) -> Result<(), String> { + if value == 0 { + return Err("max size must be nonzero".to_string()); + } + unsafe { MAX_SIZE = value } + Ok(()) + } +} diff --git a/tests/runtime/accessors/test.wit b/tests/runtime/accessors/test.wit new file mode 100644 index 000000000..7808ef65b --- /dev/null +++ b/tests/runtime/accessors/test.wit @@ -0,0 +1,35 @@ +package test:accessors; + +interface i { + counter: get() -> u32; + counter: set(value: u32); + + read-only: get() -> string; + + bounded: get() -> u32; + bounded: set(value: u32) -> result<_, string>; + + resource blob { + constructor(init: list); + contents: func() -> list; + + position: get() -> u64; + position: set(value: u64); + + label: get() -> string; + label: set(value: string) -> result<_, string>; + + max-size: static get() -> u64; + max-size: static set(value: u64) -> result<_, string>; + } +} + +world runner { + import i; + + export run: func(); +} + +world test { + export i; +} From 615a15c357ac72564afaa49e68a850052dd2d168 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 2 Oct 2026 18:50:41 -0400 Subject: [PATCH 4/5] C accessor tests --- tests/runtime/accessors/runner.c | 91 +++++++++++++++++++++++++++++ tests/runtime/accessors/test.c | 98 ++++++++++++++++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 tests/runtime/accessors/runner.c create mode 100644 tests/runtime/accessors/test.c diff --git a/tests/runtime/accessors/runner.c b/tests/runtime/accessors/runner.c new file mode 100644 index 000000000..18033c577 --- /dev/null +++ b/tests/runtime/accessors/runner.c @@ -0,0 +1,91 @@ +//@ wasmtime-flags = '-Wcomponent-model-accessors' + +#include +#include +#include + +static void assert_str(runner_string_t *str, const char *expected) { + size_t expected_len = strlen(expected); + assert(str->len == expected_len); + assert(memcmp(str->ptr, expected, expected_len) == 0); +} + +void exports_runner_run(void) { + runner_string_t str; + runner_string_t err; + + assert(test_accessors_i_get_counter() == 0); + test_accessors_i_set_counter(5); + assert(test_accessors_i_get_counter() == 5); + test_accessors_i_set_counter(UINT32_MAX); + assert(test_accessors_i_get_counter() == UINT32_MAX); + + test_accessors_i_get_read_only(&str); + assert_str(&str, "read only"); + runner_string_free(&str); + + assert(test_accessors_i_get_bounded() == 0); + assert(test_accessors_i_set_bounded(10, &err)); + assert(test_accessors_i_get_bounded() == 10); + assert(!test_accessors_i_set_bounded(101, &err)); + assert_str(&err, "101 is out of bounds"); + runner_string_free(&err); + assert(test_accessors_i_get_bounded() == 10); + + uint8_t a_init[] = {1, 2, 3}; + uint8_t b_init[] = {4, 5}; + runner_list_u8_t a_list = {a_init, 3}; + runner_list_u8_t b_list = {b_init, 2}; + test_accessors_i_own_blob_t a_own = test_accessors_i_constructor_blob(&a_list); + test_accessors_i_own_blob_t b_own = test_accessors_i_constructor_blob(&b_list); + test_accessors_i_borrow_blob_t a = test_accessors_i_borrow_blob(a_own); + test_accessors_i_borrow_blob_t b = test_accessors_i_borrow_blob(b_own); + + runner_list_u8_t contents; + test_accessors_i_method_blob_contents(a, &contents); + assert(contents.len == 3); + assert(memcmp(contents.ptr, a_init, 3) == 0); + runner_list_u8_free(&contents); + + assert(test_accessors_i_method_get_blob_position(a) == 0); + assert(test_accessors_i_method_get_blob_position(b) == 0); + test_accessors_i_method_set_blob_position(a, 2); + assert(test_accessors_i_method_get_blob_position(a) == 2); + assert(test_accessors_i_method_get_blob_position(b) == 0); + test_accessors_i_method_set_blob_position(b, 1); + assert(test_accessors_i_method_get_blob_position(a) == 2); + assert(test_accessors_i_method_get_blob_position(b) == 1); + + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, ""); + runner_string_free(&str); + + runner_string_t label; + runner_string_set(&label, "hello"); + assert(test_accessors_i_method_set_blob_label(a, &label, &err)); + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, "hello"); + runner_string_free(&str); + test_accessors_i_method_get_blob_label(b, &str); + assert_str(&str, ""); + runner_string_free(&str); + + runner_string_set(&label, ""); + assert(!test_accessors_i_method_set_blob_label(a, &label, &err)); + assert_str(&err, "label must not be empty"); + runner_string_free(&err); + test_accessors_i_method_get_blob_label(a, &str); + assert_str(&str, "hello"); + runner_string_free(&str); + + assert(test_accessors_i_static_get_blob_max_size() == 1024); + assert(test_accessors_i_static_set_blob_max_size(2048, &err)); + assert(test_accessors_i_static_get_blob_max_size() == 2048); + assert(!test_accessors_i_static_set_blob_max_size(0, &err)); + assert_str(&err, "max size must be nonzero"); + runner_string_free(&err); + assert(test_accessors_i_static_get_blob_max_size() == 2048); + + test_accessors_i_blob_drop_own(a_own); + test_accessors_i_blob_drop_own(b_own); +} diff --git a/tests/runtime/accessors/test.c b/tests/runtime/accessors/test.c new file mode 100644 index 000000000..2af99684c --- /dev/null +++ b/tests/runtime/accessors/test.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include + +static uint32_t COUNTER = 0; +static uint32_t BOUNDED = 0; +static uint64_t MAX_SIZE = 1024; + +uint32_t exports_test_accessors_i_get_counter(void) { + return COUNTER; +} + +void exports_test_accessors_i_set_counter(uint32_t value) { + COUNTER = value; +} + +void exports_test_accessors_i_get_read_only(test_string_t *ret) { + test_string_dup(ret, "read only"); +} + +uint32_t exports_test_accessors_i_get_bounded(void) { + return BOUNDED; +} + +bool exports_test_accessors_i_set_bounded(uint32_t value, test_string_t *err) { + if (value > 100) { + char buf[64]; + snprintf(buf, sizeof(buf), "%" PRIu32 " is out of bounds", value); + test_string_dup(err, buf); + return false; + } + BOUNDED = value; + return true; +} + +struct exports_test_accessors_i_blob_t { + test_list_u8_t contents; + uint64_t position; + test_string_t label; +}; + +exports_test_accessors_i_own_blob_t exports_test_accessors_i_constructor_blob(test_list_u8_t *init) { + exports_test_accessors_i_blob_t *blob = (exports_test_accessors_i_blob_t *) malloc(sizeof(exports_test_accessors_i_blob_t)); + blob->contents = *init; + blob->position = 0; + test_string_dup(&blob->label, ""); + return exports_test_accessors_i_blob_new(blob); +} + +void exports_test_accessors_i_method_blob_contents(exports_test_accessors_i_borrow_blob_t self, test_list_u8_t *ret) { + ret->len = self->contents.len; + ret->ptr = (uint8_t *) malloc(ret->len); + memcpy(ret->ptr, self->contents.ptr, ret->len); +} + +uint64_t exports_test_accessors_i_method_get_blob_position(exports_test_accessors_i_borrow_blob_t self) { + return self->position; +} + +void exports_test_accessors_i_method_set_blob_position(exports_test_accessors_i_borrow_blob_t self, uint64_t value) { + self->position = value; +} + +void exports_test_accessors_i_method_get_blob_label(exports_test_accessors_i_borrow_blob_t self, test_string_t *ret) { + test_string_dup_n(ret, (const char *) self->label.ptr, self->label.len); +} + +bool exports_test_accessors_i_method_set_blob_label(exports_test_accessors_i_borrow_blob_t self, test_string_t *value, test_string_t *err) { + if (value->len == 0) { + test_string_free(value); + test_string_dup(err, "label must not be empty"); + return false; + } + test_string_free(&self->label); + self->label = *value; + return true; +} + +uint64_t exports_test_accessors_i_static_get_blob_max_size(void) { + return MAX_SIZE; +} + +bool exports_test_accessors_i_static_set_blob_max_size(uint64_t value, test_string_t *err) { + if (value == 0) { + test_string_dup(err, "max size must be nonzero"); + return false; + } + MAX_SIZE = value; + return true; +} + +void exports_test_accessors_i_blob_destructor(exports_test_accessors_i_blob_t *rep) { + test_list_u8_free(&rep->contents); + test_string_free(&rep->label); + free(rep); +} From 49728021129c7df2d1bd4d9a2081c18c3bb66401 Mon Sep 17 00:00:00 2001 From: Ben Visness Date: Fri, 2 Oct 2026 18:50:41 -0400 Subject: [PATCH 5/5] C++ accessor tests --- crates/test/src/cpp.rs | 8 +- .../cpp/exports-test-accessors-i-Blob.h | 45 +++++++++++ tests/runtime/accessors/runner.cpp | 60 +++++++++++++++ tests/runtime/accessors/test.cpp | 74 +++++++++++++++++++ 4 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h create mode 100644 tests/runtime/accessors/runner.cpp create mode 100644 tests/runtime/accessors/test.cpp diff --git a/crates/test/src/cpp.rs b/crates/test/src/cpp.rs index 99cda9f21..51ca2e827 100644 --- a/crates/test/src/cpp.rs +++ b/crates/test/src/cpp.rs @@ -148,6 +148,7 @@ impl LanguageMethods for Cpp { // Now compile the runner's source code to with the above object and the // component-type object into a final component. + let output = compile.output.with_extension("core.wasm"); let mut cmd = Command::new(compiler); cmd.arg(&compile.component.path) .arg(&bindings_object) @@ -170,12 +171,17 @@ impl LanguageMethods for Cpp { .arg("-std=c++20") .arg("-g") .arg("-o") - .arg(&compile.output); + .arg(&output); for flag in Vec::from(config.cflags) { cmd.arg(flag); } cmd.arg("-mexec-model=reactor"); + cmd.arg("-Wl,--skip-wit-component"); runner.run_command(&mut cmd)?; + + runner + .convert_core_module_to_component(&output, compile) + .with_context(|| format!("failed to convert {output:?}"))?; Ok(()) } diff --git a/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h b/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h new file mode 100644 index 000000000..97a15f8c4 --- /dev/null +++ b/tests/runtime/accessors/cpp/exports-test-accessors-i-Blob.h @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include +#include // Added +#include // Added +#include "wit.h" +/* User class definition file, autogenerated once, then user modified +* Updated versions of this file are generated into Blob.template. +*/ +namespace exports { + namespace test { + namespace accessors { + namespace i { + class Blob : public wit::ResourceExportBase{ + + public: + + static void Dtor(i::Blob* self){delete self;} + Blob(wit::vector init); + static Owned New(wit::vector init){return Owned(new Blob(std::move(init)));} + wit::vector Contents(); + uint64_t Position(); + void SetPosition(uint64_t value); + wit::string Label(); + std::expected SetLabel(wit::string value); + static uint64_t MaxSize(); + static std::expected SetMaxSize(uint64_t value); + static int32_t ResourceNew(i::Blob* self); + static Blob* ResourceRep(int32_t id); + static void ResourceDrop(int32_t id); + + // Modifications to the template below this line + private: + std::vector contents; + uint64_t position; + std::string label; + static uint64_t max_size; + }; + + } + } + } +} diff --git a/tests/runtime/accessors/runner.cpp b/tests/runtime/accessors/runner.cpp new file mode 100644 index 000000000..8153a35bb --- /dev/null +++ b/tests/runtime/accessors/runner.cpp @@ -0,0 +1,60 @@ +//@ wasmtime-flags = '-Wcomponent-model-accessors' + +#include +#include +#include +#include + +namespace test_imports = ::test::accessors::i; + +static bool is_err(std::expected const& r, std::string_view msg) { + return !r.has_value() && r.error().get_view() == msg; +} + +static bool equal(wit::vector const& a, std::vector const& b) { + auto view = a.get_const_view(); + return std::vector(view.begin(), view.end()) == b; +} + +void exports::runner::Run() { + assert(test_imports::Counter() == 0); + test_imports::SetCounter(5); + assert(test_imports::Counter() == 5); + test_imports::SetCounter(UINT32_MAX); + assert(test_imports::Counter() == UINT32_MAX); + + assert(test_imports::ReadOnly().get_view() == "read only"); + + assert(test_imports::Bounded() == 0); + assert(test_imports::SetBounded(10).has_value()); + assert(test_imports::Bounded() == 10); + assert(is_err(test_imports::SetBounded(101), "101 is out of bounds")); + assert(test_imports::Bounded() == 10); + + std::vector a_init{1, 2, 3}; + std::vector b_init{4, 5}; + auto a = test_imports::Blob(std::span(a_init)); + auto b = test_imports::Blob(std::span(b_init)); + assert(equal(a.Contents(), a_init)); + assert(a.Position() == 0); + assert(b.Position() == 0); + a.SetPosition(2); + assert(a.Position() == 2); + assert(b.Position() == 0); + b.SetPosition(1); + assert(a.Position() == 2); + assert(b.Position() == 1); + + assert(a.Label().get_view() == ""); + assert(a.SetLabel("hello").has_value()); + assert(a.Label().get_view() == "hello"); + assert(b.Label().get_view() == ""); + assert(is_err(a.SetLabel(""), "label must not be empty")); + assert(a.Label().get_view() == "hello"); + + assert(test_imports::Blob::MaxSize() == 1024); + assert(test_imports::Blob::SetMaxSize(2048).has_value()); + assert(test_imports::Blob::MaxSize() == 2048); + assert(is_err(test_imports::Blob::SetMaxSize(0), "max size must be nonzero")); + assert(test_imports::Blob::MaxSize() == 2048); +} diff --git a/tests/runtime/accessors/test.cpp b/tests/runtime/accessors/test.cpp new file mode 100644 index 000000000..471b4b573 --- /dev/null +++ b/tests/runtime/accessors/test.cpp @@ -0,0 +1,74 @@ +#include +#include + +namespace test_exports = ::exports::test::accessors::i; + +static uint32_t counter = 0; +static uint32_t bounded = 0; + +uint32_t test_exports::Counter() { + return counter; +} + +void test_exports::SetCounter(uint32_t value) { + counter = value; +} + +wit::string test_exports::ReadOnly() { + return wit::string::from_view("read only"); +} + +uint32_t test_exports::Bounded() { + return bounded; +} + +std::expected test_exports::SetBounded(uint32_t value) { + if (value > 100) { + return std::unexpected(wit::string::from_view(std::to_string(value) + " is out of bounds")); + } + bounded = value; + return std::expected(); +} + +uint64_t test_exports::Blob::max_size = 1024; + +test_exports::Blob::Blob(wit::vector init) : position(0) { + auto view = init.get_const_view(); + contents.assign(view.begin(), view.end()); +} + +wit::vector test_exports::Blob::Contents() { + return wit::vector::from_view(std::span(contents)); +} + +uint64_t test_exports::Blob::Position() { + return position; +} + +void test_exports::Blob::SetPosition(uint64_t value) { + position = value; +} + +wit::string test_exports::Blob::Label() { + return wit::string::from_view(label); +} + +std::expected test_exports::Blob::SetLabel(wit::string value) { + if (value.size() == 0) { + return std::unexpected(wit::string::from_view("label must not be empty")); + } + label = value.to_string(); + return std::expected(); +} + +uint64_t test_exports::Blob::MaxSize() { + return max_size; +} + +std::expected test_exports::Blob::SetMaxSize(uint64_t value) { + if (value == 0) { + return std::unexpected(wit::string::from_view("max size must be nonzero")); + } + max_size = value; + return std::expected(); +}