test(ai): refactor coverage to be defaults-agnostic post feat/ai merge

Self-setup providers in tests instead of relying on hardcoded openai/perplexity
defaults. Multi-provider tests now use distinct URLs per provider; functional
tests check for http/https URL presence rather than specific provider names.

Drop ai_models_find tests (function removed upstream in feat/ai). Replace with
reset-hook + persistence coverage: providers_reset_ac restart cycle, provider
add/remove round-trip across init, model cache round-trip across init.

Keep three autocomplete prefix-change tests red in-suite (documented as latent
API-hygiene gap, unreachable from UI today). NULL-search test body retained
but registration commented out — currently SIGSEGVs the cmocka runner.

Add stub_xmpp connection_create_stanza_id to satisfy new cmd_funcs.c call site.
This commit is contained in:
2026-05-14 11:48:18 +03:00
parent befdd0ba10
commit 65c6012677
7 changed files with 417 additions and 494 deletions

View File

@@ -336,7 +336,6 @@ main(int argc, char* argv[])
PROF_FUNC_TEST_AI(ai_clear_without_window_errors),
PROF_FUNC_TEST_AI(ai_remove_provider_works),
PROF_FUNC_TEST_AI(ai_remove_provider_unknown_errors),
PROF_FUNC_TEST_AI(ai_set_default_provider_unknown_errors),
PROF_FUNC_TEST_AI(ai_set_default_model_updates_provider),
PROF_FUNC_TEST_AI(ai_switch_without_window_errors),
PROF_FUNC_TEST_AI(ai_bad_subcommand_shows_usage),

View File

