mirror of
https://github.com/openai/codex.git
synced 2026-10-26 18:38:47 +00:00
Fixes stale test fixtures left after the active bundled model catalog updates in #18586 and #18388. Those changes made `gpt-5.4` the current default and removed several older hardcoded slugs, which left Windows Bazel shards failing TUI and config tests. What changed: - Refresh TUI model migration, availability NUX, plan-mode, status, and snapshot fixtures to use active bundled model slugs. - Update the config edit test expectation for the TOML-quoted `"gpt-5.2"` migration key. - Move the model catalog tests into `codex-rs/tui/src/app/tests/model_catalog.rs` so touching them does not trip the blob-size policy for `app.rs`. Verification: - CI Bazel/lint checks are expected to cover the affected test shards.
294 lines
8.7 KiB
Rust
294 lines
8.7 KiB
Rust
use super::*;
|
|
use codex_config::types::ModelAvailabilityNuxConfig;
|
|
use codex_protocol::openai_models::ModelAvailabilityNux;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
fn all_model_presets() -> Vec<ModelPreset> {
|
|
crate::legacy_core::test_support::all_model_presets().clone()
|
|
}
|
|
|
|
fn model_availability_nux_config(shown_count: &[(&str, u32)]) -> ModelAvailabilityNuxConfig {
|
|
ModelAvailabilityNuxConfig {
|
|
shown_count: shown_count
|
|
.iter()
|
|
.map(|(model, count)| ((*model).to_string(), *count))
|
|
.collect(),
|
|
}
|
|
}
|
|
|
|
fn model_migration_copy_to_plain_text(copy: &crate::model_migration::ModelMigrationCopy) -> String {
|
|
if let Some(markdown) = copy.markdown.as_ref() {
|
|
return markdown.clone();
|
|
}
|
|
let mut s = String::new();
|
|
for span in ©.heading {
|
|
s.push_str(&span.content);
|
|
}
|
|
s.push('\n');
|
|
s.push('\n');
|
|
for line in ©.content {
|
|
for span in &line.spans {
|
|
s.push_str(&span.content);
|
|
}
|
|
s.push('\n');
|
|
}
|
|
s
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn model_migration_prompt_only_shows_for_deprecated_models() {
|
|
let seen = BTreeMap::new();
|
|
assert!(should_show_model_migration_prompt(
|
|
"gpt-5.2",
|
|
"gpt-5.4",
|
|
&seen,
|
|
&all_model_presets()
|
|
));
|
|
assert!(should_show_model_migration_prompt(
|
|
"gpt-5.3-codex",
|
|
"gpt-5.4",
|
|
&seen,
|
|
&all_model_presets()
|
|
));
|
|
assert!(!should_show_model_migration_prompt(
|
|
"gpt-5.3-codex",
|
|
"gpt-5.3-codex",
|
|
&seen,
|
|
&all_model_presets()
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn select_model_availability_nux_picks_only_eligible_model() {
|
|
let mut presets = all_model_presets();
|
|
presets.iter_mut().for_each(|preset| {
|
|
preset.availability_nux = None;
|
|
});
|
|
let target = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4")
|
|
.expect("target preset present");
|
|
target.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "gpt-5.4 is available".to_string(),
|
|
});
|
|
|
|
let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[]));
|
|
|
|
assert_eq!(
|
|
selected,
|
|
Some(StartupTooltipOverride {
|
|
model_slug: "gpt-5.4".to_string(),
|
|
message: "gpt-5.4 is available".to_string(),
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn select_model_availability_nux_skips_missing_and_exhausted_models() {
|
|
let mut presets = all_model_presets();
|
|
presets.iter_mut().for_each(|preset| {
|
|
preset.availability_nux = None;
|
|
});
|
|
let gpt_5 = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4")
|
|
.expect("gpt-5.4 preset present");
|
|
gpt_5.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "gpt-5.4 is available".to_string(),
|
|
});
|
|
let gpt_5_2 = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4-mini")
|
|
.expect("gpt-5.4-mini preset present");
|
|
gpt_5_2.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "gpt-5.4-mini is available".to_string(),
|
|
});
|
|
|
|
let selected = select_model_availability_nux(
|
|
&presets,
|
|
&model_availability_nux_config(&[("gpt-5.4", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]),
|
|
);
|
|
|
|
assert_eq!(
|
|
selected,
|
|
Some(StartupTooltipOverride {
|
|
model_slug: "gpt-5.4-mini".to_string(),
|
|
message: "gpt-5.4-mini is available".to_string(),
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn select_model_availability_nux_uses_existing_model_order_as_priority() {
|
|
let mut presets = all_model_presets();
|
|
presets.iter_mut().for_each(|preset| {
|
|
preset.availability_nux = None;
|
|
});
|
|
let first = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4-mini")
|
|
.expect("gpt-5.4-mini preset present");
|
|
first.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "first".to_string(),
|
|
});
|
|
let second = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4")
|
|
.expect("gpt-5.4 preset present");
|
|
second.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "second".to_string(),
|
|
});
|
|
|
|
let selected = select_model_availability_nux(&presets, &model_availability_nux_config(&[]));
|
|
|
|
assert_eq!(
|
|
selected,
|
|
Some(StartupTooltipOverride {
|
|
model_slug: "gpt-5.4".to_string(),
|
|
message: "second".to_string(),
|
|
})
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn select_model_availability_nux_returns_none_when_all_models_are_exhausted() {
|
|
let mut presets = all_model_presets();
|
|
presets.iter_mut().for_each(|preset| {
|
|
preset.availability_nux = None;
|
|
});
|
|
let target = presets
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4")
|
|
.expect("target preset present");
|
|
target.availability_nux = Some(ModelAvailabilityNux {
|
|
message: "gpt-5.4 is available".to_string(),
|
|
});
|
|
|
|
let selected = select_model_availability_nux(
|
|
&presets,
|
|
&model_availability_nux_config(&[("gpt-5.4", MODEL_AVAILABILITY_NUX_MAX_SHOW_COUNT)]),
|
|
);
|
|
|
|
assert_eq!(selected, None);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn model_migration_prompt_respects_hide_flag_and_self_target() {
|
|
let mut seen = BTreeMap::new();
|
|
seen.insert("gpt-5.2".to_string(), "gpt-5.4".to_string());
|
|
assert!(!should_show_model_migration_prompt(
|
|
"gpt-5.2",
|
|
"gpt-5.4",
|
|
&seen,
|
|
&all_model_presets()
|
|
));
|
|
assert!(!should_show_model_migration_prompt(
|
|
"gpt-5.4",
|
|
"gpt-5.4",
|
|
&seen,
|
|
&all_model_presets()
|
|
));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn model_migration_prompt_skips_when_target_missing_or_hidden() {
|
|
let mut available = all_model_presets();
|
|
let mut current = available
|
|
.iter()
|
|
.find(|preset| preset.model == "gpt-5.2")
|
|
.cloned()
|
|
.expect("preset present");
|
|
current.upgrade = Some(ModelUpgrade {
|
|
id: "missing-target".to_string(),
|
|
reasoning_effort_mapping: None,
|
|
migration_config_key: HIDE_GPT5_1_MIGRATION_PROMPT_CONFIG.to_string(),
|
|
model_link: None,
|
|
upgrade_copy: None,
|
|
migration_markdown: None,
|
|
});
|
|
available.retain(|preset| preset.model != "gpt-5.2");
|
|
available.push(current.clone());
|
|
|
|
assert!(!should_show_model_migration_prompt(
|
|
¤t.model,
|
|
"missing-target",
|
|
&BTreeMap::new(),
|
|
&available,
|
|
));
|
|
|
|
assert!(target_preset_for_upgrade(&available, "missing-target").is_none());
|
|
|
|
let mut with_hidden_target = all_model_presets();
|
|
let target = with_hidden_target
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.4")
|
|
.expect("target preset present");
|
|
target.show_in_picker = false;
|
|
|
|
assert!(!should_show_model_migration_prompt(
|
|
"gpt-5.2",
|
|
"gpt-5.4",
|
|
&BTreeMap::new(),
|
|
&with_hidden_target,
|
|
));
|
|
assert!(target_preset_for_upgrade(&with_hidden_target, "gpt-5.4").is_none());
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn model_migration_prompt_shows_for_hidden_model() {
|
|
let codex_home = tempdir().expect("temp codex home");
|
|
let config = ConfigBuilder::default()
|
|
.codex_home(codex_home.path().to_path_buf())
|
|
.build()
|
|
.await
|
|
.expect("config");
|
|
|
|
let mut available_models = all_model_presets();
|
|
let current = available_models
|
|
.iter_mut()
|
|
.find(|preset| preset.model == "gpt-5.3-codex")
|
|
.expect("gpt-5.3-codex preset present");
|
|
current.show_in_picker = false;
|
|
let current = current.clone();
|
|
assert!(
|
|
!current.show_in_picker,
|
|
"expected gpt-5.3-codex to be hidden from picker for this test"
|
|
);
|
|
|
|
let upgrade = current.upgrade.as_ref().expect("upgrade configured");
|
|
available_models
|
|
.iter_mut()
|
|
.find(|preset| preset.model == upgrade.id)
|
|
.expect("upgrade target present")
|
|
.show_in_picker = true;
|
|
assert!(
|
|
should_show_model_migration_prompt(
|
|
¤t.model,
|
|
&upgrade.id,
|
|
&config.notices.model_migrations,
|
|
&available_models,
|
|
),
|
|
"expected migration prompt to be eligible for hidden model"
|
|
);
|
|
|
|
let target =
|
|
target_preset_for_upgrade(&available_models, &upgrade.id).expect("upgrade target present");
|
|
let target_description = (!target.description.is_empty()).then(|| target.description.clone());
|
|
let can_opt_out = true;
|
|
let copy = migration_copy_for_models(
|
|
¤t.model,
|
|
&upgrade.id,
|
|
upgrade.model_link.clone(),
|
|
upgrade.upgrade_copy.clone(),
|
|
upgrade.migration_markdown.clone(),
|
|
target.display_name.clone(),
|
|
target_description,
|
|
can_opt_out,
|
|
);
|
|
|
|
assert_snapshot!(
|
|
"model_migration_prompt_shows_for_hidden_model",
|
|
model_migration_copy_to_plain_text(©)
|
|
);
|
|
}
|