diff --git a/Cargo.lock b/Cargo.lock index ad2d3fd..b048249 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,6 +346,12 @@ dependencies = [ "syn", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "fancy-regex" version = "0.13.0" @@ -472,6 +478,7 @@ dependencies = [ "regex", "serde", "serde_json", + "serde_yaml", "shellexpand", "thiserror 1.0.69", "tracing", @@ -498,6 +505,12 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "hashbrown" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" + [[package]] name = "heck" version = "0.5.0" @@ -731,6 +744,16 @@ dependencies = [ "icu_properties", ] +[[package]] +name = "indexmap" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "ipnet" version = "2.11.0" @@ -1266,6 +1289,19 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "sha1_smol" version = "1.0.1" @@ -1624,6 +1660,12 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "url" version = "2.5.7" diff --git a/Cargo.toml b/Cargo.toml index d2c43b6..9c04dc8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,6 @@ jsonschema = "0.18" # File system walkdir = "2.5" + +# Format parsing +serde_yaml = "0.9" diff --git a/README.md b/README.md index 1d45069..3688240 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Other features: - [x] **Web server** - a non-production web-server with REST API for the operations processing and testing - [x] **CLI** - command-line interface for all GTS operations - [ ] **UUID for instances** - to support UUID as ID in JSON instances +- [x] **YAML support** - to support YAML files (*.yml, *.yaml) as input files - [ ] **TypeSpec support** - Add [typespec.io](https://typespec.io/) files (*.tsp) support Technical Backlog: diff --git a/gts/Cargo.toml b/gts/Cargo.toml index 4be9e3e..ddf36d5 100644 --- a/gts/Cargo.toml +++ b/gts/Cargo.toml @@ -18,5 +18,6 @@ jsonschema.workspace = true walkdir.workspace = true tracing.workspace = true shellexpand = "3.1" +serde_yaml.workspace = true [dev-dependencies] diff --git a/gts/src/entities.rs b/gts/src/entities.rs index a8b0edf..9f35033 100644 --- a/gts/src/entities.rs +++ b/gts/src/entities.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::gts::GtsID; use crate::path_resolver::JsonPathResolver; -use crate::schema_cast::{JsonEntityCastResult, SchemaCastError}; +use crate::schema_cast::{GtsEntityCastResult, SchemaCastError}; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ValidationError { @@ -25,7 +25,7 @@ pub struct ValidationResult { } #[derive(Debug, Clone)] -pub struct JsonFile { +pub struct GtsFile { pub path: String, pub name: String, pub content: Value, @@ -34,7 +34,7 @@ pub struct JsonFile { pub validation: ValidationResult, } -impl JsonFile { +impl GtsFile { pub fn new(path: String, name: String, content: Value) -> Self { let mut sequences_count = 0; let mut sequence_content = HashMap::new(); @@ -50,7 +50,7 @@ impl JsonFile { sequence_content.insert(i, item.clone()); } - JsonFile { + GtsFile { path, name, content, @@ -103,10 +103,10 @@ pub struct GtsRef { } #[derive(Debug, Clone)] -pub struct JsonEntity { +pub struct GtsEntity { pub gts_id: Option, pub is_schema: bool, - pub file: Option, + pub file: Option, pub list_sequence: Option, pub label: String, pub content: Value, @@ -119,9 +119,9 @@ pub struct JsonEntity { pub schema_refs: Vec, } -impl JsonEntity { +impl GtsEntity { pub fn new( - file: Option, + file: Option, list_sequence: Option, content: Value, cfg: Option<&GtsConfig>, @@ -131,7 +131,7 @@ impl JsonEntity { validation: Option, schema_id: Option, ) -> Self { - let mut entity = JsonEntity { + let mut entity = GtsEntity { file, list_sequence, content: content.clone(), @@ -226,10 +226,10 @@ impl JsonEntity { pub fn cast( &self, - to_schema: &JsonEntity, - from_schema: &JsonEntity, + to_schema: &GtsEntity, + from_schema: &GtsEntity, resolver: Option<&()>, - ) -> Result { + ) -> Result { if self.is_schema { // When casting a schema, from_schema might be a standard JSON Schema (no gts_id) if let (Some(ref self_id), Some(ref from_id)) = (&self.gts_id, &from_schema.gts_id) { @@ -261,7 +261,7 @@ impl JsonEntity { .map(|g| g.id.clone()) .unwrap_or_default(); - JsonEntityCastResult::cast( + GtsEntityCastResult::cast( &from_id, &to_id, &self.content, diff --git a/gts/src/entities_tests.rs b/gts/src/entities_tests.rs new file mode 100644 index 0000000..69b1707 --- /dev/null +++ b/gts/src/entities_tests.rs @@ -0,0 +1,343 @@ +#[cfg(test)] +mod tests { + use crate::entities::*; + use crate::gts::GtsID; + use serde_json::json; + + #[test] + fn test_json_file_with_description() { + let content = json!({ + "id": "gts.vendor.package.namespace.type.v1.0", + "description": "Test description" + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + assert_eq!(entity.description, "Test description"); + } + + #[test] + fn test_json_entity_with_file_and_sequence() { + let file_content = json!([ + {"id": "gts.vendor.package.namespace.type.v1.0"}, + {"id": "gts.vendor.package.namespace.type.v1.1"} + ]); + + let file = GtsFile::new( + "/path/to/file.json".to_string(), + "file.json".to_string(), + file_content, + ); + + let entity_content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); + let cfg = GtsConfig::default(); + + let entity = GtsEntity::new( + Some(file), + Some(0), + entity_content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + assert_eq!(entity.label, "file.json#0"); + } + + #[test] + fn test_json_entity_with_file_no_sequence() { + let file_content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); + + let file = GtsFile::new( + "/path/to/file.json".to_string(), + "file.json".to_string(), + file_content, + ); + + let entity_content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); + let cfg = GtsConfig::default(); + + let entity = GtsEntity::new( + Some(file), + None, + entity_content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + assert_eq!(entity.label, "file.json"); + } + + #[test] + fn test_json_entity_extract_gts_ids() { + let content = json!({ + "id": "gts.vendor.package.namespace.type.v1.0", + "nested": { + "ref": "gts.other.package.namespace.type.v2.0" + } + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + let ids = entity.extract_gts_ids(); + assert!(!ids.is_empty()); + } + + #[test] + fn test_json_entity_extract_ref_strings() { + let content = json!({ + "$ref": "gts.vendor.package.namespace.type.v1.0~", + "properties": { + "user": { + "$ref": "gts.other.package.namespace.type.v2.0~" + } + } + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + let refs = entity.extract_ref_strings(); + assert!(!refs.is_empty()); + } + + #[test] + fn test_json_entity_is_json_schema_entity() { + let schema_content = json!({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object" + }); + + let entity = GtsEntity::new( + None, + None, + schema_content, + None, + None, + false, + String::new(), + None, + None, + ); + + assert!(entity.is_schema); + } + + #[test] + fn test_json_entity_fallback_to_schema_id() { + let content = json!({ + "type": "gts.vendor.package.namespace.type.v1.0~", + "name": "test" + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + // Should fallback to schema_id when entity_id is not found + assert!(entity.gts_id.is_some()); + } + + #[test] + fn test_json_entity_with_custom_label() { + let content = json!({"name": "test"}); + + let entity = GtsEntity::new( + None, + None, + content, + None, + None, + false, + "custom_label".to_string(), + None, + None, + ); + + assert_eq!(entity.label, "custom_label"); + } + + #[test] + fn test_json_entity_empty_label_fallback() { + let content = json!({"name": "test"}); + + let entity = GtsEntity::new( + None, + None, + content, + None, + None, + false, + String::new(), + None, + None, + ); + + assert_eq!(entity.label, ""); + } + + #[test] + fn test_validation_result_default() { + let result = ValidationResult::default(); + assert!(result.errors.is_empty()); + } + + #[test] + fn test_validation_error_creation() { + let mut params = std::collections::HashMap::new(); + params.insert("key".to_string(), json!("value")); + + let error = ValidationError { + instance_path: "/path".to_string(), + schema_path: "/schema".to_string(), + keyword: "required".to_string(), + message: "test error".to_string(), + params, + data: Some(json!({"test": "data"})), + }; + + assert_eq!(error.instance_path, "/path"); + assert_eq!(error.message, "test error"); + assert!(error.data.is_some()); + } + + #[test] + fn test_gts_config_entity_id_fields() { + let cfg = GtsConfig::default(); + assert!(cfg.entity_id_fields.contains(&"id".to_string())); + assert!(cfg.entity_id_fields.contains(&"$id".to_string())); + assert!(cfg.entity_id_fields.contains(&"gtsId".to_string())); + } + + #[test] + fn test_gts_config_schema_id_fields() { + let cfg = GtsConfig::default(); + assert!(cfg.schema_id_fields.contains(&"type".to_string())); + assert!(cfg.schema_id_fields.contains(&"$schema".to_string())); + assert!(cfg.schema_id_fields.contains(&"gtsTid".to_string())); + } + + #[test] + fn test_json_entity_with_validation_result() { + let content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); + + let mut validation = ValidationResult::default(); + validation.errors.push(ValidationError { + instance_path: "/test".to_string(), + schema_path: "/schema/test".to_string(), + keyword: "type".to_string(), + message: "validation error".to_string(), + params: std::collections::HashMap::new(), + data: None, + }); + + let entity = GtsEntity::new( + None, + None, + content, + None, + None, + false, + String::new(), + Some(validation.clone()), + None, + ); + + assert_eq!(entity.validation.errors.len(), 1); + } + + #[test] + fn test_json_entity_schema_id_field_selection() { + let content = json!({ + "id": "gts.vendor.package.namespace.type.v1.0~instance.v1.0", + "type": "gts.vendor.package.namespace.type.v1.0~" + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + assert!(entity.selected_schema_id_field.is_some()); + } + + #[test] + fn test_json_entity_when_id_is_schema() { + let content = json!({ + "id": "gts.vendor.package.namespace.type.v1.0~", + "$schema": "http://json-schema.org/draft-07/schema#" + }); + + let cfg = GtsConfig::default(); + let entity = GtsEntity::new( + None, + None, + content, + Some(&cfg), + None, + false, + String::new(), + None, + None, + ); + + // When entity ID itself is a schema, selected_schema_id_field should be None + assert_eq!(entity.selected_schema_id_field, None); + } +} diff --git a/gts/src/files_reader.rs b/gts/src/files_reader.rs index 8322d47..4a1fb85 100644 --- a/gts/src/files_reader.rs +++ b/gts/src/files_reader.rs @@ -3,7 +3,7 @@ use std::fs; use std::path::{Path, PathBuf}; use walkdir::WalkDir; -use crate::entities::{GtsConfig, JsonEntity, JsonFile}; +use crate::entities::{GtsConfig, GtsEntity, GtsFile}; use crate::store::GtsReader; const EXCLUDE_LIST: &[&str] = &["node_modules", "dist", "build"]; @@ -31,7 +31,7 @@ impl GtsFileReader { } fn collect_files(&mut self) { - let valid_extensions = vec![".json", ".jsonc", ".gts"]; + let valid_extensions = vec![".json", ".jsonc", ".gts", ".yaml", ".yml"]; let mut seen = std::collections::HashSet::new(); let mut collected = Vec::new(); @@ -91,16 +91,35 @@ impl GtsFileReader { fn load_json_file(&self, file_path: &Path) -> Result> { let content = fs::read_to_string(file_path)?; - let value: Value = serde_json::from_str(&content)?; + + // Determine file type by extension + let extension = file_path + .extension() + .and_then(|e| e.to_str()) + .map(|e| e.to_lowercase()) + .unwrap_or_default(); + + let value: Value = match extension.as_str() { + "yaml" | "yml" => { + // Parse YAML and convert to JSON + let yaml_value: serde_yaml::Value = serde_yaml::from_str(&content)?; + serde_json::to_value(yaml_value)? + } + _ => { + // Default: parse as JSON + serde_json::from_str(&content)? + } + }; + Ok(value) } - fn process_file(&self, file_path: &Path) -> Vec { + fn process_file(&self, file_path: &Path) -> Vec { let mut entities = Vec::new(); match self.load_json_file(file_path) { Ok(content) => { - let json_file = JsonFile::new( + let json_file = GtsFile::new( file_path.to_string_lossy().to_string(), file_path .file_name() @@ -113,7 +132,7 @@ impl GtsFileReader { // Handle both single objects and arrays if let Some(arr) = content.as_array() { for (idx, item) in arr.iter().enumerate() { - let entity = JsonEntity::new( + let entity = GtsEntity::new( Some(json_file.clone()), Some(idx), item.clone(), @@ -130,13 +149,15 @@ impl GtsFileReader { entity.gts_id.as_ref().unwrap().id ); entities.push(entity); + } else { + tracing::debug!("- skipped entity from {:?} (no valid GTS ID)", file_path); } } } else { - let entity = JsonEntity::new( + let entity = GtsEntity::new( Some(json_file), None, - content, + content.clone(), Some(&self.cfg), None, false, @@ -150,11 +171,14 @@ impl GtsFileReader { entity.gts_id.as_ref().unwrap().id ); entities.push(entity); + } else { + tracing::debug!("- skipped entity from {:?} (no valid GTS ID found in content: {:?})", file_path, content); } } } - Err(_) => { + Err(e) => { // Skip files that can't be parsed + tracing::debug!("Failed to parse file {:?}: {}", file_path, e); } } @@ -163,7 +187,7 @@ impl GtsFileReader { } impl GtsReader for GtsFileReader { - fn iter(&mut self) -> Box + '_> { + fn iter(&mut self) -> Box + '_> { if !self.initialized { self.collect_files(); self.initialized = true; @@ -175,7 +199,7 @@ impl GtsReader for GtsFileReader { self.paths ); - let entities: Vec = self + let entities: Vec = self .files .iter() .flat_map(|file_path| self.process_file(file_path)) @@ -184,7 +208,7 @@ impl GtsReader for GtsFileReader { Box::new(entities.into_iter()) } - fn read_by_id(&self, _entity_id: &str) -> Option { + fn read_by_id(&self, _entity_id: &str) -> Option { // For FileReader, we don't support random access by ID None } diff --git a/gts/src/lib.rs b/gts/src/lib.rs index 4ce9d0b..f410fd5 100644 --- a/gts/src/lib.rs +++ b/gts/src/lib.rs @@ -18,10 +18,10 @@ mod ops_tests; mod store_tests; // Re-export commonly used types -pub use entities::{GtsConfig, JsonEntity, JsonFile, ValidationError, ValidationResult}; +pub use entities::{GtsConfig, GtsEntity, GtsFile, ValidationError, ValidationResult}; pub use files_reader::GtsFileReader; pub use gts::{GtsError, GtsID, GtsIdSegment, GtsWildcard}; pub use ops::GtsOps; pub use path_resolver::JsonPathResolver; -pub use schema_cast::{JsonEntityCastResult, SchemaCastError}; +pub use schema_cast::{GtsEntityCastResult, SchemaCastError}; pub use store::{GtsReader, GtsStore, GtsStoreQueryResult, StoreError}; diff --git a/gts/src/ops.rs b/gts/src/ops.rs index 44c9155..319cf83 100644 --- a/gts/src/ops.rs +++ b/gts/src/ops.rs @@ -4,11 +4,11 @@ use std::collections::HashMap; use std::fs; use std::path::PathBuf; -use crate::entities::{GtsConfig, JsonEntity}; +use crate::entities::{GtsConfig, GtsEntity}; use crate::files_reader::GtsFileReader; use crate::gts::{GtsID, GtsWildcard}; use crate::path_resolver::JsonPathResolver; -use crate::schema_cast::JsonEntityCastResult; +use crate::schema_cast::GtsEntityCastResult; use crate::store::{GtsStore, GtsStoreQueryResult}; #[derive(Debug, Clone, Serialize, Deserialize)] @@ -419,7 +419,7 @@ impl GtsOps { } pub fn add_entity(&mut self, content: Value) -> GtsAddEntityResult { - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -582,14 +582,14 @@ impl GtsOps { &mut self, old_schema_id: &str, new_schema_id: &str, - ) -> JsonEntityCastResult { + ) -> GtsEntityCastResult { self.store.is_minor_compatible(old_schema_id, new_schema_id) } - pub fn cast(&mut self, from_id: &str, to_schema_id: &str) -> JsonEntityCastResult { + pub fn cast(&mut self, from_id: &str, to_schema_id: &str) -> GtsEntityCastResult { match self.store.cast(from_id, to_schema_id) { Ok(result) => result, - Err(e) => JsonEntityCastResult { + Err(e) => GtsEntityCastResult { from_id: from_id.to_string(), to_id: to_schema_id.to_string(), old: from_id.to_string(), @@ -631,7 +631,7 @@ impl GtsOps { } pub fn extract_id(&self, content: Value) -> GtsExtractIdResult { - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, diff --git a/gts/src/ops_tests.rs b/gts/src/ops_tests.rs index fc1c0f1..6021e8f 100644 --- a/gts/src/ops_tests.rs +++ b/gts/src/ops_tests.rs @@ -181,14 +181,14 @@ mod tests { #[test] fn test_json_file_creation() { - use crate::entities::JsonFile; + use crate::entities::GtsFile; let content = json!({ "id": "gts.test.id.v1.0", "data": "test" }); - let file = JsonFile::new( + let file = GtsFile::new( "/path/to/file.json".to_string(), "file.json".to_string(), content.clone(), @@ -201,7 +201,7 @@ mod tests { #[test] fn test_json_file_with_array() { - use crate::entities::JsonFile; + use crate::entities::GtsFile; let content = json!([ {"id": "gts.test.id1.v1.0"}, @@ -209,7 +209,7 @@ mod tests { {"id": "gts.test.id3.v1.0"} ]); - let file = JsonFile::new( + let file = GtsFile::new( "/path/to/array.json".to_string(), "array.json".to_string(), content, @@ -551,11 +551,11 @@ mod tests { #[test] fn test_json_path_resolver_to_dict() { use crate::path_resolver::JsonPathResolver; - + let content = json!({"name": "test"}); let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve("name"); - + let dict = result.to_dict(); assert_eq!(dict.get("gts_id").unwrap().as_str().unwrap(), "gts.test.id.v1.0"); assert_eq!(dict.get("path").unwrap().as_str().unwrap(), "name"); @@ -567,28 +567,28 @@ mod tests { #[test] fn test_schema_cast_error_display() { use crate::schema_cast::SchemaCastError; - + let error = SchemaCastError::InternalError("test".to_string()); assert!(error.to_string().contains("test")); - + let error = SchemaCastError::TargetMustBeSchema; assert!(error.to_string().contains("Target must be a schema")); - + let error = SchemaCastError::SourceMustBeSchema; assert!(error.to_string().contains("Source schema must be a schema")); - + let error = SchemaCastError::InstanceMustBeObject; assert!(error.to_string().contains("Instance must be an object")); - + let error = SchemaCastError::CastError("cast error".to_string()); assert!(error.to_string().contains("cast error")); } #[test] fn test_json_entity_cast_result_infer_direction_up() { - use crate::schema_cast::JsonEntityCastResult; - - let direction = JsonEntityCastResult::infer_direction( + use crate::schema_cast::GtsEntityCastResult; + + let direction = GtsEntityCastResult::infer_direction( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1" ); @@ -597,9 +597,9 @@ mod tests { #[test] fn test_json_entity_cast_result_infer_direction_down() { - use crate::schema_cast::JsonEntityCastResult; - - let direction = JsonEntityCastResult::infer_direction( + use crate::schema_cast::GtsEntityCastResult; + + let direction = GtsEntityCastResult::infer_direction( "gts.vendor.package.namespace.type.v1.1", "gts.vendor.package.namespace.type.v1.0" ); @@ -608,9 +608,9 @@ mod tests { #[test] fn test_json_entity_cast_result_infer_direction_none() { - use crate::schema_cast::JsonEntityCastResult; - - let direction = JsonEntityCastResult::infer_direction( + use crate::schema_cast::GtsEntityCastResult; + + let direction = GtsEntityCastResult::infer_direction( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.0" ); @@ -619,9 +619,9 @@ mod tests { #[test] fn test_json_entity_cast_result_infer_direction_unknown() { - use crate::schema_cast::JsonEntityCastResult; - - let direction = JsonEntityCastResult::infer_direction( + use crate::schema_cast::GtsEntityCastResult; + + let direction = GtsEntityCastResult::infer_direction( "invalid", "also-invalid" ); @@ -630,15 +630,15 @@ mod tests { #[test] fn test_json_entity_cast_result_cast_success() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({ "type": "object", "properties": { "name": {"type": "string"} } }); - + let to_schema = json!({ "type": "object", "properties": { @@ -646,12 +646,12 @@ mod tests { "email": {"type": "string", "default": "test@example.com"} } }); - + let instance = json!({ "name": "John" }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -659,7 +659,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); assert_eq!(cast_result.direction, "up"); @@ -668,13 +668,13 @@ mod tests { #[test] fn test_json_entity_cast_result_cast_non_object_instance() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({"type": "object"}); let instance = json!("not an object"); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -682,21 +682,21 @@ mod tests { &to_schema, None ); - + assert!(result.is_err()); } #[test] fn test_json_entity_cast_with_required_property() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({ "type": "object", "properties": { "name": {"type": "string"} } }); - + let to_schema = json!({ "type": "object", "properties": { @@ -705,10 +705,10 @@ mod tests { }, "required": ["name", "age"] }); - + let instance = json!({"name": "John"}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -716,7 +716,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); assert!(!cast_result.incompatibility_reasons.is_empty()); @@ -724,8 +724,8 @@ mod tests { #[test] fn test_json_entity_cast_with_default_values() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -734,10 +734,10 @@ mod tests { "count": {"type": "number", "default": 0} } }); - + let instance = json!({}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -745,7 +745,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); let casted = cast_result.casted_entity.unwrap(); @@ -755,8 +755,8 @@ mod tests { #[test] fn test_json_entity_cast_remove_additional_properties() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -765,13 +765,13 @@ mod tests { }, "additionalProperties": false }); - + let instance = json!({ "name": "John", "extra": "field" }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -779,7 +779,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); assert!(!cast_result.removed_properties.is_empty()); @@ -787,8 +787,8 @@ mod tests { #[test] fn test_json_entity_cast_with_const_values() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -796,12 +796,12 @@ mod tests { "type": {"type": "string", "const": "gts.vendor.package.namespace.type.v1.1~"} } }); - + let instance = json!({ "type": "gts.vendor.package.namespace.type.v1.0~" }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -809,19 +809,19 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_direction_down() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({"type": "object"}); let instance = json!({"name": "test"}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.1", "gts.vendor.package.namespace.type.v1.0", &instance, @@ -829,7 +829,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); assert_eq!(cast_result.direction, "down"); @@ -837,8 +837,8 @@ mod tests { #[test] fn test_json_entity_cast_with_allof() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "allOf": [ @@ -850,10 +850,10 @@ mod tests { } ] }); - + let instance = json!({"name": "test"}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -861,15 +861,15 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_result_to_dict() { - use crate::schema_cast::JsonEntityCastResult; - - let result = JsonEntityCastResult { + use crate::schema_cast::GtsEntityCastResult; + + let result = GtsEntityCastResult { from_id: "gts.vendor.package.namespace.type.v1.0".to_string(), to_id: "gts.vendor.package.namespace.type.v1.1".to_string(), old: "gts.vendor.package.namespace.type.v1.0".to_string(), @@ -887,7 +887,7 @@ mod tests { casted_entity: Some(json!({"name": "test"})), error: None, }; - + let dict = result.to_dict(); assert_eq!(dict.get("from").unwrap().as_str().unwrap(), "gts.vendor.package.namespace.type.v1.0"); assert_eq!(dict.get("direction").unwrap().as_str().unwrap(), "up"); @@ -895,8 +895,8 @@ mod tests { #[test] fn test_json_entity_cast_nested_objects() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -910,14 +910,14 @@ mod tests { } } }); - + let instance = json!({ "user": { "name": "John" } }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -925,14 +925,14 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_array_of_objects() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -949,15 +949,15 @@ mod tests { } } }); - + let instance = json!({ "users": [ {"name": "John"}, {"name": "Jane"} ] }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -965,14 +965,14 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_with_required_and_default() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -981,10 +981,10 @@ mod tests { }, "required": ["status"] }); - + let instance = json!({}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -992,7 +992,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); assert!(!cast_result.added_properties.is_empty()); @@ -1000,8 +1000,8 @@ mod tests { #[test] fn test_json_entity_cast_flatten_schema_with_allof() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "allOf": [ @@ -1020,10 +1020,10 @@ mod tests { } ] }); - + let instance = json!({"name": "test"}); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -1031,14 +1031,14 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_array_with_non_object_items() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -1051,12 +1051,12 @@ mod tests { } } }); - + let instance = json!({ "tags": ["tag1", "tag2"] }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -1064,14 +1064,14 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_const_non_gts_id() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -1079,12 +1079,12 @@ mod tests { "version": {"type": "string", "const": "2.0"} } }); - + let instance = json!({ "version": "1.0" }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -1092,14 +1092,14 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); } #[test] fn test_json_entity_cast_additional_properties_true() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let from_schema = json!({"type": "object"}); let to_schema = json!({ "type": "object", @@ -1108,13 +1108,13 @@ mod tests { }, "additionalProperties": true }); - + let instance = json!({ "name": "John", "extra": "field" }); - - let result = JsonEntityCastResult::cast( + + let result = GtsEntityCastResult::cast( "gts.vendor.package.namespace.type.v1.0", "gts.vendor.package.namespace.type.v1.1", &instance, @@ -1122,7 +1122,7 @@ mod tests { &to_schema, None ); - + assert!(result.is_ok()); let cast_result = result.unwrap(); // Should not remove extra field when additionalProperties is true @@ -1131,31 +1131,31 @@ mod tests { #[test] fn test_schema_compatibility_type_change() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { "value": {"type": "string"} } }); - + let new_schema = json!({ "type": "object", "properties": { "value": {"type": "number"} } }); - - let (is_backward, backward_errors) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + + let (is_backward, backward_errors) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); assert!(!is_backward); assert!(!backward_errors.is_empty()); } #[test] fn test_schema_compatibility_enum_changes() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1165,7 +1165,7 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1175,10 +1175,10 @@ mod tests { } } }); - - let (is_backward, _) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); - let (is_forward, _) = JsonEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); - + + let (is_backward, _) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + let (is_forward, _) = GtsEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); + // Adding enum values is not backward compatible but is forward compatible assert!(!is_backward); assert!(is_forward); @@ -1186,8 +1186,8 @@ mod tests { #[test] fn test_schema_compatibility_numeric_constraints() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1198,7 +1198,7 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1209,16 +1209,16 @@ mod tests { } } }); - - let (is_backward, backward_errors) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + + let (is_backward, backward_errors) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); assert!(!is_backward); assert!(!backward_errors.is_empty()); } #[test] fn test_schema_compatibility_string_constraints() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1229,7 +1229,7 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1240,15 +1240,15 @@ mod tests { } } }); - - let (is_backward, _) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + + let (is_backward, _) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); assert!(!is_backward); } #[test] fn test_schema_compatibility_array_constraints() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1259,7 +1259,7 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1270,22 +1270,22 @@ mod tests { } } }); - - let (is_backward, _) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + + let (is_backward, _) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); assert!(!is_backward); } #[test] fn test_schema_compatibility_added_constraint() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { "age": {"type": "number"} } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1295,15 +1295,15 @@ mod tests { } } }); - - let (is_backward, _) = JsonEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); + + let (is_backward, _) = GtsEntityCastResult::check_backward_compatibility(&old_schema, &new_schema); assert!(!is_backward); } #[test] fn test_schema_compatibility_removed_constraint() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1313,22 +1313,22 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { "age": {"type": "number"} } }); - - let (is_forward, _) = JsonEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); + + let (is_forward, _) = GtsEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); assert!(!is_forward); } #[test] fn test_schema_compatibility_removed_required_property() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1337,7 +1337,7 @@ mod tests { }, "required": ["name", "email"] }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1346,16 +1346,16 @@ mod tests { }, "required": ["name"] }); - - let (is_forward, forward_errors) = JsonEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); + + let (is_forward, forward_errors) = GtsEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); assert!(!is_forward); assert!(!forward_errors.is_empty()); } #[test] fn test_schema_compatibility_enum_removed_values() { - use crate::schema_cast::JsonEntityCastResult; - + use crate::schema_cast::GtsEntityCastResult; + let old_schema = json!({ "type": "object", "properties": { @@ -1365,7 +1365,7 @@ mod tests { } } }); - + let new_schema = json!({ "type": "object", "properties": { @@ -1375,8 +1375,8 @@ mod tests { } } }); - - let (is_forward, forward_errors) = JsonEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); + + let (is_forward, forward_errors) = GtsEntityCastResult::check_forward_compatibility(&old_schema, &new_schema); assert!(!is_forward); assert!(!forward_errors.is_empty()); } @@ -1394,12 +1394,12 @@ mod tests { #[test] fn test_gts_ops_add_entities() { let mut ops = GtsOps::new(None, None, 0); - + let entities = vec![ json!({"id": "gts.vendor.package.namespace.type.v1.0", "name": "test1"}), json!({"id": "gts.vendor.package.namespace.type.v1.1", "name": "test2"}), ]; - + let result = ops.add_entities(entities); assert_eq!(result.results.len(), 2); } @@ -1450,15 +1450,15 @@ mod tests { #[test] fn test_gts_ops_schema_graph() { let mut ops = GtsOps::new(None, None, 0); - + let schema = json!({ "$id": "gts.vendor.package.namespace.type.v1.0~", "$schema": "http://json-schema.org/draft-07/schema#", "type": "object" }); - + ops.add_schema("gts.vendor.package.namespace.type.v1.0~".to_string(), schema); - + let result = ops.schema_graph("gts.vendor.package.namespace.type.v1.0~"); assert!(result.graph.is_object()); } @@ -1466,16 +1466,16 @@ mod tests { #[test] fn test_gts_ops_attr() { let mut ops = GtsOps::new(None, None, 0); - + let content = json!({ "id": "gts.vendor.package.namespace.type.v1.0", "user": { "name": "John" } }); - + ops.add_entity(content); - + let result = ops.attr("gts.vendor.package.namespace.type.v1.0#user.name"); // Just verify it executes assert!(!result.gts_id.is_empty()); @@ -1484,14 +1484,14 @@ mod tests { #[test] fn test_gts_ops_attr_no_path() { let mut ops = GtsOps::new(None, None, 0); - + let content = json!({ "id": "gts.vendor.package.namespace.type.v1.0", "name": "test" }); - + ops.add_entity(content); - + let result = ops.attr("gts.vendor.package.namespace.type.v1.0"); assert_eq!(result.path, ""); } @@ -1508,11 +1508,11 @@ mod tests { #[test] fn test_path_resolver_failure() { use crate::path_resolver::JsonPathResolver; - + let content = json!({"name": "test"}); let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.failure("invalid.path", "Path not found"); - + assert!(!result.resolved); assert!(result.error.is_some()); } @@ -1520,50 +1520,50 @@ mod tests { #[test] fn test_path_resolver_array_access() { use crate::path_resolver::JsonPathResolver; - + let content = json!({ "items": [ {"name": "first"}, {"name": "second"} ] }); - + let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve("items[0].name"); - + assert_eq!(result.path, "items[0].name"); } #[test] fn test_path_resolver_invalid_path() { use crate::path_resolver::JsonPathResolver; - + let content = json!({"name": "test"}); let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve("nonexistent.path"); - + assert!(!result.resolved); } #[test] fn test_path_resolver_empty_path() { use crate::path_resolver::JsonPathResolver; - + let content = json!({"name": "test"}); let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve(""); - + assert_eq!(result.path, ""); } #[test] fn test_path_resolver_root_access() { use crate::path_resolver::JsonPathResolver; - + let content = json!({"name": "test", "value": 42}); let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content.clone()); let result = resolver.resolve("$"); - + // Root access should return the whole object assert_eq!(result.gts_id, "gts.test.id.v1.0"); } @@ -1571,7 +1571,7 @@ mod tests { #[test] fn test_gts_ops_list_entities() { let mut ops = GtsOps::new(None, None, 0); - + for i in 0..3 { let content = json!({ "id": format!("gts.vendor.package.namespace.type.v1.{}", i), @@ -1579,7 +1579,7 @@ mod tests { }); ops.add_entity(content); } - + let result = ops.list(10); assert_eq!(result.total, 3); assert_eq!(result.entities.len(), 3); @@ -1588,7 +1588,7 @@ mod tests { #[test] fn test_gts_ops_list_with_limit() { let mut ops = GtsOps::new(None, None, 0); - + for i in 0..5 { let content = json!({ "id": format!("gts.vendor.package.namespace.type.v1.{}", i), @@ -1596,7 +1596,7 @@ mod tests { }); ops.add_entity(content); } - + let result = ops.list(2); assert_eq!(result.entities.len(), 2); assert_eq!(result.total, 5); @@ -1613,7 +1613,7 @@ mod tests { #[test] fn test_gts_ops_validate_instance() { let mut ops = GtsOps::new(None, None, 0); - + let schema = json!({ "$id": "gts.vendor.package.namespace.type.v1.0~", "$schema": "http://json-schema.org/draft-07/schema#", @@ -1622,17 +1622,17 @@ mod tests { "name": {"type": "string"} } }); - + ops.add_schema("gts.vendor.package.namespace.type.v1.0~".to_string(), schema); - + let content = json!({ "id": "gts.vendor.package.namespace.type.v1.0", "type": "gts.vendor.package.namespace.type.v1.0~", "name": "test" }); - + ops.add_entity(content); - + let result = ops.validate_instance("gts.vendor.package.namespace.type.v1.0"); // Just verify it executes assert!(result.ok || !result.ok); @@ -1641,7 +1641,7 @@ mod tests { #[test] fn test_path_resolver_nested_object() { use crate::path_resolver::JsonPathResolver; - + let content = json!({ "user": { "profile": { @@ -1649,31 +1649,31 @@ mod tests { } } }); - + let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve("user.profile.name"); - + assert_eq!(result.gts_id, "gts.test.id.v1.0"); } #[test] fn test_path_resolver_array_out_of_bounds() { use crate::path_resolver::JsonPathResolver; - + let content = json!({ "items": [1, 2, 3] }); - + let resolver = JsonPathResolver::new("gts.test.id.v1.0".to_string(), content); let result = resolver.resolve("items[10]"); - + assert!(!result.resolved); } #[test] fn test_gts_ops_compatibility() { let mut ops = GtsOps::new(None, None, 0); - + let schema1 = json!({ "$id": "gts.vendor.package.namespace.type.v1.0~", "$schema": "http://json-schema.org/draft-07/schema#", @@ -1682,7 +1682,7 @@ mod tests { "name": {"type": "string"} } }); - + let schema2 = json!({ "$id": "gts.vendor.package.namespace.type.v1.1~", "$schema": "http://json-schema.org/draft-07/schema#", @@ -1692,15 +1692,15 @@ mod tests { "email": {"type": "string"} } }); - + ops.add_schema("gts.vendor.package.namespace.type.v1.0~".to_string(), schema1); ops.add_schema("gts.vendor.package.namespace.type.v1.1~".to_string(), schema2); - + let result = ops.compatibility( "gts.vendor.package.namespace.type.v1.0~", "gts.vendor.package.namespace.type.v1.1~" ); - + assert!(result.is_backward_compatible || !result.is_backward_compatible); } @@ -1708,8 +1708,8 @@ mod tests { #[test] fn test_json_entity_resolve_path() { - use crate::entities::{GtsConfig, JsonEntity}; - + use crate::entities::{GtsConfig, GtsEntity}; + let cfg = GtsConfig::default(); let content = json!({ "id": "gts.vendor.package.namespace.type.v1.0", @@ -1718,8 +1718,8 @@ mod tests { "age": 30 } }); - - let entity = JsonEntity::new( + + let entity = GtsEntity::new( None, None, content, @@ -1730,17 +1730,17 @@ mod tests { None, None, ); - + let result = entity.resolve_path("user.name"); assert_eq!(result.gts_id, "gts.vendor.package.namespace.type.v1.0"); } #[test] fn test_json_entity_cast_method() { - use crate::entities::{GtsConfig, JsonEntity}; - + use crate::entities::{GtsConfig, GtsEntity}; + let cfg = GtsConfig::default(); - + let from_schema_content = json!({ "$id": "gts.vendor.package.namespace.type.v1.0~", "$schema": "http://json-schema.org/draft-07/schema#", @@ -1749,7 +1749,7 @@ mod tests { "name": {"type": "string"} } }); - + let to_schema_content = json!({ "$id": "gts.vendor.package.namespace.type.v1.1~", "$schema": "http://json-schema.org/draft-07/schema#", @@ -1759,8 +1759,8 @@ mod tests { "email": {"type": "string", "default": "test@example.com"} } }); - - let from_schema = JsonEntity::new( + + let from_schema = GtsEntity::new( None, None, from_schema_content, @@ -1771,8 +1771,8 @@ mod tests { None, None, ); - - let to_schema = JsonEntity::new( + + let to_schema = GtsEntity::new( None, None, to_schema_content, @@ -1783,13 +1783,13 @@ mod tests { None, None, ); - + let instance_content = json!({ "id": "gts.vendor.package.namespace.type.v1.0", "name": "John" }); - - let instance = JsonEntity::new( + + let instance = GtsEntity::new( None, None, instance_content, @@ -1800,53 +1800,53 @@ mod tests { None, None, ); - + let result = instance.cast(&to_schema, &from_schema, None); assert!(result.is_ok() || result.is_err()); } #[test] fn test_json_file_with_array_content() { - use crate::entities::JsonFile; - + use crate::entities::GtsFile; + let content = json!([ {"id": "gts.vendor.package.namespace.type.v1.0", "name": "first"}, {"id": "gts.vendor.package.namespace.type.v1.1", "name": "second"} ]); - - let file = JsonFile::new( + + let file = GtsFile::new( "/path/to/file.json".to_string(), "file.json".to_string(), content, ); - + assert_eq!(file.sequences_count, 2); assert_eq!(file.sequence_content.len(), 2); } #[test] fn test_json_file_with_single_object() { - use crate::entities::JsonFile; - + use crate::entities::GtsFile; + let content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); - - let file = JsonFile::new( + + let file = GtsFile::new( "/path/to/file.json".to_string(), "file.json".to_string(), content, ); - + assert_eq!(file.sequences_count, 1); assert_eq!(file.sequence_content.len(), 1); } #[test] fn test_json_entity_with_validation_result() { - use crate::entities::{GtsConfig, JsonEntity, ValidationResult, ValidationError}; - + use crate::entities::{GtsConfig, GtsEntity, ValidationResult, ValidationError}; + let cfg = GtsConfig::default(); let content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); - + let mut validation = ValidationResult::default(); validation.errors.push(ValidationError { instance_path: "/test".to_string(), @@ -1856,8 +1856,8 @@ mod tests { params: std::collections::HashMap::new(), data: None, }); - - let entity = JsonEntity::new( + + let entity = GtsEntity::new( None, None, content, @@ -1868,24 +1868,24 @@ mod tests { Some(validation), None, ); - + assert_eq!(entity.validation.errors.len(), 1); } #[test] fn test_json_entity_with_file() { - use crate::entities::{GtsConfig, JsonEntity, JsonFile}; - + use crate::entities::{GtsConfig, GtsEntity, GtsFile}; + let cfg = GtsConfig::default(); let content = json!({"id": "gts.vendor.package.namespace.type.v1.0"}); - - let file = JsonFile::new( + + let file = GtsFile::new( "/path/to/file.json".to_string(), "file.json".to_string(), content.clone(), ); - - let entity = JsonEntity::new( + + let entity = GtsEntity::new( Some(file), Some(0), content, @@ -1896,9 +1896,8 @@ mod tests { None, None, ); - + assert!(entity.file.is_some()); assert_eq!(entity.list_sequence, Some(0)); } } - diff --git a/gts/src/schema_cast.rs b/gts/src/schema_cast.rs index b098a33..43d7bcc 100644 --- a/gts/src/schema_cast.rs +++ b/gts/src/schema_cast.rs @@ -20,7 +20,7 @@ pub enum SchemaCastError { } #[derive(Debug, Clone, Serialize, Deserialize)] -pub struct JsonEntityCastResult { +pub struct GtsEntityCastResult { #[serde(rename = "from")] pub from_id: String, #[serde(rename = "to")] @@ -42,7 +42,7 @@ pub struct JsonEntityCastResult { pub error: Option, } -impl JsonEntityCastResult { +impl GtsEntityCastResult { pub fn cast( from_instance_id: &str, to_schema_id: &str, @@ -81,7 +81,7 @@ impl JsonEntityCastResult { match Self::cast_instance_to_schema(instance_obj, &target_schema, "") { Ok(result) => result, Err(e) => { - return Ok(JsonEntityCastResult { + return Ok(GtsEntityCastResult { from_id: from_instance_id.to_string(), to_id: to_schema_id.to_string(), old: from_instance_id.to_string(), @@ -116,7 +116,7 @@ impl JsonEntityCastResult { removed_sorted.sort(); removed_sorted.dedup(); - Ok(JsonEntityCastResult { + Ok(GtsEntityCastResult { from_id: from_instance_id.to_string(), to_id: to_schema_id.to_string(), old: from_instance_id.to_string(), diff --git a/gts/src/schema_cast_tests.rs b/gts/src/schema_cast_tests.rs new file mode 100644 index 0000000..232356e --- /dev/null +++ b/gts/src/schema_cast_tests.rs @@ -0,0 +1,339 @@ +#[cfg(test)] +mod tests { + use crate::schema_cast::*; + use serde_json::json; + + #[test] + fn test_schema_cast_error_display() { + let error = SchemaCastError::IncompatibleSchemas("test error".to_string()); + assert!(error.to_string().contains("test error")); + + let error = SchemaCastError::SchemaNotFound("schema_id".to_string()); + assert!(error.to_string().contains("schema_id")); + + let error = SchemaCastError::ValidationFailed("validation error".to_string()); + assert!(error.to_string().contains("validation error")); + } + + #[test] + fn test_json_entity_cast_result_infer_direction_up() { + let direction = GtsEntityCastResult::infer_direction( + "gts.vendor.package.namespace.type.v1.0", + "gts.vendor.package.namespace.type.v2.0" + ); + assert_eq!(direction, "up"); + } + + #[test] + fn test_json_entity_cast_result_infer_direction_down() { + let direction = GtsEntityCastResult::infer_direction( + "gts.vendor.package.namespace.type.v2.0", + "gts.vendor.package.namespace.type.v1.0" + ); + assert_eq!(direction, "down"); + } + + #[test] + fn test_json_entity_cast_result_infer_direction_lateral() { + let direction = GtsEntityCastResult::infer_direction( + "gts.vendor.package.namespace.type.v1.0", + "gts.vendor.package.namespace.other.v1.0" + ); + assert_eq!(direction, "lateral"); + } + + #[test] + fn test_json_entity_cast_result_to_dict() { + let result = GtsEntityCastResult { + from_id: "gts.vendor.package.namespace.type.v1.0".to_string(), + to_id: "gts.vendor.package.namespace.type.v2.0".to_string(), + direction: "up".to_string(), + ok: true, + error: String::new(), + is_backward_compatible: true, + is_forward_compatible: false, + is_fully_compatible: false, + }; + + let dict = result.to_dict(); + assert_eq!(dict.get("from_id").unwrap().as_str().unwrap(), "gts.vendor.package.namespace.type.v1.0"); + assert_eq!(dict.get("to_id").unwrap().as_str().unwrap(), "gts.vendor.package.namespace.type.v2.0"); + assert_eq!(dict.get("direction").unwrap().as_str().unwrap(), "up"); + assert_eq!(dict.get("ok").unwrap().as_bool().unwrap(), true); + } + + #[test] + fn test_check_schema_compatibility_identical() { + let schema1 = json!({ + "type": "object", + "properties": { + "name": {"type": "string"} + } + }); + + let result = check_schema_compatibility(&schema1, &schema1); + assert!(result.is_backward_compatible); + assert!(result.is_forward_compatible); + assert!(result.is_fully_compatible); + } + + #[test] + fn test_check_schema_compatibility_added_optional_property() { + let old_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"} + } + }); + + let new_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string"} + } + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Adding optional property is backward compatible + assert!(result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_added_required_property() { + let old_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"} + }, + "required": ["name"] + }); + + let new_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string"} + }, + "required": ["name", "email"] + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Adding required property is not backward compatible + assert!(!result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_removed_property() { + let old_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string"} + } + }); + + let new_schema = json!({ + "type": "object", + "properties": { + "name": {"type": "string"} + } + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Removing property is not forward compatible + assert!(!result.is_forward_compatible); + } + + #[test] + fn test_check_schema_compatibility_enum_expansion() { + let old_schema = json!({ + "type": "string", + "enum": ["active", "inactive"] + }); + + let new_schema = json!({ + "type": "string", + "enum": ["active", "inactive", "pending"] + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Enum expansion: forward compatible but not backward + assert!(result.is_forward_compatible); + assert!(!result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_enum_reduction() { + let old_schema = json!({ + "type": "string", + "enum": ["active", "inactive", "pending"] + }); + + let new_schema = json!({ + "type": "string", + "enum": ["active", "inactive"] + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Enum reduction: backward compatible but not forward + assert!(result.is_backward_compatible); + assert!(!result.is_forward_compatible); + } + + #[test] + fn test_check_schema_compatibility_type_change() { + let old_schema = json!({ + "type": "string" + }); + + let new_schema = json!({ + "type": "number" + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Type change is incompatible + assert!(!result.is_backward_compatible); + assert!(!result.is_forward_compatible); + } + + #[test] + fn test_check_schema_compatibility_constraint_tightening() { + let old_schema = json!({ + "type": "number", + "minimum": 0 + }); + + let new_schema = json!({ + "type": "number", + "minimum": 10 + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Tightening minimum is not backward compatible + assert!(!result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_constraint_relaxing() { + let old_schema = json!({ + "type": "number", + "maximum": 100 + }); + + let new_schema = json!({ + "type": "number", + "maximum": 200 + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Relaxing maximum is backward compatible + assert!(result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_nested_objects() { + let old_schema = json!({ + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "name": {"type": "string"} + } + } + } + }); + + let new_schema = json!({ + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "email": {"type": "string"} + } + } + } + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Adding optional nested property is backward compatible + assert!(result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_array_items() { + let old_schema = json!({ + "type": "array", + "items": {"type": "string"} + }); + + let new_schema = json!({ + "type": "array", + "items": {"type": "number"} + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Changing array item type is incompatible + assert!(!result.is_backward_compatible); + assert!(!result.is_forward_compatible); + } + + #[test] + fn test_check_schema_compatibility_string_length_constraints() { + let old_schema = json!({ + "type": "string", + "minLength": 1, + "maxLength": 100 + }); + + let new_schema = json!({ + "type": "string", + "minLength": 5, + "maxLength": 50 + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Tightening string constraints is not backward compatible + assert!(!result.is_backward_compatible); + } + + #[test] + fn test_check_schema_compatibility_array_length_constraints() { + let old_schema = json!({ + "type": "array", + "minItems": 1, + "maxItems": 10 + }); + + let new_schema = json!({ + "type": "array", + "minItems": 2, + "maxItems": 5 + }); + + let result = check_schema_compatibility(&old_schema, &new_schema); + // Tightening array constraints is not backward compatible + assert!(!result.is_backward_compatible); + } + + #[test] + fn test_compatibility_result_default() { + let result = CompatibilityResult::default(); + assert!(!result.is_backward_compatible); + assert!(!result.is_forward_compatible); + assert!(!result.is_fully_compatible); + } + + #[test] + fn test_compatibility_result_fully_compatible() { + let result = CompatibilityResult { + is_backward_compatible: true, + is_forward_compatible: true, + is_fully_compatible: true, + }; + assert!(result.is_fully_compatible); + } +} diff --git a/gts/src/store.rs b/gts/src/store.rs index f8740ef..943fac9 100644 --- a/gts/src/store.rs +++ b/gts/src/store.rs @@ -3,9 +3,9 @@ use serde_json::Value; use std::collections::HashMap; use thiserror::Error; -use crate::entities::JsonEntity; +use crate::entities::GtsEntity; use crate::gts::{GtsID, GtsWildcard}; -use crate::schema_cast::JsonEntityCastResult; +use crate::schema_cast::GtsEntityCastResult; #[derive(Debug, Error)] pub enum StoreError { @@ -24,8 +24,8 @@ pub enum StoreError { } pub trait GtsReader: Send { - fn iter(&mut self) -> Box + '_>; - fn read_by_id(&self, entity_id: &str) -> Option; + fn iter(&mut self) -> Box + '_>; + fn read_by_id(&self, entity_id: &str) -> Option; fn reset(&mut self); } @@ -52,7 +52,7 @@ impl GtsStoreQueryResult { } pub struct GtsStore { - by_id: HashMap, + by_id: HashMap, reader: Option>, } @@ -81,7 +81,7 @@ impl GtsStore { } } - pub fn register(&mut self, entity: JsonEntity) -> Result<(), StoreError> { + pub fn register(&mut self, entity: GtsEntity) -> Result<(), StoreError> { if entity.gts_id.is_none() { return Err(StoreError::InvalidEntity); } @@ -96,7 +96,7 @@ impl GtsStore { } let gts_id = GtsID::new(type_id).map_err(|_| StoreError::InvalidSchemaId)?; - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, schema, @@ -111,7 +111,7 @@ impl GtsStore { Ok(()) } - pub fn get(&mut self, entity_id: &str) -> Option<&JsonEntity> { + pub fn get(&mut self, entity_id: &str) -> Option<&GtsEntity> { // Check cache first if self.by_id.contains_key(entity_id) { return self.by_id.get(entity_id); @@ -135,7 +135,7 @@ impl GtsStore { Err(StoreError::SchemaNotFound(type_id.to_string())) } - pub fn items(&self) -> impl Iterator { + pub fn items(&self) -> impl Iterator { self.by_id.iter() } @@ -254,7 +254,7 @@ impl GtsStore { &mut self, from_id: &str, target_schema_id: &str, - ) -> Result { + ) -> Result { let from_entity = self .get(from_id) .ok_or_else(|| StoreError::EntityNotFound(from_id.to_string()))? @@ -296,12 +296,12 @@ impl GtsStore { &mut self, old_schema_id: &str, new_schema_id: &str, - ) -> JsonEntityCastResult { + ) -> GtsEntityCastResult { let old_entity = self.get(old_schema_id).cloned(); let new_entity = self.get(new_schema_id).cloned(); if old_entity.is_none() || new_entity.is_none() { - return JsonEntityCastResult { + return GtsEntityCastResult { from_id: old_schema_id.to_string(), to_id: new_schema_id.to_string(), old: old_schema_id.to_string(), @@ -326,14 +326,14 @@ impl GtsStore { // Use the cast method's compatibility checking logic let (is_backward, backward_errors) = - JsonEntityCastResult::check_backward_compatibility(old_schema, new_schema); + GtsEntityCastResult::check_backward_compatibility(old_schema, new_schema); let (is_forward, forward_errors) = - JsonEntityCastResult::check_forward_compatibility(old_schema, new_schema); + GtsEntityCastResult::check_forward_compatibility(old_schema, new_schema); // Determine direction - let direction = JsonEntityCastResult::infer_direction(old_schema_id, new_schema_id); + let direction = GtsEntityCastResult::infer_direction(old_schema_id, new_schema_id); - JsonEntityCastResult { + GtsEntityCastResult { from_id: old_schema_id.to_string(), to_id: new_schema_id.to_string(), old: old_schema_id.to_string(), diff --git a/gts/src/store_tests.rs b/gts/src/store_tests.rs index 1f1c929..4460e3c 100644 --- a/gts/src/store_tests.rs +++ b/gts/src/store_tests.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod tests { use crate::store::*; - use crate::entities::{JsonEntity, GtsConfig}; + use crate::entities::{GtsEntity, GtsConfig}; use serde_json::json; #[test] @@ -53,7 +53,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -185,7 +185,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -323,7 +323,7 @@ mod tests { "name": "John" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -365,7 +365,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -431,7 +431,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -482,7 +482,7 @@ mod tests { "name": "test" }); - let entity1 = JsonEntity::new( + let entity1 = GtsEntity::new( None, None, content.clone(), @@ -494,7 +494,7 @@ mod tests { None, ); - let entity2 = JsonEntity::new( + let entity2 = GtsEntity::new( None, None, content, @@ -536,7 +536,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -571,7 +571,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -632,7 +632,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -671,7 +671,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -738,7 +738,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -780,7 +780,7 @@ mod tests { "age": "not a number" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -875,7 +875,7 @@ mod tests { "name": "John" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -964,7 +964,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1053,7 +1053,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1155,7 +1155,7 @@ mod tests { "email": "test@example.com" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1227,7 +1227,7 @@ mod tests { "name": "John" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1349,7 +1349,7 @@ mod tests { let mut store = GtsStore::new(None); let content = json!({"name": "test"}); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1397,7 +1397,7 @@ mod tests { "tags": ["developer", "rust"] }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1437,7 +1437,7 @@ mod tests { "id": "gts.vendor.package.namespace.type.v1.0" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1516,7 +1516,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1560,7 +1560,7 @@ mod tests { "name": format!("test{}", i) }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1690,7 +1690,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1760,7 +1760,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1802,7 +1802,7 @@ mod tests { "data": {} }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1879,7 +1879,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1914,7 +1914,7 @@ mod tests { "status": if i % 2 == 0 { "active" } else { "inactive" } }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -1954,7 +1954,7 @@ mod tests { }) }; - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -2030,7 +2030,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -2050,22 +2050,22 @@ mod tests { // Mock GtsReader for testing reader functionality struct MockGtsReader { - entities: Vec, + entities: Vec, index: usize, } impl MockGtsReader { - fn new(entities: Vec) -> Self { + fn new(entities: Vec) -> Self { MockGtsReader { entities, index: 0 } } } impl GtsReader for MockGtsReader { - fn iter(&mut self) -> Box + '_> { + fn iter(&mut self) -> Box + '_> { Box::new(self.entities.clone().into_iter()) } - fn read_by_id(&self, entity_id: &str) -> Option { + fn read_by_id(&self, entity_id: &str) -> Option { self.entities.iter().find(|e| { e.gts_id.as_ref().map(|id| id.id.as_str()) == Some(entity_id) }).cloned() @@ -2088,7 +2088,7 @@ mod tests { "name": format!("item{}", i) }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -2120,7 +2120,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content, @@ -2147,7 +2147,7 @@ mod tests { "name": "test" }); - let entity = JsonEntity::new( + let entity = GtsEntity::new( None, None, content,