test: trim redundant test coverage

This commit is contained in:
wonfen
2026-08-19 10:24:37 +08:00
parent 807f9a206d
commit e15ddab542
38 changed files with 194 additions and 4259 deletions
+17 -125
View File
@@ -166,24 +166,26 @@ impl<T, E: std::fmt::Display> WithErrorCode<T> for Result<T, E> {
#[cfg(test)]
mod tests {
use super::{CommandFailure, WithErrorCode as _, coded_error, proxy_aware_coded_error, proxy_aware_error};
use crate::core::proxy_control::SysproxyFailure;
use anyhow::Context as _;
use super::{CommandFailure, WithErrorCode as _, proxy_aware_coded_error};
use crate::core::proxy_control::SysproxyFailure;
#[test]
fn coded_error_preserves_stable_code_and_diagnostic_detail() {
fn command_failure_matches_the_frontend_wire_contract() {
assert_eq!(
coded_error("CORE_RESTART_FAILED", "connection refused"),
CommandFailure {
code: Some("CORE_RESTART_FAILED".to_owned()),
detail: "connection refused".to_owned(),
operation: None,
}
serde_json::to_value(CommandFailure::coded("CORE_START_FAILED", "connection refused"))
.unwrap_or(serde_json::Value::Null),
serde_json::json!({ "code": "CORE_START_FAILED", "detail": "connection refused" })
);
assert_eq!(
serde_json::to_value(CommandFailure::plain("disk full")).unwrap_or(serde_json::Value::Null),
serde_json::json!({ "detail": "disk full" })
);
}
#[test]
fn with_error_code_preserves_whole_anyhow_context_chain() {
fn coded_errors_preserve_the_anyhow_context_chain() {
let source: anyhow::Result<()> = Err(anyhow::anyhow!("connection refused"))
.context("failed to reach the mihomo core")
.context("failed to restart the core");
@@ -193,37 +195,15 @@ mod tests {
.err()
.unwrap_or_else(|| CommandFailure::plain("the call should have failed"));
assert_eq!(failure.code.as_deref(), Some("CORE_RESTART_FAILED"));
assert_eq!(
failure,
CommandFailure {
code: Some("CORE_RESTART_FAILED".to_owned()),
detail: "failed to restart the core: failed to reach the mihomo core: connection refused".to_owned(),
operation: None,
}
failure.detail,
"failed to restart the core: failed to reach the mihomo core: connection refused"
);
}
#[test]
fn with_error_code_leaves_plain_display_errors_untouched() {
let source: Result<(), &str> = Err("plain failure");
let failure = source
.with_error_code("PROFILE_READ_FAILED")
.err()
.unwrap_or_else(|| CommandFailure::plain("the call should have failed"));
assert_eq!(
failure,
CommandFailure {
code: Some("PROFILE_READ_FAILED".to_owned()),
detail: "plain failure".to_owned(),
operation: None,
}
);
}
#[test]
fn a_classification_outranks_the_code_naming_the_operation() {
fn system_proxy_classification_outranks_the_operation_code() {
let failure = anyhow::Error::new(sysproxy::Error::RequiresAdminPrivileges)
.context(SysproxyFailure::PrivilegeRequired)
.context("failed to restart the core");
@@ -231,94 +211,6 @@ mod tests {
let reported = proxy_aware_coded_error(&failure, "CORE_RESTART_FAILED");
assert_eq!(reported.code.as_deref(), Some("SYSPROXY_PRIVILEGE_REQUIRED"));
assert!(reported.detail.contains("failed to restart the core"), "{reported:?}");
assert!(reported.detail.contains("admin privileges"), "{reported:?}");
}
#[test]
fn without_a_classification_the_callers_code_is_used() {
let failure = anyhow::anyhow!("connection refused").context("failed to start the core");
let reported = proxy_aware_coded_error(&failure, "CORE_START_FAILED");
assert_eq!(
reported,
CommandFailure {
code: Some("CORE_START_FAILED".to_owned()),
detail: "failed to start the core: connection refused".to_owned(),
operation: None,
}
);
}
#[test]
fn commands_that_report_plain_text_stay_uncoded_without_a_classification() {
let failure = anyhow::anyhow!("disk full").context("failed to save the configuration");
let reported = proxy_aware_error(&failure);
assert_eq!(
reported,
CommandFailure {
code: None,
detail: "failed to save the configuration: disk full".to_owned(),
operation: None,
}
);
}
#[test]
fn commands_that_report_plain_text_still_carry_a_classification() {
let failure = anyhow::Error::new(SysproxyFailure::DirectFallback {
detail: "service could not set the proxy".to_owned(),
})
.context("failed to apply the verge patch");
let reported = proxy_aware_error(&failure);
assert_eq!(reported.code.as_deref(), Some("SYSPROXY_DIRECT_FALLBACK"));
assert!(
reported.detail.contains("failed to apply the verge patch"),
"{reported:?}"
);
assert!(
reported.detail.contains("service could not set the proxy"),
"{reported:?}"
);
}
#[test]
fn a_command_that_knows_the_request_can_say_which_way_it_went() {
let asking_on = CommandFailure::coded("SYSPROXY_PRIVILEGE_REQUIRED", "refused")
.asking_for(Some(crate::core::notification::FailedOperation::SystemProxyEnable));
assert_eq!(
serde_json::to_value(asking_on).unwrap_or(serde_json::Value::Null),
serde_json::json!({
"code": "SYSPROXY_PRIVILEGE_REQUIRED",
"detail": "refused",
"operation": "systemProxyEnable",
})
);
assert_eq!(
serde_json::to_value(CommandFailure::coded("CORE_START_FAILED", "no").asking_for(None))
.unwrap_or(serde_json::Value::Null),
serde_json::json!({ "code": "CORE_START_FAILED", "detail": "no" })
);
}
#[test]
fn the_serialised_shape_is_what_the_frontend_reads() {
assert_eq!(
serde_json::to_value(CommandFailure::coded("CORE_START_FAILED", "connection refused"))
.unwrap_or(serde_json::Value::Null),
serde_json::json!({ "code": "CORE_START_FAILED", "detail": "connection refused" })
);
assert_eq!(
serde_json::to_value(CommandFailure::plain("disk full")).unwrap_or(serde_json::Value::Null),
serde_json::json!({ "detail": "disk full" })
);
assert!(reported.detail.contains("failed to restart the core"));
}
}
-28
View File
@@ -32,31 +32,3 @@ const fn system_proxy_operation(payload: &IVerge) -> Option<FailedOperation> {
None => None,
}
}
#[cfg(test)]
mod tests {
use super::system_proxy_operation;
use crate::{config::IVerge, core::notification::FailedOperation};
#[test]
fn only_a_system_proxy_toggle_says_which_way_it_was_going() {
let asking_on = IVerge {
enable_system_proxy: Some(true),
..IVerge::default()
};
let asking_off = IVerge {
enable_system_proxy: Some(false),
..IVerge::default()
};
assert_eq!(
system_proxy_operation(&asking_on),
Some(FailedOperation::SystemProxyEnable)
);
assert_eq!(
system_proxy_operation(&asking_off),
Some(FailedOperation::SystemProxyDisable)
);
assert_eq!(system_proxy_operation(&IVerge::default()), None);
}
}
+3 -36
View File
@@ -385,37 +385,10 @@ pub enum ConfigType {
Run,
Check,
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
#[allow(unused_variables)]
#[allow(clippy::expect_used)]
fn test_prfitem_from_merge_size() {
let merge_item = PrfItem::from_merge(Some("Merge".into())).expect("Failed to create merge item in test");
let prfitem_size = mem::size_of_val(&merge_item);
let boxed_merge_item = Box::new(merge_item);
let box_prfitem_size = mem::size_of_val(&boxed_merge_item);
assert!(box_prfitem_size < prfitem_size);
}
#[test]
#[allow(unused_variables)]
fn test_draft_size_non_boxed() {
let draft = Draft::new(IRuntime::new());
let iruntime_size = std::mem::size_of_val(&draft);
assert_eq!(iruntime_size, std::mem::size_of::<Draft<IRuntime>>());
}
#[test]
#[allow(unused_variables)]
fn test_draft_size_boxed() {
let draft = Draft::new(Box::new(IRuntime::new()));
let box_iruntime_size = std::mem::size_of_val(&draft);
assert_eq!(box_iruntime_size, std::mem::size_of::<Draft<Box<IRuntime>>>());
}
#[tokio::test]
async fn failed_profile_index_survives_startup_without_cleanup() -> Result<()> {
@@ -431,14 +404,8 @@ mod tests {
let profile_was_preserved = tokio::fs::try_exists(&active_profile).await?;
tokio::fs::remove_dir_all(&profiles_dir).await?;
assert!(
profile_was_preserved,
"startup must not delete profiles when profiles.yaml could not be loaded"
);
assert!(
profiles.data_arc().get_items().is_none(),
"startup must not replace an unreadable profile index with defaults"
);
assert!(profile_was_preserved);
assert!(profiles.data_arc().get_items().is_none());
Ok(())
}
}
+5 -22
View File
@@ -73,40 +73,23 @@ where
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::panic, reason = "tests assert by panicking")]
mod tests {
use super::*;
#[test]
fn a_selected_port_wins_over_the_merge_config() {
assert_eq!(resolve_desired(None, Some(9000), 7897), 9000);
}
#[test]
fn the_merge_config_answers_when_nothing_is_selected() {
fn desired_port_uses_session_then_selection_then_merge_priority() {
assert_eq!(resolve_desired(Some(7900), Some(9000), 8080), 7900);
assert_eq!(resolve_desired(None, Some(9000), 8080), 9000);
assert_eq!(resolve_desired(None, None, 8080), 8080);
}
#[test]
fn a_session_fallback_outranks_the_port_still_written_down() {
assert_eq!(resolve_desired(Some(7900), Some(7897), 7897), 7900);
}
#[tokio::test]
async fn a_reporting_core_overrides_what_we_configured() {
async fn effective_port_prefers_a_bound_core_port() {
assert_eq!(resolve_effective(|| async { Ok(7898) }, 7897).await, 7898);
}
#[tokio::test]
async fn an_unreachable_core_leaves_the_configured_port_standing() {
assert_eq!(resolve_effective(|| async { Ok(0) }, 7897).await, 7897);
assert_eq!(
resolve_effective(|| async { anyhow::bail!("core is not running") }, 7897).await,
7897
);
}
#[tokio::test]
async fn a_core_that_has_not_bound_yet_is_not_believed() {
assert_eq!(resolve_effective(|| async { Ok(0) }, 7897).await, 7897);
}
}
-16
View File
@@ -565,19 +565,3 @@ fn fix_dirty_url(input: &str) -> Result<Url> {
Ok(url)
}
#[cfg(test)]
mod tests {
use super::{PrfOption, allow_auto_update_enabled};
#[test]
fn auto_update_defaults_to_enabled_and_preserves_explicit_false() {
assert!(allow_auto_update_enabled(None));
let disabled = PrfOption {
allow_auto_update: Some(false),
..PrfOption::default()
};
assert!(!allow_auto_update_enabled(Some(&disabled)));
}
}
-13
View File
@@ -234,16 +234,3 @@ impl Logger {
}
}
}
#[cfg(test)]
mod tests {
use super::should_sync_service_writer;
use crate::core::manager::RunningMode;
#[test]
fn service_writer_sync_requires_service_running_mode() {
assert!(should_sync_service_writer(RunningMode::Service));
assert!(!should_sync_service_writer(RunningMode::Sidecar));
assert!(!should_sync_service_writer(RunningMode::NotRunning));
}
}
-148
View File
@@ -298,151 +298,3 @@ impl NotificationSystem {
}
}
}
#[cfg(test)]
mod tests {
use super::{FailedOperation, FailureTable};
fn table() -> FailureTable {
FailureTable::default()
}
#[test]
fn reading_does_not_clear() {
let table = table();
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_PRIVILEGE_REQUIRED",
"refused".into(),
);
assert_eq!(table.snapshot(), table.snapshot());
assert_eq!(table.snapshot().len(), 1);
}
#[test]
fn a_code_keeps_only_its_most_recent_failure() {
let table = table();
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_PRIVILEGE_REQUIRED",
"first".into(),
);
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_PRIVILEGE_REQUIRED",
"second".into(),
);
let failures = table.snapshot();
assert_eq!(failures.len(), 1);
assert_eq!(failures[0].detail, "second");
}
#[test]
fn a_new_failure_under_a_known_code_gets_a_new_sequence() {
let table = table();
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_DIRECT_FALLBACK",
"a".into(),
);
let first = table.snapshot()[0].sequence;
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_DIRECT_FALLBACK",
"b".into(),
);
assert!(table.snapshot()[0].sequence > first);
}
#[test]
fn failures_are_reported_oldest_first() {
let table = table();
table.record(FailedOperation::SystemProxyRestore, "FIRST", "a".into());
table.record(FailedOperation::SystemProxyRestore, "SECOND", "b".into());
let failures = table.snapshot();
let codes: Vec<&str> = failures.iter().map(|failure| failure.code.as_str()).collect();
assert_eq!(codes, ["FIRST", "SECOND"]);
}
#[test]
fn a_working_proxy_retires_what_it_disproves() {
let table = table();
table.record(
FailedOperation::SystemProxyRestore,
"SYSPROXY_PRIVILEGE_REQUIRED",
"refused".into(),
);
assert!(table.retire_system_proxy(false));
assert!(table.snapshot().is_empty());
}
#[test]
fn a_users_request_is_retired_only_by_reaching_the_state_they_asked_for() {
let table = table();
table.record(
FailedOperation::SystemProxyDisable,
"SYSPROXY_PRIVILEGE_REQUIRED",
"refused".into(),
);
assert!(!table.retire_system_proxy(true));
assert_eq!(table.snapshot().len(), 1);
assert!(table.retire_system_proxy(false));
assert!(table.snapshot().is_empty());
}
#[test]
fn a_failed_enable_is_retired_by_the_proxy_coming_on() {
let table = table();
table.record(
FailedOperation::SystemProxyEnable,
"SYSPROXY_DIRECT_FALLBACK",
"fell back".into(),
);
assert!(!table.retire_system_proxy(false));
assert!(table.retire_system_proxy(true));
assert!(table.snapshot().is_empty());
}
#[test]
fn a_stopped_guard_is_retired_by_a_guard_starting_again_and_not_by_an_apply() {
let table = table();
table.record(
FailedOperation::SystemProxyGuard,
"SYSPROXY_GUARD_STOPPED",
"gave up".into(),
);
assert!(!table.retire_system_proxy(true));
assert!(!table.retire_system_proxy(false));
assert_eq!(table.snapshot().len(), 1);
assert!(table.retire_guard());
assert!(table.snapshot().is_empty());
}
#[test]
fn retiring_a_guard_leaves_everything_else_alone() {
let table = table();
table.record(
FailedOperation::SystemProxyEnable,
"SYSPROXY_PRIVILEGE_REQUIRED",
"refused".into(),
);
assert!(!table.retire_guard());
assert_eq!(table.snapshot().len(), 1);
}
#[test]
fn retiring_nothing_reports_nothing() {
assert!(!table().retire_system_proxy(true));
}
}
-70
View File
@@ -492,73 +492,3 @@ impl SilentUpdater {
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn test_version_equal() {
assert!(version_lte("2.4.7", "2.4.7"));
}
#[test]
fn test_version_less() {
assert!(version_lte("2.4.7", "2.4.8"));
assert!(version_lte("2.4.7", "2.5.0"));
assert!(version_lte("2.4.7", "3.0.0"));
}
#[test]
fn test_version_greater() {
assert!(!version_lte("2.4.8", "2.4.7"));
assert!(!version_lte("2.5.0", "2.4.7"));
assert!(!version_lte("3.0.0", "2.4.7"));
}
#[test]
fn test_version_with_v_prefix() {
assert!(version_lte("v2.4.7", "2.4.8"));
assert!(version_lte("2.4.7", "v2.4.8"));
assert!(version_lte("v2.4.7", "v2.4.8"));
}
#[test]
fn test_version_with_prerelease() {
assert!(version_lte("2.4.7", "2.4.8-alpha"));
assert!(version_lte("2.4.8-alpha", "2.4.8"));
assert!(version_lte("2.4.8-alpha", "2.4.8-beta"));
}
#[test]
fn test_version_different_lengths() {
assert!(version_lte("2.4", "2.4.1"));
assert!(!version_lte("2.4.1", "2.4"));
assert!(version_lte("2.4.0", "2.4"));
}
#[test]
fn test_cache_meta_serialize_roundtrip() {
let meta = UpdateCacheMeta {
version: "2.5.0".to_string(),
downloaded_at: "2026-03-31T00:00:00Z".to_string(),
};
let json = serde_json::to_string(&meta).unwrap();
let parsed: UpdateCacheMeta = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.version, "2.5.0");
assert_eq!(parsed.downloaded_at, "2026-03-31T00:00:00Z");
}
#[test]
fn test_cache_meta_invalid_json() {
let result = serde_json::from_str::<UpdateCacheMeta>("not valid json");
assert!(result.is_err());
}
#[test]
fn test_cache_meta_missing_required_field() {
let result = serde_json::from_str::<UpdateCacheMeta>(r#"{"version":"2.5.0"}"#);
assert!(result.is_err()); // missing downloaded_at
}
}
-100
View File
@@ -173,103 +173,3 @@ pub async fn copy_icon_file(path: String, icon_info: IconInfo) -> CmdResult<Stri
Err("file not found".into())
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn normalize_icon_segment_accepts_single_name() {
assert!(normalize_icon_segment("group-icon.png").is_ok());
assert!(normalize_icon_segment("alpha_1.webp").is_ok());
}
#[test]
fn normalize_icon_segment_rejects_traversal_and_separators() {
for name in ["../x", "..\\x", "a/b", "a\\b", "..", "a..b"] {
assert!(normalize_icon_segment(name).is_err(), "name should be rejected: {name}");
}
}
#[test]
fn normalize_icon_segment_rejects_empty() {
assert!(normalize_icon_segment("").is_err());
assert!(normalize_icon_segment(" ").is_err());
}
#[cfg(target_os = "windows")]
#[test]
fn normalize_icon_segment_rejects_windows_absolute_names() {
for name in [r"C:\temp\icon.png", r"\\server\share\icon.png"] {
assert!(normalize_icon_segment(name).is_err(), "name should be rejected: {name}");
}
}
#[cfg(not(target_os = "windows"))]
#[test]
fn normalize_icon_segment_rejects_unix_absolute_names() {
assert!(normalize_icon_segment("/tmp/icon.png").is_err());
}
#[test]
fn ensure_icon_cache_target_accepts_direct_child_only() {
let base = PathBuf::from("icons").join("cache");
let valid = ensure_icon_cache_target(&base, "ok.png");
assert_eq!(valid.unwrap(), base.join("ok.png"));
let nested = base.join("nested").join("ok.png");
assert!(ensure_icon_cache_target(&base, nested.to_string_lossy().as_ref()).is_err());
assert!(ensure_icon_cache_target(&base, "../ok.png").is_err());
}
#[test]
fn looks_like_svg_accepts_plain_svg() {
assert!(looks_like_svg(br#"<svg xmlns="http://www.w3.org/2000/svg"></svg>"#));
}
#[test]
fn looks_like_svg_accepts_xml_prefixed_svg() {
assert!(looks_like_svg(
br#"<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg"></svg>"#
));
}
#[test]
fn looks_like_svg_accepts_doctype_svg() {
assert!(looks_like_svg(
br#"<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"><svg xmlns="http://www.w3.org/2000/svg"></svg>"#
));
}
#[test]
fn looks_like_svg_accepts_bom_and_leading_whitespace() {
assert!(looks_like_svg(
b"\xEF\xBB\xBF \n\t<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>"
));
}
#[test]
fn looks_like_svg_rejects_non_svg_payloads() {
assert!(!looks_like_svg(br#"{"status":"ok"}"#));
assert!(!looks_like_svg(br"text/plain"));
}
#[test]
fn looks_like_html_detects_common_html_prefixes() {
assert!(looks_like_html(br"<!DOCTYPE html><html></html>"));
assert!(looks_like_html(br"<html><body>oops</body></html>"));
assert!(looks_like_html(br"<head><title>oops</title></head>"));
assert!(looks_like_html(
b"\xEF\xBB\xBF \n\t<!DOCTYPE HTML><html><body>oops</body></html>"
));
}
#[test]
fn is_supported_icon_content_rejects_html_and_accepts_svg() {
assert!(!is_supported_icon_content(br"<!DOCTYPE html><html></html>"));
assert!(is_supported_icon_content(
br#"<svg xmlns="http://www.w3.org/2000/svg"></svg>"#
));
}
}
-12
View File
@@ -137,15 +137,3 @@ pub async fn copy_clash_env() {
logging!(error, Type::ProxyMode, "Failed to write to clipboard");
}
}
#[cfg(test)]
mod tests {
use super::toggle_operation;
use crate::core::notification::FailedOperation;
#[test]
fn a_failed_toggle_records_which_way_the_user_was_asking() {
assert_eq!(toggle_operation(true), FailedOperation::SystemProxyEnable);
assert_eq!(toggle_operation(false), FailedOperation::SystemProxyDisable);
}
}
-16
View File
@@ -103,19 +103,3 @@ pub async fn notify_event<'a>(event: NotificationEvent<'a>) {
}
}
}
#[cfg(test)]
mod tests {
use super::needs_system_notification;
use crate::utils::window_manager::WindowState;
#[test]
fn a_system_notification_is_sent_exactly_where_the_window_cannot_speak() {
assert!(needs_system_notification(WindowState::Hidden));
assert!(needs_system_notification(WindowState::Minimized));
assert!(needs_system_notification(WindowState::NotExist));
assert!(!needs_system_notification(WindowState::VisibleFocused));
assert!(!needs_system_notification(WindowState::VisibleUnfocused));
}
}
-23
View File
@@ -184,26 +184,3 @@ pub fn reload_main_window_if_needed() {
logging!(warn, Type::Window, "重载页面失败: {e}");
}
}
#[cfg(test)]
mod tests {
use super::restored_window_size_is_too_small;
#[test]
fn restored_window_size_rejects_zero_dimensions() {
assert!(restored_window_size_is_too_small(0, 700));
assert!(restored_window_size_is_too_small(940, 0));
}
#[test]
fn restored_window_size_rejects_dimensions_below_minimum() {
assert!(restored_window_size_is_too_small(519, 700));
assert!(restored_window_size_is_too_small(940, 519));
}
#[test]
fn restored_window_size_accepts_minimum_or_larger_dimensions() {
assert!(!restored_window_size_is_too_small(520, 520));
assert!(!restored_window_size_is_too_small(940, 700));
}
}
-25
View File
@@ -21,28 +21,3 @@ macro_rules! singleton {
}
};
}
#[cfg(test)]
mod tests {
struct TestStruct {
value: i32,
}
impl TestStruct {
fn new() -> Self {
Self { value: 42 }
}
}
singleton!(TestStruct, TEST_INSTANCE);
#[test]
fn test_singleton_macro() {
let instance1 = TestStruct::global();
let instance2 = TestStruct::global();
assert_eq!(instance1.value, 42);
assert_eq!(instance2.value, 42);
assert!(std::ptr::eq(instance1, instance2));
}
}
-28
View File
@@ -30,31 +30,3 @@ pub fn format_bytes_per_second(bytes_per_sec: u64) -> String {
format!("{:.0}{}", value.round(), SPEED_UNITS[unit_index])
}
}
#[cfg(test)]
mod tests {
use super::format_bytes_per_second;
#[test]
fn format_handles_byte_boundaries() {
assert_eq!(format_bytes_per_second(0), "0B/s");
assert_eq!(format_bytes_per_second(999), "999B/s");
assert_eq!(format_bytes_per_second(1000), "1.0K/s");
assert_eq!(format_bytes_per_second(1024), "1.0K/s");
}
#[test]
fn format_handles_decimal_and_integer_rules() {
assert_eq!(format_bytes_per_second(9 * 1024), "9.0K/s");
assert_eq!(format_bytes_per_second(10 * 1024 - 1), "10K/s");
assert_eq!(format_bytes_per_second(10 * 1024), "10K/s");
assert_eq!(format_bytes_per_second(123 * 1024), "123K/s");
}
#[test]
fn format_handles_unit_promotion_after_rounding() {
assert_eq!(format_bytes_per_second(999 * 1024 + 512), "1.0M/s");
assert_eq!(format_bytes_per_second(1024 * 1024), "1.0M/s");
assert_eq!(format_bytes_per_second(1536 * 1024), "1.5M/s");
}
}
-20
View File
@@ -63,23 +63,3 @@ fn append_error(path: &Path, detail: &str) -> Result<()> {
file.flush().context("failed to flush startup log")?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::append_error;
#[test]
fn startup_log_is_created_and_appended() -> anyhow::Result<()> {
let root = std::env::temp_dir().join(format!("startup-error-log-{}", std::process::id()));
let path = root.join("nested/startup.log");
append_error(&path, "first failure")?;
append_error(&path, "second failure")?;
let content = std::fs::read_to_string(&path)?;
assert!(content.contains("ERROR [Startup] first failure"));
assert!(content.contains("ERROR [Startup] second failure"));
std::fs::remove_dir_all(root)?;
Ok(())
}
}