use super::model::{InputProvider, Selector, Value};
use crate::protocol::models::LicenseState;
#[derive(Debug, Clone)]
pub struct GatewardenEvalInput {
state: LicenseState,
signature_verified: bool,
}
impl GatewardenEvalInput {
pub fn from_validated_response(state: LicenseState, signature_verified: bool) -> Self {
Self {
state,
signature_verified,
}
}
}
impl InputProvider for GatewardenEvalInput {
fn value_for(&self, selector: &Selector) -> Value {
match selector {
Selector::SignaturePresent => Value::Bool(self.signature_verified),
Selector::StateCode => Value::String(self.state.code.clone()),
Selector::StateValid => Value::Bool(self.state.valid),
Selector::Entitlements => Value::Strings(self.state.entitlements.clone()),
Selector::ExpiresAt => {
if self.state.expires_at.is_some() {
Value::Bool(true)
} else {
Value::Missing
}
}
Selector::UsageRemaining => {
Value::Missing
}
_ => Value::Missing,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::{DateTime, Utc};
fn sample_valid_state() -> LicenseState {
LicenseState {
valid: true,
entitlements: vec!["VISION_ANALYSIS".to_string(), "PREMIUM".to_string()],
expires_at: Some("2026-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
max_uses: Some(1000),
current_uses: Some(42),
code: "VALID".to_string(),
detail: Some("License is valid".to_string()),
}
}
fn sample_expired_state() -> LicenseState {
LicenseState {
valid: false,
entitlements: vec![],
expires_at: Some("2020-01-01T00:00:00Z".parse::<DateTime<Utc>>().unwrap()),
max_uses: None,
current_uses: None,
code: "EXPIRED".to_string(),
detail: Some("License has expired".to_string()),
}
}
fn sample_no_expiry_state() -> LicenseState {
LicenseState {
valid: true,
entitlements: vec!["BASIC".to_string()],
expires_at: None,
max_uses: None,
current_uses: None,
code: "VALID".to_string(),
detail: None,
}
}
#[test]
fn test_signature_present_selector() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(
input.value_for(&Selector::SignaturePresent),
Value::Bool(true)
);
let state2 = sample_valid_state();
let input2 = GatewardenEvalInput::from_validated_response(state2, false);
assert_eq!(
input2.value_for(&Selector::SignaturePresent),
Value::Bool(false)
);
}
#[test]
fn test_state_code_selector() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(
input.value_for(&Selector::StateCode),
Value::String("VALID".to_string())
);
let expired_state = sample_expired_state();
let input2 = GatewardenEvalInput::from_validated_response(expired_state, true);
assert_eq!(
input2.value_for(&Selector::StateCode),
Value::String("EXPIRED".to_string())
);
}
#[test]
fn test_state_valid_selector() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(input.value_for(&Selector::StateValid), Value::Bool(true));
let expired_state = sample_expired_state();
let input2 = GatewardenEvalInput::from_validated_response(expired_state, true);
assert_eq!(input2.value_for(&Selector::StateValid), Value::Bool(false));
}
#[test]
fn test_entitlements_selector() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
let expected = vec!["VISION_ANALYSIS".to_string(), "PREMIUM".to_string()];
assert_eq!(
input.value_for(&Selector::Entitlements),
Value::Strings(expected)
);
let expired_state = sample_expired_state();
let input2 = GatewardenEvalInput::from_validated_response(expired_state, true);
assert_eq!(
input2.value_for(&Selector::Entitlements),
Value::Strings(vec![])
);
}
#[test]
fn test_expires_at_selector_present() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(input.value_for(&Selector::ExpiresAt), Value::Bool(true));
}
#[test]
fn test_expires_at_selector_missing() {
let state = sample_no_expiry_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(input.value_for(&Selector::ExpiresAt), Value::Missing);
}
#[test]
fn test_usage_remaining_selector() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(input.value_for(&Selector::UsageRemaining), Value::Missing);
}
#[test]
fn test_other_selectors_return_missing() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state, true);
assert_eq!(input.value_for(&Selector::ProfileId), Value::Missing);
assert_eq!(input.value_for(&Selector::DigestMatches), Value::Missing);
assert_eq!(
input.value_for(&Selector::ResponseAgeSeconds),
Value::Missing
);
assert_eq!(input.value_for(&Selector::BridgeTokenValid), Value::Missing);
}
#[test]
fn test_multiple_entitlements() {
let state = LicenseState {
valid: true,
entitlements: vec![
"ENT_A".to_string(),
"ENT_B".to_string(),
"ENT_C".to_string(),
],
expires_at: None,
max_uses: None,
current_uses: None,
code: "VALID".to_string(),
detail: None,
};
let input = GatewardenEvalInput::from_validated_response(state, true);
let expected = vec![
"ENT_A".to_string(),
"ENT_B".to_string(),
"ENT_C".to_string(),
];
assert_eq!(
input.value_for(&Selector::Entitlements),
Value::Strings(expected)
);
}
#[test]
fn test_constructor_captures_state() {
let state = sample_valid_state();
let input = GatewardenEvalInput::from_validated_response(state.clone(), true);
assert_eq!(input.state.code, "VALID");
assert_eq!(input.state.valid, true);
assert!(input.signature_verified);
}
}