]> git.mdlowis.com Git - projs/tide.git/commitdiff
Added tests for search, undo, and redo
authorMichael D. Lowis <mike@mdlowis.com>
Thu, 15 Dec 2016 02:52:00 +0000 (21:52 -0500)
committerMichael D. Lowis <mike@mdlowis.com>
Thu, 15 Dec 2016 02:52:00 +0000 (21:52 -0500)
libedit/buf.c
libedit/view.c
tests/xedit.c

index a01d1e73f8ccdd3dfe24a5ab9e821cd0134452a0..16b302ec2cfd147995dadc735f37be6e65534489 100644 (file)
@@ -331,8 +331,8 @@ static int range_match(Buf* buf, unsigned dbeg, unsigned dend, unsigned mbeg, un
 
 void buf_find(Buf* buf, size_t* beg, size_t* end) {
     unsigned dbeg = *beg, dend = *end;
-    unsigned mbeg = dend+1, mend = mbeg + (dend-dbeg);
-    while (mend != dbeg) {
+    unsigned mbeg = dbeg+1, mend = dend+1;
+    while (true) {
         if ((buf_get(buf, mbeg)   == buf_get(buf, dbeg)) &&
             (buf_get(buf, mend-1) == buf_get(buf, dend-1)) &&
             (0 == range_match(buf,dbeg,dend,mbeg,mend)))
@@ -342,7 +342,7 @@ void buf_find(Buf* buf, size_t* beg, size_t* end) {
             break;
         }
         mbeg++, mend++;
-        if (mend >= buf_end(buf)) {
+        if (mend > buf_end(buf)) {
             unsigned n = mend-mbeg;
             mbeg = 0, mend = n;
         }
@@ -385,8 +385,7 @@ void buf_findstr(Buf* buf, char* str, size_t* beg, size_t* end) {
     Rune* runes = charstorunes(str);
     size_t rlen = runelen(runes);
     unsigned start = *beg, mbeg = start+1, mend = mbeg + rlen;
-
-    while (mbeg != start) {
+    while (true) {
         if ((buf_get(buf, mbeg) == runes[0]) &&
             (buf_get(buf, mend-1) == runes[rlen-1]) &&
             (0 == rune_match(buf, mbeg, mend, runes)))
@@ -396,10 +395,9 @@ void buf_findstr(Buf* buf, char* str, size_t* beg, size_t* end) {
             break;
         }
         mbeg++, mend++;
-        if (mend >= buf_end(buf))
+        if (mend > buf_end(buf))
             mbeg = 0, mend = rlen;
     }
-
     free(runes);
 }
 
index 61b93e1c352d89bfa8575d22aa4205645193c4f8..31eb4ebd110d9b666e5d850d7fd19a084e5a6f00 100644 (file)
@@ -395,7 +395,7 @@ void view_find(View* view, size_t row, size_t col) {
         }
         view->selection = sel;
         view->sync_needed = true;
-        view->sync_center   = true;
+        view->sync_center = true;
     }
 }
 
index df2bec8294985543582578aef7084a40ccc5e3f4..f29bdfc8c8b4e3f726e977a03370f2ff2022a17b 100644 (file)
@@ -424,6 +424,21 @@ TEST_SUITE(XeditTests) {
         CHECK(getsel(EDIT)->end == 2);
     }
     
+    TEST(esc should select previously inserted text) {
+        setup_view(EDIT, "foo", 0);
+        send_keys(ModNone, KEY_ESCAPE);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 3);
+    }
+    
+    TEST(esc should select nothing if no previous insert) {
+        setup_view(EDIT, "foob", 4);
+        send_keys(ModNone, KEY_BACKSPACE);
+        send_keys(ModNone, KEY_ESCAPE);
+        CHECK(getsel(EDIT)->beg == 3);
+        CHECK(getsel(EDIT)->end == 3);
+    }
+    
     /* Key Handling - Standard Text Editing Shortcuts
      *************************************************************************/
     TEST(cut and paste should delete selection and transfer it to+from the system clipboard) {
@@ -481,6 +496,71 @@ TEST_SUITE(XeditTests) {
     
     /* Key Handling - Special 
      *************************************************************************/
+    TEST(backspace should do nothing on empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModNone, KEY_BACKSPACE);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(verify_text(EDIT, ""));
+    }
+
+    TEST(backspace should do nothing at beginning of buffer) {
+        setup_view(EDIT, "abc", 0);
+        send_keys(ModNone, KEY_BACKSPACE);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(verify_text(EDIT, "abc"));
+    }
+    
+    TEST(backspace should delete previous character) {
+        setup_view(EDIT, "abc", 1);
+        send_keys(ModNone, KEY_BACKSPACE);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(verify_text(EDIT, "bc"));
+    }
+    
+    TEST(backspace should delete selection) {
+        setup_view(EDIT, "abcde", 0);
+        getview(EDIT)->selection = (Sel){ .beg = 1, .end = 4 };
+        send_keys(ModNone, KEY_BACKSPACE);
+        CHECK(getsel(EDIT)->beg == 1);
+        CHECK(getsel(EDIT)->end == 1);
+        CHECK(verify_text(EDIT, "ae"));
+    }
+    
+    TEST(delete should do nothing on empty buffer) {
+        setup_view(EDIT, "", 0);
+        send_keys(ModNone, KEY_DELETE);
+        CHECK(getsel(EDIT)->beg == 0);
+        CHECK(getsel(EDIT)->end == 0);
+        CHECK(verify_text(EDIT, ""));
+    }
+
+    TEST(delete should do nothing at end of buffer) {
+        setup_view(EDIT, "abc", 3);
+        send_keys(ModNone, KEY_DELETE);
+        CHECK(getsel(EDIT)->beg == 3);
+        CHECK(getsel(EDIT)->end == 3);
+        CHECK(verify_text(EDIT, "abc"));
+    }
+    
+    TEST(delete should delete next character) {
+        setup_view(EDIT, "abc", 2);
+        send_keys(ModNone, KEY_DELETE);
+        CHECK(getsel(EDIT)->beg == 2);
+        CHECK(getsel(EDIT)->end == 2);
+        CHECK(verify_text(EDIT, "ab"));
+    }
+    
+    TEST(delete should delete selection) {
+        setup_view(EDIT, "abcde", 0);
+        getview(EDIT)->selection = (Sel){ .beg = 1, .end = 4 };
+        send_keys(ModNone, KEY_DELETE);
+        CHECK(getsel(EDIT)->beg == 1);
+        CHECK(getsel(EDIT)->end == 1);
+        CHECK(verify_text(EDIT, "ae"));
+    }
     
     /* Key Handling - Implementation Specific
      *************************************************************************/
@@ -496,6 +576,32 @@ TEST_SUITE(XeditTests) {
         CHECK(Focused == TAGS);
     }
     
+    TEST(ctrl+q should quit) {
+        setup_view(TAGS, "", 0);
+        setup_view(EDIT, "", 0);
+        getbuf(EDIT)->modified = false;
+        ExitCode = 42;
+        send_keys(ModCtrl, 'q');
+        CHECK(ExitCode == 0);
+        CHECK(verify_text(TAGS, ""));
+    }
+    
+    TEST(ctrl+f should find next occurrence of selected text) {
+        setup_view(EDIT, "foobarfoo", 0);
+        getview(EDIT)->selection = (Sel){ 0, 3, 0 };
+        send_keys(ModCtrl, 'f');
+        CHECK(getview(EDIT)->selection.beg == 6);
+        CHECK(getview(EDIT)->selection.end == 9);
+    }
+    
+    TEST(ctrl+f should wrap around to beginning of buffer) {
+        setup_view(EDIT, "foobarbazfoo", 0);
+        getview(EDIT)->selection = (Sel){ 9, 12, 0 };
+        send_keys(ModCtrl, 'f');
+        CHECK(getview(EDIT)->selection.beg == 0);
+        CHECK(getview(EDIT)->selection.end == 3);
+    }
+    
     /* Mouse Input Handling
      *************************************************************************/
     
@@ -507,7 +613,11 @@ TEST_SUITE(XeditTests) {
         setup_view(TAGS, ":s/foo/bar/", 0);
         getview(TAGS)->selection = (Sel){ .beg = 0, .end = 11 };
         send_keys(ModCtrl, 'd');
-        CHECK(verify_text(EDIT, "bar"));        
+        #ifdef __MACH__
+        CHECK(verify_text(EDIT, "bar\r\n"));
+        #else
+        CHECK(verify_text(EDIT, "bar"));
+        #endif
     }
     
     TEST(Commands starting with | should be take selection as input and replace it with output) {
@@ -516,7 +626,11 @@ TEST_SUITE(XeditTests) {
         setup_view(TAGS, "|sed -e 's/foo/bar/'", 0);
         getview(TAGS)->selection = (Sel){ .beg = 0, .end = 20 };
         send_keys(ModCtrl, 'd');
-        CHECK(verify_text(EDIT, "bar"));        
+        #ifdef __MACH__
+        CHECK(verify_text(EDIT, "bar\r\n"));
+        #else
+        CHECK(verify_text(EDIT, "bar"));
+        #endif
     }
     
     TEST(Commands starting with ! should execute in the background with no input or output) {
@@ -587,12 +701,28 @@ TEST_SUITE(XeditTests) {
         exec("Quit");
         CHECK(ExitCode == 42);
         CHECK(verify_text(TAGS, "File is modified. Repeat action twice in < 250ms to quit."));
-        usleep(249 * 1000);
         exec("Quit");
         CHECK(ExitCode == 0);
         CHECK(verify_text(TAGS, "File is modified. Repeat action twice in < 250ms to quit."));
     }
-
+    
+    TEST(Save should save changes to disk with crlf line endings) {
+        setup_view(TAGS, "", 0);
+        view_init(getview(EDIT), "docs/crlf.txt");
+        CHECK(verify_text(EDIT, "this file\r\nuses\r\ndos\r\nline\r\nendings\r\n"));
+        exec("Save");
+        view_init(getview(EDIT), "docs/crlf.txt");
+        CHECK(verify_text(EDIT, "this file\r\nuses\r\ndos\r\nline\r\nendings\r\n"));
+    }
+    
+    TEST(Save should save changes to disk with lf line endings) {
+        setup_view(TAGS, "", 0);
+        view_init(getview(EDIT), "docs/lf.txt");
+        CHECK(verify_text(EDIT, "this file\nuses\nunix\nline\nendings\n"));
+        exec("Save");
+        view_init(getview(EDIT), "docs/lf.txt");
+        CHECK(verify_text(EDIT, "this file\nuses\nunix\nline\nendings\n"));
+    }
     
     TEST(Cut and Paste tags should move selection to new location) {
         setup_view(EDIT, "foo\nbar\nbaz\n", 0);
@@ -634,13 +764,61 @@ TEST_SUITE(XeditTests) {
         CHECK(verify_text(EDIT, ""));
     }
     
-    TEST(Find should find next occurrence of selected text in EDIT view) {
+    TEST(Undo+Redo should undo+redo the previous delete with two non-contiguous deletes logged) {
+        setup_view(EDIT, "foobarbaz", 0);
+        getview(EDIT)->selection = (Sel){ 0, 3, 0 };
+        send_keys(ModNone, KEY_DELETE);
+        getview(EDIT)->selection = (Sel){ 3, 6, 0 };
+        send_keys(ModNone, KEY_DELETE);
+        CHECK(verify_text(EDIT, "bar"));
+        exec("Undo");
+        CHECK(verify_text(EDIT, "barbaz"));
+        exec("Redo");
+        CHECK(verify_text(EDIT, "bar"));
+    }
+    
+    TEST(Undo+Redo should undo+redo the previous delete performed with backspace) {
+        setup_view(EDIT, "foo", 0);
+        getview(EDIT)->selection = (Sel){ 3, 3, 0 };
+        for(int i = 0; i < 3; i++)
+            send_keys(ModNone, KEY_BACKSPACE);
+        CHECK(verify_text(EDIT, ""));
+        exec("Undo");
+        CHECK(verify_text(EDIT, "foo"));
+        exec("Redo");
+        CHECK(verify_text(EDIT, ""));
+    }
+
+    TEST(Find should find next occurrence of text selected in EDIT view) {
+        setup_view(EDIT, "foobarfoo", 0);
+        getview(EDIT)->selection = (Sel){ 0, 3, 0 };
+        exec("Find");
+        CHECK(getview(EDIT)->selection.beg == 6);
+        CHECK(getview(EDIT)->selection.end == 9);
+    }
+    
+    TEST(Find should find wrap around to beginning of EDIT buffer) {
+        setup_view(EDIT, "foobarbazfoo", 0);
+        getview(EDIT)->selection = (Sel){ 9, 12, 0 };
+        exec("Find");
+        CHECK(getview(EDIT)->selection.beg == 0);
+        CHECK(getview(EDIT)->selection.end == 3);
     }
     
-    TEST(Find should find next occurrence of selected text in TAGS view) {
+    TEST(Find should find next occurrence of text selected in TAGS view) {
+        setup_view(TAGS, "foo", 0);
+        getview(TAGS)->selection = (Sel){ 0, 3, 0 };
+        setup_view(EDIT, "barfoo", 0);
+        exec("Find");
+        CHECK(getview(EDIT)->selection.beg == 3);
+        CHECK(getview(EDIT)->selection.end == 6);
     }
     
-    TEST(Find should find next occurrence of selected text after selected tag) {
+    TEST(Find should find next occurrence of text selected after tag) {
+        setup_view(EDIT, "barfoo", 0);
+        exec("Find foo");
+        CHECK(getview(EDIT)->selection.beg == 3);
+        CHECK(getview(EDIT)->selection.end == 6);
     }
 
 #if 0