openidauthzen 0.1.0-alpha.1

OpenID AuthZEN Authorization API 1.0 — Policy Decision and Enforcement Points for Rust
Documentation
use openidauthzen::*;

#[test]
fn page_should_omit_all_fields_when_none() {
    let page = Page { token: None, limit: None, properties: None };
    let json = serde_json::to_value(&page).unwrap();
    assert!(json.as_object().unwrap().is_empty());
}

#[test]
fn page_should_serialize_token_and_limit() {
    let page = Page {
        token: Some("abc123".to_owned()),
        limit: Some(10),
        properties: None,
    };
    let json = serde_json::to_value(&page).unwrap();
    assert_eq!(json["token"], "abc123");
    assert_eq!(json["limit"], 10);
}

#[test]
fn page_should_include_properties_when_present() {
    let page = Page {
        token: None,
        limit: None,
        properties: Some(serde_json::json!({"sort": "asc"})),
    };
    let json = serde_json::to_value(&page).unwrap();
    assert_eq!(json["properties"]["sort"], "asc");
}

#[test]
fn page_response_should_omit_all_fields_when_none() {
    let pr = PageResponse {
        next_token: None,
        count: None,
        total: None,
        properties: None,
    };
    let json = serde_json::to_value(&pr).unwrap();
    assert!(json.as_object().unwrap().is_empty());
}

#[test]
fn page_response_should_serialize_all_fields() {
    let pr = PageResponse {
        next_token: Some("a3M9NDU2O3N6PTI=".to_owned()),
        count: Some(2),
        total: Some(3),
        properties: None,
    };
    let json = serde_json::to_value(&pr).unwrap();
    assert_eq!(json["next_token"], "a3M9NDU2O3N6PTI=");
    assert_eq!(json["count"], 2);
    assert_eq!(json["total"], 3);
}

#[test]
fn page_response_should_roundtrip_spec_example() {
    let json = r#"{"next_token": "a3M9NDU2O3N6PTI=", "count": 2, "total": 3}"#;
    let pr: PageResponse = serde_json::from_str(json).unwrap();
    assert_eq!(pr.next_token.as_deref(), Some("a3M9NDU2O3N6PTI="));
    assert_eq!(pr.count, Some(2));
    assert_eq!(pr.total, Some(3));

    let roundtripped: PageResponse = serde_json::from_value(serde_json::to_value(&pr).unwrap()).unwrap();
    assert_eq!(roundtripped, pr);
}

#[test]
fn subject_search_request_should_serialize_all_fields() {
    let req = SubjectSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: None, properties: None },
        action: Action { name: "can_read".to_owned(), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
        context: Some({
            let mut m = serde_json::Map::new();
            m.insert("time".to_owned(), serde_json::json!("2024-10-26T01:22-07:00"));
            m
        }),
        page: Some(Page { token: None, limit: Some(10), properties: None }),
    };
    let json = serde_json::to_value(&req).unwrap();
    assert_eq!(json["subject"]["type"], "user");
    assert_eq!(json["action"]["name"], "can_read");
    assert_eq!(json["resource"]["id"], "123");
    assert_eq!(json["page"]["limit"], 10);
}

#[test]
fn subject_search_request_should_omit_context_and_page_when_none() {
    let req = SubjectSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: None, properties: None },
        action: Action { name: "can_read".to_owned(), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert!(json.get("context").is_none());
    assert!(json.get("page").is_none());
}

#[test]
fn subject_search_request_should_roundtrip_spec_example() {
    let json = r#"{
        "subject": {"type": "user"},
        "action": {"name": "can_read"},
        "resource": {"type": "account", "id": "123"},
        "context": {"time": "2024-10-26T01:22-07:00"}
    }"#;
    let req: SubjectSearchRequest = serde_json::from_str(json).unwrap();
    assert_eq!(req.subject.subject_type, "user");
    assert!(req.subject.id.is_none());

    let roundtripped: SubjectSearchRequest = serde_json::from_value(serde_json::to_value(&req).unwrap()).unwrap();
    assert_eq!(roundtripped, req);
}

