Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

153 changes: 153 additions & 0 deletions src/core/all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,4 +474,157 @@ mod tests {
let err = validate_registry(&registered, &declared).expect_err("expected duplicate input");
assert!(err.contains("duplicate required input `use_cache` in `doctor.models`"));
}

#[test]
fn validate_registry_accepts_valid_registry() {
let declared = vec![
schema("ns1", "fn1", vec![]),
schema("ns1", "fn2", vec![]),
schema("ns2", "fn1", vec![]),
];
let registered = declared
.iter()
.map(|s| RegisteredController {
schema: s.clone(),
handler: noop_handler,
})
.collect::<Vec<_>>();
assert!(validate_registry(&registered, &declared).is_ok());
}

#[test]
fn rpc_method_name_formats_correctly() {
let s = schema("memory", "doc_put", vec![]);
assert_eq!(rpc_method_name(&s), "openhuman.memory_doc_put");
}

#[test]
fn registered_controller_rpc_method_name() {
let s = schema("billing", "get_balance", vec![]);
let rc = RegisteredController {
schema: s,
handler: noop_handler,
};
assert_eq!(rc.rpc_method_name(), "openhuman.billing_get_balance");
}

#[test]
fn namespace_description_known_namespaces() {
assert!(namespace_description("memory").is_some());
assert!(namespace_description("billing").is_some());
assert!(namespace_description("config").is_some());
assert!(namespace_description("health").is_some());
assert!(namespace_description("voice").is_some());
assert!(namespace_description("webhooks").is_some());
}

#[test]
fn namespace_description_unknown_returns_none() {
assert!(namespace_description("nonexistent_xyz").is_none());
}

#[test]
fn validate_params_accepts_valid_params() {
let s = schema(
"test",
"fn",
vec![FieldSchema {
name: "key",
ty: TypeSchema::String,
comment: "a key",
required: true,
}],
);
let mut params = Map::new();
params.insert("key".into(), Value::String("value".into()));
assert!(validate_params(&s, &params).is_ok());
}

#[test]
fn validate_params_rejects_missing_required() {
let s = schema(
"test",
"fn",
vec![FieldSchema {
name: "key",
ty: TypeSchema::String,
comment: "a key",
required: true,
}],
);
let params = Map::new();
let err = validate_params(&s, &params).unwrap_err();
assert!(err.contains("missing required param 'key'"));
}

#[test]
fn validate_params_rejects_unknown_param() {
let s = schema("test", "fn", vec![]);
let mut params = Map::new();
params.insert("unknown".into(), Value::Null);
let err = validate_params(&s, &params).unwrap_err();
assert!(err.contains("unknown param 'unknown'"));
}

#[test]
fn validate_params_accepts_empty_for_no_required() {
let s = schema("test", "fn", vec![]);
assert!(validate_params(&s, &Map::new()).is_ok());
}

#[test]
fn all_registered_controllers_is_nonempty() {
let controllers = all_registered_controllers();
assert!(
controllers.len() > 50,
"expected many controllers, got {}",
controllers.len()
);
}

#[test]
fn all_controller_schemas_matches_registered_count() {
let schemas = all_controller_schemas();
let controllers = all_registered_controllers();
assert_eq!(schemas.len(), controllers.len());
}

#[test]
fn schema_for_rpc_method_finds_known_method() {
let schema = schema_for_rpc_method("openhuman.health_snapshot");
assert!(schema.is_some(), "health.snapshot should be findable");
let s = schema.unwrap();
assert_eq!(s.namespace, "health");
assert_eq!(s.function, "snapshot");
}

#[test]
fn schema_for_rpc_method_returns_none_for_unknown() {
assert!(schema_for_rpc_method("openhuman.nonexistent_method_xyz").is_none());
}

#[test]
fn rpc_method_from_parts_finds_known() {
let method = rpc_method_from_parts("health", "snapshot");
assert_eq!(method.as_deref(), Some("openhuman.health_snapshot"));
}

#[test]
fn rpc_method_from_parts_returns_none_for_unknown() {
assert!(rpc_method_from_parts("fake", "method").is_none());
}

#[test]
fn no_duplicate_rpc_methods_in_registry() {
let controllers = all_registered_controllers();
let mut methods: Vec<String> = controllers.iter().map(|c| c.rpc_method_name()).collect();
let original_len = methods.len();
methods.sort();
methods.dedup();
assert_eq!(
methods.len(),
original_len,
"duplicate RPC methods found in registry"
);
}
}
29 changes: 29 additions & 0 deletions src/openhuman/accessibility/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,32 @@ const KCG_EVENT_SOURCE_STATE_COMBINED_SESSION_STATE: i32 = 0;
const KVK_TAB: u16 = 48;
#[cfg(target_os = "macos")]
const KVK_ESCAPE: u16 = 53;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn is_tab_key_down_returns_bool() {
// Just verify it doesn't panic and returns a bool.
let _result: bool = is_tab_key_down();
}

#[test]
fn is_escape_key_down_returns_bool() {
let _result: bool = is_escape_key_down();
}

#[cfg(target_os = "macos")]
#[test]
fn input_monitoring_recheck_interval_is_positive() {
assert!(INPUT_MONITORING_RECHECK_MS > 0);
}

