Skip to content

Commit

Permalink
[test]: Add a test for #[schema(transparent)] attribute and for JSON …
Browse files Browse the repository at this point in the history
…representation of schema

Signed-off-by: Nikita Strygin <[email protected]>
  • Loading branch information
DCNick3 committed Aug 2, 2023
1 parent e91c0b1 commit 5f14413
Show file tree
Hide file tree
Showing 8 changed files with 323 additions and 5 deletions.
1 change: 1 addition & 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 @@ -74,6 +74,7 @@ bytes = "1.4.0"

vergen = { version = "8.1.1", default-features = false }
trybuild = "1.0.73"
impls = "1.0.3"

base64 = { version = "0.13.1", default-features = false }
hex = { version = "0.4.3", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion macro/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ darling = { workspace = true }
iroha_macro = { workspace = true }

trybuild = { workspace = true }
impls = "1.0.3"
impls = { workspace = true }
5 changes: 3 additions & 2 deletions schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ serde = { workspace = true, features = ["derive", "alloc"] }
fixnum = { workspace = true, features = ["i64"] }

[dev-dependencies]
parity-scale-codec = { version = "3.2.1", default-features = false, features = ["derive", "full"] }
impls = "1.0.3"
parity-scale-codec = { workspace = true, default-features = false, features = ["derive", "full"] }
impls = { workspace = true }
serde_json = { workspace = true, features = ["std"] }
2 changes: 1 addition & 1 deletion schema/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ manyhow = { workspace = true, features = ["syn1", "darling"] }
darling = { workspace = true }

[dev-dependencies]
iroha_schema = { workspace = true}
iroha_schema = { workspace = true }

trybuild = { workspace = true }
1 change: 0 additions & 1 deletion schema/derive/tests/ui_pass/derive_into_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ pub struct FakeString {}
#[derive(IntoSchema)]
pub enum Enum {
Zero,
// how does it work? We don't allow discriminants, but still try to parse them?
One,
#[codec(index = 42)]
FortyTwo,
Expand Down
239 changes: 239 additions & 0 deletions schema/tests/schema_json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
//! This test checks how the json-serialized schema looks like.

#![allow(dead_code)]
#![allow(unused_tuple_struct_fields)]

use iroha_schema::IntoSchema;
use serde_json::json;

macro_rules! check_schema_impl {
($ty:ident, $type_name:ident, $json:tt) => {{
assert_eq!(
$ty::type_name(),
stringify!($type_name),
"Type name of {} is not equal to the expected one",
stringify!($ty)
);
let __schema = serde_json::value::to_value(&$ty::schema())
.expect("Failed to serialize schema to JSON");
// println!("{}: {}", stringify!($ty), __schema);
assert_eq!(
__schema.get(&$ty::type_name()).unwrap().clone(),
json!($json),
"Schema of {} is not equal to the expected one",
stringify!($ty)
);
}};
}

/// It expects to have three parameters: a type definition item, an expected schema type name and a JSON schema.
///
/// The json is passed to the `serde_json::json!` macro, so it can be a string, an array or an object.
///
/// Only the schema of the type itself is checked, not the schema of its fields.
///
/// NOTE: this macro doesn't support generics.
macro_rules! check_schema {
($(#[$($meta:tt)*])* struct $ty:ident, $type_name:ident, $json:tt) => {{
#[derive(IntoSchema)]
$(#[$($meta)*])*
struct $ty;
check_schema_impl!($ty, $type_name, $json);
}};
($(#[$($meta:tt)*])* struct $ty:ident ($($body:tt)*), $type_name:ident, $json:tt) => {{
#[derive(IntoSchema)]
$(#[$($meta)*])*
struct $ty($($body)*);
check_schema_impl!($ty, $type_name, $json);
}};
($(#[$($meta:tt)*])* struct $ty:ident {$($body:tt)*}, $type_name:ident, $json:tt) => {{
#[derive(IntoSchema)]
$(#[$($meta)*])*
struct $ty {$($body)*}
check_schema_impl!($ty, $type_name, $json);
}};
($(#[$($meta:tt)*])* enum $ty:ident {$($body:tt)*}, $type_name:ident, $json:tt) => {{
#[derive(IntoSchema)]
$(#[$($meta)*])*
enum $ty {$($body)*}
check_schema_impl!($ty, $type_name, $json);
}};
}

#[test]
fn test_struct() {
check_schema!(
struct EmptyNamedStruct {},
EmptyNamedStruct,
{"Struct": []}
);

// this behaviour is weird...
check_schema!(
struct EmptyTupleStruct(),
EmptyTupleStruct,
null
);
check_schema!(
struct UnitStruct,
UnitStruct,
null
);

check_schema!(
struct NormalStruct {
normal_field_1: u32,
normal_field_2: u32,
},
NormalStruct,
{"Struct": [
{"name": "normal_field_1", "type": "u32"},
{"name": "normal_field_2", "type": "u32"}
]}
);
check_schema!(
struct NewtypeStruct(u32),
NewtypeStruct,
"u32"
);
check_schema!(
struct TupleStruct(u32, u32),
TupleStruct,
{"Tuple": [
"u32", "u32"
]}
);
}

#[test]
fn test_struct_codec_attr() {
check_schema!(
struct SkipField {
#[codec(skip)]
skipped_field: u32,
normal_field: u32,
},
SkipField,
{"Struct": [
{"name": "normal_field", "type": "u32"}
]}
);
check_schema!(
struct CompactField {
#[codec(compact)]
compact_field: u32,
},
CompactField,
{"Struct": [
{"name": "compact_field", "type": "Compact<u32>"}
]}
);
}

#[test]
fn test_transparent() {
check_schema!(
#[schema(transparent)]
struct TransparentStruct(u32),
u32,
{"Int": "FixedWidth"}
);
check_schema!(
#[schema(transparent = "u32")]
struct TransparentStructExplicitInt {
a: u32,
b: i32,
},
u32,
{"Int": "FixedWidth"}
);
check_schema!(
#[schema(transparent = "String")]
struct TransparentStructExplicitString {
a: u32,
b: i32,
},
String,
"String"
);
check_schema!(
#[schema(transparent = "String")]
enum TransparentEnum {
Variant1,
Variant2,
},
String,
"String"
);
}

#[test]
fn test_enum() {
check_schema!(
enum EmptyEnum {},
EmptyEnum,
{"Enum": []}
);
check_schema!(
enum DatalessEnum {
Variant1,
Variant2,
},
DatalessEnum,
{"Enum": [
{"discriminant": 0, "tag": "Variant1"},
{"discriminant": 1, "tag": "Variant2"}
]}
);
check_schema!(
enum DataEnum {
Variant1(u32),
// these variants are not supported by the schema
//Variant2(u32, u32),
//Variant2 { a: u32, b: u32 },
Variant3(String)
},
DataEnum,
{"Enum": [
{"discriminant": 0, "tag": "Variant1", "type": "u32"},
{"discriminant": 1, "tag": "Variant3", "type": "String"}
]}
)
}

#[test]
fn test_enum_codec_attr() {
check_schema!(
enum SkipEnum {
#[codec(skip)]
Variant1,
Variant2,
},
SkipEnum,
{"Enum": [
{"discriminant": 1, "tag": "Variant2"}
]}
);
check_schema!(
enum IndexEnum {
// ERROR: Fieldless enums with explicit discriminants are not allowed
// Variant1 = 12,
#[codec(index = 42)]
Variant2,
},
IndexEnum,
{"Enum": [
{"discriminant": 42, "tag": "Variant2"}
]}
);
check_schema!(
enum IndexDataEnum {
#[codec(index = 42)]
Variant2(u32),
},
IndexDataEnum,
{"Enum": [
{"discriminant": 42, "tag": "Variant2", "type": "u32"}
]}
)
}
77 changes: 77 additions & 0 deletions schema/tests/transparent_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
extern crate alloc;

use core::any::TypeId;

use iroha_schema::prelude::*;
use parity_scale_codec::{Decode, Encode};

/// This type tests transparent type inference
#[derive(Decode, Encode, IntoSchema)]
#[schema(transparent)]
struct TransparentStruct(u32);

/// This type tests explicit transparent type (u32)
#[derive(Decode, Encode, IntoSchema)]
#[schema(transparent = "u32")]
struct TransparentStructExplicitInt {
a: u32,
b: i32,
}

/// This type tests explicit transparent type (String)
#[derive(Decode, Encode, IntoSchema)]
#[schema(transparent = "String")]
struct TransparentStructExplicitString {
a: u32,
b: i32,
}

/// This type tests transparent type being an enum
#[derive(Decode, Encode, IntoSchema)]
#[schema(transparent = "String")]
enum TransparentEnum {
Variant1,
Variant2,
}

#[test]
fn transparent_types() {
use alloc::collections::BTreeMap;

use IntMode::*;
use Metadata::*;

let expected = [
(
TypeId::of::<std::string::String>(),
("String".to_string(), String),
),
(TypeId::of::<u32>(), ("u32".to_string(), Int(FixedWidth))),
(
TypeId::of::<TransparentStruct>(),
("u32".to_string(), Int(FixedWidth)),
),
(
TypeId::of::<TransparentStructExplicitInt>(),
("u32".to_string(), Int(FixedWidth)),
),
(
TypeId::of::<TransparentStructExplicitString>(),
("String".to_string(), String),
),
(
TypeId::of::<TransparentEnum>(),
("String".to_string(), String),
),
]
.into_iter()
.collect::<BTreeMap<_, _>>();

let mut schema = MetaMap::new();
TransparentStruct::update_schema_map(&mut schema);
TransparentStructExplicitInt::update_schema_map(&mut schema);
TransparentStructExplicitString::update_schema_map(&mut schema);
TransparentEnum::update_schema_map(&mut schema);

assert_eq!(schema, expected);
}

0 comments on commit 5f14413

Please sign in to comment.