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

derive: implement #[valuable] attributes #75

Merged
merged 14 commits into from
Aug 26, 2024
130 changes: 129 additions & 1 deletion tests/tests/derive.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![cfg(feature = "derive")]
#![allow(dead_code)]

use valuable::Valuable;
use valuable::*;

use std::collections::HashMap;
use std::env;
Expand Down Expand Up @@ -66,6 +66,134 @@ fn test_derive_mut() {
}
}

#[test]
fn test_rename() {
#[derive(Valuable)]
#[valuable(rename = "A")]
struct S {
#[valuable(rename = "b")]
f: (),
}

#[derive(Valuable)]
#[valuable(rename = "C")]
enum E {
#[valuable(rename = "D")]
S {
#[valuable(rename = "e")]
f: (),
},
#[valuable(rename = "F")]
T(()),
#[valuable(rename = "G")]
U,
}

let s = Structable::definition(&S { f: () });
assert_eq!(s.name(), "A");
assert!(matches!(s.fields(), Fields::Named(f) if f[0].name() == "b"));
let e = Enumerable::definition(&E::S { f: () });
assert_eq!(e.name(), "C");
assert_eq!(e.variants()[0].name(), "D");
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f[0].name() == "e"));
let e = Enumerable::definition(&E::T(()));
assert_eq!(e.variants()[1].name(), "F");
let e = Enumerable::definition(&E::U);
assert_eq!(e.variants()[2].name(), "G");
}

#[test]
fn test_skip_empty() {
struct NotValuable;

#[derive(Valuable)]
struct S {
#[valuable(skip)]
f: NotValuable,
}

#[derive(Valuable)]
struct T(#[valuable(skip)] NotValuable);

#[derive(Valuable)]
enum E {
S {
#[valuable(skip)]
f: NotValuable,
},
T(#[valuable(skip)] NotValuable),
}

let s = Structable::definition(&S { f: NotValuable });
assert!(matches!(s.fields(), Fields::Named(f) if f.is_empty()));
let s = Structable::definition(&T(NotValuable));
assert!(matches!(s.fields(), Fields::Unnamed(f) if *f == 0));
let e = Enumerable::definition(&E::S { f: NotValuable });
assert_eq!(e.variants().len(), 2);
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f.is_empty()));
assert!(matches!(e.variants()[1].fields(), Fields::Unnamed(f) if *f == 0));
}

#[test]
fn test_skip() {
struct NotValuable;

#[derive(Valuable)]
struct S {
f1: (),
#[valuable(skip)]
f2: NotValuable,
f3: (),
}

#[derive(Valuable)]
struct T((), #[valuable(skip)] NotValuable, ());

#[derive(Valuable)]
enum E {
S {
f1: (),
#[valuable(skip)]
f2: NotValuable,
f3: (),
},
T((), #[valuable(skip)] NotValuable, ()),
}

let s = Structable::definition(&S {
f1: (),
f2: NotValuable,
f3: (),
});
assert!(matches!(s.fields(), Fields::Named(f) if f.len() == 2));
let s = Structable::definition(&T((), NotValuable, ()));
assert!(matches!(s.fields(), Fields::Unnamed(f) if *f == 2));
let e = Enumerable::definition(&E::S {
f1: (),
f2: NotValuable,
f3: (),
});
assert_eq!(e.variants().len(), 2);
assert!(matches!(e.variants()[0].fields(), Fields::Named(f) if f.len() == 2));
assert!(matches!(e.variants()[1].fields(), Fields::Unnamed(f) if *f == 2));
}

#[test]
fn test_transparent() {
#[derive(Valuable)]
#[valuable(transparent)]
struct S {
f: u8,
}

#[derive(Valuable)]
#[valuable(transparent)]
struct T(char);

assert!(matches!(Valuable::as_value(&S { f: 0 }), Value::U8(0)));
assert!(matches!(Valuable::as_value(&T('a')), Value::Char('a')));
}

#[rustversion::attr(not(stable), ignore)]
#[test]
fn ui() {
Expand Down
53 changes: 53 additions & 0 deletions tests/tests/ui/unexpected.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
use valuable::*;

#[derive(Valuable)]
struct Rename1 {
#[valuable(rename = b)]
f: (),
}
#[derive(Valuable)]
struct Rename2 {
#[valuable(rename = 'b')]
f: (),
}

#[derive(Valuable)]
struct Transparent1 {
#[valuable(transparent)]
f: (),
}
#[derive(Valuable)]
#[valuable(transparent)]
enum Transparent2 {
V(()),
}
#[derive(Valuable)]
#[valuable(transparent)]
struct Transparent3 {
f1: (),
f2: (),
}
#[derive(Valuable)]
#[valuable(transparent, rename = "a")]
struct Transparent4 {
f: (),
}

#[derive(Valuable)]
#[valuable(skip)]
struct Skip1 {
f: (),
}
#[derive(Valuable)]
#[valuable(skip)]
enum Skip2 {
#[valuable(skip)]
V(()),
}
#[derive(Valuable)]
struct Skip3 {
#[valuable(skip, rename = "a")]
f: (),
}

fn main() {}
63 changes: 63 additions & 0 deletions tests/tests/ui/unexpected.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
error: expected string literal
--> tests/ui/unexpected.rs:5:25
|
5 | #[valuable(rename = b)]
| ^

error: expected string literal
--> tests/ui/unexpected.rs:10:25
|
10 | #[valuable(rename = 'b')]
| ^^^

error: #[valuable(transparent)] may only be used on structs
--> tests/ui/unexpected.rs:16:16
|
16 | #[valuable(transparent)]
| ^^^^^^^^^^^

error: #[valuable(transparent)] may only be used on structs
--> tests/ui/unexpected.rs:20:12
|
20 | #[valuable(transparent)]
| ^^^^^^^^^^^

error: #[valuable(transparent)] struct needs exactly one field, but has 2
--> tests/ui/unexpected.rs:25:1
|
25 | / #[valuable(transparent)]
26 | | struct Transparent3 {
27 | | f1: (),
28 | | f2: (),
29 | | }
| |_^

error: #[valuable(transparent)] may not be used together with #[valuable(rename)]
--> tests/ui/unexpected.rs:31:25
|
31 | #[valuable(transparent, rename = "a")]
| ^^^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:37:12
|
37 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:42:12
|
42 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may only be used on fields
--> tests/ui/unexpected.rs:44:16
|
44 | #[valuable(skip)]
| ^^^^

error: #[valuable(skip)] may not be used together with #[valuable(rename)]
--> tests/ui/unexpected.rs:49:22
|
49 | #[valuable(skip, rename = "a")]
| ^^^^^^
Loading