Add test for base keymap setting

Mikayla Maki created

Change summary

crates/settings/src/settings_file.rs | 143 +++++++++++++++++++++++++++++
1 file changed, 142 insertions(+), 1 deletion(-)

Detailed changes

crates/settings/src/settings_file.rs 🔗

@@ -54,10 +54,151 @@ impl SettingsFile {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use crate::{watched_json::watch_settings_file, EditorSettings, Settings, SoftWrap};
+    use crate::{
+        watch_files, watched_json::watch_settings_file, EditorSettings, Settings, SoftWrap,
+    };
     use fs::FakeFs;
+    use gpui::{actions, Action};
     use theme::ThemeRegistry;
 
+    #[gpui::test]
+    async fn test_base_keymap(cx: &mut gpui::TestAppContext) {
+        let executor = cx.background();
+        let fs = FakeFs::new(executor.clone());
+        let font_cache = cx.font_cache();
+
+        actions!(test, [A, B]);
+        // From the Atom keymap
+        actions!(workspace, [ActivatePreviousPane]);
+        // From the JetBrains keymap
+        actions!(pane, [ActivatePrevItem]);
+
+        fs.save(
+            "/settings.json".as_ref(),
+            &r#"
+            {
+                "base_keymap": "Atom"
+            }
+            "#
+            .into(),
+            Default::default(),
+        )
+        .await
+        .unwrap();
+
+        fs.save(
+            "/keymap.json".as_ref(),
+            &r#"
+            [
+                {
+                    "bindings": {
+                        "backspace": "test::A"
+                    }
+                }
+            ]
+            "#
+            .into(),
+            Default::default(),
+        )
+        .await
+        .unwrap();
+
+        let settings_file =
+            WatchedJsonFile::new(fs.clone(), &executor, "/settings.json".as_ref()).await;
+        let keymaps_file =
+            WatchedJsonFile::new(fs.clone(), &executor, "/keymap.json".as_ref()).await;
+
+        let default_settings = cx.read(Settings::test);
+
+        cx.update(|cx| {
+            cx.add_global_action(|_: &A, _cx| {
+            });
+            cx.add_global_action(|_: &B, _cx| {
+            });
+            cx.add_global_action(|_: &ActivatePreviousPane, _cx| {
+            });
+            cx.add_global_action(|_: &ActivatePrevItem, _cx| {
+            });
+            watch_files(
+                default_settings,
+                settings_file,
+                ThemeRegistry::new((), font_cache),
+                keymaps_file,
+                cx,
+            )
+        });
+
+        cx.foreground().run_until_parked();
+
+        // Test loading the keymap base at all
+        cx.update(|cx| {
+            assert_keybindings_for(cx, vec![("backspace", &A), ("k", &ActivatePreviousPane)], line!());
+        });
+
+        // Test modifying the users keymap, while retaining the base keymap
+        fs.save(
+            "/keymap.json".as_ref(),
+            &r#"
+            [
+                {
+                    "bindings": {
+                        "backspace": "test::B"
+                    }
+                }
+            ]
+            "#
+            .into(),
+            Default::default(),
+        )
+        .await
+        .unwrap();
+        
+        cx.foreground().run_until_parked();
+
+        cx.update(|cx| {
+            assert_keybindings_for(cx, vec![("backspace", &B), ("k", &ActivatePreviousPane)], line!());
+        });
+        
+        // Test modifying the base, while retaining the users keymap
+        fs.save(
+            "/settings.json".as_ref(),
+            &r#"
+            {
+                "base_keymap": "JetBrains"
+            }
+            "#
+            .into(),
+            Default::default(),
+        )
+        .await
+        .unwrap();
+        
+        cx.foreground().run_until_parked();
+
+        cx.update(|cx| {
+            assert_keybindings_for(cx, vec![("backspace", &B), ("[", &ActivatePrevItem)], line!());
+        });
+    }
+
+    fn assert_keybindings_for<'a>(
+        cx: &mut MutableAppContext,
+        actions: Vec<(&'static str, &'a dyn Action)>,
+        line: u32,
+    ) {
+        
+        for (key, action) in actions {
+            // assert that...
+            assert!(cx.available_actions(0, 0).any(|(_, bound_action, b)| {
+                // action names match...
+                bound_action.name() == action.name()
+                    && bound_action.namespace() == action.namespace()
+                    // and key strokes contain the given key
+                    && b.iter()
+                        .any(|binding| binding.keystrokes().iter().any(|k| k.key == key))
+            }), "On {} Failed to find {} with keybinding {}", line,  action.name(), key);
+        }
+    }
+
     #[gpui::test]
     async fn test_watch_settings_files(cx: &mut gpui::TestAppContext) {
         let executor = cx.background();