initial skeleton

This commit is contained in:
stoorps 2026-03-19 18:46:50 +00:00
parent dc79fa2448
commit 71f89dde9c
Signed by: stoorps
SSH key fingerprint: SHA256:AZlPfu9hTu042EGtZElmDQoy+KvMOeShLDan/fYLoNI
60 changed files with 3480 additions and 0 deletions

View file

@ -0,0 +1,7 @@
use aim_core::adapters::traits::AdapterCapabilities;
#[test]
fn adapter_capabilities_can_report_exact_resolution_only() {
let capabilities = AdapterCapabilities::exact_resolution_only();
assert!(!capabilities.supports_search);
}

View file

@ -0,0 +1,12 @@
use aim_core::adapters::all_adapter_kinds;
#[test]
fn all_expected_adapter_kinds_are_registered() {
let kinds = all_adapter_kinds();
assert!(kinds.contains(&"gitlab"));
assert!(kinds.contains(&"direct-url"));
assert!(kinds.contains(&"zsync"));
assert!(kinds.contains(&"sourceforge"));
assert!(kinds.contains(&"custom-json"));
}

View file

@ -0,0 +1,18 @@
use aim_core::app::add::build_add_plan;
use aim_core::app::query::resolve_query;
#[test]
fn github_adapter_can_normalize_owner_repo_source() {
let source = resolve_query("sharkdp/bat").unwrap();
assert_eq!(source.kind.as_str(), "github");
}
#[test]
fn add_flow_builds_github_plan_from_owner_repo_query() {
let plan = build_add_plan("sharkdp/bat").unwrap();
assert_eq!(plan.resolution.source.kind.as_str(), "github");
assert_eq!(plan.resolution.source.locator, "sharkdp/bat");
assert_eq!(plan.resolution.release.version, "latest");
}

View file

@ -0,0 +1,31 @@
use aim_core::app::identity::{IdentityFallback, resolve_identity};
use aim_core::domain::app::IdentityConfidence;
#[test]
fn unresolved_identity_can_fall_back_to_url() {
let identity = resolve_identity(
None,
None,
Some("https://example.com/app.AppImage"),
IdentityFallback::AllowRawUrl,
)
.unwrap();
assert!(identity.stable_id.contains("example.com"));
assert_eq!(identity.confidence, IdentityConfidence::RawUrlFallback);
}
#[test]
fn explicit_id_is_treated_as_confident() {
let identity = resolve_identity(
Some("Bat"),
Some("sharkdp/bat"),
Some("https://github.com/sharkdp/bat/releases"),
IdentityFallback::AllowRawUrl,
)
.unwrap();
assert_eq!(identity.stable_id, "sharkdp-bat");
assert_eq!(identity.display_name, "Bat");
assert_eq!(identity.confidence, IdentityConfidence::Confident);
}

View file

@ -0,0 +1,21 @@
use std::path::Path;
use aim_core::domain::app::InstallScope;
use aim_core::integration::paths::{desktop_entry_path, managed_appimage_path};
#[test]
fn user_scope_path_lands_under_home_managed_dir() {
let path = managed_appimage_path(Path::new("/home/test"), InstallScope::User, "bat");
assert_eq!(
path,
Path::new("/home/test/.local/lib/aim/appimages/bat.AppImage")
);
}
#[test]
fn system_scope_desktop_entry_uses_system_prefix() {
let path = desktop_entry_path(Path::new("/home/test"), InstallScope::System, "bat");
assert_eq!(path, Path::new("/usr/share/applications/aim-bat.desktop"));
}

View file

@ -0,0 +1,8 @@
use aim_core::app::scope::{ScopeOverride, resolve_install_scope};
use aim_core::domain::app::InstallScope;
#[test]
fn explicit_scope_override_beats_effective_user() {
let scope = resolve_install_scope(false, ScopeOverride::System);
assert_eq!(scope, InstallScope::System);
}

View file

@ -0,0 +1,8 @@
use aim_core::app::query::resolve_query;
use aim_core::domain::source::SourceKind;
#[test]
fn owner_repo_defaults_to_github() {
let source = resolve_query("sharkdp/bat").unwrap();
assert_eq!(source.kind, SourceKind::GitHub);
}

View file

@ -0,0 +1,10 @@
use aim_core::registry::store::RegistryStore;
use tempfile::tempdir;
#[test]
fn registry_round_trips_app_records() {
let dir = tempdir().unwrap();
let store = RegistryStore::new(dir.path().join("registry.toml"));
let loaded = store.load().unwrap();
assert!(loaded.apps.is_empty());
}

View file

@ -0,0 +1,49 @@
use aim_core::app::interaction::InteractionRequest;
use aim_core::app::list::build_list_rows;
use aim_core::app::remove::resolve_registered_app;
use aim_core::domain::app::AppRecord;
#[test]
fn remove_flow_rejects_unknown_app_names() {
let result = resolve_registered_app("bat", &[]);
assert!(result.is_err());
}
#[test]
fn list_flow_returns_display_rows_for_registered_apps() {
let rows = build_list_rows(&[AppRecord {
stable_id: "bat".to_owned(),
display_name: "Bat".to_owned(),
}]);
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].stable_id, "bat");
assert_eq!(rows[0].display_name, "Bat");
}
#[test]
fn ambiguous_remove_matches_include_stable_ids_for_client_choice() {
let apps = [
AppRecord {
stable_id: "bat".to_owned(),
display_name: "Bat".to_owned(),
},
AppRecord {
stable_id: "bat-nightly".to_owned(),
display_name: "Bat".to_owned(),
},
];
let error = resolve_registered_app("Bat", &apps).unwrap_err();
assert_eq!(
error,
aim_core::app::remove::ResolveRegisteredAppError::Ambiguous {
request: InteractionRequest::SelectRegisteredApp {
query: "Bat".to_owned(),
matches: vec!["Bat (bat)".to_owned(), "Bat (bat-nightly)".to_owned()],
},
}
);
}

View file

@ -0,0 +1,22 @@
use aim_core::app::update::build_update_plan;
use aim_core::domain::app::AppRecord;
#[test]
fn empty_registry_produces_empty_plan() {
let plan = build_update_plan(&[]).unwrap();
assert!(plan.items.is_empty());
}
#[test]
fn installed_apps_are_carried_into_review_plan() {
let apps = [AppRecord {
stable_id: "bat".to_owned(),
display_name: "Bat".to_owned(),
}];
let plan = build_update_plan(&apps).unwrap();
assert_eq!(plan.items.len(), 1);
assert_eq!(plan.items[0].stable_id, "bat");
}