about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile1
-rw-r--r--ranger/container/bookmarks.py18
-rw-r--r--ranger/container/history.py9
-rw-r--r--ranger/core/actions.py2
-rw-r--r--tests/__init__.py0
-rw-r--r--tests/ranger/__init__.py0
-rw-r--r--tests/ranger/container/__init__.py0
-rw-r--r--tests/ranger/container/test_bookmarks.py52
-rw-r--r--tests/ranger/container/test_container.py99
10 files changed, 166 insertions, 16 deletions
diff --git a/.gitignore b/.gitignore
index 5357ead2..81e1b8b5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@
 stuff/*
 doc/ranger.1.html
 build
+pytestdebug.log
diff --git a/Makefile b/Makefile
index f6208015..71899dcd 100644
--- a/Makefile
+++ b/Makefile
@@ -65,6 +65,7 @@ test:
 		echo "Testing $$FILE..."; \
 		RANGER_DOCTEST=1 PYTHONPATH=".:"$$PYTHONPATH ${PYTHON} $$FILE; \
 	done
+	py.test tests
 
 man:
 	pod2man --stderr --center='ranger manual' --date='$(NAME)-$(VERSION)' \
diff --git a/ranger/container/bookmarks.py b/ranger/container/bookmarks.py
index cbb95864..02f3e3bc 100644
--- a/ranger/container/bookmarks.py
+++ b/ranger/container/bookmarks.py
@@ -30,6 +30,7 @@ class Bookmarks(object):
         """
         self.autosave = autosave
         self.dct = {}
+        self.original_dict = {}
         self.path = bookmarkfile
         self.bookmarktype = bookmarktype
 
@@ -42,14 +43,6 @@ class Bookmarks(object):
 
         self._set_dict(new_dict, original=new_dict)
 
-    def delete(self, key):
-        """Delete the bookmark with the given key"""
-        if key == '`':
-            key = "'"
-        if key in self.dct:
-            del self.dct[key]
-            if self.autosave: self.save()
-
     def enter(self, key):
         """Enter the bookmark with the given key.
 
@@ -70,6 +63,15 @@ class Bookmarks(object):
         self["'"] = value
         if self.autosave: self.save()
 
+    def __delitem__(self, key):
+        """Delete the bookmark with the given key"""
+        if key == '`':
+            key = "'"
+        if key in self.dct:
+            del self.dct[key]
+            if self.autosave: self.save()
+
+
     def __iter__(self):
         return iter(self.dct.items())
 
diff --git a/ranger/container/history.py b/ranger/container/history.py
index 8300edae..db2ea8ab 100644
--- a/ranger/container/history.py
+++ b/ranger/container/history.py
@@ -8,6 +8,7 @@ class HistoryEmptyException(Exception):
 
 class History(object):
     def __init__(self, maxlen=None, unique=True):
+        assert maxlen is not None, "maxlen cannot be None"
         if isinstance(maxlen, History):
             self._history = list(maxlen._history)
             self._index = maxlen._index
@@ -54,7 +55,7 @@ class History(object):
     def rebase(self, other_history):
         assert isinstance(other_history, History)
         index_offset = len(self._history) - self._index
-        self._history[:self._index] = list(other_history._history)
+        self._history[:self._index + 1] = list(other_history._history)
         if len(self._history) > self.maxlen:
             self._history = self._history[-self.maxlen:]
         self._index = len(self._history) - index_offset
@@ -112,9 +113,6 @@ class History(object):
     def __iter__(self):
         return self._history.__iter__()
 
-    def next(self):
-        return self._history.next()
-
     def forward(self):
         if self._history:
             self._index += 1
@@ -129,6 +127,3 @@ class History(object):
             self._index = len(self._history) - 1
         else:
             self._index = 0
-
-    def _left(self):  # used for unit test
-        return self._history[0:self._index+1]
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 63916145..e692eb39 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -790,7 +790,7 @@ class Actions(FileManagerAware, SettingsAware):
     def unset_bookmark(self, key):
         """Delete the bookmark with the name <key>"""
         self.bookmarks.update_if_outdated()
-        self.bookmarks.delete(str(key))
+        del self.bookmarks[str(key)]
 
     def draw_bookmarks(self):
         self.ui.browser.draw_bookmarks = True
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/__init__.py
diff --git a/tests/ranger/__init__.py b/tests/ranger/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/ranger/__init__.py
diff --git a/tests/ranger/container/__init__.py b/tests/ranger/container/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/ranger/container/__init__.py
diff --git a/tests/ranger/container/test_bookmarks.py b/tests/ranger/container/test_bookmarks.py
new file mode 100644
index 00000000..46c615c6
--- /dev/null
+++ b/tests/ranger/container/test_bookmarks.py
@@ -0,0 +1,52 @@
+import os
+import time
+import pytest
+
+from ranger.container.bookmarks import Bookmarks
+
+def testbookmarks(tmpdir):
+    # Bookmarks point to directory location and allow fast access to
+    # 'favorite' directories. They are persisted to a bookmark file, plain text.
+    bookmarkfile = tmpdir.join("bookmarkfile")
+    bmstore = Bookmarks(str(bookmarkfile))
+
+    # loading an empty bookmark file doesnot crash
+    bmstore.load()
+
+    # One can add / remove and check existing of bookmark
+    bmstore["h"] = "world"
+    assert "h" in bmstore
+    del bmstore["h"]
+
+    # Only one letter/digit bookmarks are valid, adding something else fails
+    # silently
+    bmstore["hello"] = "world"
+    assert "hello" not in bmstore
+
+    # The default bookmark is ', remember allows to set it
+    bmstore.remember("the milk")
+    assert bmstore["'"] == "the milk"
+
+    # We can persist bookmarks to disk and restore them from disk
+    bmstore.save()
+    secondstore = Bookmarks(str(bookmarkfile))
+    secondstore.load()
+    assert "'" in secondstore
+    assert secondstore["'"] == "the milk"
+
+    # We don't uneccesary update when the file on disk does not change
+    origupdate = secondstore.update
+    class OutOfDateException(Exception):
+        pass
+    def crash():
+        raise OutOfDateException("Don't access me")
+    secondstore.update = crash
+    secondstore.update_if_outdated()
+
+    # If the modification time change, we try to read the file
+    newtime = time.time() - 5
+    os.utime(str(bookmarkfile), (newtime, newtime))
+    with pytest.raises(OutOfDateException):
+        secondstore.update_if_outdated()
+    secondstore.update = origupdate
+    secondstore.update_if_outdated()
diff --git a/tests/ranger/container/test_container.py b/tests/ranger/container/test_container.py
new file mode 100644
index 00000000..fafb30c5
--- /dev/null
+++ b/tests/ranger/container/test_container.py
@@ -0,0 +1,99 @@
+from ranger.container import history
+
+
+HISTORY_TEST_ENTRIES = [str(k) for k in range(20)]
+OTHER_TEST_ENTRIES = [str(k) for k in range(40,45)]
+
+def testhistorybasic():
+    # A history is a buffer of limited size that stores the last `maxlen`
+    # item added to it. It has a `current` index that serves as a cursor.
+
+    # A history has a limited size, check that only `maxlen` items are stored
+    h = history.History(maxlen=10)
+    for entry in HISTORY_TEST_ENTRIES:
+        h.add(entry)
+
+    # 10 items are stored
+    assert len(h) == 10
+    assert h.current() == "19"
+    assert h.top() == "19"
+    assert h.bottom() == "10"
+
+    # going back in time affects only changes current item
+    h.back()
+    assert len(h) == 10
+    assert h.current() == "18"
+    assert h.top() == "19"
+    assert h.bottom() == "10"
+
+    # __iter__ is actually an interator and we can iterate through the list
+    it = iter(h)
+    assert iter(it) == it
+    assert list(it) == HISTORY_TEST_ENTRIES[10:]
+
+    # search allows to go back in time as long as a pattern matches and we don't
+    # go over a step limit
+    assert h.search("45", -9) == "18"
+    assert h.search("1", -5) == "13"
+
+    # fast forward selects the last item
+    h.fast_forward()
+    assert h.current() == "19"
+
+    # back followed by forward is a noop
+    h.back()
+    h.forward()
+    assert h.current() == "19"
+
+    # move can be expressed as multiple calls to back and forward
+    h.move(-3)
+    h.forward()
+    h.forward()
+    h.forward()
+    assert h.current() == "19"
+
+    # back, forward, move play well with boundaries
+    for _ in range(30):
+        h.back()
+
+    for _ in range(30):
+        h.forward()
+
+    for _ in range(30):
+        h.move(-2)
+
+    for _ in range(30):
+        h.move(2)
+    assert h.current() == "19"
+
+    # we can create an history from another history
+    h = history.History(maxlen=10)
+    for entry in HISTORY_TEST_ENTRIES:
+        h.add(entry)
+    # XXX maxlen should not be used to refer to something that isn't a length
+    otherh = history.History(maxlen=h)
+    assert(list(h) == list(otherh))
+
+    # Rebase allow to merge entries with another history
+    otherh = history.History(maxlen=h)
+    for entry in OTHER_TEST_ENTRIES:
+        otherh.add(entry)
+    assert list(otherh)[-3:] == ["42", "43", "44"]
+    h.rebase(otherh)
+    assert h.current() == "44"
+    assert list(h)[-3:] == ['42', '43', '44']
+
+    # modify, modifies the top of the stack
+    h.modify("23")
+    assert h.current() == "23"
+
+
+def testhistoryunique():
+    # Check that unique history refuses to store duplicated entries
+    h = history.History(maxlen=10, unique=True)
+    for entry in HISTORY_TEST_ENTRIES:
+        h.add(entry)
+    assert h.current() == "19"
+    h.add("17")
+    assert list(h).count("17") == 1
+    assert h.current() == "17"