From 46f4b5d1ccde4e494432313ffa06006934ba7447 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 1 Dec 2025 18:28:41 +0100 Subject: [PATCH 1/7] add a tidy test --- src/tools/tidy/src/alphabetical/tests.rs | 59 ++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 3e0dd798ab9df..5bfb37a098fc6 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -337,3 +337,62 @@ fn test_numeric_bad() { "; bad(lines, "bad:3: line not in alphabetical order"); } + +#[test] +fn multiline() { + let lines = "\ + tidy-alphabetical-start + (b, + a); + ( + b, + a + ) + tidy-alphabetical-end + "; + good(lines); + + let lines = "\ + tidy-alphabetical-start + ( + b, + a + ) + (b, + a); + tidy-alphabetical-end + "; + good(lines); + + let lines = "\ + tidy-alphabetical-start + (c, + a); + ( + b, + a + ) + tidy-alphabetical-end + "; + bad(lines, "bad:5: line not in alphabetical order"); + + let lines = "\ + tidy-alphabetical-start + ( + c, + a + ) + (b, + a); + tidy-alphabetical-end + "; + bad(lines, "bad:6: line not in alphabetical order"); + + let lines = "\ + force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], + 'force use of unwind tables'), + incremental: Option = (None, parse_opt_string, [UNTRACKED], + 'enable incremental compilation'), + "; + good(lines); +} From 3a0f23b7ba36bcaf74d3fe488bd7380c13f41dbf Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 2/7] refactor tidy alphabetical lint This slightly changes alphabetical lint semantics... specifically if an "item" is multiline (when the next line does not have the same indentation) we now consider all lines (ignoring starting whitespace) for ordering, not just the first one. --- src/tools/tidy/src/alphabetical.rs | 289 +++++++++++++++++++++-------- 1 file changed, 207 insertions(+), 82 deletions(-) diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 3845e2269e9b2..6a1e777d9f2ad 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -9,19 +9,33 @@ //! // tidy-alphabetical-end //! ``` //! -//! The following lines are ignored: -//! - Empty lines -//! - Lines that are indented with more or less spaces than the first line -//! - Lines starting with `//`, `#` (except those starting with `#!`), `)`, `]`, `}` if the comment -//! has the same indentation as the first line -//! - Lines starting with a closing delimiter (`)`, `[`, `}`) are ignored. +//! Empty lines and lines starting (ignoring spaces) with `//` or `#` (except those starting with +//! `#!`) are considered comments are are sorted together with the next line (but do not affect +//! sorting). //! -//! If a line ends with an opening delimiter, we effectively join the following line to it before -//! checking it. E.g. `foo(\nbar)` is treated like `foo(bar)`. +//! If the following lines have higher indentation we effectively join them with the current line +//! before comparing it. If the next line with the same indentation starts (ignoring spaces) with +//! a closing delimiter (`)`, `[`, `}`) it is joined as well. +//! +//! E.g. +//! +//! ```rust,ignore ilustrative example for sorting mentioning non-existent functions +//! foo(a, +//! b); +//! bar( +//! a, +//! b +//! ); +//! // are treated for sorting purposes as +//! foo(a, b); +//! bar(a, b); +//! ``` use std::cmp::Ordering; -use std::fmt::Display; +use std::fs; +use std::io::{Seek, Write}; use std::iter::Peekable; +use std::ops::{Range, RangeBounds}; use std::path::Path; use crate::diagnostics::{CheckId, RunningCheck, TidyCtx}; @@ -38,94 +52,190 @@ fn is_close_bracket(c: char) -> bool { matches!(c, ')' | ']' | '}') } +fn is_empty_or_comment(line: &&str) -> bool { + let trimmed_line = line.trim_start_matches(' ').trim_end_matches('\n'); + + trimmed_line.is_empty() + || trimmed_line.starts_with("//") + || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) +} + const START_MARKER: &str = "tidy-alphabetical-start"; const END_MARKER: &str = "tidy-alphabetical-end"; -fn check_section<'a>( - file: impl Display, - lines: impl Iterator, - check: &mut RunningCheck, -) { - let mut prev_line = String::new(); - let mut first_indent = None; - let mut in_split_line = None; - - for (idx, line) in lines { - if line.is_empty() { - continue; - } +/// Given contents of a section that is enclosed between [`START_MARKER`] and [`END_MARKER`], sorts +/// them according to the rules described at the top of the module. +fn sort_section(section: &str) -> String { + /// A sortable item + struct Item { + /// Full contents including comments and whitespace + full: String, + /// Trimmed contents for sorting + trimmed: String, + } - if line.contains(START_MARKER) { - check.error(format!( - "{file}:{} found `{START_MARKER}` expecting `{END_MARKER}`", - idx + 1 - )); - return; - } + let mut items = Vec::new(); + let mut lines = section.split_inclusive('\n').peekable(); + + let end_comments = loop { + let mut full = String::new(); + let mut trimmed = String::new(); - if line.contains(END_MARKER) { - return; + while let Some(comment) = lines.next_if(is_empty_or_comment) { + full.push_str(comment); } - let indent = first_indent.unwrap_or_else(|| { - let indent = indentation(line); - first_indent = Some(indent); - indent - }); - - let line = if let Some(prev_split_line) = in_split_line { - // Join the split lines. - in_split_line = None; - format!("{prev_split_line}{}", line.trim_start()) - } else { - line.to_string() + let Some(line) = lines.next() else { + // remember comments at the end of a block + break full; }; - if indentation(&line) != indent { - continue; - } + let mut push = |line| { + full.push_str(line); + trimmed.push_str(line.trim_start_matches(' ').trim_end_matches('\n')) + }; - let trimmed_line = line.trim_start_matches(' '); + push(line); - if trimmed_line.starts_with("//") - || (trimmed_line.starts_with('#') && !trimmed_line.starts_with("#!")) - || trimmed_line.starts_with(is_close_bracket) + let indent = indentation(line); + let mut multiline = false; + + // If the item is split between multiple lines... + while let Some(more_indented) = + lines.next_if(|&line: &&_| indent < indentation(line) || line == "\n") { - continue; + multiline = true; + push(more_indented); } - if line.trim_end().ends_with('(') { - in_split_line = Some(line); - continue; + if multiline + && let Some(indented) = + // Only append next indented line if it looks like a closing bracket. + // Otherwise we incorrectly merge code like this (can be seen in + // compiler/rustc_session/src/options.rs): + // + // force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], + // "force use of unwind tables"), + // incremental: Option = (None, parse_opt_string, [UNTRACKED], + // "enable incremental compilation"), + lines.next_if(|l| { + indentation(l) == indent + && l.trim_start_matches(' ').starts_with(is_close_bracket) + }) + { + push(indented); } - let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' '); + items.push(Item { full, trimmed }); + }; - if version_sort(trimmed_line, prev_line_trimmed_lowercase).is_lt() { - check.error(format!("{file}:{}: line not in alphabetical order", idx + 1)); - } + items.sort_by(|a, b| version_sort(&a.trimmed, &b.trimmed)); + items.into_iter().map(|l| l.full).chain([end_comments]).collect() +} - prev_line = line; - } +fn check_lines<'a>(path: &Path, content: &'a str, tidy_ctx: &TidyCtx, check: &mut RunningCheck) { + let mut offset = 0; + + loop { + let rest = &content[offset..]; + let start = rest.find(START_MARKER); + let end = rest.find(END_MARKER); + + match (start, end) { + // error handling + + // end before start + (Some(start), Some(end)) if end < start => { + check.error(format!( + "{path}:{line_number} found `{END_MARKER}` expecting `{START_MARKER}`", + path = path.display(), + line_number = content[..offset + end].lines().count(), + )); + break; + } - check.error(format!("{file}: reached end of file expecting `{END_MARKER}`")); -} + // end without a start + (None, Some(end)) => { + check.error(format!( + "{path}:{line_number} found `{END_MARKER}` expecting `{START_MARKER}`", + path = path.display(), + line_number = content[..offset + end].lines().count(), + )); + break; + } -fn check_lines<'a>( - file: &impl Display, - mut lines: impl Iterator, - check: &mut RunningCheck, -) { - while let Some((idx, line)) = lines.next() { - if line.contains(END_MARKER) { - check.error(format!( - "{file}:{} found `{END_MARKER}` expecting `{START_MARKER}`", - idx + 1 - )); - } + // start without an end + (Some(start), None) => { + check.error(format!( + "{path}:{line_number} `{START_MARKER}` without a matching `{END_MARKER}`", + path = path.display(), + line_number = content[..offset + start].lines().count(), + )); + break; + } + + // a second start in between start/end pair + (Some(start), Some(end)) + if rest[start + START_MARKER.len()..end].contains(START_MARKER) => + { + check.error(format!( + "{path}:{line_number} found `{START_MARKER}` expecting `{END_MARKER}`", + path = path.display(), + line_number = content[..offset + + sub_find(rest, start + START_MARKER.len()..end, START_MARKER) + .unwrap() + .start] + .lines() + .count() + )); + break; + } - if line.contains(START_MARKER) { - check_section(file, &mut lines, check); + // happy happy path :3 + (Some(start), Some(end)) => { + assert!(start <= end); + + // "...␤// tidy-alphabetical-start␤...␤// tidy-alphabetical-end␤..." + // start_nl_end --^ ^-- end_nl_start ^-- end_nl_end + + // Position after the newline after start marker + let start_nl_end = sub_find(rest, start + START_MARKER.len().., "\n").unwrap().end; + + // Position before the new line before the end marker + let end_nl_start = rest[..end].rfind('\n').unwrap(); + + // Position after the newline after end marker + let end_nl_end = sub_find(rest, end + END_MARKER.len().., "\n") + .map(|r| r.end) + .unwrap_or(content.len() - offset); + + let section = &rest[start_nl_end..=end_nl_start]; + let sorted = sort_section(section); + + // oh nyooo :( + if sorted != section { + let base_line_number = content[..offset + start_nl_end].lines().count(); + let line_offset = sorted + .lines() + .zip(section.lines()) + .enumerate() + .find(|(_, (a, b))| a != b) + .unwrap() + .0; + let line_number = base_line_number + line_offset; + + check.error(format!( + "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", + path = path.display(), + )); + } + + // Start the next search after the end section + offset += end_nl_end; + } + + // No more alphabetical lists, yay :3 + (None, None) => break, } } } @@ -133,13 +243,14 @@ fn check_lines<'a>( pub fn check(path: &Path, tidy_ctx: TidyCtx) { let mut check = tidy_ctx.start_check(CheckId::new("alphabetical").path(path)); - let skip = - |path: &_, _is_dir| filter_dirs(path) || path.ends_with("tidy/src/alphabetical/tests.rs"); + let skip = |path: &_, _is_dir| { + filter_dirs(path) + || path.ends_with("tidy/src/alphabetical.rs") + || path.ends_with("tidy/src/alphabetical/tests.rs") + }; - walk(path, skip, &mut |entry, contents| { - let file = &entry.path().display(); - let lines = contents.lines().enumerate(); - check_lines(file, lines, &mut check) + walk(path, skip, &mut |entry, content| { + check_lines(entry.path(), content, &tidy_ctx, &mut check) }); } @@ -195,3 +306,17 @@ fn version_sort(a: &str, b: &str) -> Ordering { it1.next().cmp(&it2.next()) } + +/// Finds `pat` in `s[range]` and returns a range such that `s[ret] == pat`. +fn sub_find(s: &str, range: impl RangeBounds, pat: &str) -> Option> { + s[(range.start_bound().cloned(), range.end_bound().cloned())] + .find(pat) + .map(|pos| { + pos + match range.start_bound().cloned() { + std::ops::Bound::Included(x) => x, + std::ops::Bound::Excluded(x) => x + 1, + std::ops::Bound::Unbounded => 0, + } + }) + .map(|pos| pos..pos + pat.len()) +} From 4fef9bdbd6f1daf1c1155df70438746f65f9a09a Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 3/7] implement tidy bless for alphabetical blocks --- Cargo.lock | 1 + src/tools/tidy/Cargo.toml | 1 + src/tools/tidy/src/alphabetical.rs | 44 ++++++++++++++++++++---------- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d8d5111583e5..0e15485355461 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5615,6 +5615,7 @@ dependencies = [ "semver", "serde", "similar", + "tempfile", "termcolor", "toml 0.7.8", "walkdir", diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml index c1f27de7ed4a5..47b59543c59cc 100644 --- a/src/tools/tidy/Cargo.toml +++ b/src/tools/tidy/Cargo.toml @@ -18,6 +18,7 @@ rustc-hash = "2.0.0" fluent-syntax = "0.12" similar = "2.5.0" toml = "0.7.8" +tempfile = "3.15.0" [features] build-metrics = ["dep:serde"] diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs index 6a1e777d9f2ad..4ef1775d4bed9 100644 --- a/src/tools/tidy/src/alphabetical.rs +++ b/src/tools/tidy/src/alphabetical.rs @@ -214,20 +214,36 @@ fn check_lines<'a>(path: &Path, content: &'a str, tidy_ctx: &TidyCtx, check: &mu // oh nyooo :( if sorted != section { - let base_line_number = content[..offset + start_nl_end].lines().count(); - let line_offset = sorted - .lines() - .zip(section.lines()) - .enumerate() - .find(|(_, (a, b))| a != b) - .unwrap() - .0; - let line_number = base_line_number + line_offset; - - check.error(format!( - "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", - path = path.display(), - )); + if !tidy_ctx.is_bless_enabled() { + let base_line_number = content[..offset + start_nl_end].lines().count(); + let line_offset = sorted + .lines() + .zip(section.lines()) + .enumerate() + .find(|(_, (a, b))| a != b) + .unwrap() + .0; + let line_number = base_line_number + line_offset; + + check.error(format!( + "{path}:{line_number}: line not in alphabetical order (tip: use --bless to sort this list)", + path = path.display(), + )); + } else { + // Use atomic rename as to not corrupt the file upon crashes/ctrl+c + let mut tempfile = + tempfile::Builder::new().tempfile_in(path.parent().unwrap()).unwrap(); + + fs::copy(path, tempfile.path()).unwrap(); + + tempfile + .as_file_mut() + .seek(std::io::SeekFrom::Start((offset + start_nl_end) as u64)) + .unwrap(); + tempfile.as_file_mut().write_all(sorted.as_bytes()).unwrap(); + + tempfile.persist(path).unwrap(); + } } // Start the next search after the end section From a93d661475081ccf07af196625c9fa5190fabd81 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Sat, 16 Aug 2025 14:26:34 +0200 Subject: [PATCH 4/7] bless tidy tests --- src/tools/tidy/src/alphabetical/tests.rs | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 5bfb37a098fc6..6a756a84cf999 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -7,7 +7,7 @@ use crate::diagnostics::{TidyCtx, TidyFlags}; fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) { let tidy_ctx = TidyCtx::new(Path::new("/"), false, TidyFlags::default()); let mut check = tidy_ctx.start_check("alphabetical-test"); - check_lines(&name, lines.lines().enumerate(), &mut check); + check_lines(Path::new(name), lines, &tidy_ctx, &mut check); assert_eq!(expected_bad, check.is_bad()); let errors = check.get_errors(); @@ -95,7 +95,7 @@ fn test_rust_bad() { def // tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -107,7 +107,7 @@ fn test_toml_bad() { def # tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -121,7 +121,7 @@ fn test_features_bad() { #![feature(def)] tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -134,7 +134,7 @@ fn test_indent_bad() { def $ tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -150,7 +150,7 @@ fn test_split_bad() { ) && tidy-alphabetical-end "; - bad(lines, "bad:7: line not in alphabetical order"); + bad(lines, "bad:3: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -160,7 +160,7 @@ fn test_double_start() { abc tidy-alphabetical-start "; - bad(lines, "bad:3 found `tidy-alphabetical-start` expecting `tidy-alphabetical-end`"); + bad(lines, "bad:0 `tidy-alphabetical-start` without a matching `tidy-alphabetical-end`"); } #[test] @@ -179,7 +179,7 @@ fn test_missing_end() { tidy-alphabetical-start abc "; - bad(lines, "bad: reached end of file expecting `tidy-alphabetical-end`"); + bad(lines, "bad:0 `tidy-alphabetical-start` without a matching `tidy-alphabetical-end`"); } #[test] @@ -319,7 +319,7 @@ fn test_numeric_bad() { item2 # tidy-alphabetical-end "; - bad(lines, "bad:4: line not in alphabetical order"); + bad(lines, "bad:2: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ # tidy-alphabetical-start @@ -327,7 +327,7 @@ fn test_numeric_bad() { zve64d # tidy-alphabetical-end "; - bad(lines, "bad:3: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ # tidy-alphabetical-start @@ -335,7 +335,7 @@ fn test_numeric_bad() { 00 # tidy-alphabetical-end "; - bad(lines, "bad:3: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); } #[test] @@ -347,7 +347,7 @@ fn multiline() { ( b, a - ) + ); tidy-alphabetical-end "; good(lines); @@ -357,7 +357,7 @@ fn multiline() { ( b, a - ) + ); (b, a); tidy-alphabetical-end @@ -371,22 +371,22 @@ fn multiline() { ( b, a - ) + ); tidy-alphabetical-end "; - bad(lines, "bad:5: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ tidy-alphabetical-start ( c, a - ) + ); (b, a); tidy-alphabetical-end "; - bad(lines, "bad:6: line not in alphabetical order"); + bad(lines, "bad:1: line not in alphabetical order (tip: use --bless to sort this list)"); let lines = "\ force_unwind_tables: Option = (None, parse_opt_bool, [TRACKED], From 3e811b30d8585bf792c4cc5e362777382545e6d7 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 1 Dec 2025 17:28:58 +0100 Subject: [PATCH 5/7] drive-by: tidy: fixup style --- src/tools/tidy/src/diagnostics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/diagnostics.rs b/src/tools/tidy/src/diagnostics.rs index 159500751aa5a..88816b5abefff 100644 --- a/src/tools/tidy/src/diagnostics.rs +++ b/src/tools/tidy/src/diagnostics.rs @@ -6,10 +6,10 @@ use std::sync::{Arc, Mutex}; use termcolor::Color; +/// CLI flags used by tidy. #[derive(Clone, Default)] -///CLI flags used by tidy. pub struct TidyFlags { - ///Applies style and formatting changes during a tidy run. + /// Applies style and formatting changes during a tidy run. bless: bool, } From dcc785d09ca637cf653d51c60f0f3a22237f94e1 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Mon, 18 Aug 2025 17:42:43 +0200 Subject: [PATCH 6/7] bless tidy --- compiler/rustc_type_ir/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index c1e3019612676..8065db1e05dd7 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -4,11 +4,11 @@ #![allow(rustc::usage_of_ty_tykind)] #![allow(rustc::usage_of_type_ir_inherent)] #![allow(rustc::usage_of_type_ir_traits)] +#![cfg_attr(feature = "nightly", allow(internal_features))] #![cfg_attr( feature = "nightly", feature(associated_type_defaults, never_type, rustc_attrs, negative_impls) )] -#![cfg_attr(feature = "nightly", allow(internal_features))] // tidy-alphabetical-end extern crate self as rustc_type_ir; From 8b6431d27f255ccdbc1e79c3af3f5c80c487df6e Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 3 Dec 2025 15:40:02 +0100 Subject: [PATCH 7/7] add tests for tidy alphabetical blessing --- src/tools/tidy/src/alphabetical/tests.rs | 107 +++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs index 6a756a84cf999..e5cab33101260 100644 --- a/src/tools/tidy/src/alphabetical/tests.rs +++ b/src/tools/tidy/src/alphabetical/tests.rs @@ -29,6 +29,23 @@ fn bad(lines: &str, expected_msg: &str) { test(lines, "bad", expected_msg, true); } +#[track_caller] +fn bless_test(before: &str, after: &str) { + let tempfile = tempfile::Builder::new().tempfile().unwrap(); + std::fs::write(tempfile.path(), before).unwrap(); + + let tidy_ctx = TidyCtx::new(Path::new("/"), false, TidyFlags::new(&["--bless".to_owned()])); + + let mut check = tidy_ctx.start_check("alphabetical-test"); + check_lines(tempfile.path(), before, &tidy_ctx, &mut check); + + assert!(!check.is_bad()); + let new = std::fs::read_to_string(tempfile.path()).unwrap(); + assert_eq!(new, after); + + good(&new); +} + #[test] fn test_no_markers() { let lines = "\ @@ -396,3 +413,93 @@ fn multiline() { "; good(lines); } + +#[test] +fn bless_smoke() { + let before = "\ + tidy-alphabetical-start + 08 + 1 + 11 + 03 + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 1 + 03 + 08 + 11 + tidy-alphabetical-end + "; + + bless_test(before, after); +} + +#[test] +fn bless_multiline() { + let before = "\ + tidy-alphabetical-start + 08 { + z} + 08 { + x + } + 1 + 08 {y} + 02 + 11 ( + 0 + ) + 03 + addition + notaddition + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 1 + 02 + 03 + addition + 08 { + x + } + 08 {y} + 08 { + z} + 11 ( + 0 + ) + notaddition + tidy-alphabetical-end + "; + + bless_test(before, after); +} + +#[test] +fn bless_funny_numbers() { + // Because `2` is indented it gets merged into one entry with `1` and gets + // interpreted by version sort as `12`, which is greater than `3`. + // + // This is neither a wanted nor an unwanted behavior, this test just checks + // that it hasn't changed. + + let before = "\ + tidy-alphabetical-start + 1 + 2 + 3 + tidy-alphabetical-end + "; + let after = "\ + tidy-alphabetical-start + 3 + 1 + 2 + tidy-alphabetical-end + "; + + bless_test(before, after); +}