diff options
Diffstat (limited to 'plugins/warp/tests/container.rs')
| -rw-r--r-- | plugins/warp/tests/container.rs | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/plugins/warp/tests/container.rs b/plugins/warp/tests/container.rs new file mode 100644 index 00000000..31b47377 --- /dev/null +++ b/plugins/warp/tests/container.rs @@ -0,0 +1,280 @@ +use std::collections::HashSet; +use std::path::PathBuf; +use std::str::FromStr; +use uuid::Uuid; +use warp::r#type::class::BooleanClass; +use warp::r#type::class::TypeClass::Void; +use warp::r#type::guid::TypeGUID; +use warp::r#type::{ComputedType, Type}; +use warp::signature::function::{Function, FunctionGUID}; +use warp::symbol::{Symbol, SymbolClass}; +use warp::target::Target; +use warp_ninja::container::disk::DiskContainer; +use warp_ninja::container::memory::{MemoryContainer, MemorySource}; +use warp_ninja::container::{Container, ContainerError, SourceId, SourcePath}; + +fn type_0() -> (TypeGUID, Type) { + let ty = Type::builder() + .name("type_0") + .class(BooleanClass::builder().width(1).build()) + .build(); + (TypeGUID::from(&ty), ty) +} + +fn type_1() -> (TypeGUID, Type) { + let ty = Type::builder() + .name("type_1") + .class(BooleanClass::builder().width(4).build()) + .build(); + (TypeGUID::from(&ty), ty) +} + +fn type_2() -> (TypeGUID, Type) { + let ty = Type::builder() + .name("type_2") + .class(BooleanClass::builder().width(8).build()) + .build(); + (TypeGUID::from(&ty), ty) +} + +fn func_0() -> (FunctionGUID, Function) { + let guid = FunctionGUID::from(Uuid::from_str("d4e56ec8-1f2b-4a87-9f2c-bc3f10c4d8e9").unwrap()); + let function = Function { + guid, + symbol: Symbol { + name: "func_0".to_string(), + modifiers: Default::default(), + class: SymbolClass::Function, + }, + // TODO: We might want to give this an actual function type. + ty: Some(Type::builder::<String, _>().class(Void).build()), + constraints: Default::default(), + comments: vec![], + variables: vec![], + }; + (guid, function) +} + +fn func_1() -> (FunctionGUID, Function) { + let guid = FunctionGUID::from(Uuid::from_str("b713c293-463a-5baa-b31b-ed010510d5c0").unwrap()); + let function = Function { + guid, + symbol: Symbol { + name: "func_1".to_string(), + modifiers: Default::default(), + class: SymbolClass::Function, + }, + // TODO: We might want to give this an actual function type. + ty: Some(Type::builder::<String, _>().class(Void).build()), + constraints: Default::default(), + comments: vec![], + variables: vec![], + }; + (guid, function) +} + +#[test] +fn test_sources_with_type_guid() { + let source1 = SourceId::new(); + let source2 = SourceId::new(); + let (guid_1, ty_1) = type_0(); + let (guid_2, ty_2) = type_1(); + + let container = MemoryContainer::new() + .with_source_type(source1, guid_1, ty_1) + .with_source_type(source1, guid_2, ty_2.clone()) + .with_source_type(source2, guid_2, ty_2); + + let result = container + .sources_with_type_guid(&guid_2) + .expect("Failed to get sources"); + // HashSet used for unordered comparison + let result_set: HashSet<_> = result.into_iter().collect(); + let expected_set: HashSet<_> = vec![source1, source2].into_iter().collect(); + assert_eq!(result_set, expected_set); + + let result = container + .sources_with_type_guid(&guid_1) + .expect("Failed to get sources"); + // HashSet used for unordered comparison + let result_set: HashSet<_> = result.into_iter().collect(); + let expected_set: HashSet<_> = vec![source1].into_iter().collect(); + assert_eq!(result_set, expected_set); +} + +#[test] +fn test_sources_with_function_guid() { + let target = Target::default(); + + let source1 = SourceId::new(); + let source2 = SourceId::new(); + let (guid_1, fn_1) = func_0(); + let (guid_2, fn_2) = func_1(); + + let container = MemoryContainer::new() + .with_source_function(source1, guid_1, fn_1) + .with_source_function(source1, guid_2, fn_2.clone()) + .with_source_function(source2, guid_2, fn_2); + + let result = container + .sources_with_function_guid(&target, &guid_2) + .expect("Failed to get sources"); + // HashSet used for unordered comparison + let result_set: HashSet<_> = result.into_iter().collect(); + let expected_set: HashSet<_> = vec![source1, source2].into_iter().collect(); + assert_eq!(result_set, expected_set); + + let result = container + .sources_with_function_guid(&target, &guid_1) + .expect("Failed to get sources"); + assert_eq!(result, vec![source1]); +} + +#[test] +fn test_sources_with_type_guids() { + let source1 = SourceId::new(); + let source2 = SourceId::new(); + let (guid_1, ty_1) = type_0(); + let (guid_2, ty_2) = type_1(); + let (guid_3, ty_3) = type_2(); + + let container = MemoryContainer::new() + .with_source_type(source1, guid_1, ty_1) + .with_source_type(source1, guid_2, ty_2.clone()) + .with_source_type(source2, guid_2, ty_2) + .with_source_type(source2, guid_3, ty_3); + + let result = container + .sources_with_type_guids(&[guid_2.clone(), guid_3.clone()]) + .expect("Failed to get sources"); + assert_eq!(result.len(), 2); + assert!(result.get(&guid_2).unwrap().contains(&source1)); + assert!(result.get(&guid_2).unwrap().contains(&source2)); + assert!(result.get(&guid_3).unwrap().contains(&source2)); +} + +#[test] +fn test_add_types() { + let source1 = SourceId::new(); + let source2 = SourceId::new(); + let (guid_1, ty_1) = type_0(); + let (guid_2, ty_2) = type_1(); + let mut container = MemoryContainer::new() + .with_source( + source1, + MemorySource { + writable: false, + ..Default::default() + }, + ) + .with_source_type(source1, guid_1, ty_1.clone()) + .with_source_type(source2, guid_2, ty_2.clone()); + + assert_eq!( + container.add_types(&source1, &[ty_1.clone()]), + Err(ContainerError::SourceNotWritable(source1)), + "Source should not be writable" + ); + assert_eq!( + container.add_types(&source2, &[ty_1.clone()]), + Ok(()), + "Source should be writable" + ); + container + .type_with_guid(&source1, &guid_1) + .expect("Failed to get existing type"); + container + .type_with_guid(&source2, &guid_1) + .expect("Failed to get added type"); + container + .type_with_guid(&source2, &guid_2) + .expect("Failed to get existing type"); +} + +#[test] +fn test_disk_container() { + // We are going to use the OUT_DIR as the disk container path, this might have other artifacts in it + // so it's a good test to make sure that we handle bad files gracefully. + let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR environment variable is not set"); + let out_dir_path: PathBuf = out_dir.parse().expect("Failed to parse OUT_DIR as path"); + + // TODO: Use a temp file for this instead lol. + let added_type_path = out_dir_path.join("added_type.warp"); + // Make sure that we have deleted the previous runs artifacts. + if std::fs::exists(&added_type_path).unwrap() { + std::fs::remove_file(&added_type_path).expect("Failed to remove existing file"); + } + + // Write a simple test to open a file with DiskContainer + let mut container = DiskContainer::new_from_dir(out_dir_path.clone()); + + // Just pass in the default target, there is no target specified in the file. + let target = Target::default(); + + // Test type retrieval. + // Type -> type_10 : 2f6d2876-ec42-5ca1-bee3-f12fe91d7e13 + let type_0 = TypeGUID::from(Uuid::from_str("2f6d2876-ec42-5ca1-bee3-f12fe91d7e13").unwrap()); + let sources: Vec<SourceId> = container + .sources_with_type_guid(&type_0) + .expect("Failed to get sources") + .into_iter() + .collect(); + assert_eq!(sources.len(), 1); + let result_type_0 = container + .type_with_guid(&sources[0], &type_0) + .expect("Failed to get type") + .expect("Type not found"); + assert_eq!(result_type_0.name, Some("type_10".to_string())); + let result_type_guids_0 = container + .type_guids_with_name(&sources[0], "type_10") + .expect("Failed to get type guids"); + assert_eq!(result_type_guids_0.len(), 1); + assert_eq!(result_type_guids_0[0], type_0); + + // Test function retrieval. + // Function -> function_95 : d5da0413-a020-5db8-b838-4d0ea8bd3dcb + let func_0 = + FunctionGUID::from(Uuid::from_str("d5da0413-a020-5db8-b838-4d0ea8bd3dcb").unwrap()); + let func_sources = container + .sources_with_function_guid(&target, &func_0) + .expect("Failed to get sources"); + assert_eq!(func_sources.len(), 1); + let result_func_0 = container + .functions_with_guid(&target, &func_sources[0], &func_0) + .expect("Failed to get functions"); + assert_eq!(result_func_0.len(), 1); + assert_eq!(result_func_0[0].symbol.name, "function_95".to_string()); + + // Test adding a type to an existing disk source. + let mut result_type_0_mut = result_type_0.clone(); + result_type_0_mut.name = Some("added_type".to_string()); + let computed_result_type_0 = ComputedType::new(result_type_0_mut); + container + .add_types(&sources[0], &[computed_result_type_0.ty]) + .expect("Failed to add type"); + let result_type_1 = container + .type_guids_with_name(&sources[0], "added_type") + .expect("Failed to get added type"); + assert_eq!( + result_type_1, + vec![computed_result_type_0.guid], + "Added type was not found in the existing source" + ); + + // Test commiting the updated source. + // NOTE: Because we don't want to modify the file, we are going to change the source path + // before trying to commit it, this is a bit hacky and should not really be done in real code. + let source = container + .sources + .get_mut(&sources[0]) + .expect("Container does not contain the source"); + source.path = SourcePath::new(out_dir_path.join("added_type.warp")); + container + .commit_source(&sources[0]) + .expect("Failed to commit source"); + assert_eq!( + std::fs::exists(&added_type_path).unwrap(), + true, + "File was not created" + ); +} |
