Files
codex/codex-rs/features/src/tests.rs
T
Eric Traut 8a6a039f26 Remove terminal resize reflow flag gates (#27794)
## Why

`terminal_resize_reflow` is now stable and should behave as always on.
Keeping the disabled runtime paths around made the feature look
configurable even though the rollout is complete, and old config could
still suggest there was a supported off mode.

## What Changed

- Marked `terminal_resize_reflow` as `Stage::Removed` while keeping it
default-enabled for compatibility.
- Ignored `[features].terminal_resize_reflow` config entries so stale
`false` settings no longer affect the effective feature set.
- Removed TUI branches that depended on the flag being disabled, so
draw, replay buffering, stream finalization, and resize scheduling all
assume resize reflow is active.
- Simplified resize smoke coverage to exercise the always-on behavior
only.

## Verification

- `just test -p codex-features`
- `just test -p codex-tui resize_reflow`
- `just test -p codex-tui initial_replay_buffer
thread_switch_replay_buffer`
2026-06-15 08:23:02 -07:00

762 lines
24 KiB
Rust

use crate::Feature;
use crate::FeatureConfigSource;
use crate::FeatureOverrides;
use crate::FeatureToml;
use crate::Features;
use crate::FeaturesToml;
use crate::Stage;
use crate::feature_for_key;
use crate::unstable_features_warning_event;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::WarningEvent;
use pretty_assertions::assert_eq;
use std::collections::BTreeMap;
use toml::Table;
use toml::Value as TomlValue;
#[test]
fn under_development_features_are_disabled_by_default() {
for spec in crate::FEATURES {
if matches!(spec.stage, Stage::UnderDevelopment) {
assert_eq!(
spec.default_enabled, false,
"feature `{}` is under development and must be disabled by default",
spec.key
);
}
}
}
#[test]
fn default_enabled_features_are_stable() {
for spec in crate::FEATURES {
if spec.default_enabled {
assert!(
matches!(spec.stage, Stage::Stable | Stage::Removed),
"feature `{}` is enabled by default but is not stable/removed ({:?})",
spec.key,
spec.stage
);
}
}
}
#[test]
fn use_legacy_landlock_is_deprecated_and_disabled_by_default() {
assert_eq!(Feature::UseLegacyLandlock.stage(), Stage::Deprecated);
assert_eq!(Feature::UseLegacyLandlock.default_enabled(), false);
}
#[test]
fn use_linux_sandbox_bwrap_is_removed_and_disabled_by_default() {
assert_eq!(Feature::UseLinuxSandboxBwrap.stage(), Stage::Removed);
assert_eq!(Feature::UseLinuxSandboxBwrap.default_enabled(), false);
}
#[test]
fn undo_is_removed_and_disabled_by_default() {
assert_eq!(Feature::GhostCommit.stage(), Stage::Removed);
assert_eq!(Feature::GhostCommit.default_enabled(), false);
}
#[test]
fn image_detail_original_is_removed_and_disabled_by_default() {
assert_eq!(Feature::ImageDetailOriginal.stage(), Stage::Removed);
assert_eq!(Feature::ImageDetailOriginal.default_enabled(), false);
}
#[test]
fn apply_patch_freeform_is_removed_and_disabled_by_default() {
assert_eq!(Feature::ApplyPatchFreeform.stage(), Stage::Removed);
assert_eq!(Feature::ApplyPatchFreeform.default_enabled(), false);
assert_eq!(
feature_for_key("apply_patch_freeform"),
Some(Feature::ApplyPatchFreeform)
);
}
#[test]
fn plugin_hooks_is_removed_and_disabled_by_default() {
assert_eq!(Feature::PluginHooks.stage(), Stage::Removed);
assert_eq!(Feature::PluginHooks.default_enabled(), false);
assert_eq!(feature_for_key("plugin_hooks"), Some(Feature::PluginHooks));
}
#[test]
fn external_migration_is_removed_and_disabled_by_default() {
assert_eq!(Feature::ExternalMigration.stage(), Stage::Removed);
assert_eq!(Feature::ExternalMigration.default_enabled(), false);
assert_eq!(
feature_for_key("external_migration"),
Some(Feature::ExternalMigration)
);
}
#[test]
fn removed_apps_mcp_path_override_shapes_are_ignored() {
let features = [
toml::from_str::<FeaturesToml>("apps_mcp_path_override = true")
.expect("boolean compatibility form should deserialize"),
toml::from_str::<FeaturesToml>(
r#"
[apps_mcp_path_override]
enabled = true
path = "/custom/mcp"
"#,
)
.expect("structured compatibility form should deserialize"),
];
assert_eq!(
features.map(|features| features.entries()),
[BTreeMap::new(), BTreeMap::new()]
);
}
#[test]
fn code_mode_only_requires_code_mode() {
let mut features = Features::with_defaults();
features.enable(Feature::CodeModeOnly);
features.normalize_dependencies();
assert_eq!(features.enabled(Feature::CodeModeOnly), true);
assert_eq!(features.enabled(Feature::CodeMode), true);
}
#[test]
fn guardian_approval_is_stable_and_enabled_by_default() {
let spec = Feature::GuardianApproval.info();
assert_eq!(spec.stage, Stage::Stable);
assert_eq!(Feature::GuardianApproval.default_enabled(), true);
}
#[test]
fn request_permissions_is_under_development() {
assert_eq!(
Feature::ExecPermissionApprovals.stage(),
Stage::UnderDevelopment
);
assert_eq!(Feature::ExecPermissionApprovals.default_enabled(), false);
}
#[test]
fn request_permissions_tool_is_under_development() {
assert_eq!(
Feature::RequestPermissionsTool.stage(),
Stage::UnderDevelopment
);
assert_eq!(Feature::RequestPermissionsTool.default_enabled(), false);
}
#[test]
fn terminal_resize_reflow_is_removed_and_enabled_by_default() {
assert_eq!(
feature_for_key("terminal_resize_reflow"),
Some(Feature::TerminalResizeReflow)
);
assert_eq!(Feature::TerminalResizeReflow.stage(), Stage::Removed);
assert_eq!(Feature::TerminalResizeReflow.default_enabled(), true);
}
#[test]
fn from_sources_ignores_removed_terminal_resize_reflow_feature_key() {
let features_toml = FeaturesToml::from(BTreeMap::from([(
"terminal_resize_reflow".to_string(),
false,
)]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
assert_eq!(features.enabled(Feature::TerminalResizeReflow), true);
}
#[test]
fn tool_suggest_is_stable_and_enabled_by_default() {
assert_eq!(Feature::ToolSuggest.stage(), Stage::Stable);
assert_eq!(Feature::ToolSuggest.default_enabled(), true);
}
#[test]
fn network_proxy_is_experimental_and_disabled_by_default() {
assert_eq!(
feature_for_key("network_proxy"),
Some(Feature::NetworkProxy)
);
assert!(matches!(
Feature::NetworkProxy.stage(),
Stage::Experimental { .. }
));
assert_eq!(Feature::NetworkProxy.default_enabled(), false);
}
#[test]
fn tool_search_is_removed_and_disabled_by_default() {
assert_eq!(Feature::ToolSearch.stage(), Stage::Removed);
assert_eq!(Feature::ToolSearch.default_enabled(), false);
assert_eq!(feature_for_key("tool_search"), Some(Feature::ToolSearch));
}
#[test]
fn secret_auth_storage_defaults_to_windows_only() {
assert_eq!(Feature::SecretAuthStorage.stage(), Stage::Stable);
assert_eq!(Feature::SecretAuthStorage.default_enabled(), cfg!(windows));
assert_eq!(
feature_for_key("secret_auth_storage"),
Some(Feature::SecretAuthStorage)
);
}
#[test]
fn browser_controls_are_stable_and_enabled_by_default() {
assert_eq!(Feature::InAppBrowser.stage(), Stage::Stable);
assert_eq!(Feature::InAppBrowser.default_enabled(), true);
assert_eq!(
feature_for_key("in_app_browser"),
Some(Feature::InAppBrowser)
);
assert_eq!(Feature::BrowserUse.stage(), Stage::Stable);
assert_eq!(Feature::BrowserUse.default_enabled(), true);
assert_eq!(feature_for_key("browser_use"), Some(Feature::BrowserUse));
assert_eq!(Feature::BrowserUseExternal.stage(), Stage::Stable);
assert_eq!(Feature::BrowserUseExternal.default_enabled(), true);
assert_eq!(
feature_for_key("browser_use_external"),
Some(Feature::BrowserUseExternal)
);
assert_eq!(Feature::ComputerUse.stage(), Stage::Stable);
assert_eq!(Feature::ComputerUse.default_enabled(), true);
assert_eq!(feature_for_key("computer_use"), Some(Feature::ComputerUse));
}
#[test]
fn use_linux_sandbox_bwrap_is_a_removed_feature_key() {
assert_eq!(
feature_for_key("use_legacy_landlock"),
Some(Feature::UseLegacyLandlock)
);
assert_eq!(
feature_for_key("use_linux_sandbox_bwrap"),
Some(Feature::UseLinuxSandboxBwrap)
);
}
#[test]
fn image_generation_is_stable_and_enabled_by_default() {
assert_eq!(Feature::ImageGeneration.stage(), Stage::Stable);
assert_eq!(Feature::ImageGeneration.default_enabled(), true);
}
#[test]
fn image_generation_extension_is_under_development_and_disabled_by_default() {
assert_eq!(Feature::ImageGenExt.stage(), Stage::UnderDevelopment);
assert_eq!(Feature::ImageGenExt.default_enabled(), false);
assert_eq!(feature_for_key("imagegenext"), Some(Feature::ImageGenExt));
}
#[test]
fn use_legacy_landlock_config_records_deprecation_notice() {
let mut entries = BTreeMap::new();
entries.insert("use_legacy_landlock".to_string(), true);
let mut features = Features::with_defaults();
features.apply_map(&entries);
let usages = features.legacy_feature_usages().collect::<Vec<_>>();
assert_eq!(usages.len(), 1);
assert_eq!(usages[0].alias, "features.use_legacy_landlock");
assert_eq!(usages[0].feature, Feature::UseLegacyLandlock);
assert_eq!(
usages[0].summary,
"`[features].use_legacy_landlock` is deprecated and will be removed soon."
);
assert_eq!(
usages[0].details.as_deref(),
Some("Remove this setting to stop opting into the legacy Linux sandbox behavior.")
);
}
#[test]
fn image_detail_original_is_a_removed_feature_key() {
assert_eq!(
feature_for_key("image_detail_original"),
Some(Feature::ImageDetailOriginal)
);
}
#[test]
fn js_repl_features_are_removed_feature_keys() {
assert_eq!(Feature::JsRepl.stage(), Stage::Removed);
assert_eq!(Feature::JsRepl.default_enabled(), false);
assert_eq!(feature_for_key("js_repl"), Some(Feature::JsRepl));
assert_eq!(Feature::JsReplToolsOnly.stage(), Stage::Removed);
assert_eq!(Feature::JsReplToolsOnly.default_enabled(), false);
assert_eq!(
feature_for_key("js_repl_tools_only"),
Some(Feature::JsReplToolsOnly)
);
}
#[test]
fn tool_call_mcp_elicitation_is_stable_and_enabled_by_default() {
assert_eq!(Feature::ToolCallMcpElicitation.stage(), Stage::Stable);
assert_eq!(Feature::ToolCallMcpElicitation.default_enabled(), true);
}
#[test]
fn auth_elicitation_is_under_development() {
assert_eq!(Feature::AuthElicitation.stage(), Stage::UnderDevelopment);
assert_eq!(Feature::AuthElicitation.default_enabled(), false);
assert_eq!(
feature_for_key("auth_elicitation"),
Some(Feature::AuthElicitation)
);
}
#[test]
fn mentions_v2_is_stable_and_enabled_by_default() {
assert_eq!(Feature::MentionsV2.stage(), Stage::Stable);
assert_eq!(Feature::MentionsV2.default_enabled(), true);
assert_eq!(feature_for_key("mentions_v2"), Some(Feature::MentionsV2));
}
#[test]
fn remote_control_is_removed_and_disabled_by_default() {
assert_eq!(Feature::RemoteControl.stage(), Stage::Removed);
assert_eq!(Feature::RemoteControl.default_enabled(), false);
assert_eq!(
feature_for_key("remote_control"),
Some(Feature::RemoteControl)
);
}
#[test]
fn remote_control_config_is_ignored() {
let mut entries = BTreeMap::new();
entries.insert("remote_control".to_string(), true);
let mut features = Features::with_defaults();
features.apply_map(&entries);
assert_eq!(features.enabled(Feature::RemoteControl), false);
}
#[test]
fn workspace_dependencies_is_stable_and_enabled_by_default() {
assert_eq!(Feature::WorkspaceDependencies.stage(), Stage::Stable);
assert_eq!(Feature::WorkspaceDependencies.default_enabled(), true);
assert_eq!(
feature_for_key("workspace_dependencies"),
Some(Feature::WorkspaceDependencies)
);
}
#[test]
fn telepathy_is_legacy_alias_for_chronicle() {
assert_eq!(Feature::Chronicle.stage(), Stage::UnderDevelopment);
assert_eq!(Feature::Chronicle.default_enabled(), false);
assert_eq!(feature_for_key("chronicle"), Some(Feature::Chronicle));
assert_eq!(feature_for_key("telepathy"), Some(Feature::Chronicle));
}
#[test]
fn collab_is_legacy_alias_for_multi_agent() {
assert_eq!(feature_for_key("multi_agent"), Some(Feature::Collab));
assert_eq!(feature_for_key("collab"), Some(Feature::Collab));
}
#[test]
fn codex_hooks_is_legacy_alias_for_hooks() {
assert_eq!(feature_for_key("hooks"), Some(Feature::CodexHooks));
assert_eq!(feature_for_key("codex_hooks"), Some(Feature::CodexHooks));
}
#[test]
fn multi_agent_is_stable_and_enabled_by_default() {
assert_eq!(Feature::Collab.stage(), Stage::Stable);
assert_eq!(Feature::Collab.default_enabled(), true);
}
#[test]
fn enable_fanout_is_under_development() {
assert_eq!(Feature::SpawnCsv.stage(), Stage::UnderDevelopment);
assert_eq!(Feature::SpawnCsv.default_enabled(), false);
}
#[test]
fn enable_fanout_normalization_enables_multi_agent_one_way() {
let mut enable_fanout_features = Features::with_defaults();
enable_fanout_features.enable(Feature::SpawnCsv);
enable_fanout_features.normalize_dependencies();
assert_eq!(enable_fanout_features.enabled(Feature::SpawnCsv), true);
assert_eq!(enable_fanout_features.enabled(Feature::Collab), true);
let mut collab_features = Features::with_defaults();
collab_features.enable(Feature::Collab);
collab_features.normalize_dependencies();
assert_eq!(collab_features.enabled(Feature::Collab), true);
assert_eq!(collab_features.enabled(Feature::SpawnCsv), false);
}
#[test]
fn apps_require_feature_flag_and_chatgpt_auth() {
let mut features = Features::with_defaults();
assert!(!features.apps_enabled_for_auth(/*has_chatgpt_auth*/ false));
features.enable(Feature::Apps);
assert!(!features.apps_enabled_for_auth(/*has_chatgpt_auth*/ false));
assert!(features.apps_enabled_for_auth(/*has_chatgpt_auth*/ true));
}
#[test]
fn from_sources_applies_base_profile_and_overrides() {
let mut base_entries = BTreeMap::new();
base_entries.insert("plugins".to_string(), true);
let base_features = FeaturesToml {
entries: base_entries,
..Default::default()
};
let mut profile_entries = BTreeMap::new();
profile_entries.insert("code_mode_only".to_string(), true);
let profile_features = FeaturesToml {
entries: profile_entries,
..Default::default()
};
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&base_features),
..Default::default()
},
FeatureConfigSource {
features: Some(&profile_features),
..Default::default()
},
FeatureOverrides {
web_search_request: Some(false),
},
);
assert_eq!(features.enabled(Feature::Plugins), true);
assert_eq!(features.enabled(Feature::CodeModeOnly), true);
assert_eq!(features.enabled(Feature::CodeMode), true);
assert_eq!(features.enabled(Feature::ApplyPatchFreeform), false);
assert_eq!(features.enabled(Feature::WebSearchRequest), false);
}
#[test]
fn from_sources_ignores_removed_image_detail_original_feature_key() {
let features_toml = FeaturesToml::from(BTreeMap::from([(
"image_detail_original".to_string(),
true,
)]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
}
#[test]
fn from_sources_ignores_removed_undo_feature_key() {
let features_toml = FeaturesToml::from(BTreeMap::from([("undo".to_string(), true)]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
}
#[test]
fn from_sources_ignores_removed_js_repl_feature_keys() {
let features_toml = FeaturesToml::from(BTreeMap::from([
("js_repl".to_string(), true),
("js_repl_tools_only".to_string(), true),
]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
}
#[test]
fn from_sources_ignores_removed_apply_patch_freeform_feature_key() {
let features_toml =
FeaturesToml::from(BTreeMap::from([("apply_patch_freeform".to_string(), true)]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
}
#[test]
fn from_sources_ignores_removed_plugin_hooks_feature_key() {
let features_toml = FeaturesToml::from(BTreeMap::from([("plugin_hooks".to_string(), true)]));
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features, Features::with_defaults());
}
#[test]
fn multi_agent_v2_feature_config_deserializes_boolean_toggle() {
let features: FeaturesToml = toml::from_str(
r#"
multi_agent_v2 = true
"#,
)
.expect("features table should deserialize");
assert_eq!(
features.entries(),
BTreeMap::from([("multi_agent_v2".to_string(), true)])
);
assert_eq!(features.multi_agent_v2, Some(FeatureToml::Enabled(true)));
}
#[test]
fn multi_agent_v2_feature_config_deserializes_table() {
let features: FeaturesToml = toml::from_str(
r#"
[multi_agent_v2]
enabled = true
max_concurrent_threads_per_session = 4
min_wait_timeout_ms = 2500
max_wait_timeout_ms = 120000
default_wait_timeout_ms = 30000
usage_hint_enabled = false
usage_hint_text = "Custom delegation guidance."
root_agent_usage_hint_text = "Root guidance."
subagent_usage_hint_text = "Subagent guidance."
tool_namespace = "agents"
hide_spawn_agent_metadata = true
non_code_mode_only = true
"#,
)
.expect("features table should deserialize");
assert_eq!(
features.entries(),
BTreeMap::from([("multi_agent_v2".to_string(), true)])
);
assert_eq!(
features.multi_agent_v2,
Some(crate::FeatureToml::Config(crate::MultiAgentV2ConfigToml {
enabled: Some(true),
max_concurrent_threads_per_session: Some(4),
min_wait_timeout_ms: Some(2500),
max_wait_timeout_ms: Some(120000),
default_wait_timeout_ms: Some(30000),
usage_hint_enabled: Some(false),
usage_hint_text: Some("Custom delegation guidance.".to_string()),
root_agent_usage_hint_text: Some("Root guidance.".to_string()),
subagent_usage_hint_text: Some("Subagent guidance.".to_string()),
tool_namespace: Some("agents".to_string()),
hide_spawn_agent_metadata: Some(true),
non_code_mode_only: Some(true),
}))
);
}
#[test]
fn multi_agent_v2_feature_config_usage_hint_enabled_does_not_enable_feature() {
let features_toml: FeaturesToml = toml::from_str(
r#"
[multi_agent_v2]
usage_hint_enabled = false
"#,
)
.expect("features table should deserialize");
let features = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(features.enabled(Feature::MultiAgentV2), false);
assert_eq!(features_toml.entries(), BTreeMap::new());
assert_eq!(
features_toml.multi_agent_v2,
Some(crate::FeatureToml::Config(crate::MultiAgentV2ConfigToml {
enabled: None,
max_concurrent_threads_per_session: None,
min_wait_timeout_ms: None,
max_wait_timeout_ms: None,
default_wait_timeout_ms: None,
usage_hint_enabled: Some(false),
usage_hint_text: None,
root_agent_usage_hint_text: None,
subagent_usage_hint_text: None,
tool_namespace: None,
hide_spawn_agent_metadata: None,
non_code_mode_only: None,
}))
);
}
#[test]
fn materialize_resolved_enabled_writes_all_features_and_preserves_custom_config() {
let mut features = Features::with_defaults();
features.enable(Feature::CodeMode);
features.enable(Feature::MultiAgentV2);
features.enable(Feature::NetworkProxy);
let mut features_toml = FeaturesToml {
multi_agent_v2: Some(FeatureToml::Config(crate::MultiAgentV2ConfigToml {
enabled: Some(false),
min_wait_timeout_ms: Some(2500),
..Default::default()
})),
network_proxy: Some(FeatureToml::Config(crate::NetworkProxyConfigToml {
enabled: Some(false),
proxy_url: Some("http://127.0.0.1:43128".to_string()),
..Default::default()
})),
entries: BTreeMap::new(),
..Default::default()
};
features_toml.materialize_resolved_enabled(&features);
let entries = features_toml.entries();
for spec in crate::FEATURES {
assert_eq!(
entries.get(spec.key),
Some(&features.enabled(spec.id)),
"{}",
spec.key
);
}
assert_eq!(
features_toml.multi_agent_v2,
Some(FeatureToml::Config(crate::MultiAgentV2ConfigToml {
enabled: Some(true),
min_wait_timeout_ms: Some(2500),
..Default::default()
}))
);
assert_eq!(
features_toml.network_proxy,
Some(FeatureToml::Config(crate::NetworkProxyConfigToml {
enabled: Some(true),
proxy_url: Some("http://127.0.0.1:43128".to_string()),
..Default::default()
}))
);
let replayed = Features::from_sources(
FeatureConfigSource {
features: Some(&features_toml),
..Default::default()
},
FeatureConfigSource::default(),
FeatureOverrides::default(),
);
assert_eq!(replayed.enabled(Feature::ApplyPatchFreeform), false);
}
#[test]
fn unstable_warning_event_only_mentions_enabled_under_development_features() {
let mut configured_features = Table::new();
configured_features.insert("child_agents_md".to_string(), TomlValue::Boolean(true));
configured_features.insert("personality".to_string(), TomlValue::Boolean(true));
configured_features.insert("unknown".to_string(), TomlValue::Boolean(true));
let mut features = Features::with_defaults();
features.enable(Feature::ChildAgentsMd);
let warning = unstable_features_warning_event(
Some(&configured_features),
/*suppress_unstable_features_warning*/ false,
&features,
"/tmp/config.toml",
)
.expect("warning event");
let EventMsg::Warning(WarningEvent { message }) = warning.msg else {
panic!("expected warning event");
};
assert!(message.contains("child_agents_md"));
assert!(!message.contains("personality"));
assert!(message.contains("/tmp/config.toml"));
}
#[test]
fn unstable_warning_event_mentions_enabled_structured_under_development_feature() {
let configured_features: Table = toml::from_str(
r#"
multi_agent_v2 = { enabled = true, tool_namespace = "agents" }
code_mode = true
"#,
)
.expect("features table should deserialize");
let mut features = Features::with_defaults();
features.enable(Feature::MultiAgentV2);
features.enable(Feature::CodeMode);
let warning = unstable_features_warning_event(
Some(&configured_features),
/*suppress_unstable_features_warning*/ false,
&features,
"/tmp/config.toml",
)
.expect("warning event");
let EventMsg::Warning(WarningEvent { message }) = warning.msg else {
panic!("expected warning event");
};
assert_eq!(
"Under-development features enabled: code_mode, multi_agent_v2. Under-development features are incomplete and may behave unpredictably. To suppress this warning, set `suppress_unstable_features_warning = true` in /tmp/config.toml.".to_string(),
message
);
}