Просмотр исходного кода

Merge pull request #28 from devmil/feature/add_tests

Adds some basic tests for CircularList and renames utli
xuty 4 лет назад
Родитель
Сommit
e60952f74b

+ 3 - 3
lib/buffer/buffer.dart

@@ -5,9 +5,9 @@ import 'package:xterm/buffer/reflow_strategy_narrower.dart';
 import 'package:xterm/buffer/reflow_strategy_wider.dart';
 import 'package:xterm/buffer/reflow_strategy_wider.dart';
 import 'package:xterm/terminal/charset.dart';
 import 'package:xterm/terminal/charset.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/terminal/terminal.dart';
-import 'package:xterm/utli/circular_list.dart';
-import 'package:xterm/utli/scroll_range.dart';
-import 'package:xterm/utli/unicode_v11.dart';
+import 'package:xterm/util/circular_list.dart';
+import 'package:xterm/util/scroll_range.dart';
+import 'package:xterm/util/unicode_v11.dart';
 
 
 class Buffer {
 class Buffer {
   Buffer(this.terminal) {
   Buffer(this.terminal) {

+ 1 - 1
lib/buffer/reflow_strategy.dart

@@ -1,6 +1,6 @@
 import 'package:xterm/buffer/buffer.dart';
 import 'package:xterm/buffer/buffer.dart';
 import 'package:xterm/buffer/buffer_line.dart';
 import 'package:xterm/buffer/buffer_line.dart';
-import 'package:xterm/utli/circular_list.dart';
+import 'package:xterm/util/circular_list.dart';
 
 
 abstract class ReflowStrategy {
 abstract class ReflowStrategy {
   final Buffer _buffer;
   final Buffer _buffer;

+ 1 - 1
lib/frontend/oscillator.dart

@@ -1,6 +1,6 @@
 import 'dart:async';
 import 'dart:async';
 
 
-import 'package:xterm/utli/observable.dart';
+import 'package:xterm/util/observable.dart';
 
 
 class Oscillator with Observable {
 class Oscillator with Observable {
   Oscillator(this.duration);
   Oscillator(this.duration);

+ 2 - 2
lib/frontend/terminal_view.dart

@@ -18,8 +18,8 @@ import 'package:xterm/frontend/cache.dart';
 import 'package:xterm/mouse/position.dart';
 import 'package:xterm/mouse/position.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/theme/terminal_style.dart';
 import 'package:xterm/theme/terminal_style.dart';
-import 'package:xterm/utli/bit_flags.dart';
-import 'package:xterm/utli/hash_values.dart';
+import 'package:xterm/util/bit_flags.dart';
+import 'package:xterm/util/hash_values.dart';
 
 
 typedef TerminalResizeHandler = void Function(int width, int height);
 typedef TerminalResizeHandler = void Function(int width, int height);
 
 

+ 1 - 1
lib/terminal/ansi.dart

@@ -3,7 +3,7 @@ import 'dart:collection';
 import 'package:xterm/terminal/csi.dart';
 import 'package:xterm/terminal/csi.dart';
 import 'package:xterm/terminal/osc.dart';
 import 'package:xterm/terminal/osc.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/terminal/terminal.dart';
-import 'package:xterm/utli/lookup_table.dart';
+import 'package:xterm/util/lookup_table.dart';
 
 
 /// Handler of terminal sequences. Returns true if the sequence is consumed,
 /// Handler of terminal sequences. Returns true if the sequence is consumed,
 /// false to indicate that the sequence is not completed and no charater is
 /// false to indicate that the sequence is not completed and no charater is

+ 1 - 1
lib/terminal/csi.dart

@@ -4,7 +4,7 @@ import 'dart:convert';
 import 'package:xterm/terminal/modes.dart';
 import 'package:xterm/terminal/modes.dart';
 import 'package:xterm/terminal/sgr.dart';
 import 'package:xterm/terminal/sgr.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/terminal/terminal.dart';
-import 'package:xterm/utli/lookup_table.dart';
+import 'package:xterm/util/lookup_table.dart';
 
 
 typedef CsiSequenceHandler = void Function(CSI, Terminal);
 typedef CsiSequenceHandler = void Function(CSI, Terminal);
 
 

+ 1 - 1
lib/terminal/sgr.dart

@@ -2,7 +2,7 @@ import 'package:xterm/buffer/cell_flags.dart';
 import 'package:xterm/theme/terminal_color.dart';
 import 'package:xterm/theme/terminal_color.dart';
 import 'package:xterm/terminal/csi.dart';
 import 'package:xterm/terminal/csi.dart';
 import 'package:xterm/terminal/terminal.dart';
 import 'package:xterm/terminal/terminal.dart';
-import 'package:xterm/utli/lookup_table.dart';
+import 'package:xterm/util/lookup_table.dart';
 
 
 /// SGR selects one or more character attributes at the same time.
 /// SGR selects one or more character attributes at the same time.
 /// Multiple params (up to 32) are applied from in order from left to right.
 /// Multiple params (up to 32) are applied from in order from left to right.

+ 2 - 2
lib/terminal/terminal.dart

@@ -17,8 +17,8 @@ import 'package:xterm/terminal/tabs.dart';
 import 'package:xterm/theme/terminal_color.dart';
 import 'package:xterm/theme/terminal_color.dart';
 import 'package:xterm/theme/terminal_theme.dart';
 import 'package:xterm/theme/terminal_theme.dart';
 import 'package:xterm/theme/terminal_themes.dart';
 import 'package:xterm/theme/terminal_themes.dart';
-import 'package:xterm/utli/debug_handler.dart';
-import 'package:xterm/utli/observable.dart';
+import 'package:xterm/util/debug_handler.dart';
+import 'package:xterm/util/observable.dart';
 
 
 typedef TerminalInputHandler = void Function(String);
 typedef TerminalInputHandler = void Function(String);
 typedef BellHandler = void Function();
 typedef BellHandler = void Function();

+ 0 - 0
lib/utli/ansi_color.dart → lib/util/ansi_color.dart


+ 0 - 0
lib/utli/bit_flags.dart → lib/util/bit_flags.dart


+ 18 - 14
lib/utli/circular_list.dart → lib/util/circular_list.dart

@@ -100,6 +100,9 @@ class CircularList<T> {
   /// Deletes item at [index].
   /// Deletes item at [index].
   void remove(int index, [int count = 1]) {
   void remove(int index, [int count = 1]) {
     if (count > 0) {
     if (count > 0) {
+      if (index + count >= _length) {
+        count = _length - index;
+      }
       for (var i = index; i < _length - count; i++) {
       for (var i = index; i < _length - count; i++) {
         _array[_getCyclicIndex(i)] = _array[_getCyclicIndex(i + count)];
         _array[_getCyclicIndex(i)] = _array[_getCyclicIndex(i + count)];
       }
       }
@@ -109,6 +112,11 @@ class CircularList<T> {
 
 
   /// Inserts [item] at [index].
   /// Inserts [item] at [index].
   void insert(int index, T item) {
   void insert(int index, T item) {
+    if (index == 0 && _length >= _array.length) {
+      // when something is inserted at index 0 and the list is full then
+      // the new value immediately gets removed => nothing changes
+      return;
+    }
     for (var i = _length - 1; i >= index; i--) {
     for (var i = _length - 1; i >= index; i--) {
       _array[_getCyclicIndex(i + 1)] = _array[_getCyclicIndex(i)];
       _array[_getCyclicIndex(i + 1)] = _array[_getCyclicIndex(i)];
     }
     }
@@ -124,20 +132,16 @@ class CircularList<T> {
 
 
   /// Inserts [items] at [index] in order.
   /// Inserts [items] at [index] in order.
   void insertAll(int index, List<T> items) {
   void insertAll(int index, List<T> items) {
-    for (var i = _length - 1; i >= index; i--) {
-      _array[_getCyclicIndex(i + 1)] = _array[_getCyclicIndex(i)];
-    }
-
-    for (var i = 0; i < items.length; i++) {
-      _array[_getCyclicIndex(index + i)] = items[i];
-    }
-
-    if (_length + items.length > _array.length) {
-      final countToTrim = _length + items.length - _array.length;
-      _startIndex += countToTrim;
-      length = _array.length;
-    } else {
-      _length += items.length;
+    for (var i = items.length - 1; i >= 0; i--) {
+      insert(index, items[i]);
+      // when the list is full then we have to move the index down
+      // as newly inserted values remove values with a lower index
+      if (_length >= _array.length) {
+        index--;
+        if (index < 0) {
+          return;
+        }
+      }
     }
     }
   }
   }
 
 

+ 1 - 1
lib/utli/debug_handler.dart → lib/util/debug_handler.dart

@@ -1,6 +1,6 @@
 import 'package:convert/convert.dart';
 import 'package:convert/convert.dart';
 import 'package:xterm/terminal/csi.dart';
 import 'package:xterm/terminal/csi.dart';
-import 'package:xterm/utli/ansi_color.dart';
+import 'package:xterm/util/ansi_color.dart';
 
 
 class DebugHandler {
 class DebugHandler {
   final _buffer = StringBuffer();
   final _buffer = StringBuffer();

+ 0 - 0
lib/utli/hash_values.dart → lib/util/hash_values.dart


+ 0 - 0
lib/utli/lookup_table.dart → lib/util/lookup_table.dart


+ 0 - 0
lib/utli/observable.dart → lib/util/observable.dart


+ 0 - 0
lib/utli/scroll_range.dart → lib/util/scroll_range.dart


+ 0 - 0
lib/utli/unicode_v11.dart → lib/util/unicode_v11.dart


+ 299 - 0
test/util/circular_list_test.dart

@@ -0,0 +1,299 @@
+import 'package:flutter_test/flutter_test.dart';
+import 'package:xterm/util/circular_list.dart';
+
+void main() {
+  group("CircularList Tests", () {
+    test("normal creation test", () {
+      final cl = CircularList<int>(1000);
+
+      expect(cl, isNotNull);
+      expect(cl.maxLength, 1000);
+    });
+
+    test("change max value", () {
+      final cl = CircularList<int>(2000);
+      expect(cl.maxLength, 2000);
+      cl.maxLength = 3000;
+      expect(cl.maxLength, 3000);
+    });
+
+    test("circle works", () {
+      final cl = CircularList<int>(10);
+      expect(cl.maxLength, 10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[9], 9);
+
+      cl.push(10);
+
+      expect(cl.length, 10);
+      expect(cl[0], 1);
+      expect(cl[9], 10);
+    });
+
+    test("change max value after circle", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(15, (index) => index));
+
+      expect(cl.length, 10);
+      expect(cl[0], 5);
+      expect(cl[9], 14);
+
+      cl.maxLength = 20;
+
+      expect(cl.length, 10);
+      expect(cl[0], 5);
+      expect(cl[9], 14);
+
+      cl.pushAll(List<int>.generate(5, (index) => 15 + index));
+
+      expect(cl[0], 5);
+      expect(cl[9], 14);
+      expect(cl[14], 19);
+    });
+
+    test("setting the length erases trail", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[9], 9);
+
+      cl.length = 5;
+
+      expect(cl.length, 5);
+      expect(cl[0], 0);
+      expect(() => cl[5], throwsRangeError);
+    });
+
+    test("foreach works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+
+      final collectedItems = List<int>.empty(growable: true);
+
+      cl.forEach((item) {
+        collectedItems.add(item);
+      });
+
+      expect(collectedItems.length, 10);
+      expect(collectedItems[0], 0);
+      expect(collectedItems[9], 9);
+    });
+
+    test("index operator set works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+
+      expect(cl.length, 10);
+      expect(cl[5], 5);
+
+      cl[5] = 50;
+
+      expect(cl[5], 50);
+    });
+
+    test("clear works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl[5], 5);
+
+      cl.clear();
+
+      expect(cl.length, 0);
+      expect(() => cl[5], throwsRangeError);
+    });
+
+    test("pop works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[9], 9);
+
+      final val = cl.pop();
+
+      expect(val, 9);
+      expect(cl.length, 9);
+      expect(() => cl[9], throwsRangeError);
+      expect(cl[8], 8);
+    });
+
+    test("pop on empty throws", () {
+      final cl = CircularList<int>(10);
+      expect(() => cl.pop(), throwsA(anything));
+    });
+
+    test("remove one works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[5], 5);
+
+      cl.remove(5);
+
+      expect(cl.length, 9);
+      expect(cl[5], 6);
+    });
+
+    test("remove multiple works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[5], 5);
+
+      cl.remove(5, 3);
+
+      expect(cl.length, 7);
+      expect(cl[5], 8);
+    });
+
+    test("remove circle works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(15, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 5);
+
+      cl.remove(0, 9);
+
+      expect(cl.length, 1);
+      expect(cl[0], 14);
+    });
+
+    test("remove too much works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[5], 5);
+
+      cl.remove(5, 10);
+
+      expect(cl.length, 5);
+      expect(cl[0], 0);
+    });
+
+    test("insert works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(5, (index) => index));
+      expect(cl.length, 5);
+      expect(cl[0], 0);
+      cl.insert(0, 100);
+
+      expect(cl.length, 6);
+      expect(cl[0], 100);
+      expect(cl[1], 0);
+    });
+
+    test("insert circular works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.insert(1, 100);
+
+      expect(cl.length, 10);
+      expect(cl[0], 100); //circle leads to 100 moving one index down
+      expect(cl[1], 1);
+    });
+
+    test("insert circular immediately remove works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.insert(0, 100);
+
+      expect(cl.length, 10);
+      expect(cl[0], 0); //the inserted 100 fell over immediately
+      expect(cl[1], 1);
+    });
+
+    test("insert all works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.insertAll(2, List<int>.generate(2, (index) => 20 + index));
+
+      expect(cl.length, 10);
+      expect(cl[0], 20);
+      expect(cl[1], 21);
+      expect(cl[3], 3);
+      expect(cl[9], 9);
+    });
+
+    test("trim start works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.trimStart(5);
+
+      expect(cl.length, 5);
+      expect(cl[0], 5);
+      expect(cl[1], 6);
+      expect(cl[4], 9);
+    });
+
+    test("trim start with more than length works", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.trimStart(15);
+
+      expect(cl.length, 0);
+    });
+
+    test("shift elements works", () {
+      final cl = CircularList<int>(20);
+      cl.pushAll(List<int>.generate(20, (index) => index));
+      expect(cl.length, 20);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      cl.shiftElements(5, 3, 2);
+
+      expect(cl.length, 20);
+      expect(cl[0], 0); // untouched
+      expect(cl[1], 1); // untouched
+      expect(cl[5], 5); // moved
+      expect(cl[6], 6); // moved
+      expect(cl[7], 5); // moved (7) and target (5)
+      expect(cl[8], 6); // target (6)
+      expect(cl[9], 7); // target (7)
+      expect(cl[10], 10); // untouched
+      expect(cl[11], 11); // untouched
+    });
+
+    test("shift elements over bounds throws", () {
+      final cl = CircularList<int>(10);
+      cl.pushAll(List<int>.generate(10, (index) => index));
+      expect(cl.length, 10);
+      expect(cl[0], 0);
+      expect(cl[1], 1);
+      expect(cl[9], 9);
+
+      expect(() => cl.shiftElements(8, 2, 3), throwsA(anything));
+      expect(() => cl.shiftElements(2, 3, -3), throwsA(anything));
+    });
+  });
+}