#[test]
fn subject_search_response_should_serialize_results() {
    let resp = SubjectSearchResponse {
        results: vec![
            Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
            Subject { subject_type: "user".to_owned(), id: Some("bob@example.com".to_owned()), properties: None },
        ],
        page: None,
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["results"].as_array().unwrap().len(), 2);
    assert_eq!(json["results"][0]["id"], "alice@example.com");
}

#[test]
fn subject_search_response_should_omit_page_and_context_when_none() {
    let resp = SubjectSearchResponse {
        results: vec![],
        page: None,
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert!(json.get("page").is_none());
    assert!(json.get("context").is_none());
}

#[test]
fn subject_search_response_should_include_pagination() {
    let resp = SubjectSearchResponse {
        results: vec![
            Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        ],
        page: Some(PageResponse {
            next_token: Some("token123".to_owned()),
            count: Some(1),
            total: Some(5),
            properties: None,
        }),
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["page"]["next_token"], "token123");
    assert_eq!(json["page"]["count"], 1);
}

#[test]
fn resource_search_request_should_serialize_all_fields() {
    let req = ResourceSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        action: Action { name: "can_read".to_owned(), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: None, properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert_eq!(json["subject"]["id"], "alice@example.com");
    assert_eq!(json["resource"]["type"], "account");
    assert!(json["resource"].get("id").is_none());
}

#[test]
fn resource_search_request_should_omit_optional_fields_when_none() {
    let req = ResourceSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        action: Action { name: "can_read".to_owned(), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: None, properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert!(json.get("context").is_none());
    assert!(json.get("page").is_none());
}

#[test]
fn resource_search_response_should_serialize_results() {
    let resp = ResourceSearchResponse {
        results: vec![
            Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
            Resource { resource_type: "account".to_owned(), id: Some("456".to_owned()), properties: None },
        ],
        page: None,
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["results"].as_array().unwrap().len(), 2);
    assert_eq!(json["results"][1]["id"], "456");
}

#[test]
fn resource_search_response_should_include_pagination() {
    let resp = ResourceSearchResponse {
        results: vec![],
        page: Some(PageResponse {
            next_token: Some("".to_owned()),
            count: Some(0),
            total: Some(0),
            properties: None,
        }),
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["page"]["next_token"], "");
}

#[test]
fn action_search_request_should_not_have_action_field() {
    let req = ActionSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert!(json.get("action").is_none());
}

#[test]
fn action_search_request_should_serialize_subject_and_resource() {
    let req = ActionSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert_eq!(json["subject"]["type"], "user");
    assert_eq!(json["resource"]["id"], "123");
}

#[test]
fn action_search_request_should_omit_optional_fields_when_none() {
    let req = ActionSearchRequest {
        subject: Subject { subject_type: "user".to_owned(), id: Some("alice@example.com".to_owned()), properties: None },
        resource: Resource { resource_type: "account".to_owned(), id: Some("123".to_owned()), properties: None },
        context: None,
        page: None,
    };
    let json = serde_json::to_value(&req).unwrap();
    assert!(json.get("context").is_none());
    assert!(json.get("page").is_none());
}

#[test]
fn action_search_response_should_serialize_results() {
    let resp = ActionSearchResponse {
        results: vec![
            Action { name: "can_read".to_owned(), properties: None },
            Action { name: "can_write".to_owned(), properties: None },
        ],
        page: None,
        context: None,
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["results"].as_array().unwrap().len(), 2);
    assert_eq!(json["results"][0]["name"], "can_read");
    assert_eq!(json["results"][1]["name"], "can_write");
}

#[test]
fn action_search_response_should_include_pagination() {
    let resp = ActionSearchResponse {
        results: vec![],
        page: Some(PageResponse {
            next_token: Some("next".to_owned()),
            count: Some(0),
            total: None,
            properties: None,
        }),
        context: Some(serde_json::json!({"query_execution_time_ms": 42})),
    };
    let json = serde_json::to_value(&resp).unwrap();
    assert_eq!(json["page"]["next_token"], "next");
    assert_eq!(json["context"]["query_execution_time_ms"], 42);
}