more tests for scrolling
This commit is contained in:
@@ -93,7 +93,7 @@ class InnerBigText(QWidget):
|
|||||||
self.scroll_by_lines(-3)
|
self.scroll_by_lines(-3)
|
||||||
|
|
||||||
def wheelEvent(self, event: QWheelEvent):
|
def wheelEvent(self, event: QWheelEvent):
|
||||||
direction = 1 if event.angleDelta().y() > 0 else -1
|
direction = 1 if event.angleDelta().y() < 0 else -1
|
||||||
#print("wheel event fired :) %s" % (direction))
|
#print("wheel event fired :) %s" % (direction))
|
||||||
self.scroll_by_lines(direction * 3)
|
self.scroll_by_lines(direction * 3)
|
||||||
|
|
||||||
@@ -164,9 +164,9 @@ class InnerBigText(QWidget):
|
|||||||
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show)
|
self.lines = self.model.data(self._byte_offset, self.scroll_lines, lines_to_show)
|
||||||
#print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines)))
|
#print("lines_to_show: %d returned: %d" % (lines_to_show, len(self.lines)))
|
||||||
self.scroll_lines=0
|
self.scroll_lines=0
|
||||||
self._byte_offset = self.lines[0].byte_offset()
|
self._byte_offset = self.lines[0].byte_offset() if len(self.lines) > 0 else 0
|
||||||
# document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown
|
# document length == maximum + pageStep + aFewBytesSoThatTheLastLineIsShown
|
||||||
self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1 - 10)
|
self.parent.v_scroll_bar.setMaximum(self.model.byte_count() - 1)
|
||||||
|
|
||||||
|
|
||||||
for l in self.lines:
|
for l in self.lines:
|
||||||
|
|||||||
5
line.py
5
line.py
@@ -31,4 +31,7 @@ class Line:
|
|||||||
return self._line[offset:offset+length]
|
return self._line[offset:offset+length]
|
||||||
|
|
||||||
def suffix(self, index: int) -> str:
|
def suffix(self, index: int) -> str:
|
||||||
return self._line[index:]
|
return self._line[index:]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "%s (%d->%d)" % (self._line, self._byte_offset, self._byte_end)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import math
|
||||||
import threading
|
import threading
|
||||||
from typing import List
|
from typing import List
|
||||||
import os
|
|
||||||
from line import Line
|
from line import Line
|
||||||
|
import os
|
||||||
from settings import Settings
|
from settings import Settings
|
||||||
|
|
||||||
|
|
||||||
@@ -13,11 +13,12 @@ class LogFileModel:
|
|||||||
self._file = file
|
self._file = file
|
||||||
|
|
||||||
def data(self, byte_offset, scroll_lines, lines) -> List[Line]:
|
def data(self, byte_offset, scroll_lines, lines) -> List[Line]:
|
||||||
#print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines))
|
print("data(%s, %s, %s)" % (byte_offset, scroll_lines, lines))
|
||||||
lines_before_offset: List[Line] = []
|
lines_before_offset: List[Line] = []
|
||||||
lines_after_offset: List[Line] = []
|
lines_after_offset: List[Line] = []
|
||||||
result: List[Line] = []
|
result: List[Line] = []
|
||||||
lines_to_find = lines + abs(scroll_lines)
|
lines_to_find = lines + abs(scroll_lines)
|
||||||
|
lines_to_return = math.ceil(lines)
|
||||||
|
|
||||||
with self._lock:
|
with self._lock:
|
||||||
# TODO handle lines longer than 4096 bytes
|
# TODO handle lines longer than 4096 bytes
|
||||||
@@ -42,18 +43,12 @@ class LogFileModel:
|
|||||||
eof_reached = False
|
eof_reached = False
|
||||||
break
|
break
|
||||||
|
|
||||||
if scroll_lines > 0:
|
all_lines = lines_before_offset + lines_after_offset
|
||||||
result = result + lines_before_offset[-scroll_lines:]
|
start = max(0, len(lines_before_offset) + scroll_lines)
|
||||||
result = result + lines_after_offset
|
if start + lines_to_return-1 < len(all_lines):
|
||||||
elif eof_reached:
|
result = all_lines[start:start+lines_to_return]
|
||||||
# we always return the number of requested lines even if we reach the end of the file
|
|
||||||
lines_to_return_from_before_offset = int(lines_to_find - len(lines_after_offset));
|
|
||||||
#print(lines_to_return_from_before_offset)
|
|
||||||
if lines_to_return_from_before_offset > 0:
|
|
||||||
result = result + lines_before_offset[-lines_to_return_from_before_offset:]
|
|
||||||
result = result + lines_after_offset
|
|
||||||
else:
|
else:
|
||||||
result = result + lines_after_offset[-scroll_lines:]
|
result = all_lines[-lines_to_return+1:]
|
||||||
|
|
||||||
#print("returning %s lines" % (len(result)))
|
#print("returning %s lines" % (len(result)))
|
||||||
return result
|
return result
|
||||||
|
|||||||
15
scribble.py
Normal file
15
scribble.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
before = []#[0,1,2,3]
|
||||||
|
after = ["a","b","c","d"]
|
||||||
|
both = before + after
|
||||||
|
scroll = -3
|
||||||
|
lines = 1
|
||||||
|
start = len(before) + scroll
|
||||||
|
if start+lines < len(both):
|
||||||
|
result = both[start:start+lines]
|
||||||
|
else:
|
||||||
|
result = both[-lines:]
|
||||||
|
print("%s" % result)
|
||||||
142
testlogfilemodel.py
Normal file
142
testlogfilemodel.py
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
import unittest
|
||||||
|
import tempfile
|
||||||
|
from os.path import join
|
||||||
|
|
||||||
|
from logFileModel import LogFileModel
|
||||||
|
from line import Line
|
||||||
|
|
||||||
|
|
||||||
|
class TestLogFileModel(unittest.TestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.test_dir = tempfile.TemporaryDirectory()
|
||||||
|
self.tmpfile = join(self.test_dir.name, "my.log")
|
||||||
|
self.model = LogFileModel(self.tmpfile)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.test_dir.cleanup()
|
||||||
|
|
||||||
|
def write_str(self, string: str):
|
||||||
|
with open(self.tmpfile, "w+b") as f:
|
||||||
|
f.write(string.encode("utf8"))
|
||||||
|
|
||||||
|
def test_load_from_beginning(self):
|
||||||
|
self.write_str("1\n2\n3\n4\n5\n6\n7\n")
|
||||||
|
expected_lines = ["1", "2", "3", "4", "5"]
|
||||||
|
|
||||||
|
lines = self.model.data(0, 0, 5)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_load_from_middle_of_first_line(self):
|
||||||
|
self.write_str("abc\ndef\nghi\njkl")
|
||||||
|
expected_lines = ["def", "ghi", "jkl"]
|
||||||
|
|
||||||
|
lines = self.model.data(1, 0, 3)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_read_from_newline_character(self):
|
||||||
|
self.write_str("abc\ndef\nghi\njkl")
|
||||||
|
expected_lines = ["def", "ghi"]
|
||||||
|
|
||||||
|
lines = self.model.data(3, 0, 2)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
|
||||||
|
def test_negative_byte_offset(self):
|
||||||
|
self.write_str("abc\ndef\nghi\njkl")
|
||||||
|
expected_lines = ["abc","def"]
|
||||||
|
|
||||||
|
lines = self.model.data(-1, 0, 2)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_empty_last_line_is_ignored(self):
|
||||||
|
self.write_str("1\n")
|
||||||
|
expected_lines = ["1"]
|
||||||
|
|
||||||
|
lines = self.model.data(0, 0, 5)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_load_more_lines_than_are_available(self):
|
||||||
|
"""
|
||||||
|
Wants to read 4 lines in a file with only 3 lines.
|
||||||
|
Returns all three lines.
|
||||||
|
"""
|
||||||
|
self.write_str("abc\ndef\nghi")
|
||||||
|
expected_lines = ["abc", "def", "ghi"]
|
||||||
|
|
||||||
|
lines = self.model.data(0, 0, 4)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_read_behind_eof(self):
|
||||||
|
"""
|
||||||
|
Wants to read 4 lines from the middle of the second line.
|
||||||
|
File has only 3 lines.
|
||||||
|
Returns all 3 lines.
|
||||||
|
"""
|
||||||
|
text = "abc\ndef\nghi"
|
||||||
|
self.write_str(text)
|
||||||
|
expected_lines = ["abc", "def", "ghi"]
|
||||||
|
|
||||||
|
lines = self.model.data(text.index("e"), 0, 4)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
def test_read_after_scrolling_2_lines(self):
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||||
|
self.write_str(text)
|
||||||
|
expected_lines = ["3___", "4___"]
|
||||||
|
|
||||||
|
lines = self.model.data(text.index("1___"), 2, 2)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
|
||||||
|
def test_scroll_with_float(self):
|
||||||
|
"""
|
||||||
|
If lines to lines to return is a float, then the value is rounded up.
|
||||||
|
Floats mean that the text area is such that a line is partially visible.
|
||||||
|
"""
|
||||||
|
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||||
|
self.write_str(text)
|
||||||
|
expected_lines = ["3___","4___", "5___"]
|
||||||
|
|
||||||
|
lines = self.model.data(text.index("1___"), 2, 2.1)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
|
||||||
|
def test_scroll_up_at_beginning_of_file(self):
|
||||||
|
"""
|
||||||
|
Scrolling up at beginning of file.
|
||||||
|
Return
|
||||||
|
"""
|
||||||
|
text = "0___\n1___\n2___\n3___\n4___\n5___"
|
||||||
|
self.write_str(text)
|
||||||
|
expected_lines = ["0___", "1___"]
|
||||||
|
|
||||||
|
lines = self.model.data(5, -2, 2)
|
||||||
|
|
||||||
|
line_str = [l.line() for l in lines]
|
||||||
|
self.assertEqual(expected_lines, line_str)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
|
||||||
Reference in New Issue
Block a user