use borrowize::View;
use std::path::Path;
#[derive(Debug, PartialEq, Eq)]
struct Tag(&'static str);
#[derive(View)]
struct User {
id: u64,
name: String,
tags: Vec<Tag>,
}
#[test]
fn creates_default_borrowed_view() {
let user = User {
id: 7,
name: "Ada".to_owned(),
tags: vec![Tag("admin"), Tag("editor")],
};
let view = user.view();
assert_eq!(*view.id, 7);
assert_eq!(view.name, "Ada");
assert_eq!(view.tags, [Tag("admin"), Tag("editor")]);
}
#[test]
fn manual_default_view_matches_automatic_view() {
let user = User {
id: 8,
name: "Grace".to_owned(),
tags: vec![Tag("operator")],
};
let automatic = user.view();
let manual = UserView {
id: &user.id,
name: user.name.as_str(),
tags: user.tags.as_slice(),
};
assert_user_views_eq(&manual, &automatic);
}
fn assert_user_views_eq(left: &UserView<'_>, right: &UserView<'_>) {
assert_eq!(left.id, right.id);
assert_eq!(left.name, right.name);
assert_eq!(left.tags, right.tags);
}
#[derive(View)]
struct CommonTypes<'a> {
label: &'a str,
bytes: [u8; 3],
maybe_name: Option<String>,
maybe_id: Option<u64>,
boxed: Box<u64>,
path: std::path::PathBuf,
}
#[test]
fn maps_common_owned_types() {
let value = CommonTypes {
label: "source",
bytes: [1, 2, 3],
maybe_name: Some("Grace".to_owned()),
maybe_id: Some(11),
boxed: Box::new(13),
path: Path::new("/tmp/borrowize").to_path_buf(),
};
let view = value.view();
assert_eq!(view.label, "source");
assert_eq!(view.bytes, &[1, 2, 3]);
assert_eq!(view.maybe_name, Some("Grace"));
assert_eq!(view.maybe_id, Some(&11));
assert_eq!(*view.boxed, 13);
assert_eq!(view.path, Path::new("/tmp/borrowize"));
}
#[test]
fn supports_manual_view_construction_with_visibility_overrides() {
let (id, name) = visibility_boundaries::sibling::public_field_access();
let restricted_data = visibility_boundaries::sibling::restricted_field_access();
assert_eq!(*id, 21);
assert_eq!(name, "manual");
assert_eq!(restricted_data, &[3, 5, 8]);
}
mod visibility_boundaries {
pub mod source {
use borrowize::View;
#[derive(View)]
#[borrowize(view_visibility = "pub", field_visibility = "pub", no_method)]
#[allow(dead_code)]
pub struct PublicSource {
id: u64,
name: String,
}
#[derive(View)]
#[borrowize(
view_name = "RestrictedView",
view_visibility = "pub",
field_visibility = "pub",
no_method
)]
#[allow(dead_code)]
pub struct RestrictedSource {
label: String,
#[borrowize(borrowed_type = "&'borrowize [u8]", visibility = "pub(super)")]
data: Vec<u8>,
}
}
pub mod sibling {
const ID: u64 = 21;
const DATA: &[u8] = &[3, 5, 8];
pub fn public_field_access() -> (&'static u64, &'static str) {
let view = super::source::PublicSourceView {
id: &ID,
name: "manual",
};
(view.id, view.name)
}
pub fn restricted_field_access() -> &'static [u8] {
let view = super::source::RestrictedView {
label: "restricted",
data: DATA,
};
view.data
}
}
}
#[derive(View)]
#[borrowize(method_name = "as_encoded_view", method_visibility = "pub")]
struct Encoded {
#[borrowize(
borrowed_type = "&'borrowize str",
generation_expression = "::std::str::from_utf8(&self.bytes).expect(\"test input is utf8\")"
)]
bytes: Vec<u8>,
}
#[test]
fn supports_method_and_generation_expression_overrides() {
let encoded = Encoded {
bytes: b"payload".to_vec(),
};
let view = encoded.as_encoded_view();
assert_eq!(view.bytes, "payload");
}
#[derive(View)]
enum Event<'a> {
Created {
id: u64,
name: String,
tags: Vec<Tag>,
borrowed: &'a Tag,
maybe_name: Option<String>,
maybe_borrowed: Option<&'a Tag>,
},
Empty,
}
#[test]
fn creates_borrowed_view_for_named_enum_variants() {
let tag = Tag("primary");
let event = Event::Created {
id: 34,
name: "enum".to_owned(),
tags: vec![Tag("first"), Tag("second")],
borrowed: &tag,
maybe_name: Some("maybe".to_owned()),
maybe_borrowed: Some(&tag),
};
let view = event.view();
match view {
EventView::Created {
id,
name,
tags,
borrowed,
maybe_name,
maybe_borrowed,
} => {
assert_eq!(*id, 34);
assert_eq!(name, "enum");
assert_eq!(tags, [Tag("first"), Tag("second")]);
assert_eq!(borrowed, &tag);
assert_eq!(maybe_name, Some("maybe"));
assert_eq!(maybe_borrowed, Some(&tag));
}
EventView::Empty => panic!("expected created view"),
}
}
#[test]
fn creates_borrowed_view_for_unit_enum_variants() {
let event = Event::Empty;
let view = event.view();
match view {
EventView::Empty => {}
EventView::Created { .. } => panic!("expected empty view"),
}
}
#[derive(View)]
#[allow(dead_code)]
enum GenericEnum<'a, T, const N: usize>
where
T: 'a,
{
Items {
values: Vec<T>,
borrowed: &'a T,
fixed: [u8; N],
},
Empty,
}
#[test]
fn preserves_generics_and_where_clauses_on_enums() {
let item = 89;
let value = GenericEnum::Items {
values: vec![3, 5, 8],
borrowed: &item,
fixed: [1, 2, 3],
};
let view = value.view();
match view {
GenericEnumView::Items {
values,
borrowed,
fixed,
} => {
assert_eq!(values, &[3, 5, 8]);
assert_eq!(*borrowed, 89);
assert_eq!(fixed, &[1, 2, 3]);
}
GenericEnumView::Empty => panic!("expected items view"),
}
}
#[derive(View)]
#[borrowize(view_name = "WireView", method_name = "as_wire_view")]
#[allow(dead_code)]
enum Wire {
Data {
#[borrowize(
borrowed_type = "&'borrowize str",
generation_expression = "::std::str::from_utf8(bytes).expect(\"test input is utf8\")"
)]
bytes: Vec<u8>,
},
Empty,
}
#[test]
fn supports_enum_field_overrides() {
let value = Wire::Data {
bytes: b"payload".to_vec(),
};
let view = value.as_wire_view();
match view {
WireView::Data { bytes } => assert_eq!(bytes, "payload"),
WireView::Empty => panic!("expected data view"),
}
}
#[derive(View)]
struct Generic<'a, T, const N: usize>
where
T: 'a,
{
name: String,
items: Vec<T>,
borrowed: &'a T,
fixed: [u8; N],
}
#[test]
fn preserves_generics_and_where_clauses() {
let item = 42;
let value = Generic {
name: "generic".to_owned(),
items: vec![1, 2],
borrowed: &item,
fixed: [9, 8],
};
let view = value.view();
assert_eq!(view.name, "generic");
assert_eq!(view.items, &[1, 2]);
assert_eq!(*view.borrowed, 42);
assert_eq!(view.fixed, &[9, 8]);
}