#![cfg(test)]
use crate::query::apply_create_defaults;
use crate::{CreateDefault, CreateDefaultType, SqlValue};
use cratestack_core::{CoolContext, CoolError, Value};
fn required_string_default(column: &'static str, auth_field: &'static str) -> CreateDefault {
CreateDefault {
column,
auth_field,
ty: CreateDefaultType::String,
nullable: true,
auth_field_required: true,
}
}
fn optional_string_default(
column: &'static str,
auth_field: &'static str,
nullable: bool,
) -> CreateDefault {
CreateDefault {
column,
auth_field,
ty: CreateDefaultType::String,
nullable,
auth_field_required: false,
}
}
#[test]
fn missing_required_auth_field_is_a_validation_error() {
let default = required_string_default("organization_id", "organization.id");
let ctx = CoolContext::authenticated([("id".to_owned(), Value::String("usr_1".to_owned()))]);
let err = apply_create_defaults(Vec::new(), &[default], &ctx)
.expect_err("missing required auth field must fail validation");
assert!(
matches!(err, CoolError::Validation(_)),
"expected Validation, got {err:?}"
);
}
#[test]
fn present_required_auth_field_resolves_normally() {
let default = required_string_default("organization_id", "organization.id");
let ctx = CoolContext::authenticated([(
"organization".to_owned(),
Value::Map(std::collections::BTreeMap::from([(
"id".to_owned(),
Value::String("org_1".to_owned()),
)])),
)]);
let values = apply_create_defaults(Vec::new(), &[default], &ctx)
.expect("present required auth field should resolve");
assert_eq!(values.len(), 1);
assert_eq!(values[0].column, "organization_id");
assert_eq!(values[0].value, SqlValue::String("org_1".to_owned()));
}
#[test]
fn missing_optional_auth_field_still_resolves_to_null() {
let default = optional_string_default("nickname", "nickname", true);
let ctx = CoolContext::authenticated([("id".to_owned(), Value::String("usr_1".to_owned()))]);
let values = apply_create_defaults(Vec::new(), &[default], &ctx)
.expect("missing optional auth field with nullable column should resolve to NULL");
assert_eq!(values[0].value, SqlValue::NullString);
}
#[test]
fn missing_optional_auth_field_with_non_nullable_column_still_errors() {
let default = optional_string_default("owner_id", "userId", false);
let authenticated =
CoolContext::authenticated([("id".to_owned(), Value::String("usr_1".to_owned()))]);
let err = apply_create_defaults(Vec::new(), &[default], &authenticated)
.expect_err("missing auth field for non-nullable column should fail validation");
assert!(matches!(err, CoolError::Validation(_)));
let anonymous = CoolContext::anonymous();
let err = apply_create_defaults(Vec::new(), &[default], &anonymous)
.expect_err("unauthenticated caller should be forbidden, not validation-failed");
assert!(matches!(err, CoolError::Forbidden(_)));
}
#[test]
fn missing_required_auth_field_with_anonymous_caller_is_forbidden_not_validation() {
let default = required_string_default("owner_id", "userId");
let anonymous = CoolContext::anonymous();
let err = apply_create_defaults(Vec::new(), &[default], &anonymous)
.expect_err("anonymous caller must still be forbidden");
assert!(
matches!(err, CoolError::Forbidden(_)),
"expected Forbidden, got {err:?}"
);
}
#[test]
fn present_auth_field_with_wrong_type_is_a_validation_error() {
let default = required_string_default("organization_id", "organization");
let ctx = CoolContext::authenticated([(
"organization".to_owned(),
Value::Int(1), )]);
let err = apply_create_defaults(Vec::new(), &[default], &ctx)
.expect_err("type-mismatched auth field should fail validation");
assert!(matches!(err, CoolError::Validation(_)));
}