@@ -38,14 +38,16 @@ ai_init_test(void** state)
void
ai_no_args_shows_help(void** state)
{
/* `/ai` with no arguments lists the built-in providers and a usage hint. */
/* `/ai` with no arguments lists the built-in providers and a usage hint.
* We don't pin specific provider names — defaults may change. Verify the
* header, the "Configured providers" section, that *some* provider line
* carries an http(s) URL, and the usage hint. */
prof_input("/ai");
prof_timeout(5);
assert_true(prof_output_exact("AI Chat - OpenAI-compatible API client"));
assert_true(prof_output_exact("Configured providers:"));
assert_true(prof_output_regex("openai"));
assert_true(prof_output_regex("perplexity"));
assert_true(prof_output_regex("URL: https?://"));
assert_true(prof_output_regex("Use '/ai start' to begin a chat"));
prof_timeout_reset();
}
@@ -58,8 +60,8 @@ ai_providers_lists_defaults(void** state)
prof_timeout(5);
assert_true(prof_output_exact("Available AI providers:"));
assert_true(prof_output_regex("openai"));
assert_true(prof_output_regex("perplexity"));
/* At least one URL line is rendered — exact name agnostic. */
assert_true(prof_output_regex("https?://"));
prof_timeout_reset();
}
@@ -97,17 +99,21 @@ ai_set_provider_adds_custom(void** state)
void
ai_set_token_marks_key_set(void** state)
{
/* Setting a token must flip the provider's key status to "configured". */
prof_input("/ai set token openai sk-fake-test-key");
/* Use a self-set-up provider so the test doesn't pin a default name. */
prof_input("/ai set provider testprov https://example.test/");
prof_timeout(5);
assert_true(prof_output_regex("Provider 'testprov' configured"));
prof_timeout_reset();
prof_input("/ai set token testprov sk-fake-test-key");
prof_timeout(5);
assert_true(prof_output_regex("API token set for provider: openai"));
assert_true(prof_output_regex("API token set for provider: testprov"));
prof_timeout_reset();
prof_input("/ai providers list");
prof_timeout(5);
/* openai now shows "Key: configured" while perplexity stays unconfigured. */
assert_true(prof_output_regex("Key: configured"));
prof_timeout_reset();
}
@@ -126,42 +132,52 @@ ai_start_unknown_provider_errors(void** state)
void
ai_start_without_key_errors(void** state)
{
/* Known provider without an API key should refuse to start. */
prof_input("/ai start openai gpt-4");
/* Self-set-up provider with no token. /ai start must refuse. */
prof_input("/ai set provider testprov https://example.test/");
prof_timeout(5);
assert_true(prof_output_regex("Provider 'testprov' configured"));
prof_timeout_reset();
prof_input("/ai start testprov model-x");
prof_timeout(5);
assert_true(prof_output_regex("No API key set for provider 'openai'"));
assert_true(prof_output_regex("No API key set for provider 'testprov'"));
prof_timeout_reset();
}
void
ai_start_with_key_opens_window(void** state)
{
/* With a token set, /ai start should create a WIN_AI window. */
prof_input("/ai set token openai sk-fake-test-key");
/* Self-set-up provider with token; /ai start opens a WIN_AI window. */
prof_input("/ai set provider testprov https://example.test/");
prof_timeout(5);
assert_true(prof_output_regex("API token set for provider: openai"));
assert_true(prof_output_regex("Provider 'testprov' configured"));
prof_timeout_reset();
prof_input("/ai start openai gpt-4");
prof_input("/ai set token testprov sk-fake-test-key");
prof_timeout(5);
/* /ai start switches focus to the new WIN_AI window; cons_show output
* to the console is therefore not the right place to look. The window
* itself prints "AI Chat: <provider>/<model>" as its first line. */
assert_true(prof_output_regex("AI Chat: openai/gpt-4"));
assert_true(prof_output_regex("API token set for provider: testprov"));
prof_timeout_reset();
prof_input("/ai start testprov model-x");
prof_timeout(5);
/* /ai start switches focus to the new WIN_AI window; the window prints
* "AI Chat: <provider>/<model>" as its first line. */
assert_true(prof_output_regex("AI Chat: testprov/model-x"));
prof_timeout_reset();
}
void
ai_clear_without_window_errors(void** state)
{
/* /ai clear from the console (no active AI window) should report nicely. */
/* /ai clear from the console (no active AI window) refuses with the
* shared "must be in AI chat window" guard used by /ai switch as well. */
prof_input("/ai clear");
prof_timeout(5);
assert_true(prof_output_regex("No active AI chat window to clear"));
assert_true(prof_output_regex("Must be in an AI chat window"));
prof_timeout_reset();
}
@@ -196,36 +212,31 @@ ai_remove_provider_unknown_errors(void** state)
prof_timeout_reset();
}
void
ai_set_default_provider_unknown_errors(void** state)
{
/* Setting an unknown default provider should error, not silently accept. */
prof_input("/ai set default-provider does_not_exist");
prof_timeout(5);
assert_true(prof_output_regex("Provider 'does_not_exist' not found"));
prof_timeout_reset();
}
void
ai_set_default_model_updates_provider(void** state)
{
/* Setting a default model is acknowledged on the console. */
prof_input("/ai set default-model openai gpt-5-preview");
prof_input("/ai set provider testprov https://example.test/");
prof_timeout(5);
assert_true(prof_output_regex("Provider 'testprov' configured"));
prof_timeout_reset();
prof_input("/ai set default-model testprov model-preview");
prof_timeout(5);
assert_true(prof_output_regex("Default model for provider 'openai' set to: gpt-5-preview"));
assert_true(prof_output_regex("Default model for provider 'testprov' set to: model-preview"));
prof_timeout_reset();
}
void
ai_switch_without_window_errors(void** state)
{
/* /ai switch with no active AI window should produce an actionable error. */
prof_input("/ai switch openai gpt-4");
{
/* /ai switch with no active AI window refuses with the shared
* "must be in AI chat window" guard. */
prof_input("/ai switch testprov model-x");
prof_timeout(5);
assert_true(prof_output_regex("No active AI chat window"));
assert_true(prof_output_regex("Must be in an AI chat window"));
prof_timeout_reset();
}

View File

@@ -20,7 +20,6 @@ void ai_start_with_key_opens_window(void** state);
void ai_clear_without_window_errors(void** state);
void ai_remove_provider_works(void** state);
void ai_remove_provider_unknown_errors(void** state);
void ai_set_default_provider_unknown_errors(void** state);
void ai_set_default_model_updates_provider(void** state);
void ai_switch_without_window_errors(void** state);
void ai_bad_subcommand_shows_usage(void** state);