use indexmap::IndexMap;
use syn::{parse_quote, Type};
use crate::composable::TypeModel;
use crate::context::TypeChain;
use crate::kind::{ObjectKind};
use quote::ToTokens;
#[test]
fn type_chain_replace_unknown_with_refined() {
let mut chain = TypeChain::default();
let key: Type = parse_quote!(T);
chain.add_one(key.clone(), ObjectKind::unknown_type(parse_quote!(UnknownTy)));
assert_eq!(chain.get(&key).unwrap().maybe_type().unwrap(), parse_quote!(UnknownTy));
let refined = ObjectKind::object_model_type(TypeModel::new_default(parse_quote!(RefinedTy)));
chain.add_one(key.clone(), refined);
assert_eq!(chain.get(&key).unwrap().maybe_type().unwrap(), parse_quote!(RefinedTy));
}
#[test]
fn type_chain_keep_refined_over_non_bounds() {
let mut chain = TypeChain::default();
let key: Type = parse_quote!(K);
chain.add_one(key.clone(), ObjectKind::object_model_type(TypeModel::new_default(parse_quote!(Refined1))));
chain.add_one(key.clone(), ObjectKind::unknown_type(parse_quote!(SomethingElse)));
assert_eq!(chain.get(&key).unwrap().maybe_type().unwrap(), parse_quote!(Refined1));
}
#[test]
fn type_chain_replace_with_bounds() {
use crate::composable::GenericBoundsModel;
use crate::composer::CommaPunctuatedNestedArguments;
let mut chain = TypeChain::default();
let key: Type = parse_quote!(B);
chain.add_one(key.clone(), ObjectKind::object_model_type(TypeModel::new_default(parse_quote!(Refined2))));
let gb = GenericBoundsModel::new(&parse_quote!(T), IndexMap::new(), syn::Generics::default(), CommaPunctuatedNestedArguments::default());
chain.add_one(key.clone(), ObjectKind::bounds(gb));
assert_eq!(chain.get(&key).unwrap().maybe_type().unwrap(), parse_quote!(T));
}
#[test]
fn type_chain_replace_with_item_always() {
use crate::kind::ScopeItemKind;
let mut chain = TypeChain::default();
let key: Type = parse_quote!(C);
chain.add_one(key.clone(), ObjectKind::object_model_type(TypeModel::new_default(parse_quote!(BaseTy))));
let item: syn::ItemStruct = parse_quote!(struct S;);
let scope: syn::Path = parse_quote!(my_crate);
let item_kind = ScopeItemKind::item_struct(&item, &scope);
let ty_kind = crate::kind::TypeModelKind::Object(TypeModel::new_default(parse_quote!(NewTy)));
let candidate = ObjectKind::new_item(ty_kind, item_kind);
chain.add_one(key.clone(), candidate);
assert_eq!(chain.get(&key).unwrap().maybe_type().unwrap(), parse_quote!(NewTy));
}
#[test]
fn type_chain_selfless_filters_self_and_excluding_filters_non_generics() {
use syn::{Generics};
let mut chain = TypeChain::default();
chain.add_one(parse_quote!(Self), ObjectKind::unknown_type(parse_quote!(Foo)));
chain.add_one(parse_quote!(T), ObjectKind::unknown_type(parse_quote!(Foo)));
chain.add_one(parse_quote!(U), ObjectKind::unknown_type(parse_quote!(Bar)));
chain.add_one(parse_quote!(V), ObjectKind::unknown_type(parse_quote!(Baz)));
let selfless = chain.selfless();
assert!(selfless.inner.keys().all(|k| k.to_token_stream().to_string() != "Self"));
let gens: Generics = parse_quote!(<T, U>);
let filtered = chain.excluding_self_and_bounds(&gens);
let keys_str = filtered.inner.keys().map(|k| k.to_token_stream().to_string()).collect::<Vec<_>>();
assert!(keys_str.contains(&"V".to_string()));
assert!(!keys_str.contains(&"Self".to_string()));
assert!(!keys_str.contains(&"T".to_string()));
assert!(!keys_str.contains(&"U".to_string()));
}