@@ -58,6 +58,10 @@ impl KeyBindings {
5858
5959 let mut report = format ! ( "Valid keymap: {}\n " , keymap_path. display( ) ) ;
6060
61+ // Sort categories for stable output
62+ let mut categories: Vec < _ > = keymap. 0 . iter ( ) . collect ( ) ;
63+ categories. sort_unstable_by_key ( |( category, _) | format ! ( "{category:?}" ) ) ;
64+
6165 for ( category, bindings) in keymap. 0 {
6266 report. push_str ( & format ! ( "Category: {category:?}\n " ) ) ;
6367 report. push_str ( & format ! ( " {} key bindings defined\n " , bindings. len( ) ) ) ;
@@ -68,7 +72,11 @@ impl KeyBindings {
6872 * action_counts. entry ( * action) . or_insert ( 0 ) += 1 ;
6973 }
7074
71- for ( action, count) in action_counts {
75+ // Sort actions for stable output
76+ let mut sorted_actions: Vec < _ > = action_counts. into_iter ( ) . collect ( ) ;
77+ sorted_actions. sort_unstable_by_key ( |( action, _) | format ! ( "{action:?}" ) ) ;
78+
79+ for ( action, count) in sorted_actions {
7280 if count > 1 {
7381 report. push_str ( & format ! ( " - {action:?}: {count} keys bound\n " ) ) ;
7482 }
@@ -662,4 +670,60 @@ mod tests {
662670 Some ( Action :: Quit )
663671 ) ;
664672 }
673+
674+ #[ test]
675+ fn test_validate_nonexistent_keymap ( ) -> TestResult {
676+ let temp_dir = tempfile:: tempdir ( ) ?;
677+ let keymap_path = temp_dir. path ( ) . join ( "keymap.toml" ) ;
678+
679+ let result = KeyBindings :: validate_and_report ( Some ( keymap_path. clone ( ) ) ) ;
680+
681+ let error = result. unwrap_err ( ) ;
682+ assert ! ( error. starts_with( "No keymap.toml found at:" ) ) ;
683+ assert ! ( error. contains( "Run with --dump-default-keymap to create one." ) ) ;
684+ Ok ( ( ) )
685+ }
686+
687+ #[ test]
688+ fn test_validate_invalid_toml ( ) -> TestResult {
689+ let temp_dir = tempfile:: tempdir ( ) ?;
690+ let keymap_path = temp_dir. path ( ) . join ( "keymap.toml" ) ;
691+
692+ fs:: write ( & keymap_path, "this is not valid toml [[[" ) ?;
693+
694+ let result = KeyBindings :: validate_and_report ( Some ( keymap_path) ) ;
695+
696+ let error = result. unwrap_err ( ) ;
697+ assert ! ( error. starts_with( "Invalid keymap.toml:" ) ) ;
698+ Ok ( ( ) )
699+ }
700+
701+ #[ test]
702+ fn test_validate_valid_keymap_report ( ) -> TestResult {
703+ let temp_dir = tempfile:: tempdir ( ) ?;
704+ let keymap_path = temp_dir. path ( ) . join ( "keymap.toml" ) ;
705+
706+ let valid_keymap = r#"
707+ [Global]
708+ "<a>" = "navigate-select"
709+ "<b>" = "navigate-select"
710+ "<space>" = "navigate-select"
711+ "<q>" = "quit"
712+ "<ctrl-c>" = "quit"
713+ "<esc>" = "close"
714+ "# ;
715+ fs:: write ( & keymap_path, valid_keymap) ?;
716+
717+ let report = KeyBindings :: validate_and_report ( Some ( keymap_path) ) ?;
718+
719+ insta:: with_settings!( {
720+ filters => vec![
721+ ( r"Valid keymap: .*/keymap\.toml" , "Valid keymap: [TEMP_PATH]/keymap.toml" ) ,
722+ ]
723+ } , {
724+ insta:: assert_snapshot!( report) ;
725+ } ) ;
726+
727+ Ok ( ( ) )
728+ }
665729}
0 commit comments