actl-uia 0.1.8

Windows UIA backend: the ONLY crate allowed to touch COM/unsafe
use super::*;

#[test]
fn role_only_queries_have_a_native_seed() {
    assert_eq!(super::super::role_id("document"), Some(50030));
    assert_eq!(super::super::role_id("Edit"), Some(50004));
    assert_eq!(super::super::role_id("unknown-role"), None);
    let q = query(r#"{"match":{"role":"Document"}}"#);
    assert_eq!(
        resolve(&provider(vec![node("doc", "Document", vec![])]), &q)
            .unwrap()
            .item
            .role,
        "Document"
    );
}

#[derive(Clone)]
struct Provider {
    hits: Vec<Fake>,
    item: Fake,
    error: Option<ErrorCode>,
}
impl Tree for Provider {
    fn exact_candidates(
        &self,
        _: &Filter,
        _: Scope,
        _: bool,
    ) -> Result<Option<Vec<Self>>, CtlError> {
        if let Some(code) = self.error {
            return Err(CtlError::new(code, "provider failed"));
        }
        Ok(Some(
            self.hits
                .iter()
                .map(|item| Self {
                    item: item.clone(),
                    hits: vec![],
                    error: None,
                })
                .collect(),
        ))
    }
    fn children(&self) -> Result<Vec<Self>, CtlError> {
        panic!("provider query must not fall back to DFS")
    }
    fn matches(&self, filter: &Filter) -> Result<bool, CtlError> {
        if self.item.broken {
            Err(CtlError::internal("property unavailable"))
        } else {
            self.item.matches(filter)
        }
    }
    fn evidence(&self) -> Result<serde_json::Value, CtlError> {
        self.item.evidence()
    }
}
fn provider(hits: Vec<Fake>) -> Provider {
    Provider {
        hits,
        item: node("root", "Window", vec![]),
        error: None,
    }
}

#[test]
fn complete_candidates_are_rechecked_and_duplicates_rejected() {
    let q = query(r#"{"match":{"id":"same","role":"Button"}}"#);
    let p = provider(vec![
        node("same", "Pane", vec![]),
        node("same", "Button", vec![]),
    ]);
    assert_eq!(resolve(&p, &q).unwrap().item.role, "Button");
    let p = provider(vec![node("same", "Button", vec![]); 2]);
    assert_eq!(resolve(&p, &q).err().unwrap().code, ErrorCode::Ambiguous);
    assert_eq!(
        resolve(&provider(vec![]), &q).err().unwrap().code,
        ErrorCode::NotFound
    );
}

#[test]
fn provider_and_late_property_failures_cannot_prove_uniqueness() {
    let q = query(r#"{"match":{"id":"same"}}"#);
    for code in [
        ErrorCode::Internal,
        ErrorCode::StaleRef,
        ErrorCode::PermDenied,
    ] {
        let mut p = provider(vec![node("same", "Button", vec![])]);
        p.error = Some(code);
        assert_eq!(resolve(&p, &q).err().unwrap().code, code);
    }
    let mut bad = node("same", "Button", vec![]);
    bad.broken = true;
    let p = provider(vec![node("same", "Button", vec![]), bad]);
    assert_eq!(resolve(&p, &q).err().unwrap().code, ErrorCode::Internal);
    let p = provider(vec![
        node("same", "Button", vec![]);
        crate::MAX_ELEMENTS + 1
    ]);
    let error = resolve(&p, &q).err().unwrap();
    assert_eq!(error.code, ErrorCode::NotActionable);
    assert_eq!(
        serde_json::to_value(actl_core::ErrorEnvelope::new("find", &error, 0)).unwrap(),
        serde_json::from_str::<serde_json::Value>(include_str!(
            "../../../tests/golden/selector_candidate_budget.json"
        ))
        .unwrap()
    );
}