use serde_json::json;
use crate::common::{ValidationErrorCode, builders::UserBuilder, fixtures::rfc_examples};
use scim_server::error::ValidationError;
use scim_server::schema::{SchemaRegistry, validation::OperationContext};
#[test]
fn test_missing_schemas_attribute() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let invalid_user = UserBuilder::new().without_schemas().build();
assert!(!invalid_user.as_object().unwrap().contains_key("schemas"));
let result = registry.validate_json_resource_with_context(
"User",
&invalid_user,
OperationContext::Update,
);
assert!(result.is_err());
match result {
Err(ValidationError::MissingSchemas) => {
}
Err(other) => panic!("Expected MissingSchemas error, got {:?}", other),
Ok(_) => panic!("Expected validation to fail, but it passed"),
}
}
#[test]
fn test_empty_schemas_array() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let invalid_user = UserBuilder::new().with_empty_schemas().build();
assert_eq!(invalid_user["schemas"], json!([]));
let result = registry.validate_json_resource_with_context(
"User",
&invalid_user,
OperationContext::Update,
);
assert!(result.is_err());
match result {
Err(ValidationError::EmptySchemas) => {
}
Err(other) => panic!("Expected EmptySchemas error, got {:?}", other),
Ok(_) => panic!("Expected validation to fail, but it passed"),
}
}
#[test]
fn test_invalid_schema_uri_format() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let invalid_user = UserBuilder::new().with_invalid_schema_uri().build();
assert_eq!(invalid_user["schemas"][0], "not-a-valid-uri");
let result = registry.validate_json_resource_with_context(
"User",
&invalid_user,
OperationContext::Update,
);
assert!(result.is_err());
match result {
Err(ValidationError::InvalidSchemaUri { uri }) => {
assert_eq!(uri, "not-a-valid-uri");
}
Err(other) => panic!("Expected InvalidSchemaUri error, got {:?}", other),
Ok(_) => panic!("Expected validation to fail, but it passed"),
}
}
#[test]
fn test_unknown_schema_uri() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let invalid_user = UserBuilder::new().with_unknown_schema_uri().build();
assert_eq!(
invalid_user["schemas"][0],
"urn:ietf:params:scim:schemas:core:2.0:UnknownResource"
);
let result = registry.validate_json_resource_with_context(
"User",
&invalid_user,
OperationContext::Update,
);
assert!(result.is_err());
match result {
Err(ValidationError::UnknownSchemaUri { uri }) => {
assert_eq!(uri, "urn:ietf:params:scim:schemas:core:2.0:UnknownResource");
}
Err(other) => panic!("Expected UnknownSchemaUri error, got {:?}", other),
Ok(_) => panic!("Expected validation to fail, but it passed"),
}
}
#[test]
fn test_duplicate_schema_uris() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let invalid_user = UserBuilder::new().with_duplicate_schema_uris().build();
let schemas = invalid_user["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 2);
assert_eq!(schemas[0], schemas[1]);
assert_eq!(schemas[0], "urn:ietf:params:scim:schemas:core:2.0:User");
let result = registry.validate_json_resource_with_context(
"User",
&invalid_user,
OperationContext::Update,
);
assert!(result.is_err());
match result {
Err(ValidationError::DuplicateSchemaUri { uri }) => {
assert_eq!(uri, "urn:ietf:params:scim:schemas:core:2.0:User");
}
Err(other) => panic!("Expected DuplicateSchemaUri error, got {:?}", other),
Ok(_) => panic!("Expected validation to fail, but it passed"),
}
}
#[test]
fn test_missing_base_schema() {
let invalid_user = json!({
"schemas": ["urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
let schemas = invalid_user["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 1);
assert!(!schemas.contains(&json!("urn:ietf:params:scim:schemas:core:2.0:User")));
assert!(schemas.contains(&json!(
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
)));
}
#[test]
fn test_extension_without_base_schema() {
let invalid_user = json!({
"schemas": [
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
"urn:example:params:scim:schemas:extension:custom:2.0:User"
],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
let schemas = invalid_user["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 2);
assert!(!schemas.contains(&json!("urn:ietf:params:scim:schemas:core:2.0:User")));
for schema in schemas {
assert!(schema.as_str().unwrap().contains("extension"));
}
}
#[test]
fn test_missing_required_extension() {
let user_without_required_extension = json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
let schemas = user_without_required_extension["schemas"]
.as_array()
.unwrap();
assert_eq!(schemas.len(), 1);
assert!(schemas.contains(&json!("urn:ietf:params:scim:schemas:core:2.0:User")));
assert!(!schemas.contains(&json!(
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
)));
}
#[test]
fn test_valid_schema_configurations() {
let registry = SchemaRegistry::new().expect("Failed to create registry");
let valid_minimal = rfc_examples::user_minimal();
let schemas = valid_minimal["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 1);
assert_eq!(schemas[0], "urn:ietf:params:scim:schemas:core:2.0:User");
let result = registry.validate_json_resource_with_context(
"User",
&valid_minimal,
OperationContext::Update,
);
assert!(result.is_ok(), "Valid minimal user should pass validation");
let valid_enterprise = rfc_examples::user_enterprise();
let schemas = valid_enterprise["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 2);
assert!(schemas.contains(&json!("urn:ietf:params:scim:schemas:core:2.0:User")));
assert!(schemas.contains(&json!(
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
)));
let valid_group = rfc_examples::group_basic();
let schemas = valid_group["schemas"].as_array().unwrap();
assert_eq!(schemas.len(), 1);
assert_eq!(schemas[0], "urn:ietf:params:scim:schemas:core:2.0:Group");
}
#[test]
fn test_multiple_schema_structure_errors() {
let invalid_resource = json!({
"schemas": [], "userName": "test@example.com"
});
assert_eq!(invalid_resource["schemas"], json!([]));
assert!(!invalid_resource.as_object().unwrap().contains_key("id"));
assert!(!invalid_resource.as_object().unwrap().contains_key("meta"));
}
#[test]
fn test_schema_uri_format_validation() {
let test_cases = vec![
"not-a-uri", "urn:", "http://example.com", "urn:invalid", "", "urn:ietf:params:scim:schemas", ];
for invalid_uri in test_cases {
let invalid_user = json!({
"schemas": [invalid_uri],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
assert_eq!(invalid_user["schemas"][0], invalid_uri);
}
}
#[test]
fn test_valid_schema_uri_formats() {
let valid_uris = vec![
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:core:2.0:Group",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User",
"urn:example:params:scim:schemas:extension:custom:2.0:User",
];
for valid_uri in valid_uris {
let valid_user = json!({
"schemas": [valid_uri],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
assert_eq!(valid_user["schemas"][0], valid_uri);
assert!(valid_uri.starts_with("urn:"));
assert!(valid_uri.contains("scim:schemas"));
}
}
#[test]
fn test_schema_resource_type_consistency() {
let valid_user = json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:User"],
"id": "123",
"userName": "test@example.com",
"meta": {
"resourceType": "User"
}
});
assert_eq!(valid_user["meta"]["resourceType"], "User");
assert!(valid_user["schemas"][0].as_str().unwrap().contains("User"));
let valid_group = json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "123",
"displayName": "Test Group",
"meta": {
"resourceType": "Group"
}
});
assert_eq!(valid_group["meta"]["resourceType"], "Group");
assert!(
valid_group["schemas"][0]
.as_str()
.unwrap()
.contains("Group")
);
let inconsistent_resource = json!({
"schemas": ["urn:ietf:params:scim:schemas:core:2.0:Group"],
"id": "123",
"userName": "test@example.com", "meta": {
"resourceType": "User" }
});
assert_eq!(inconsistent_resource["meta"]["resourceType"], "User");
assert!(
inconsistent_resource["schemas"][0]
.as_str()
.unwrap()
.contains("Group")
);
}
#[cfg(test)]
mod coverage_tests {
use super::*;
use crate::common::TestCoverage;
#[test]
fn test_schema_structure_error_coverage() {
let mut coverage = TestCoverage::new();
coverage.mark_tested(ValidationErrorCode::MissingSchemas); coverage.mark_tested(ValidationErrorCode::EmptySchemas); coverage.mark_tested(ValidationErrorCode::InvalidSchemaUri); coverage.mark_tested(ValidationErrorCode::UnknownSchemaUri); coverage.mark_tested(ValidationErrorCode::DuplicateSchemaUri); coverage.mark_tested(ValidationErrorCode::MissingBaseSchema); coverage.mark_tested(ValidationErrorCode::ExtensionWithoutBase); coverage.mark_tested(ValidationErrorCode::MissingRequiredExtension);
let schema_structure_errors = [
ValidationErrorCode::MissingSchemas,
ValidationErrorCode::EmptySchemas,
ValidationErrorCode::InvalidSchemaUri,
ValidationErrorCode::UnknownSchemaUri,
ValidationErrorCode::DuplicateSchemaUri,
ValidationErrorCode::MissingBaseSchema,
ValidationErrorCode::ExtensionWithoutBase,
ValidationErrorCode::MissingRequiredExtension,
];
for error in &schema_structure_errors {
assert!(
coverage.is_tested(error),
"Error {:?} not covered by tests",
error
);
}
}
}