Skip to content

Commit

Permalink
Initialize a test suite for wit-encoder (#1626)
Browse files Browse the repository at this point in the history
* change `wit-encoder` indent to 2

* test empty `Result`s in `wit-encoder`

* import wit test files for `wit-encoder`

* use external wit test file for `functions.rs` test

* add `empty` test

* add `wit-encoder` overlap tests

* fix more existing tests

* Add `include` capabilities to `wit-encoder`

* tidy up

* rebase on main

* check in `.gitattributes` to normalize line endings

Rebasing brok

* remove additional wit files

* inline tests
  • Loading branch information
yoshuawuyts committed Jun 20, 2024
1 parent 8afdf05 commit 3e38098
Show file tree
Hide file tree
Showing 18 changed files with 314 additions and 134 deletions.
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
* text=auto
*.waves text eol=lf
*.out text eol=lf
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ bitflags = "2.5.0"
hashbrown = { version = "0.14.3", default-features = false, features = ['ahash'] }
ahash = { version = "0.8.11", default-features = false }
termcolor = "1.2.0"
indoc = "2.0.5"

wasm-compose = { version = "0.211.1", path = "crates/wasm-compose" }
wasm-encoder = { version = "0.211.1", path = "crates/wasm-encoder" }
Expand Down
3 changes: 3 additions & 0 deletions crates/wit-encoder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ workspace = true
[dependencies]
semver = { workspace = true }
pretty_assertions = { workspace = true }

[dev-dependencies]
indoc = { workspace = true }
13 changes: 12 additions & 1 deletion crates/wit-encoder/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ where
impl Results {
// For the common case of an empty results list.
pub fn empty() -> Results {
Results::Named(Default::default())
Results::Named(Params::empty())
}

pub fn anon(type_: Type) -> Results {
Expand Down Expand Up @@ -166,3 +166,14 @@ impl StandaloneFunc {
self.docs = docs.map(|d| d.into());
}
}

#[cfg(test)]
mod test {
use crate::Results;

#[test]
fn is_empty() {
let res = Results::empty();
assert!(res.is_empty());
}
}
26 changes: 26 additions & 0 deletions crates/wit-encoder/src/include.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use std::fmt;

use crate::{Ident, Render};

/// Enable the union of a world with another world
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Include {
use_path: Ident,
include_names_list: Vec<String>,
}

impl Include {
pub fn new(use_path: impl Into<Ident>) -> Self {
Self {
use_path: use_path.into(),
include_names_list: vec![],
}
}
}

impl Render for Include {
fn render(&self, f: &mut fmt::Formatter<'_>, opts: &crate::RenderOpts) -> fmt::Result {
write!(f, "{}include {};\n", opts.spaces(), self.use_path)?;
Ok(())
}
}
2 changes: 2 additions & 0 deletions crates/wit-encoder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod enum_;
mod flags;
mod function;
mod ident;
mod include;
mod interface;
mod package;
mod record;
Expand All @@ -24,6 +25,7 @@ pub use enum_::*;
pub use flags::*;
pub use function::*;
pub use ident::*;
pub use include::*;
pub use interface::*;
pub use package::*;
pub use record::*;
Expand Down
13 changes: 9 additions & 4 deletions crates/wit-encoder/src/package.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,21 @@ impl Package {
impl Render for Package {
fn render(&self, f: &mut fmt::Formatter<'_>, opts: &RenderOpts) -> fmt::Result {
write!(f, "{}package {};\n", opts.spaces(), self.name)?;
write!(f, "\n")?;
for item in &self.items {
write!(f, "\n")?;
match item {
PackageItem::Interface(interface) => {
if let Some(docs) = &interface.docs {
docs.render(f, opts)?;
}
write!(f, "{}interface {} {{\n", opts.spaces(), interface.name)?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
write!(f, "{}interface {} {{", opts.spaces(), interface.name)?;
if !interface.items.is_empty() {
write!(f, "\n")?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
} else {
write!(f, "}}\n")?;
}
}
PackageItem::World(world) => {
world.render(f, opts)?;
Expand Down
2 changes: 1 addition & 1 deletion crates/wit-encoder/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub struct RenderOpts {
impl Default for RenderOpts {
fn default() -> Self {
Self {
indent_width: 4,
indent_width: 2,
ident_count: 0,
}
}
Expand Down
7 changes: 5 additions & 2 deletions crates/wit-encoder/src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,8 +317,11 @@ impl Render for TypeDef {
if let Some(docs) = &self.docs {
docs.render(f, opts)?;
}
write!(f, "{}record {} {{\n", opts.spaces(), self.name)?;
for field in &record.fields {
write!(f, "{}record {} {{", opts.spaces(), self.name)?;
for (index, field) in record.fields.iter().enumerate() {
if index == 0 {
write!(f, "\n")?;
}
let opts = opts.indent();
if let Some(docs) = &field.docs {
docs.render(f, &opts)?;
Expand Down
34 changes: 27 additions & 7 deletions crates/wit-encoder/src/world.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fmt;

use crate::{ident::Ident, Docs, Interface, Render, RenderOpts, StandaloneFunc};
use crate::{ident::Ident, Docs, Include, Interface, Render, RenderOpts, StandaloneFunc};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct World {
Expand Down Expand Up @@ -52,6 +52,9 @@ impl World {
pub fn function_export(&mut self, value: StandaloneFunc) {
self.item(WorldItem::function_export(value));
}
pub fn include(&mut self, value: impl Into<Ident>) {
self.item(WorldItem::include(value));
}

/// Set the documentation
pub fn docs(&mut self, docs: Option<impl Into<Docs>>) {
Expand Down Expand Up @@ -88,18 +91,28 @@ impl Render for World {
docs.render(f, opts)?;
}
import(f, opts)?;
write!(f, "{}: interface {{\n", interface.name)?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
write!(f, "{}: interface {{", interface.name)?;
if !interface.items.is_empty() {
write!(f, "\n")?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
} else {
write!(f, "}}\n")?;
}
}
WorldItem::InlineInterfaceExport(interface) => {
if let Some(docs) = &interface.docs {
docs.render(f, opts)?;
}
export(f, opts)?;
write!(f, "{}: interface {{\n", interface.name)?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
write!(f, "{}: interface {{", interface.name)?;
if !interface.items.is_empty() {
write!(f, "\n")?;
interface.items.render(f, &opts.indent())?;
write!(f, "{}}}\n", opts.spaces())?;
} else {
write!(f, "}}\n")?;
}
}
WorldItem::NamedInterfaceImport(interface) => {
if let Some(docs) = &interface.docs {
Expand Down Expand Up @@ -129,6 +142,7 @@ impl Render for World {
export(f, opts)?;
render_function(f, opts, function)?;
}
WorldItem::Include(include) => include.render(f, opts)?,
}
}
let opts = &opts.outdent();
Expand Down Expand Up @@ -156,6 +170,9 @@ pub enum WorldItem {

/// A function is being directly exported from this world.
FunctionExport(StandaloneFunc),

/// Include type
Include(Include),
}

impl WorldItem {
Expand All @@ -177,6 +194,9 @@ impl WorldItem {
pub fn function_export(value: StandaloneFunc) -> Self {
Self::FunctionExport(value)
}
pub fn include(value: impl Into<Ident>) -> Self {
Self::Include(Include::new(value))
}
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
Expand Down
12 changes: 12 additions & 0 deletions crates/wit-encoder/tests/empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use pretty_assertions::assert_eq;
use wit_encoder::{Package, PackageName};

const PACKAGE: &str = indoc::indoc! {"
package foo:empty;
"};

#[test]
fn concrete_types() {
let package = Package::new(PackageName::new("foo", "empty", None));
assert_eq!(package.to_string(), PACKAGE);
}
70 changes: 35 additions & 35 deletions crates/wit-encoder/tests/functions.rs
Original file line number Diff line number Diff line change
@@ -1,88 +1,88 @@
use pretty_assertions::assert_eq;
use wit_encoder::{Params, Result_, Results, StandaloneFunc, Type};
use wit_encoder::{
Interface, Package, PackageName, Params, Result_, Results, StandaloneFunc, Type,
};

const PACKAGE: &str = "package foo:functions;
const PACKAGE: &str = indoc::indoc! {"
package foo:functions;
interface functions {
f1: func();
f2: func(a: u32);
f3: func() -> u32;
/// this is a documentation comment
/// for the f4 function
f4: func() -> tuple<u32, u32>;
f5: func(a: f32, b: f32) -> tuple<u32, u32>;
f6: func(a: option<u32>) -> result<u32, f32>;
f7: func() -> (u: u32, f: f32);
f8: func() -> (u: u32);
f9: func() -> result<f32>;
f10: func() -> result<_, f32>;
f11: func() -> result;
}
";
interface functions {
f1: func();
f2: func(a: u32);
f4: func() -> u32;
f6: func() -> tuple<u32, u32>;
f7: func(a: f32, b: f32) -> tuple<u32, u32>;
f8: func(a: option<u32>) -> result<u32, f32>;
f9: func() -> (u: u32, f: f32);
f10: func() -> (u: u32);
f11: func() -> result<f32>;
f12: func() -> result<_, f32>;
f13: func() -> result;
}
"};

#[test]
fn smoke() {
let name = wit_encoder::PackageName::new("foo", "functions", None);
let mut package = wit_encoder::Package::new(name);
fn concrete_types() {
let name = PackageName::new("foo", "functions", None);
let mut package = Package::new(name);

package.interface({
let mut interface = wit_encoder::Interface::new("functions");
let mut interface = Interface::new("functions");
interface.function(StandaloneFunc::new("f1"));
interface.function({
let mut func = StandaloneFunc::new("f2");
func.params(Params::from_iter([("a", Type::U32)]));
func
});
interface.function({
let mut func = StandaloneFunc::new("f3");
func.results(Type::U32);
let mut func = StandaloneFunc::new("f4");
func.results(Results::anon(Type::U32));
func
});
interface.function({
let mut func = StandaloneFunc::new("f4");
func.results(Type::tuple(vec![Type::U32, Type::U32]));
func.docs(Some("this is a documentation comment\nfor the f4 function"));
let mut func = StandaloneFunc::new("f6");
func.results(Results::anon(Type::tuple(vec![Type::U32, Type::U32])));
func
});
interface.function({
let mut func = StandaloneFunc::new("f5");
let mut func = StandaloneFunc::new("f7");
func.params(Params::from_iter([("a", Type::F32), ("b", Type::F32)]));
func.results(Type::tuple(vec![Type::U32, Type::U32]));
func
});
interface.function({
let mut func = StandaloneFunc::new("f6");
let mut func = StandaloneFunc::new("f8");
func.params(Params::from_iter([("a", Type::option(Type::U32))]));
func.results(Type::result(Result_::both(Type::U32, Type::F32)));
func
});
interface.function({
let mut func = StandaloneFunc::new("f7");
let mut func = StandaloneFunc::new("f9");
func.results(Results::named(vec![("u", Type::U32), ("f", Type::F32)]));
func
});
interface.function({
let mut func = StandaloneFunc::new("f8");
let mut func = StandaloneFunc::new("f10");
func.results(Results::named(vec![("u", Type::U32)]));
func
});
interface.function({
let mut func = StandaloneFunc::new("f9");
let mut func = StandaloneFunc::new("f11");
func.results(Type::result(Result_::ok(Type::F32)));
func
});
interface.function({
let mut func = StandaloneFunc::new("f10");
let mut func = StandaloneFunc::new("f12");
func.results(Type::result(Result_::err(Type::F32)));
func
});
interface.function({
let mut func = StandaloneFunc::new("f11");
let mut func = StandaloneFunc::new("f13");
func.results(Type::result(Result_::empty()));
func
});
interface
});

assert_eq!(PACKAGE, package.to_string());
assert_eq!(package.to_string(), PACKAGE);
}
23 changes: 23 additions & 0 deletions crates/wit-encoder/tests/import-export-overlap1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use pretty_assertions::assert_eq;
use wit_encoder::{Package, PackageName, StandaloneFunc, World};

const PACKAGE: &str = indoc::indoc! {"
package foo:foo;
world foo {
import a: func();
export a: func();
}
"};

#[test]
fn concrete_types() {
let mut package = Package::new(PackageName::new("foo", "foo", None));

let mut world = World::new("foo");
world.function_import(StandaloneFunc::new("a"));
world.function_export(StandaloneFunc::new("a"));
package.world(world);

assert_eq!(package.to_string(), PACKAGE);
}
Loading

0 comments on commit 3e38098

Please sign in to comment.