#![cfg(all(feature = "derive", feature = "assert"))]
use std::fmt::Display;
use tabled::{assert::test_table, Table, Tabled};
use super::{sstr, test_enum, test_struct, test_tuple};
test_tuple!(
display_option,
declare: { { u8 #[tabled(display = "display_option")] Option<sstr> } }
init: {
fn display_option(o: &Option<sstr>) -> String {
match o {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some v2"] }
);
test_tuple!(
display_option_args,
declare: { { u8 #[tabled(display("display_option", 1, "234"))] Option<sstr> } }
init: {
fn display_option(_opt: &Option<sstr>, val: usize, text: &str) -> String {
format!("some {val} {text}")
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some 1 234"] }
);
test_tuple!(
display_option_self,
declare: { { u8 #[tabled(display = "Self::display_option")] Option<sstr> } }
init: {
impl Test {
fn display_option(o: &Option<sstr>) -> String {
match o {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some v2"] }
);
test_tuple!(
display_option_self_2,
declare: { { u8 #[tabled(display("Self::display_option", self))] Option<sstr> } }
init: {
impl Test {
fn display_option(_opt: &Option<sstr>, o: &Test) -> String {
match o.1 {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some v2"] }
);
test_tuple!(
display_option_self_3,
declare: { { u8 #[tabled(display("display_option", self))] Option<sstr> } }
init: {
fn display_option(_opt: &Option<sstr>, o: &Test) -> String {
match o.1 {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some v2"] }
);
test_tuple!(
display_option_self_4,
declare: { { u8 #[tabled(display("display_option", self.0, self.0))] Option<sstr> } }
init: {
fn display_option(_opt: &Option<sstr>, o1: u8, o2: u8) -> String {
format!("some {o1}.{o2}")
}
}
define: { 0 Some("v2") }
assert_headers: { ["0", "1"] }
assert_fields: { ["0", "some 0.0"] }
);
test_enum!(
enum_with_display,
declare: {
{
#[tabled(inline)]
A(
#[tabled(display = "format::<4>")]
sstr
)
B
}
}
init: {
fn format<const ID: usize>(_: sstr) -> String {
ID.to_string()
}
}
assert_headers: { ["0", "B"] }
assert: {
A("") => ["4", ""],
B => ["", "+"],
}
);
test_enum!(
enum_with_display_self,
declare: {
{
#[tabled(inline)]
A(
#[tabled(display("Self::format::<4>", self))]
sstr
)
B
}
}
init: {
impl Test {
fn format<const ID: usize>(_opt: &sstr, _: &Self) -> String {
ID.to_string()
}
}
}
assert_headers: { ["0", "B"] }
assert: {
A("") => ["4", ""],
B => ["", "+"],
}
);
test_enum!(
enum_with_display_self_complex_0,
declare: {
{
#[tabled(inline)]
A(
#[tabled(display("Self::format::<4>", self, self.0))]
sstr
)
B
}
}
init: {
impl Test {
fn format<const ID: usize>(_opt: &sstr, _: &Self, _: sstr) -> String {
ID.to_string()
}
}
}
assert_headers: { ["0", "B"] }
assert: {
A("") => ["4", ""],
B => ["", "+"],
}
);
test_enum!(
enum_with_display_self_complex_1,
declare: {
{
#[tabled(inline)]
A{
#[tabled(display("Self::format::<4>", self, self.asd))]
asd: sstr
}
B
}
}
init: {
impl Test {
fn format<const ID: usize>(_opt: &sstr, _: &Self, _: sstr) -> String {
ID.to_string()
}
}
}
assert_headers: { ["asd", "B"] }
assert: {
A { asd: "" } => ["4", ""],
B => ["", "+"],
}
);
test_enum!(
enum_display_with_variant,
declare: {
{
#[tabled(display = "display_variant1")]
AbsdEgh { a: u8, b: i32 }
#[tabled(display = "display_variant2::<200>")]
B(String)
K
}
}
init: {
fn display_variant1(_: &Test) -> &'static str {
"Hello World"
}
fn display_variant2<const VAL: usize>(_: &Test) -> String {
format!("asd {VAL}")
}
}
assert_headers: { ["AbsdEgh", "B", "K"] }
assert: {
AbsdEgh { a: 0, b: 0 } => ["Hello World", "", ""],
B(String::new()) => ["", "asd 200", ""],
K => ["", "", "+"],
}
);
test_enum!(
enum_display_with_self_variant,
declare: {
{
#[tabled(display("display_variant1", self))]
AbsdEgh { a: u8, b: i32 }
#[tabled(display("display_variant2::<200, _>", self))]
B(String)
K
}
}
init: {
fn display_variant1<D>(_: &Test, _: &D) -> &'static str {
"Hello World"
}
fn display_variant2<const VAL: usize, D>(_: &Test, _: &D) -> String {
format!("asd {VAL}")
}
}
assert_headers: { ["AbsdEgh", "B", "K"] }
assert: {
AbsdEgh { a: 0, b: 0 } => ["Hello World", "", ""],
B(String::new()) => ["", "asd 200", ""],
K => ["", "", "+"],
}
);
test_enum!(
enum_display_with_arguments,
declare: {
{
#[tabled(display("display1", 1, 2, self))]
AbsdEgh { a: u8, b: i32 }
#[tabled(display("display2::<200>", "Hello World"))]
B(String)
#[tabled(display("display1", 100, 200, self))]
K
}
}
init: {
fn display1<D>(_: &Test, val: usize, val2: usize, _: &D) -> String {
format!("{val} {val2}")
}
fn display2<const VAL: usize>(_: &Test, val: &str) -> String {
format!("asd {VAL} {val}")
}
}
assert_headers: { ["AbsdEgh", "B", "K"] }
assert: {
AbsdEgh { a: 0, b: 0 } => ["1 2", "", ""],
B(String::new()) => ["", "asd 200 Hello World", ""],
K => ["", "", "100 200"],
}
);
test_struct!(
struct_display_with,
declare: {
{
f1: u8,
#[tabled(display = "display_option")]
f2: Option<sstr>,
}
}
init: {
fn display_option(o: &Option<sstr>) -> String {
match o {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "some v2"] }
);
test_struct!(
struct_display_with_args,
declare: {
{
f1: u8,
#[tabled(display("display_option", 1, 2, 3))]
f2: Option<sstr>,
}
}
init: {
fn display_option(_opt: &Option<sstr>, v1: usize, v2: usize, v3: usize) -> String {
format!("{v1} {v2} {v3}")
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "1 2 3"] }
);
test_struct!(
struct_display_with_args_using_self,
declare: {
{
f1: u8,
#[tabled(display("display_option", &self.f1, 2, 3))]
f2: Option<sstr>,
}
}
init: {
fn display_option(_opt: &Option<sstr>, v1: &u8, v2: usize, v3: usize) -> String {
format!("{v1} {v2} {v3}")
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "0 2 3"] }
);
test_struct!(
struct_display_with_self_static_method,
declare: {
{
f1: u8,
#[tabled(display = "Self::display_option")]
f2: Option<sstr>,
}
}
init: {
impl Test {
fn display_option(o: &Option<sstr>) -> String {
match o {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "some v2"] }
);
test_struct!(
struct_display_with_self_static_method_2,
declare: {
{
f1: u8,
#[tabled(display("Self::display_option", self))]
f2: Option<sstr>,
}
}
init: {
impl Test {
fn display_option(_opt: &Option<sstr>, o: &Test) -> String {
match o.f2 {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "some v2"] }
);
test_struct!(
struct_display_with_self_2_self_static_method_2,
declare: {
{
f1: u8,
#[tabled(display("Self::display_option", self))]
f2: Option<sstr>,
}
}
init: {
impl Test {
fn display_option(_opt: &Option<sstr>, s: &Self) -> String {
match s.f2 {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "some v2"] }
);
test_struct!(
struct_display_with_self_2_self_static_method,
declare: {
{
f1: u8,
#[tabled(display("display_option", self))]
f2: Option<sstr>,
}
}
init: {
fn display_option(_opt: &Option<sstr>, o: &Test) -> String {
match o.f2 {
Some(s) => format!("some {s}"),
None => "none".to_string(),
}
}
}
define: { f1: 0, f2: Some("v2") }
assert_headers: { ["f1", "f2"] }
assert_fields: { ["0", "some v2"] }
);
test_struct!(
struct_display_with_args_using_self_array_and_func,
declare: {
{
#[tabled(skip)]
f1: [u8; 4],
#[tabled(display("display_option", &[self.f1[0], self.f1[1]], ToString::to_string(&self.f3.to_string())))]
f2: Option<sstr>,
f3: usize,
}
}
init: {
fn display_option(_opt: &Option<sstr>, v1: &[u8; 2], v4: String) -> String {
format!("{} {} {v4}", v1[0], v1[1])
}
}
define: { f1: [0, 1, 2, 3], f2: Some("v2"), f3: 100 }
assert_headers: { ["f2", "f3"] }
assert_fields: { ["0 1 100", "100"] }
);
#[test]
#[allow(dead_code)]
fn test_macros_in_display_with() {
#[derive(Tabled)]
#[tabled(rename_all = "camelCase")]
struct Country {
name: String,
#[tabled(display("display_capital", format!(".{}", self.capital)))]
capital: String,
#[tabled(display("display_perimeter", self))]
area_km2: f32,
#[tabled(display = "str::to_lowercase")]
national_currency: String,
national_currency_short: String,
}
fn display_perimeter(_area: &f32, country: &Country) -> sstr {
if country.area_km2 > 1_000_000.0 {
"Very Big Land"
} else {
"Big Land"
}
}
fn display_capital(_capital: &str, country: String) -> std::borrow::Cow<'static, str> {
format!("{country}!").into()
}
}
#[cfg(test)]
mod test_display_enum {
use super::*;
#[derive(Tabled)]
pub enum User {
#[tabled(display("some::bar::user_fmt"))]
Public { id: usize },
#[tabled(display("user_fmt"))]
Private { id: usize },
}
fn user_fmt(_: &User) -> String {
String::from("...")
}
pub mod some {
pub mod bar {
pub fn user_fmt(_: &super::super::User) -> String {
String::from("111")
}
}
}
test_table!(
test_display_enum,
{
let data = [
User::Public { id: 0 },
User::Private { id: 1 },
];
Table::new(data)
},
"+--------+---------+"
"| Public | Private |"
"+--------+---------+"
"| 111 | |"
"+--------+---------+"
"| | ... |"
"+--------+---------+"
);
}
test_table!(
test_display_type_0,
{
#[derive(Tabled)]
#[tabled(display(Password, "password_fmt"))]
struct User {
id: usize,
pass: Password,
mirrow: Password,
}
struct Password([u8; 4]);
fn password_fmt(p: &Password) -> String {
p.0.iter().sum::<u8>().to_string()
}
let data = [
User { id: 0, pass: Password([0, 1, 2, 3]), mirrow: Password([1, 1, 1, 1]) },
User { id: 1, pass: Password([1, 1, 2, 3]), mirrow: Password([2, 2, 1, 1]) },
];
Table::new(data)
},
"+----+------+--------+"
"| id | pass | mirrow |"
"+----+------+--------+"
"| 0 | 6 | 4 |"
"+----+------+--------+"
"| 1 | 7 | 6 |"
"+----+------+--------+"
);
test_table!(
test_display_type_args,
{
#[derive(Tabled)]
#[tabled(display(Password, "password_fmt", self, 0))]
struct User {
id: usize,
pass: Password,
mirrow: Password,
}
struct Password([u8; 4]);
fn password_fmt(p: &Password, _: &User, _: usize) -> String {
p.0.iter().sum::<u8>().to_string()
}
let data = [
User {
id: 0,
pass: Password([0, 1, 2, 3]),
mirrow: Password([1, 1, 1, 1]),
},
User {
id: 1,
pass: Password([1, 1, 2, 3]),
mirrow: Password([2, 2, 1, 1]),
},
];
Table::new(data)
},
"+----+------+--------+"
"| id | pass | mirrow |"
"+----+------+--------+"
"| 0 | 6 | 4 |"
"+----+------+--------+"
"| 1 | 7 | 6 |"
"+----+------+--------+"
);
test_table!(
test_display_type_generic,
{
#[derive(Tabled)]
#[tabled(display(Password, "password_fmt"))]
struct User {
id: usize,
pass: Password<usize>,
mirrow: Password<u8>,
}
struct Password<T>([T; 4]);
fn password_fmt<T>(p: &Password<T>) -> String where T: Display {
p.0.iter().map(|s| s.to_string()).collect::<Vec<_>>().join("-")
}
let data = [
User {
id: 0,
pass: Password([0, 1, 2, 3]),
mirrow: Password([1, 1, 1, 1]),
},
User {
id: 1,
pass: Password([1, 1, 2, 3]),
mirrow: Password([2, 2, 1, 1]),
},
];
Table::new(data)
},
"+----+---------+---------+"
"| id | pass | mirrow |"
"+----+---------+---------+"
"| 0 | 0-1-2-3 | 1-1-1-1 |"
"+----+---------+---------+"
"| 1 | 1-1-2-3 | 2-2-1-1 |"
"+----+---------+---------+"
);
test_table!(
test_display_type_generic_use,
{
#[derive(Tabled)]
#[tabled(display(Password<usize>, "password_usize_fmt"))]
#[tabled(display(Password<u8>, "password_u8_fmt"))]
struct User {
id: usize,
pass: Password<usize>,
mirrow: Password<u8>,
}
struct Password<T>([T; 4]);
fn password_usize_fmt(p: &Password<usize>) -> String {
p.0.iter().sum::<usize>().to_string()
}
fn password_u8_fmt(p: &Password<u8>) -> String {
p.0.iter().sum::<u8>().to_string()
}
let data = [
User {
id: 0,
pass: Password([0, 1, 2, 3]),
mirrow: Password([1, 1, 1, 1]),
},
User {
id: 1,
pass: Password([1, 1, 2, 3]),
mirrow: Password([2, 2, 1, 1]),
},
];
Table::new(data)
},
"+----+------+--------+"
"| id | pass | mirrow |"
"+----+------+--------+"
"| 0 | 6 | 4 |"
"+----+------+--------+"
"| 1 | 7 | 6 |"
"+----+------+--------+"
);
test_struct!(
display_with_and_rename,
declare: {
{
f1: sstr,
f2: sstr,
#[tabled(display = "print", rename = "asd")]
f3: usize,
}
}
init: {
fn print<T>(_: T) -> String { String::new() }
}
define: { f1: "123", f2: "456", f3: 789 }
assert_headers: { ["f1", "f2", "asd"] }
assert_fields: { ["123", "456", ""] }
);
test_struct!(
display_with_and_rename_2,
declare: {
{
f1: sstr,
f2: sstr,
#[tabled(display = "print")]
#[tabled(rename = "asd")]
f3: usize,
}
}
init: {
fn print<T>(_: T) -> String { String::new() }
}
define: { f1: "123", f2: "456", f3: 789 }
assert_headers: { ["f1", "f2", "asd"] }
assert_fields: { ["123", "456", ""] }
);
test_struct!(
display_with_and_rename_all,
declare: {
{
f1: sstr,
f2: sstr,
#[tabled(display = "print", rename_all = "UPPERCASE")]
f3: usize,
}
}
init: {
fn print<T>(_: T) -> String { String::new() }
}
define: { f1: "123", f2: "456", f3: 789 }
assert_headers: { ["f1", "f2", "F3"] }
assert_fields: { ["123", "456", ""] }
);