Skip to content

Commit

Permalink
Add no_implicit_prelude to proc macro tests (#2033)
Browse files Browse the repository at this point in the history
* Add no_implicit_prelude to derive_props test

* Add no_implicit_prelude to html_macro tests

* Fix function_component macro tests

function_component macro tests weren't being run by try build due to
change in dir name. Imports corrected now that function_component is now
in yew.

Adds no_implicit_prelude to *-pass tests

* Add no_implicit_prelude to props_macro tests

* fix typo in comment
  • Loading branch information
mc1098 authored Sep 5, 2021
1 parent df3303f commit 58753d9
Show file tree
Hide file tree
Showing 42 changed files with 400 additions and 355 deletions.
56 changes: 54 additions & 2 deletions packages/yew-macro/src/derive_props/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::cmp::{Ord, Ordering, PartialEq, PartialOrd};
use std::convert::TryFrom;
use syn::parse::Result;
use syn::spanned::Spanned;
use syn::{Error, Expr, Field, Type, TypePath, Visibility};
use syn::{Error, Expr, Field, Path, Type, TypePath, Visibility};

#[allow(clippy::large_enum_variant)]
#[derive(PartialEq, Eq)]
Expand Down Expand Up @@ -167,7 +167,7 @@ impl PropField {
} else if matches!(
&named_field.ty,
Type::Path(TypePath { path, .. })
if path.segments.len() == 1 && path.segments[0].ident == "Option"
if is_path_an_option(path)
) {
Ok(PropAttr::Option)
} else {
Expand All @@ -178,6 +178,36 @@ impl PropField {
}
}

fn is_path_segments_an_option(path_segments: impl Iterator<Item = String>) -> bool {
fn is_option_path_seg(seg_index: usize, path: &str) -> u8 {
match (seg_index, path) {
(0, "core") => 0b001,
(0, "std") => 0b001,
(0, "Option") => 0b111,
(1, "option") => 0b010,
(2, "Option") => 0b100,
_ => 0,
}
}

path_segments
.enumerate()
.fold(0, |flags, (i, ps)| flags | is_option_path_seg(i, &ps))
== 0b111
}

/// Returns true when the [`Path`] seems like an [`Option`] type.
///
/// This function considers the following paths as Options:
/// - core::option::Option
/// - std::option::Option
/// - Option::*
///
/// Users can define their own [`Option`] type and this will return true - this is unavoidable.
fn is_path_an_option(path: &Path) -> bool {
is_path_segments_an_option(path.segments.iter().take(3).map(|ps| ps.ident.to_string()))
}

impl TryFrom<Field> for PropField {
type Error = Error;

Expand Down Expand Up @@ -223,3 +253,25 @@ impl PartialEq for PropField {
self.name == other.name
}
}

#[cfg(test)]
mod tests {
use crate::derive_props::field::is_path_segments_an_option;

#[test]
fn all_std_and_core_option_path_seg_return_true() {
assert!(is_path_segments_an_option(
vec!["core".to_owned(), "option".to_owned(), "Option".to_owned()].into_iter()
));
assert!(is_path_segments_an_option(
vec!["std".to_owned(), "option".to_owned(), "Option".to_owned()].into_iter()
));
assert!(is_path_segments_an_option(
vec!["Option".to_owned()].into_iter()
));
// why OR instead of XOR
assert!(is_path_segments_an_option(
vec!["Option".to_owned(), "Vec".to_owned(), "Option".to_owned()].into_iter()
));
}
}
4 changes: 2 additions & 2 deletions packages/yew-macro/src/html_tree/html_component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ impl ToTokens for HtmlComponent {
let value = &node_ref.value;
quote_spanned! {value.span()=> #value }
} else {
quote! { ::yew::html::NodeRef::default() }
quote! { <::yew::html::NodeRef as ::std::default::Default>::default() }
};

let key = if let Some(key) = &special_props.key {
Expand All @@ -118,7 +118,7 @@ impl ToTokens for HtmlComponent {
Some(::std::convert::Into::<::yew::virtual_dom::Key>::into(#value))
}
} else {
quote! { None }
quote! { ::std::option::Option::None }
};

tokens.extend(quote_spanned! {ty.span()=>
Expand Down
2 changes: 1 addition & 1 deletion packages/yew-macro/src/html_tree/html_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl ToTokens for HtmlElement {
::std::borrow::Cow::<'static, str>::Borrowed(#key)
)
} else {
None
::std::option::Option::None
}
}),
},
Expand Down
120 changes: 61 additions & 59 deletions packages/yew-macro/tests/derive_props/pass.rs
Original file line number Diff line number Diff line change
@@ -1,82 +1,85 @@
#![no_implicit_prelude]
#![recursion_limit = "128"]

use yew::prelude::*;

mod t1 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
pub struct Props<T: Clone + Default + PartialEq> {
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq> {
#[prop_or_default]
value: T,
}

fn optional_prop_generics_should_work() {
use ::yew::Properties;

Props::<bool>::builder().build();
Props::<bool>::builder().value(true).build();
}
}

mod t2 {
use super::*;

#[derive(Clone, PartialEq)]
#[derive(::std::clone::Clone, ::std::cmp::PartialEq)]
struct Value;
#[derive(Clone, Properties, PartialEq)]
pub struct Props<T: Clone + PartialEq> {
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<T: ::std::clone::Clone + ::std::cmp::PartialEq> {
value: T,
}

fn required_prop_generics_should_work() {
use ::yew::Properties;

Props::<Value>::builder().value(Value).build();
}
}

mod t3 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props {
b: i32,
#[prop_or_default]
a: i32,
}

fn order_is_alphabetized() {
use ::yew::Properties;

Props::builder().b(1).build();
Props::builder().a(1).b(2).build();
}
}

mod t4 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<T>
where
T: Clone + Default + PartialEq,
T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq,
{
#[prop_or_default]
value: T,
}

fn optional_prop_generics_should_work() {
use ::yew::Properties;

Props::<bool>::builder().build();
Props::<bool>::builder().value(true).build();
}
}

mod t5 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
pub struct Props<'a, T: Clone + Default + PartialEq + 'a> {
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<
'a,
T: ::std::clone::Clone + ::std::default::Default + ::std::cmp::PartialEq + 'a,
> {
#[prop_or_default]
static_value: &'static str,
value: &'a T,
}

fn optional_prop_generics_with_lifetime_should_work() {
use ::std::{convert::From, string::String};
use ::yew::Properties;

Props::<String>::builder().value(&String::from("")).build();
Props::<String>::builder()
.static_value("")
Expand All @@ -86,128 +89,127 @@ mod t5 {
}

mod t6 {
use super::*;
use std::str::FromStr;

#[derive(Properties, Clone, PartialEq)]
pub struct Props<T: FromStr + Clone + PartialEq>
#[derive(::yew::Properties, ::std::clone::Clone, ::std::cmp::PartialEq)]
pub struct Props<T: ::std::str::FromStr + ::std::clone::Clone + ::std::cmp::PartialEq>
where
<T as FromStr>::Err: Clone + PartialEq,
<T as ::std::str::FromStr>::Err: ::std::clone::Clone + ::std::cmp::PartialEq,
{
value: Result<T, <T as FromStr>::Err>,
value: ::std::result::Result<T, <T as ::std::str::FromStr>::Err>,
}

fn required_prop_generics_with_where_clause_should_work() {
use ::std::{convert::From, result::Result::Ok, string::String};
use ::yew::Properties;

Props::<String>::builder()
.value(Ok(String::from("")))
.build();
}
}

mod t7 {
use super::*;

#[derive(Clone, Debug, Eq, PartialEq)]
#[derive(::std::clone::Clone, Debug, Eq, ::std::cmp::PartialEq)]
pub enum Foo {
One,
Two,
}

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props {
#[prop_or(Foo::One)]
value: Foo,
}

fn prop_or_value_should_work() {
use ::std::assert_eq;
use ::yew::Properties;

let props = Props::builder().build();
assert_eq!(props.value, Foo::One);
Props::builder().value(Foo::Two).build();
}
}

mod t8 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props {
#[prop_or_else(|| 123)]
value: i32,
}

fn prop_or_else_closure_should_work() {
use ::std::assert_eq;
use ::yew::Properties;

let props = Props::builder().build();
assert_eq!(props.value, 123);
Props::builder().value(123).build();
}
}

mod t9 {
use super::*;
use std::str::FromStr;

#[derive(Clone, Properties, PartialEq)]
pub struct Props<T: FromStr + Clone + PartialEq>
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<T: ::std::str::FromStr + ::std::clone::Clone + ::std::cmp::PartialEq>
where
<T as FromStr>::Err: Clone + PartialEq,
<T as ::std::str::FromStr>::Err: ::std::clone::Clone + ::std::cmp::PartialEq,
{
#[prop_or_else(default_value)]
value: Result<T, <T as FromStr>::Err>,
value: ::std::result::Result<T, <T as ::std::str::FromStr>::Err>,
}

fn default_value<T: FromStr + Clone>() -> Result<T, <T as FromStr>::Err>
fn default_value<T: ::std::str::FromStr + ::std::clone::Clone>(
) -> ::std::result::Result<T, <T as ::std::str::FromStr>::Err>
where
<T as FromStr>::Err: Clone,
<T as ::std::str::FromStr>::Err: ::std::clone::Clone,
{
"123".parse()
}

fn prop_or_else_function_with_generics_should_work() {
use ::std::{assert_eq, result::Result::Ok};
use ::yew::Properties;

let props = Props::<i32>::builder().build();
assert_eq!(props.value, Ok(123));
Props::<i32>::builder().value(Ok(456)).build();
}
}

mod t10 {
use super::*;

// this test makes sure that Yew handles generic params with default values properly.

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Foo<S, M = S>
where
S: Clone + PartialEq,
M: Clone + PartialEq,
S: ::std::clone::Clone + ::std::cmp::PartialEq,
M: ::std::clone::Clone + ::std::cmp::PartialEq,
{
bar: S,
baz: M,
}
}

mod t11 {
use super::*;

// this test makes sure that Yew handles generic params with const generics properly.

#[derive(Clone, Properties, PartialEq)]
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Foo<T, const N: usize>
where
T: Clone + PartialEq,
T: ::std::clone::Clone + ::std::cmp::PartialEq,
{
bar: [T; N],
}
}

mod t12 {
use super::*;

#[derive(Clone, Properties, PartialEq)]
pub struct Props<T: Clone + PartialEq> {
value: Option<T>,
#[derive(::std::clone::Clone, ::yew::Properties, ::std::cmp::PartialEq)]
pub struct Props<T: ::std::clone::Clone + ::std::cmp::PartialEq> {
value: ::std::option::Option<T>,
}

fn optional_prop_generics_should_work() {
use ::yew::Properties;

Props::<bool>::builder().build();
Props::<bool>::builder().value(true).build();
}
Expand Down
4 changes: 2 additions & 2 deletions packages/yew-macro/tests/function_attr_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
#[rustversion::attr(stable(1.51), test)]
fn tests() {
let t = trybuild::TestCases::new();
t.pass("tests/function_attr/*-pass.rs");
t.compile_fail("tests/function_attr/*-fail.rs");
t.pass("tests/function_component_attr/*-pass.rs");
t.compile_fail("tests/function_component_attr/*-fail.rs");
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use yew::prelude::*;
use yew_functional::function_component;

#[derive(Clone, Properties, PartialEq)]
struct Props {
Expand Down
Loading

0 comments on commit 58753d9

Please sign in to comment.