diff --git a/tests/component_children.rs b/tests/component_children.rs index 9340a508..bdec1ee4 100644 --- a/tests/component_children.rs +++ b/tests/component_children.rs @@ -1,9 +1,9 @@ use pagetop::prelude::*; -// **< TestComp - componente mínimo para los tests >************************************************ +// **< TestComp - minimal component for the tests >************************************************* // -// Componente con id configurable y texto fijo de salida. El id permite probar las operaciones de -// `Children` basadas en identificador (`InsertAfterId`, `RemoveById`, etc.). +// Component with configurable id and fixed output text. The id allows testing the identifier-based +// `Children` operations (`InsertAfterId`, `RemoveById`, etc.). #[derive(AutoDefault, Clone)] struct TestComp { @@ -27,7 +27,7 @@ impl Component for TestComp { } impl TestComp { - /// Crea un componente con id y texto de salida fijos. + /// Creates a component with a fixed id and output text. fn tagged(id: &str, text: &str) -> Self { let mut c = Self::default(); c.props.alter_prop(PropsOp::set_id(id.to_string())); @@ -35,7 +35,7 @@ impl TestComp { c } - /// Crea un componente sin id, con texto de salida fijo. + /// Creates a component with no id, with fixed output text. fn text(text: &str) -> Self { let mut c = Self::default(); c.text = text.to_string(); @@ -43,7 +43,7 @@ impl TestComp { } } -// **< Child >*************************************************************************************** +// **< Child >************************************************************************************** #[pagetop::test] async fn child_default_is_empty() { @@ -78,7 +78,7 @@ async fn child_from_component_is_equivalent_to_with() { #[pagetop::test] async fn child_clone_is_deep() { - // Modificar el clon no debe afectar al original. + // Modifying the clone must not affect the original. let original = Child::with(TestComp::text("original")); let clone = original.clone(); assert_eq!( @@ -114,11 +114,11 @@ async fn children_add_appends_in_order() { async fn children_add_if_empty_only_adds_when_list_is_empty() { let mut cx = Context::default(); - // Se añade porque la lista está vacía. + // It gets added because the list is empty. let c = Children::new().with_child(ChildOp::AddIfEmpty(TestComp::text("first").into())); assert_eq!(c.len(), 1); - // No se añade porque ya hay un elemento. + // It does not get added because there is already an element. let c = c.with_child(ChildOp::AddIfEmpty(TestComp::text("second").into())); assert_eq!(c.len(), 1); assert_eq!(c.render(&mut cx).await.into_string(), "first"); @@ -297,7 +297,7 @@ async fn embed_id_returns_component_id() { #[pagetop::test] async fn embed_get_is_some_when_component_present() { let embed = Embed::with(TestComp::tagged("abc", "hello")); - // `get()` devuelve Some; la lectura del id verifica que accede al componente correctamente. + // `get()` returns Some; reading the id verifies that it accesses the component correctly. assert!(embed.get().is_some()); assert_eq!(embed.id(), Some("abc".to_string())); } @@ -332,7 +332,7 @@ async fn embed_with_component_none_empties_embed() { async fn embed_clone_is_deep() { let original = Embed::with(TestComp::tagged("orig", "text")); let mut clone = original.clone(); - // Mutar el clon no debe afectar al original. + // Mutating the clone must not affect the original. if let Some(comp) = clone.get_mut() { comp.props .alter_prop(PropsOp::set_id("clone-id".to_string())); diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index a0d383a4..c0dfc594 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -1,9 +1,9 @@ use pagetop::prelude::*; -/// Inicializa PageTop (locale, extensiones...) una sola vez para toda la suite. +/// Initializes PageTop (locale, extensions...) once for the whole suite. /// -/// Los tests de este módulo renderizan componentes directamente con `Context::default()`, por lo -/// que sólo necesitan el subsistema de localización y las extensiones registradas, no un router. +/// The tests in this module render components directly with `Context::default()`, so they only need +/// the localization subsystem and the registered extensions, not a router. async fn setup() { Application::new().await; } @@ -15,10 +15,10 @@ async fn poweredby_default_shows_only_pagetop_recognition() { let mut p = PoweredBy::default(); let html = p.render(&mut Context::default()).await.into_string(); - // Debe mostrar el bloque de reconocimiento a PageTop. + // Should show the PageTop acknowledgment block. assert!(html.contains("poweredby__pagetop")); - // Y NO debe mostrar el bloque de copyright. + // And should NOT show the copyright block. assert!(!html.contains("poweredby__copyright")); } @@ -32,14 +32,14 @@ async fn poweredby_new_includes_current_year_and_app_name() { let year = Utc::now().format("%Y").to_string(); assert!(html.contains(&year), "HTML should include the current year"); - // El nombre de la app proviene de `global::SETTINGS.app.name`. + // The app name comes from `global::SETTINGS.app.name`. let app_name = &global::SETTINGS.app.name; assert!( html.contains(app_name), "HTML should include the application name" ); - // Debe existir el span de copyright. + // The copyright span must exist. assert!(html.contains("poweredby__copyright")); } @@ -63,7 +63,7 @@ async fn poweredby_with_copyright_none_hides_text() { let html = p.render(&mut Context::default()).await.into_string(); assert!(!html.contains("poweredby__copyright")); - // El reconocimiento a PageTop siempre debe aparecer. + // The PageTop acknowledgment must always appear. assert!(html.contains("poweredby__pagetop")); } @@ -84,11 +84,11 @@ async fn poweredby_link_points_to_crates_io() { async fn poweredby_getter_reflects_internal_state() { setup().await; - // Por defecto no hay copyright. + // There is no copyright by default. let p0 = PoweredBy::default(); assert_eq!(p0.copyright(), None); - // Y `new()` lo inicializa con año + nombre de app. + // And `new()` initializes it with year + app name. let p1 = PoweredBy::new(); let c1 = p1.copyright().expect("Expected copyright to exist"); assert!(c1.contains(&Utc::now().format("%Y").to_string())); diff --git a/tests/config.rs b/tests/config.rs index 91fc8419..247636db 100644 --- a/tests/config.rs +++ b/tests/config.rs @@ -20,9 +20,9 @@ pub struct Test { pub float_value: f32, } -// La *feature* `testing` (activo con `cargo ts` / `cargo tw`) fija el modo "test" en tiempo de -// compilación dentro de `config::CONFIG_VALUES`, de forma que `global::SETTINGS` y cualquier -// `include_config!` local cargan automáticamente la configuración del modo "test". +// The `testing` *feature* (active with `cargo ts` / `cargo tw`) fixes the "test" mode at compile +// time inside `config::CONFIG_VALUES`, so that `global::SETTINGS` and any local `include_config!` +// automatically load the "test" mode configuration. #[pagetop::test] async fn check_global_config() { diff --git a/tests/error_handling.rs b/tests/error_handling.rs index aa560c17..9bd2d893 100644 --- a/tests/error_handling.rs +++ b/tests/error_handling.rs @@ -34,10 +34,9 @@ async fn panic_in_handler_returns_minimal_500_page_instead_of_crashing() { // **< ErrorPage::NotFound >************************************************************************ -// `EXTENSIONS` es un `OnceLock` global (`core/extension/all.rs`): se inicializa una sola vez por -// binario de test. Todos los tests de este fichero comparten la misma extensión raíz -// (`PanicExtension`) para que el orden de ejecución en paralelo no cambie qué rutas quedan -// registradas. +// `EXTENSIONS` is a global `OnceLock` (`core/extension/all.rs`): it is initialized only once per +// test binary. All tests in this file share the same root extension (`PanicExtension`) so that the +// parallel execution order does not change which routes end up registered. #[pagetop::test] async fn unknown_route_returns_themed_404_page() { let app = web::test::init_router(Application::prepare(&PanicExtension).await.test()); diff --git a/tests/html_markup.rs b/tests/html_markup.rs index bdf2ff79..c1d001fc 100644 --- a/tests/html_markup.rs +++ b/tests/html_markup.rs @@ -1,8 +1,8 @@ use pagetop::prelude::*; -/// Componente mínimo para probar `Markup` pasando por el ciclo real de renderizado de componentes -/// (`ComponentRender`). El parámetro de contexto `"renderable"` se usará para controlar si el -/// componente se renderiza (`true` por defecto). +/// Minimal component to test `Markup` going through the real component rendering cycle +/// (`ComponentRender`). The context parameter `"renderable"` is used to control whether the +/// component is rendered (`true` by default). #[derive(AutoDefault, Clone)] struct TestMarkupComponent { markup: Markup, @@ -23,7 +23,7 @@ impl Component for TestMarkupComponent { } } -// **< Comportamiento de Markup >******************************************************************* +// **< Markup behavior >**************************************************************************** #[pagetop::test] async fn string_in_html_macro_escapes_html_entities() { @@ -39,11 +39,11 @@ async fn preescaped_in_html_macro_is_inserted_verbatim() { #[pagetop::test] async fn unicode_is_preserved_in_markup() { - // Texto con acentos y emojis: sólo se escapan los signos HTML. + // Text with accents and emoji: only HTML signs are escaped. let esc = html! { ("Hello, tomorrow coffee ☕ & donuts!") }; assert_eq!(esc.into_string(), "Hello, tomorrow coffee ☕ & donuts!"); - // PreEscaped debe pasar íntegro. + // PreEscaped must pass through untouched. let raw = html! { (PreEscaped("Title — section © 2025")) }; assert_eq!(raw.into_string(), "Title — section © 2025"); } @@ -62,12 +62,12 @@ async fn markup_is_empty_semantics() { assert!(!html! { span { "!" } }.is_empty()); - // Espacios NO se consideran vacíos. + // Spaces are NOT considered empty. assert!(!html! { (" ") }.is_empty()); assert!(!html! { (PreEscaped(" ")) }.is_empty()); } -// **< Markup a través del ciclo de componente >**************************************************** +// **< Markup through the component cycle >********************************************************* #[pagetop::test] async fn non_renderable_component_produces_empty_markup() { @@ -88,7 +88,7 @@ async fn markup_from_component_equals_markup_reinjected_in_html_macro() { ]; for markup in cases { - // Vía 1: renderizamos a través del ciclo de componente. + // Path 1: we render through the component cycle. let via_component = { let mut cx = Context::default(); let mut comp = TestMarkupComponent { @@ -97,7 +97,7 @@ async fn markup_from_component_equals_markup_reinjected_in_html_macro() { comp.render(&mut cx).await.into_string() }; - // Vía 2: reinyectamos el Markup en `html!` directamente. + // Path 2: we reinject the Markup into `html!` directly. let via_macro = html! { (markup) }.into_string(); assert_eq!( diff --git a/tests/html_props.rs b/tests/html_props.rs index d6a8a7e4..6b5f751e 100644 --- a/tests/html_props.rs +++ b/tests/html_props.rs @@ -42,7 +42,7 @@ async fn props_set_replaces_existing_value() { #[pagetop::test] async fn props_set_does_not_create_duplicate_key() { - // Reasignar la misma clave debe reemplazar el valor, no añadir una entrada duplicada. + // Reassigning the same key must replace the value, not add a duplicate entry. let p = Props::new("key", "v1").with_prop(PropsOp::set("key", "v2")); assert_eq!( html! { span (p) {} }.into_string(), @@ -109,7 +109,7 @@ async fn props_escapes_double_quotes_in_value() { #[pagetop::test] async fn props_empty_in_html_macro_produces_no_attributes() { - // Una Props vacía no debe emitir ni siquiera un espacio en blanco extra. + // An empty Props must not emit even an extra blank space. let p = Props::default(); assert_eq!( html! { button (p) { "x" } }.into_string(), @@ -139,7 +139,7 @@ async fn props_multiple_attrs_preserve_order_in_html_macro() { #[pagetop::test] async fn props_alongside_class_and_id_in_html_macro() { - // El splice siempre se emite después de class e id, independientemente del orden escrito. + // The splice is always emitted after class and id, regardless of the order they are written in. let p = Props::new("hx-get", "/api"); assert_eq!( html! { button #mybtn .btn (p) { "Go" } }.into_string(), @@ -189,7 +189,7 @@ async fn props_conditional_expression_in_html_macro() { #[pagetop::test] async fn props_splice_empty_string_emits_nothing() { - // Un splice vacío no emite ningún atributo ni espacio extra. + // An empty splice emits no attribute nor extra space. assert_eq!(html! { span ("") { "x" } }.into_string(), "x"); } @@ -254,7 +254,7 @@ async fn get_prop_id_matches_get_id() { #[pagetop::test] async fn props_hx_target_value_with_hash_renders_correctly() { - // Regresión: r#"..."# se cerraba prematuramente al encontrar `"#lista"`. + // Regression: r#"..."# used to close prematurely when it found `"#list"`. let p = Props::new("hx-target", "#list"); assert_eq!( html! { button (p) {} }.into_string(), @@ -289,7 +289,7 @@ async fn props_chained_set_and_remove_yields_expected_state() { #[pagetop::test] async fn props_with_empty_attr_name_renders_without_validation() { - // Comportamiento documentado: los nombres no se validan; el HTML resultante no es estándar. + // Documented behavior: names are not validated; the resulting HTML is not standard. let p = Props::new("", "val"); assert_eq!( html! { span (p) {} }.into_string(), diff --git a/tests/html_props_styles.rs b/tests/html_props_styles.rs index 821dfc22..c01ae00d 100644 --- a/tests/html_props_styles.rs +++ b/tests/html_props_styles.rs @@ -55,9 +55,9 @@ async fn add_style_value_preserves_case_and_non_ascii() { #[pagetop::test] async fn add_style_value_may_contain_semicolons() { - // A diferencia de PropsOp::Set("style", ...), que interpreta la cadena como declaraciones - // separadas por ";", AddStyle recibe la propiedad y el valor ya separados, así que un ";" - // dentro del valor (p. ej. una data URI) no supone ningún problema. + // Unlike PropsOp::Set("style", ...), which interprets the string as declarations separated by + // ";", AddStyle receives the property and the value already separated, so a ";" inside the + // value (e.g. a data URI) is not a problem. let p = Props::default().with_prop(PropsOp::add_style( "background", "url(data:image/png;base64,AAAA)", @@ -188,9 +188,9 @@ async fn styles_reset_mixes_declarations_with_and_without_parens() { assert_styles(&p, Some("color: red; background: url(a;b); margin: 0")); } -// Límite conocido de PropsOp::Set("style", ...): no es un análisis CSS completo. Unos paréntesis -// sin cerrar arrastran el resto de la cadena a la misma declaración. Este test fija el -// comportamiento actual para que un cambio futuro sea deliberado, no accidental. +// Known limitation of PropsOp::Set("style", ...): it is not a full CSS parser. Unclosed parentheses +// drag the rest of the string into the same declaration. This test pins the current behavior so +// that a future change is deliberate, not accidental. #[pagetop::test] async fn styles_reset_unbalanced_parens_swallows_rest_of_string() { let p = Props::default().with_prop(PropsOp::set( diff --git a/tests/html_unit.rs b/tests/html_unit.rs index 6acae935..9016a1df 100644 --- a/tests/html_unit.rs +++ b/tests/html_unit.rs @@ -8,7 +8,7 @@ async fn unit_value_empty_and_auto_and_zero_without_unit() { assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); assert_eq!(UnitValue::from_str("AUTO").unwrap(), UnitValue::Auto); - // Cero sin unidad. + // Zero without a unit. assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); assert_eq!(UnitValue::from_str("+0").unwrap(), UnitValue::Zero); assert_eq!(UnitValue::from_str("-0").unwrap(), UnitValue::Zero); @@ -16,7 +16,7 @@ async fn unit_value_empty_and_auto_and_zero_without_unit() { #[pagetop::test] async fn unit_value_absolute_integers_with_signs_and_spaces_and_case() { - // Positivos, negativos y con espacios. + // Positive, negative, and with spaces. assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); assert_eq!(UnitValue::from_str("-5pt").unwrap(), UnitValue::Pt(-5)); assert_eq!(UnitValue::from_str(" 7 cm ").unwrap(), UnitValue::Cm(7)); @@ -24,7 +24,7 @@ async fn unit_value_absolute_integers_with_signs_and_spaces_and_case() { assert_eq!(UnitValue::from_str(" 13 mm ").unwrap(), UnitValue::Mm(13)); assert_eq!(UnitValue::from_str("4 pc").unwrap(), UnitValue::Pc(4)); - // Insensibilidad a mayúsculas. + // Case insensitivity. assert_eq!(UnitValue::from_str("10PX").unwrap(), UnitValue::Px(10)); assert_eq!(UnitValue::from_str("15Pt").unwrap(), UnitValue::Pt(15)); } @@ -55,7 +55,7 @@ async fn unit_value_relative_floats_with_signs_and_spaces_and_case() { #[pagetop::test] async fn unit_value_whitespace_between_number_and_unit_is_allowed() { - // Hay espacio entre número y unidad (la implementación actual lo admite). + // There is a space between number and unit (the current implementation allows it). assert_eq!(UnitValue::from_str("12 px").unwrap(), UnitValue::Px(12)); assert_eq!( UnitValue::from_str("1.5 rem").unwrap(), @@ -113,7 +113,7 @@ async fn unit_value_percentage_trimming_and_signs() { ); } -// ERRORES ESPERADOS (no cambiar los mensajes; con is_err() basta). +// EXPECTED ERRORS (don't change the messages; is_err() is enough). #[pagetop::test] async fn unit_value_errors_missing_unit_for_non_zero() { @@ -136,10 +136,10 @@ async fn unit_value_errors_decimals_in_absolute_units() { #[pagetop::test] async fn unit_value_errors_unknown_units_or_bad_percentages() { - // Unidad no soportada. + // Unsupported unit. assert!(UnitValue::from_str("10ch").is_err()); assert!(UnitValue::from_str("2q").is_err()); - // Falta número. + // Missing number. assert!(UnitValue::from_str("%").is_err()); assert!(UnitValue::from_str(" % ").is_err()); } @@ -147,7 +147,7 @@ async fn unit_value_errors_unknown_units_or_bad_percentages() { #[pagetop::test] async fn unit_value_errors_non_numeric_numbers() { assert!(UnitValue::from_str("NaNem").is_err()); - // Decimal no permitido por FromStr. + // Decimal not allowed by FromStr. assert!(UnitValue::from_str("1,5rem").is_err()); } @@ -190,22 +190,22 @@ async fn unit_value_serde_deserialize_struct_and_array() { #[pagetop::test] async fn unit_value_accepts_dot5_and_1dot_shorthand_for_relatives() { - // `.5` y `1.` se parsean correctamente en relativas. + // `.5` and `1.` parse correctly for relative units. assert_eq!(UnitValue::from_str(".5em").unwrap(), UnitValue::RelEm(0.5)); assert_eq!( UnitValue::from_str("1.rem").unwrap(), UnitValue::RelRem(1.0) ); assert_eq!(UnitValue::from_str("1.vh").unwrap(), UnitValue::RelVh(1.0)); - // Sin unidad debe seguir fallando. + // Without a unit it must keep failing. assert!(UnitValue::from_str("1.").is_err()); } #[pagetop::test] async fn unit_value_display_keeps_minus_zero_for_relatives() { - // Comportamiento actual: f32 Display muestra "-0" si el valor es -0.0. + // Current behavior: f32 Display shows "-0" if the value is -0.0. let v = UnitValue::RelEm(-0.0); - // Se acepta cualquiera de los dos formatos como válidos. + // Either of the two formats is accepted as valid. let s = v.to_string(); assert!( s == "-0em" || s == "0em", @@ -215,9 +215,9 @@ async fn unit_value_display_keeps_minus_zero_for_relatives() { #[pagetop::test] async fn unit_value_rejects_non_decimal_notations() { - // Octal, los ceros a la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). + // Leading zeros (e.g. `"020px"`) are interpreted in **base 10** (`20px`), not octal. assert_eq!(UnitValue::from_str("020px").unwrap(), UnitValue::Px(20)); - // Notación científica y bases no decimales (p. ej., `"1e3vw"`, `"0x10px"`) no están soportadas. + // Scientific notation and non-decimal bases (e.g., `"1e3vw"`, `"0x10px"`) are not supported. assert!(UnitValue::from_str("1e3vw").is_err()); assert!(UnitValue::from_str("0x10px").is_err()); } diff --git a/tests/theme_template.rs b/tests/theme_template.rs index 877d8edd..032527e9 100644 --- a/tests/theme_template.rs +++ b/tests/theme_template.rs @@ -1,6 +1,6 @@ use pagetop::prelude::*; -// **< Tema con plantilla propia >****************************************************************** +// **< Theme with its own template >**************************************************************** struct MarkerTemplate; @@ -36,19 +36,19 @@ async fn render_active_template(cx: &mut Context) -> String { template.render(cx).await.into_string() } -// **< Context::template() sigue al tema activo >*************************************************** +// **< Context::template() follows the active theme >*********************************************** #[pagetop::test] async fn with_theme_updates_the_effective_template() { - // Sin cambiar de tema, la plantilla activa no es la de `MarkerTheme`. + // Without changing theme, the active template is not `MarkerTheme`'s. let mut cx = Context::new(None); assert_ne!( render_active_template(&mut cx).await, "marker-template-output" ); - // Tras cambiar de tema con `with_theme()`, la plantilla activa pasa a ser la de ese tema, sin - // necesidad de llamar a `with_template()` explícitamente. + // After changing theme with `with_theme()`, the active template becomes that theme's, with no + // need to call `with_template()` explicitly. let mut cx = Context::new(None).with_theme(&MarkerTheme); assert_eq!( render_active_template(&mut cx).await, @@ -58,8 +58,8 @@ async fn with_theme_updates_the_effective_template() { #[pagetop::test] async fn explicit_template_is_not_overridden_by_a_later_with_theme() { - // Una plantilla fijada explícitamente con `with_template()` prevalece aunque `with_theme()` se - // llame después, en cualquier orden. + // A template explicitly set with `with_template()` prevails even if `with_theme()` is called + // afterwards, regardless of order. let mut cx = Context::new(None) .with_template(&MarkerTemplate) .with_theme(&pagetop::base::theme::Basic); @@ -70,7 +70,7 @@ async fn explicit_template_is_not_overridden_by_a_later_with_theme() { ); } -// **< Page::admin() sigue al tema activo >********************************************************* +// **< Page::admin() follows the active theme >***************************************************** #[pagetop::test] async fn page_admin_template_follows_a_later_with_theme() { diff --git a/tests/util.rs b/tests/util.rs index a89d6fa0..0730a2c4 100644 --- a/tests/util.rs +++ b/tests/util.rs @@ -45,15 +45,15 @@ fn assert_owned(input: &str, expected: &str) { #[pagetop::test] async fn normalize_errors() { - // Caso especial: cadena vacía. + // Special case: empty string. assert_err("", util::NormalizeAsciiError::IsEmpty); - // Sólo separadores ASCII: tras el recorte no queda nada. + // Only ASCII separators: nothing is left after trimming. for input in [" ", " ", "\t", "\n", "\r", "\t \n\r "] { assert_err(input, util::NormalizeAsciiError::EmptyAfterTrimming); } - // Cualquier byte no-ASCII debe fallar, aunque el resto pueda normalizarse. + // Any non-ASCII byte must fail, even if the rest could be normalized. for input in [ "©", "á", @@ -70,7 +70,7 @@ async fn normalize_errors() { #[pagetop::test] async fn normalize_borrowed_trim_and_already_normalized() { - // Sólo recorte (incluyendo separadores al final). + // Trimming only (including trailing separators). for (input, expected) in [ (" a", "a"), ("a ", "a"), @@ -89,7 +89,7 @@ async fn normalize_borrowed_trim_and_already_normalized() { assert_borrowed(input, expected); } - // Ya normalizado (minúsculas y un único espacio entre tokens). + // Already normalized (lowercase and a single space between tokens). for input in [ "a", "a b", @@ -107,12 +107,12 @@ async fn normalize_borrowed_trim_and_already_normalized() { "path/to/resource", "foo+bar=baz", "a-._:/+=", - "a\x1Bb", // Byte de control ASCII: se conserva tal cual. + "a\x1Bb", // ASCII control byte: preserved as-is. ] { assert_borrowed(input, input); } - // Separador "raro" al final de la cadena: se recorta y se devuelve porción. + // "Unusual" separator at the end of the string: it is trimmed and a slice is returned. for (input, expected) in [ ("foo bar\t", "foo bar"), ("foo bar\r\n", "foo bar"), @@ -124,7 +124,7 @@ async fn normalize_borrowed_trim_and_already_normalized() { #[pagetop::test] async fn normalize_owned_due_to_uppercase() { - // Sólo por mayúsculas (y otros ASCII que se preservan). + // Only due to uppercase (and other ASCII that is preserved). for (input, expected) in [ ("A", "a"), ("Foo", "foo"), @@ -141,7 +141,7 @@ async fn normalize_owned_due_to_uppercase() { ("ETag:W/\"XYZ\"", "etag:w/\"xyz\""), ("Foo+Bar=Baz", "foo+bar=baz"), ("A-._:/+=", "a-._:/+="), - ("A\x1BB", "a\x1bb"), // Sólo letras en minúsculas; el byte de control se conserva. + ("A\x1BB", "a\x1bb"), // Only letters get lowercased; the control byte is preserved. ] { assert_owned(input, expected); } @@ -149,12 +149,12 @@ async fn normalize_owned_due_to_uppercase() { #[pagetop::test] async fn normalize_owned_due_to_internal_whitespace() { - // Espacios consecutivos (deben colapsar a un único espacio). + // Consecutive spaces (must collapse to a single space). for (input, expected) in [("a b", "a b"), ("a b", "a b")] { assert_owned(input, expected); } - // Separadores ASCII distintos de ' ' entre tokens (tab, newline, CR, CRLF). + // ASCII separators other than ' ' between tokens (tab, newline, CR, CRLF). for (input, expected) in [ ("a\tb", "a b"), ("a\nb", "a b"), @@ -168,7 +168,7 @@ async fn normalize_owned_due_to_internal_whitespace() { assert_owned(input, expected); } - // Mezclas de separadores. + // Mixed separators. for (input, expected) in [ ("a \t \n b", "a b"), ("a\t \n b", "a b"), @@ -180,7 +180,7 @@ async fn normalize_owned_due_to_internal_whitespace() { assert_owned(input, expected); } - // El resultado nunca debe tener espacios al inicio/fin (tras normalizar). + // The result must never have leading/trailing spaces (after normalizing). for (input, expected) in [ (" a b ", "a b"), (" a\tb ", "a b"), @@ -192,7 +192,7 @@ async fn normalize_owned_due_to_internal_whitespace() { #[pagetop::test] async fn normalize_owned_due_to_mixed_causes() { - // Combinaciones de mayúsculas y separador no normalizado. + // Combinations of uppercase and non-normalized separators. for (input, expected) in [ (" Foo BAR\tbaz ", "foo bar baz"), ("\nFOO\rbar\tBAZ\n", "foo bar baz"), @@ -209,17 +209,17 @@ async fn normalize_owned_due_to_mixed_causes() { #[pagetop::test] async fn normalize_borrowed_vs_owned_edge_cases() { - // Un sólo token con separador al final. + // A single token with a trailing separator. for (input, expected) in [("x ", "x"), ("x\t", "x"), ("x\n", "x"), ("x\r\n", "x")] { assert_borrowed(input, expected); } - // Dos tokens con separador no normalizado. + // Two tokens with a non-normalized separator. for input in ["x y", "x\t\ty", "x \t y", "x\r\ny"] { assert_owned(input, "x y"); } - // Dos tokens con separación limpia. + // Two tokens with a clean separator. for (input, expected) in [("x y ", "x y"), ("x y\t", "x y"), ("x y\r\n", "x y")] { assert_borrowed(input, expected); } @@ -227,7 +227,7 @@ async fn normalize_borrowed_vs_owned_edge_cases() { #[pagetop::test] async fn normalize_is_idempotent() { - // La normalización debe ser idempotente: normalizar el resultado no cambia nada. + // Normalization must be idempotent: normalizing the result changes nothing. let cases = [ "a", "a b c", @@ -243,7 +243,7 @@ async fn normalize_is_idempotent() { ]; for &input in &cases { - // Todos son ASCII, pero se deja este control por si se amplía la lista en el futuro. + // All are ASCII, but this check is kept in case the list is expanded in the future. if !input.is_ascii() { continue; }