#[cfg(target_os = "macos")]
#[test]
fn kvk_constants_are_correct() {
assert_eq!(KVK_TAB, 48);
assert_eq!(KVK_ESCAPE, 53);
}
}
105 changes: 105 additions & 0 deletions src/openhuman/accessibility/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,108 @@ pub fn extract_terminal_input_context(text: &str) -> String {
}
fallback
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn is_text_role_accepts_known_roles() {
assert!(is_text_role(Some("AXTextArea")));
assert!(is_text_role(Some("AXTextField")));
assert!(is_text_role(Some("AXSearchField")));
assert!(is_text_role(Some("AXComboBox")));
assert!(is_text_role(Some("AXEditableText")));
}

#[test]
fn is_text_role_rejects_other_roles() {
assert!(!is_text_role(Some("AXButton")));
assert!(!is_text_role(Some("AXImage")));
assert!(!is_text_role(None));
assert!(!is_text_role(Some("")));
}

#[test]
fn is_terminal_app_detects_known_terminals() {
assert!(is_terminal_app(Some("iTerm2")));
assert!(is_terminal_app(Some("Terminal")));
assert!(is_terminal_app(Some("WezTerm")));
assert!(is_terminal_app(Some("Alacritty")));
assert!(is_terminal_app(Some("kitty")));
assert!(is_terminal_app(Some("Warp")));
assert!(is_terminal_app(Some("Ghostty")));
}

#[test]
fn is_terminal_app_rejects_non_terminals() {
assert!(!is_terminal_app(Some("Safari")));
assert!(!is_terminal_app(Some("Slack")));
assert!(!is_terminal_app(None));
assert!(!is_terminal_app(Some("")));
}

#[test]
fn looks_like_terminal_buffer_detects_shell_prompts() {
let buffer = "line1\nline2\nline3\nline4\n$ cargo build\nCompiling...\n";
assert!(looks_like_terminal_buffer(buffer));
}

#[test]
fn looks_like_terminal_buffer_rejects_short_text() {
assert!(!looks_like_terminal_buffer("hello"));
assert!(!looks_like_terminal_buffer("$ cmd"));
}

#[test]
fn looks_like_terminal_buffer_detects_git_status() {
let buffer = "line1\nline2\nline3\nline4\ngit status\nOn branch main\n";
assert!(looks_like_terminal_buffer(buffer));
}

#[test]
fn extract_terminal_input_context_finds_prompt_line() {
let text = "old output\n$ ls -la\ntotal 42\nfile1.txt\nfile2.txt\n";
let ctx = extract_terminal_input_context(text);
assert!(ctx.contains("$ ls"), "expected prompt line, got: {ctx}");
}

#[test]
fn extract_terminal_input_context_skips_noise() {
let text = "actual content\n• bullet point\n└── tree branch\n│ pipe\n";
let ctx = extract_terminal_input_context(text);
assert_eq!(ctx, "actual content");
}

#[test]
fn extract_terminal_input_context_empty_returns_empty() {
assert!(extract_terminal_input_context("").is_empty());
}

#[test]
fn extract_terminal_input_context_all_noise_returns_empty() {
let text = "\n\n\n";
assert!(extract_terminal_input_context(text).is_empty());
}

#[test]
fn terminal_names_is_nonempty() {
assert!(!TERMINAL_NAMES.is_empty());
}

#[test]
fn is_terminal_noise_line_detects_noise() {
assert!(is_terminal_noise_line(""));
assert!(is_terminal_noise_line(" "));
assert!(is_terminal_noise_line("• item"));
assert!(is_terminal_noise_line("└── branch"));
assert!(is_terminal_noise_line("─────"));
assert!(is_terminal_noise_line("│ pipe"));
}

#[test]
fn is_terminal_noise_line_passes_normal_text() {
assert!(!is_terminal_noise_line("hello world"));
assert!(!is_terminal_noise_line("$ command"));
}
}
36 changes: 36 additions & 0 deletions src/openhuman/channels/runtime/supervision.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,39 @@ pub(crate) fn compute_max_in_flight_messages(channel_count: usize) -> usize {
CHANNEL_MAX_IN_FLIGHT_MESSAGES,
)
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn compute_max_in_flight_messages_zero_channels() {
let result = compute_max_in_flight_messages(0);
assert_eq!(result, CHANNEL_MIN_IN_FLIGHT_MESSAGES);
}

#[test]
fn compute_max_in_flight_messages_one_channel() {
let result = compute_max_in_flight_messages(1);
assert!(result >= CHANNEL_MIN_IN_FLIGHT_MESSAGES);
assert!(result <= CHANNEL_MAX_IN_FLIGHT_MESSAGES);
}

#[test]
fn compute_max_in_flight_messages_many_channels() {
let result = compute_max_in_flight_messages(100);
assert_eq!(result, CHANNEL_MAX_IN_FLIGHT_MESSAGES);
}

#[test]
fn compute_max_in_flight_messages_clamps_to_min() {
let result = compute_max_in_flight_messages(0);
assert!(result >= CHANNEL_MIN_IN_FLIGHT_MESSAGES);
}

#[test]
fn compute_max_in_flight_messages_clamps_to_max() {
let result = compute_max_in_flight_messages(usize::MAX);
assert!(result <= CHANNEL_MAX_IN_FLIGHT_MESSAGES);
}
}
Loading
Loading