mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Simplify startup promotions to platform-specific desktop app tips (#49093)
## What changed - Replace plan-specific and Fast-mode promotions with the desktop app tip for the current platform, while preserving announcement priority and random-tip fallback. - Share desktop app tips between the preferred slot and random tip pool, including Windows. Keep Linux app tips limited to graphical sessions outside WSL. - Clarify installation and launch instructions for macOS, Windows, and Linux, and format launcher commands as code. - Remove the Fast-mode status plumbing used by tooltip selection. ## Testing Add snapshots for all three platform tips at a narrow terminal width. Update tests to cover plan-independent tip selection and platform availability. GitOrigin-RevId: 34bbc95c47c83618f9ac1691a1b69ca4690b8665
This commit is contained in:
@@ -5819,7 +5819,6 @@ async fn render_clear_ui_header_after_long_transcript_for_snapshot() -> String {
|
||||
is_first,
|
||||
/*tooltip_override*/ None,
|
||||
/*auth_plan*/ None,
|
||||
/*show_fast_status*/ false,
|
||||
)) as Arc<dyn HistoryCell>
|
||||
};
|
||||
|
||||
@@ -7521,7 +7520,6 @@ async fn backtrack_selection_preserves_selected_prompt_and_requests_branch() {
|
||||
is_first,
|
||||
/*tooltip_override*/ None,
|
||||
/*auth_plan*/ None,
|
||||
/*show_fast_status*/ false,
|
||||
)) as Arc<dyn HistoryCell>
|
||||
};
|
||||
|
||||
|
||||
@@ -2661,7 +2661,6 @@ async fn underfilled_scrollback_fetches_older_pages_without_opening_the_transcri
|
||||
/*is_first_event*/ false,
|
||||
Some("This is a test announcement".to_string()),
|
||||
/*auth_plan*/ None,
|
||||
/*show_fast_status*/ false,
|
||||
)),
|
||||
);
|
||||
app.enqueue_primary_thread_session(started.session, started.turns)
|
||||
|
||||
@@ -37,7 +37,6 @@ async fn owned_startup_hides_tip_in_transcript() -> Result<()> {
|
||||
/*is_first_event*/ false,
|
||||
Some("Use /mcp to list configured MCP tools.".into()),
|
||||
/*auth_plan*/ None,
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
history_cell::set_session_greeting(&mut session_info, &greeting);
|
||||
app.transcript_cells = vec![
|
||||
|
||||
@@ -28,7 +28,6 @@ fn insert_splash(app: &mut App, tui: &mut tui::Tui) {
|
||||
/*is_first_event*/ false,
|
||||
/*tooltip_override*/ None,
|
||||
/*auth_plan*/ None,
|
||||
/*show_fast_status*/ false,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use crate::bottom_pane::slash_commands::ServiceTierCommand;
|
||||
use crate::service_tier_resolution;
|
||||
use codex_features::Feature;
|
||||
use codex_protocol::config_types::SERVICE_TIER_DEFAULT_REQUEST_VALUE;
|
||||
use codex_protocol::config_types::ServiceTier;
|
||||
use codex_protocol::openai_models::SPEED_TIER_FAST;
|
||||
|
||||
impl ChatWidget {
|
||||
@@ -34,13 +33,6 @@ impl ChatWidget {
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn should_show_fast_status(&self, model: &str, service_tier: Option<&str>) -> bool {
|
||||
service_tier.is_some_and(|service_tier| {
|
||||
service_tier == ServiceTier::Fast.request_value()
|
||||
&& self.model_supports_service_tier(model, service_tier)
|
||||
}) && self.has_chatgpt_account
|
||||
}
|
||||
|
||||
pub(super) fn fast_mode_enabled(&self) -> bool {
|
||||
self.config.features.enabled(Feature::FastMode)
|
||||
}
|
||||
@@ -124,24 +116,6 @@ impl ChatWidget {
|
||||
.send(AppEvent::PersistServiceTierSelection { service_tier });
|
||||
}
|
||||
|
||||
fn model_supports_service_tier(&self, model: &str, service_tier: &str) -> bool {
|
||||
self.model_catalog
|
||||
.try_list_models()
|
||||
.ok()
|
||||
.and_then(|models| {
|
||||
models
|
||||
.into_iter()
|
||||
.find(|preset| preset.model == model)
|
||||
.map(|preset| {
|
||||
preset
|
||||
.service_tiers
|
||||
.iter()
|
||||
.any(|tier| tier.id == service_tier)
|
||||
})
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn current_model_fast_service_tier(&self) -> Option<ServiceTierCommand> {
|
||||
self.current_model_service_tier_commands()
|
||||
.into_iter()
|
||||
|
||||
@@ -201,8 +201,6 @@ impl ChatWidget {
|
||||
let model_for_header = self.current_model().to_string();
|
||||
if display == SessionConfiguredDisplay::Normal {
|
||||
let startup_tooltip_override = self.startup_tooltip_override.take();
|
||||
let show_fast_status = self
|
||||
.should_show_fast_status(&model_for_header, self.effective_service_tier.as_deref());
|
||||
let mut session_info_cell = history_cell::new_session_info(
|
||||
&self.config,
|
||||
&self.local_settings,
|
||||
@@ -212,7 +210,6 @@ impl ChatWidget {
|
||||
self.show_welcome_banner,
|
||||
startup_tooltip_override,
|
||||
self.plan_type,
|
||||
show_fast_status,
|
||||
);
|
||||
history_cell::set_session_greeting(
|
||||
&mut session_info_cell,
|
||||
|
||||
@@ -2377,47 +2377,6 @@ async fn commentary_completion_restores_status_indicator_before_exec_begin() {
|
||||
assert_eq!(chat.bottom_pane.status_indicator_visible(), true);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fast_status_indicator_requires_chatgpt_auth() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode());
|
||||
chat.set_service_tier(Some(ServiceTier::Fast.request_value().to_string()));
|
||||
|
||||
assert!(!chat.should_show_fast_status(chat.current_model(), chat.current_service_tier(),));
|
||||
|
||||
set_chatgpt_auth(&mut chat);
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode());
|
||||
|
||||
assert!(chat.should_show_fast_status(chat.current_model(), chat.current_service_tier(),));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fast_status_indicator_is_hidden_for_models_without_fast_support() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.2")).await;
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(!get_available_model(&chat, "gpt-5.2").supports_fast_mode());
|
||||
chat.set_service_tier(Some(ServiceTier::Fast.request_value().to_string()));
|
||||
set_chatgpt_auth(&mut chat);
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(!get_available_model(&chat, "gpt-5.2").supports_fast_mode());
|
||||
|
||||
assert!(!chat.should_show_fast_status(chat.current_model(), chat.current_service_tier(),));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn fast_status_indicator_is_hidden_when_fast_mode_is_off() {
|
||||
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.4")).await;
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode());
|
||||
set_chatgpt_auth(&mut chat);
|
||||
set_fast_mode_test_catalog(&mut chat);
|
||||
assert!(get_available_model(&chat, "gpt-5.4").supports_fast_mode());
|
||||
|
||||
assert!(!chat.should_show_fast_status(chat.current_model(), chat.current_service_tier(),));
|
||||
}
|
||||
|
||||
// Snapshot test: ChatWidget at very small heights (idle)
|
||||
// Ensures overall layout behaves when terminal height is extremely constrained.
|
||||
#[tokio::test]
|
||||
|
||||
@@ -193,7 +193,6 @@ pub(crate) fn new_session_info(
|
||||
is_first_event: bool,
|
||||
tooltip_override: Option<String>,
|
||||
auth_plan: Option<PlanType>,
|
||||
show_fast_status: bool,
|
||||
) -> SessionInfoCell {
|
||||
// Header rendered as history (so it appears at the very top).
|
||||
let header = SessionHeaderHistoryCell::new(
|
||||
@@ -246,9 +245,7 @@ pub(crate) fn new_session_info(
|
||||
} else {
|
||||
if local_settings.tui.show_tooltips
|
||||
&& let Some(tooltips) = tooltip_override
|
||||
.or_else(|| {
|
||||
tooltips::get_tooltip(auth_plan, show_fast_status, &local_settings.tui.keymap)
|
||||
})
|
||||
.or_else(|| tooltips::get_tooltip(auth_plan, &local_settings.tui.keymap))
|
||||
.map(|tip| TooltipHistoryCell::new(tip, &config.cwd))
|
||||
{
|
||||
parts.push(Box::new(tooltips));
|
||||
|
||||
@@ -747,7 +747,6 @@ async fn session_info_uses_availability_nux_tooltip_override() {
|
||||
/*is_first_event*/ false,
|
||||
Some("Model just became available".to_string()),
|
||||
Some(PlanType::Free),
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
|
||||
let rendered = render_transcript(&cell).join("\n");
|
||||
@@ -771,7 +770,6 @@ async fn session_info_availability_nux_tooltip_snapshot() {
|
||||
/*is_first_event*/ false,
|
||||
Some("Model just became available".to_string()),
|
||||
Some(PlanType::Free),
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
|
||||
let rendered = render_transcript(&cell).join("\n");
|
||||
@@ -793,7 +791,6 @@ async fn session_info_preserves_styled_tooltip_links() {
|
||||
.to_string(),
|
||||
),
|
||||
Some(PlanType::Free),
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
|
||||
let lines = cell.transcript_hyperlink_lines(/*width*/ 30);
|
||||
@@ -843,7 +840,6 @@ async fn session_info_first_event_suppresses_tooltips_and_nux() {
|
||||
/*is_first_event*/ true,
|
||||
Some("Model just became available".to_string()),
|
||||
Some(PlanType::Free),
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
|
||||
let rendered = render_transcript(&cell).join("\n");
|
||||
@@ -864,7 +860,6 @@ async fn session_info_hides_tooltips_when_disabled() {
|
||||
/*is_first_event*/ false,
|
||||
Some("Model just became available".to_string()),
|
||||
Some(PlanType::Free),
|
||||
/*show_fast_status*/ false,
|
||||
);
|
||||
|
||||
let rendered = render_transcript(&cell).join("\n");
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tui/src/tooltips.rs
|
||||
expression: rendered
|
||||
---
|
||||
Line::from_iter([Span::from("Tip:").bold(), Span::from(" Use the "), Span::from("desktop app").bold(), Span::from(". Install it")]) []
|
||||
Line::from("from") []
|
||||
Line::from(Span::from("https://learn.chatgpt.com/docs/linux/linux-app").fg(Color::Reset).underlined()) [TerminalHyperlink { columns: 0..46, destination: "https://learn.chatgpt.com/docs/linux/linux-app", destination_kind: Web }]
|
||||
Line::from_iter([Span::from("and run "), Span::from("chatgpt").fg(Color::Rgb(166, 227, 161)), Span::from(".")]) []
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
source: tui/src/tooltips.rs
|
||||
expression: rendered
|
||||
---
|
||||
Line::from_iter([Span::from("Tip:").bold(), Span::from(" Use the "), Span::from("desktop app").bold(), Span::from(". Run "), Span::from("codex app").fg(Color::Rgb(166, 227, 161))]) []
|
||||
Line::from("to open it. It installs automatically if") []
|
||||
Line::from("needed.") []
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
source: tui/src/tooltips.rs
|
||||
expression: rendered
|
||||
---
|
||||
Line::from_iter([Span::from("Tip:").bold(), Span::from(" Use the "), Span::from("desktop app").bold(), Span::from(". Install it")]) []
|
||||
Line::from("from") []
|
||||
Line::from(Span::from("https://chatgpt.com/codex?app-landing-page=true").fg(Color::Reset).underlined()) [TerminalHyperlink { columns: 0..47, destination: "https://chatgpt.com/codex?app-landing-page=true", destination_kind: Web }]
|
||||
Line::from_iter([Span::from("and run "), Span::from("codex app").fg(Color::Rgb(166, 227, 161)), Span::from(".")]) []
|
||||
+59
-103
@@ -21,16 +21,10 @@ const ANNOUNCEMENT_TIP_URL: &str =
|
||||
const IS_MACOS: bool = cfg!(target_os = "macos");
|
||||
const IS_WINDOWS: bool = cfg!(target_os = "windows");
|
||||
|
||||
const APP_TOOLTIP: &str = "Try the **Desktop app**. Run 'codex app' or visit https://chatgpt.com/codex?app-landing-page=true";
|
||||
const WINDOWS_APP_TOOLTIP: &str = "Use the **desktop app**. Install it from https://chatgpt.com/codex?app-landing-page=true and run `codex app`.";
|
||||
const MACOS_APP_TOOLTIP: &str =
|
||||
"Run `codex app` to open the Desktop app (it installs on macOS if needed).";
|
||||
const LINUX_APP_TOOLTIP: &str = "Try the **Desktop app** on Linux: install it from https://learn.chatgpt.com/docs/linux/linux-app and run 'chatgpt'.";
|
||||
const FAST_TOOLTIP: &str =
|
||||
"*New* Use **/fast** to enable our fastest inference with increased plan usage.";
|
||||
const OTHER_TOOLTIP: &str = "*New* Build faster with the **Desktop app**. Run 'codex app' or visit https://chatgpt.com/codex?app-landing-page=true";
|
||||
const OTHER_TOOLTIP_NON_MAC: &str = "*New* Build faster with Codex.";
|
||||
const FREE_GO_TOOLTIP: &str =
|
||||
"*New* For a limited time, Codex is included in your plan for free – let’s build together.";
|
||||
"Use the **desktop app**. Run `codex app` to open it. It installs automatically if needed.";
|
||||
const LINUX_APP_TOOLTIP: &str = "Use the **desktop app**. Install it from https://learn.chatgpt.com/docs/linux/linux-app and run `chatgpt`.";
|
||||
|
||||
const RAW_TOOLTIPS: &str = include_str!("../assets/tooltips.txt");
|
||||
|
||||
@@ -39,11 +33,7 @@ lazy_static! {
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|line| !line.is_empty() && !line.starts_with('#'))
|
||||
.chain(if IS_MACOS {
|
||||
Some(MACOS_APP_TOOLTIP)
|
||||
} else {
|
||||
linux_app_tooltip(LinuxDesktopSession::current())
|
||||
})
|
||||
.chain(app_tooltip())
|
||||
.collect();
|
||||
static ref ALL_TOOLTIPS: Vec<&'static str> = {
|
||||
let mut tips = Vec::new();
|
||||
@@ -68,13 +58,9 @@ fn experimental_tooltips(
|
||||
}
|
||||
|
||||
/// Pick a random tooltip to show to the user when starting Codex.
|
||||
pub(crate) fn get_tooltip(
|
||||
plan: Option<PlanType>,
|
||||
fast_mode_enabled: bool,
|
||||
keymap: &TuiKeymap,
|
||||
) -> Option<String> {
|
||||
pub(crate) fn get_tooltip(plan: Option<PlanType>, keymap: &TuiKeymap) -> Option<String> {
|
||||
let mut rng = rand::rng();
|
||||
preferred_tooltip(&mut rng, plan, fast_mode_enabled).or_else(|| pick_tooltip(&mut rng, keymap))
|
||||
preferred_tooltip(&mut rng, plan).or_else(|| pick_tooltip(&mut rng, keymap))
|
||||
}
|
||||
|
||||
/// Apply the shared announcement and promotion policy before falling back to local tips.
|
||||
@@ -82,7 +68,6 @@ pub(crate) fn get_tooltip(
|
||||
pub(crate) fn preferred_tooltip<R: Rng + ?Sized>(
|
||||
rng: &mut R,
|
||||
plan: Option<PlanType>,
|
||||
fast_mode_enabled: bool,
|
||||
) -> Option<String> {
|
||||
if let Some(announcement) = announcement::fetch_announcement_tip(plan) {
|
||||
return Some(announcement);
|
||||
@@ -90,34 +75,7 @@ pub(crate) fn preferred_tooltip<R: Rng + ?Sized>(
|
||||
|
||||
// Leave small chance for a random tooltip to be shown.
|
||||
if rng.random_ratio(/*numerator*/ 8, /*denominator*/ 10) {
|
||||
match plan {
|
||||
Some(plan_type)
|
||||
if matches!(
|
||||
plan_type,
|
||||
PlanType::Plus
|
||||
| PlanType::Enterprise
|
||||
| PlanType::Pro
|
||||
| PlanType::ProLite
|
||||
| PlanType::ProMax
|
||||
) || plan_type.is_team_like()
|
||||
|| plan_type.is_business_like() =>
|
||||
{
|
||||
if let Some(tooltip) = pick_paid_tooltip(rng, fast_mode_enabled) {
|
||||
return Some(tooltip.to_string());
|
||||
}
|
||||
}
|
||||
Some(PlanType::Go) | Some(PlanType::Free) => {
|
||||
return Some(FREE_GO_TOOLTIP.to_string());
|
||||
}
|
||||
_ => {
|
||||
let tooltip = if IS_MACOS {
|
||||
OTHER_TOOLTIP
|
||||
} else {
|
||||
OTHER_TOOLTIP_NON_MAC
|
||||
};
|
||||
return Some(tooltip.to_string());
|
||||
}
|
||||
}
|
||||
return app_tooltip().map(str::to_string);
|
||||
}
|
||||
|
||||
None
|
||||
@@ -153,29 +111,16 @@ fn linux_app_tooltip(session: LinuxDesktopSession) -> Option<&'static str> {
|
||||
(session.has_display && !session.is_wsl).then_some(LINUX_APP_TOOLTIP)
|
||||
}
|
||||
|
||||
fn paid_app_tooltip() -> Option<&'static str> {
|
||||
if IS_MACOS || IS_WINDOWS {
|
||||
Some(APP_TOOLTIP)
|
||||
fn app_tooltip() -> Option<&'static str> {
|
||||
if IS_MACOS {
|
||||
Some(MACOS_APP_TOOLTIP)
|
||||
} else if IS_WINDOWS {
|
||||
Some(WINDOWS_APP_TOOLTIP)
|
||||
} else {
|
||||
linux_app_tooltip(LinuxDesktopSession::current())
|
||||
}
|
||||
}
|
||||
|
||||
/// Paid users spend most startup sessions in a dedicated promo slot rather than the
|
||||
/// generic random tip pool. Keep this business logic explicit: we currently split
|
||||
/// that slot between the app promo and Fast mode, but suppress the Fast promo once
|
||||
/// the user already has Fast mode enabled.
|
||||
fn pick_paid_tooltip<R: Rng + ?Sized>(
|
||||
rng: &mut R,
|
||||
fast_mode_enabled: bool,
|
||||
) -> Option<&'static str> {
|
||||
if fast_mode_enabled || rng.random_bool(0.5) {
|
||||
paid_app_tooltip()
|
||||
} else {
|
||||
Some(FAST_TOOLTIP)
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_tooltip<R: Rng + ?Sized>(rng: &mut R, keymap: &TuiKeymap) -> Option<String> {
|
||||
// Resolve current settings for each new tip; never replace an invalid or unbound keymap
|
||||
// with defaults, or cache shortcut text across /keymap edits.
|
||||
@@ -495,37 +440,54 @@ mod tests {
|
||||
assert_eq!(expected, pick_tooltip(&mut rng, &TuiKeymap::default()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desktop_app_tips_render_at_narrow_width() {
|
||||
let cwd = std::env::current_dir().unwrap();
|
||||
for (platform, tip) in [
|
||||
("macos", MACOS_APP_TOOLTIP),
|
||||
("windows", WINDOWS_APP_TOOLTIP),
|
||||
("linux", LINUX_APP_TOOLTIP),
|
||||
] {
|
||||
let rendered = render_tooltip_lines(tip, /*width*/ 40, &cwd)
|
||||
.iter()
|
||||
.map(|line| format!("{:?} {:?}", line.line, line.hyperlinks))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
insta::assert_snapshot!(format!("desktop_app_tip_{platform}"), rendered);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn desktop_app_tooltip_uses_supported_platform_launcher() {
|
||||
let tooltip = TOOLTIPS
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|tip| tip.contains("Desktop app"));
|
||||
.find(|tip| tip.contains("desktop app"));
|
||||
|
||||
if linux_app_tooltip(LinuxDesktopSession::current()).is_some() {
|
||||
let tooltip = tooltip.expect("Linux should advertise the desktop app");
|
||||
assert_eq!(paid_app_tooltip(), Some(tooltip));
|
||||
assert_eq!(app_tooltip(), Some(tooltip));
|
||||
} else if IS_MACOS {
|
||||
let tooltip = tooltip.expect("macOS should advertise the desktop app");
|
||||
insta::assert_snapshot!(tooltip, @"Run `codex app` to open the Desktop app (it installs on macOS if needed).");
|
||||
assert_eq!(paid_app_tooltip(), Some(APP_TOOLTIP));
|
||||
assert_eq!(app_tooltip(), Some(tooltip));
|
||||
} else if IS_WINDOWS {
|
||||
assert_eq!(tooltip, None);
|
||||
assert_eq!(paid_app_tooltip(), Some(APP_TOOLTIP));
|
||||
let tooltip = tooltip.expect("Windows should advertise the desktop app");
|
||||
assert_eq!(app_tooltip(), Some(tooltip));
|
||||
} else {
|
||||
assert_eq!(tooltip, None);
|
||||
assert_eq!(paid_app_tooltip(), None);
|
||||
assert_eq!(app_tooltip(), None);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn linux_desktop_app_tooltip_requires_graphical_native_session() {
|
||||
let tooltip = linux_app_tooltip(LinuxDesktopSession {
|
||||
has_display: true,
|
||||
is_wsl: false,
|
||||
})
|
||||
.expect("graphical native Linux should advertise the desktop app");
|
||||
insta::assert_snapshot!(tooltip, @"Try the **Desktop app** on Linux: install it from https://learn.chatgpt.com/docs/linux/linux-app and run 'chatgpt'.");
|
||||
assert_eq!(
|
||||
linux_app_tooltip(LinuxDesktopSession {
|
||||
has_display: true,
|
||||
is_wsl: false,
|
||||
}),
|
||||
Some(LINUX_APP_TOOLTIP)
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
linux_app_tooltip(LinuxDesktopSession {
|
||||
@@ -544,30 +506,24 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paid_tooltip_pool_rotates_between_promos() {
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for seed in 0..32 {
|
||||
let mut rng = StdRng::seed_from_u64(seed);
|
||||
seen.insert(pick_paid_tooltip(
|
||||
&mut rng, /*fast_mode_enabled*/ false,
|
||||
));
|
||||
fn plans_use_platform_app_tip() {
|
||||
for plan in [
|
||||
Some(PlanType::Free),
|
||||
Some(PlanType::Go),
|
||||
Some(PlanType::Plus),
|
||||
Some(PlanType::Pro),
|
||||
None,
|
||||
] {
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for seed in 0..32 {
|
||||
let mut rng = StdRng::seed_from_u64(seed);
|
||||
seen.insert(preferred_tooltip(&mut rng, plan));
|
||||
}
|
||||
assert_eq!(
|
||||
seen,
|
||||
std::collections::BTreeSet::from([None, app_tooltip().map(str::to_string)])
|
||||
);
|
||||
}
|
||||
|
||||
let expected = std::collections::BTreeSet::from([paid_app_tooltip(), Some(FAST_TOOLTIP)]);
|
||||
assert_eq!(seen, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn paid_tooltip_pool_skips_fast_when_fast_mode_is_enabled() {
|
||||
let mut seen = std::collections::BTreeSet::new();
|
||||
for seed in 0..8 {
|
||||
let mut rng = StdRng::seed_from_u64(seed);
|
||||
seen.insert(pick_paid_tooltip(&mut rng, /*fast_mode_enabled*/ true));
|
||||
}
|
||||
|
||||
let expected = std::collections::BTreeSet::from([paid_app_tooltip()]);
|
||||
assert_eq!(seen, expected);
|
||||
assert!(!seen.contains(&Some(FAST_TOOLTIP)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user