Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] E2E tests #218

Merged
merged 12 commits into from
Feb 1, 2024
27 changes: 27 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
on: [push, pull_request]
name: Test
jobs:
e2e-dependencies:
name: Run 'dependencies' end-to-end test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: dependencies e2e test
working-directory: e2e/dependencies/consumer
run: |
cargo t
tsc bindings/* --noEmit
e2e-workspace:
name: Run 'workspace' end-to-end test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: workspace e2e test
working-directory: e2e/workspace
run: |
cargo t
tsc parent/bindings/* --noEmit

readme-up-to-date:
name: Check that README.md is up-to-date
runs-on: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/target
target/
Cargo.lock
/.idea
*.ts
Expand Down
8 changes: 8 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# e2e tests
### [dependencies](./dependencies)
A user creates the crate `consumer`, which depends on some crate `dependency1`, which possibly lives on [crates.io](https://crates.io).
If a struct in `consumer` contains a type from `dependency1`, it should be exported as well.

### [workspace](./workspace)
A user creates a workspace, containing `crate1`, `crate2`, and `parent`.
`crate1` and `crate2` are independent, but `parent` depends on both `crate1` and `crate2`.
10 changes: 10 additions & 0 deletions e2e/dependencies/consumer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "consumer"
version = "0.1.0"
edition = "2021"

[workspace]

[dependencies]
ts-rs = { path = "../../../ts-rs" }
dependency1 = { path = "../dependency1" }
10 changes: 10 additions & 0 deletions e2e/dependencies/consumer/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use ts_rs::TS;
use dependency1::LibraryType;

#[derive(TS)]
#[ts(export)]
struct ConsumerType {
pub ty: LibraryType
}

fn main() {}
9 changes: 9 additions & 0 deletions e2e/dependencies/dependency1/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "dependency1"
version = "0.1.0"
edition = "2021"

[workspace]

[dependencies]
ts-rs = { path = "../../../ts-rs" }
6 changes: 6 additions & 0 deletions e2e/dependencies/dependency1/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use ts_rs::TS;

#[derive(TS)]
pub struct LibraryType {
pub a: i32
}
Comment on lines +3 to +6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, since this type doesn't contain #[export] we'd have to come up with some other way to export it in the consumer crate

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! I'm not sure about how to exactly solve this yet - maybe a #[ts(export)] type should cause all of its dependencies to be exported as well?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd have to make sure it's only exported once, even if the same type is used in a bunch of places

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this might be confusing, as the user is not explicitly #[ts(export)]ing the type

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this might be confusing, as the user is not explicitly #[ts(export)]ing the type

The problem in that scenario is that the user just cant explicitly export it, since it's in an other crate that may not be under his control.

We'd have to make sure it's only exported once, even if the same type is used in a bunch of places

That's true, this might be the biggest challenge here.

Copy link
Contributor

@escritorio-gustavo escritorio-gustavo Jan 31, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem in that scenario is that the user just cant explicitly export it, since it's in an other crate that may not be under his control.

That is true, and it brings up the question I asked in #211:

Should library code in crates.io ever implement TS? Seems like this should be an application code decision (especially the extra dependency + tests)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(let's maybe have this discussion here then)

Should library code in crates.io ever implement TS? Seems like this should be an application code decision (especially the extra dependency + tests)

I think it'd be a good idea to support that, yeah! These libraries would probably never #[ts(export)], but making their types implement TS might be usefull in some cases, I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true, and it brings up the question I asked in #211

Speaking of which, this is getting hard to follow across two PRs, I opened a discussion (#219) to centralize this

2 changes: 2 additions & 0 deletions e2e/workspace/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[workspace]
members = ["crate1", "crate2", "parent"]
7 changes: 7 additions & 0 deletions e2e/workspace/crate1/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "crate1"
version = "0.1.0"
edition = "2021"

[dependencies]
ts-rs = { path = "../../../ts-rs" }
6 changes: 6 additions & 0 deletions e2e/workspace/crate1/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use ts_rs::TS;

#[derive(TS)]
pub struct Crate1 {
pub x: [[[i32; 128]; 128]; 128],
}
7 changes: 7 additions & 0 deletions e2e/workspace/crate2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "crate2"
version = "0.1.0"
edition = "2021"

[dependencies]
ts-rs = { path = "../../../ts-rs" }
6 changes: 6 additions & 0 deletions e2e/workspace/crate2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use ts_rs::TS;

#[derive(TS)]
pub struct Crate2 {
pub x: [[[i32; 128]; 128]; 128],
}
9 changes: 9 additions & 0 deletions e2e/workspace/parent/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "parent"
version = "0.1.0"
edition = "2021"

[dependencies]
ts-rs = { path = "../../../ts-rs" }
crate1 = { path = "../crate1" }
crate2 = { path = "../crate2" }
98 changes: 98 additions & 0 deletions e2e/workspace/parent/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use ts_rs::TS;
use crate1::Crate1;
use crate2::Crate2;

fn main() {
println!("Hello, world!");
}

#[derive(TS)]
#[ts(export)]
pub struct Parent {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent2 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent3 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent4 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent5 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent6 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent7 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent8 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent9 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent10 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent11 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent12 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent13 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent14 {
pub crate1: Crate1,
pub crate2: Crate2,
}
#[derive(TS)]
#[ts(export)]
pub struct Parent15 {
pub crate1: Crate1,
pub crate2: Crate2,
}
4 changes: 2 additions & 2 deletions macros/src/attr/field.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use syn::{Attribute, Ident, Result};
use syn::spanned::Spanned;
use syn::{Attribute, Ident, Result};

use crate::utils::parse_attrs;

Expand Down Expand Up @@ -60,7 +60,7 @@ impl FieldAttr {
self.skip = self.skip || skip;
self.optional = Optional {
optional: self.optional.optional || optional,
nullable: self.optional.nullable || nullable
nullable: self.optional.nullable || nullable,
};
self.flatten |= flatten;
}
Expand Down
29 changes: 8 additions & 21 deletions macros/src/deps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,26 @@ impl Dependencies {
/// Adds all dependencies from the given type
pub fn append_from(&mut self, ty: &Type) {
self.0
.push(quote!(dependencies.append(&mut <#ty as ts_rs::TS>::dependencies());));
.push(quote![.extend(<#ty as ts_rs::TS>::dependency_types())]);
}

/// Adds the given type if it's *not* transparent.
/// If it is, all it's child dependencies are added instead.
pub fn push_or_append_from(&mut self, ty: &Type) {
self.0.push(quote! {
if <#ty as ts_rs::TS>::transparent() {
dependencies.append(&mut <#ty as ts_rs::TS>::dependencies());
} else {
if let Some(dep) = ts_rs::Dependency::from_ty::<#ty>() {
dependencies.push(dep);
}
}
});
self.0.push(quote![.push::<#ty>()]);
}

pub fn append(&mut self, other: Dependencies) {
self.0.push(quote! {
dependencies.append(&mut #other);
})
self.0.push(quote![.extend(#other)]);
}
}

impl ToTokens for Dependencies {
fn to_tokens(&self, tokens: &mut TokenStream) {
let dependencies = &self.0;
tokens.extend(quote! {
{
let mut dependencies = Vec::new();
#( #dependencies )*
dependencies
}
})
let lines = &self.0;
tokens.extend(quote![{
use ts_rs::typelist::TypeList;
()#(#lines)*
}])
}
}
5 changes: 4 additions & 1 deletion macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,15 @@ impl DerivedTS {
#inline
}
#inline_flattened
fn dependencies() -> Vec<ts_rs::Dependency>

#[allow(clippy::unused_unit)]
fn dependency_types() -> impl ts_rs::typelist::TypeList
where
Self: 'static,
{
#dependencies
}

fn transparent() -> bool {
false
}
Expand Down
8 changes: 6 additions & 2 deletions macros/src/types/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ fn format_variant(
let ty = match (type_override, type_as) {
(Some(_), Some(_)) => syn_err!("`type` is not compatible with `as`"),
(Some(type_override), None) => quote! { #type_override },
(None, Some(type_as)) => format_type(&syn::parse_str::<Type>(&type_as)?, dependencies, generics),
(None, Some(type_as)) => {
format_type(&syn::parse_str::<Type>(&type_as)?, dependencies, generics)
}
(None, None) => format_type(&unnamed.unnamed[0].ty, dependencies, generics),
};

Expand Down Expand Up @@ -159,7 +161,9 @@ fn format_variant(
let ty = match (type_override, type_as) {
(Some(_), Some(_)) => syn_err!("`type` is not compatible with `as`"),
(Some(type_override), None) => quote! { #type_override },
(None, Some(type_as)) => format_type(&syn::parse_str::<Type>(&type_as)?, dependencies, generics),
(None, Some(type_as)) => {
format_type(&syn::parse_str::<Type>(&type_as)?, dependencies, generics)
}
(None, None) => format_type(&unnamed.unnamed[0].ty, dependencies, generics),
};

Expand Down
2 changes: 1 addition & 1 deletion macros/src/types/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub fn format_type(ty: &Type, dependencies: &mut Dependencies, generics: &Generi
// be cause the T in `[T; N]` is technically not a generic
Type::Array(type_array) => {
let formatted = format_type(&type_array.elem, dependencies, generics);
return quote!(<#type_array>::name_with_type_args(vec![#formatted]))
return quote!(<#type_array>::name_with_type_args(vec![#formatted]));
}
// The field is a slice (`[T]`) so it technically doesn't have a
// generic argument. Therefore, we handle it explicitly here like a `Vec<T>`
Expand Down
8 changes: 0 additions & 8 deletions ts-rs/src/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@ use chrono::{
};

use super::{impl_primitives, TS};
use crate::Dependency;

macro_rules! impl_dummy {
($($t:ty),*) => {$(
impl TS for $t {
fn name() -> String { String::new() }
fn inline() -> String { String::new() }
fn dependencies() -> Vec<Dependency> { vec![] }
fn transparent() -> bool { false }
}
)*};
Expand All @@ -33,9 +31,6 @@ impl<T: TimeZone + 'static> TS for DateTime<T> {
fn inline() -> String {
"string".to_owned()
}
fn dependencies() -> Vec<Dependency> {
vec![]
}
fn transparent() -> bool {
false
}
Expand All @@ -51,9 +46,6 @@ impl<T: TimeZone + 'static> TS for Date<T> {
fn inline() -> String {
"string".to_owned()
}
fn dependencies() -> Vec<Dependency> {
vec![]
}
fn transparent() -> bool {
false
}
Expand Down
Loading
Loading