123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- // Copyright (c) 2018, the Zefyr project authors. Please see the AUTHORS file
- // for details. All rights reserved. Use of this source code is governed by a
- // BSD-style license that can be found in the LICENSE file.
- import 'package:test/test.dart';
- import 'package:quill_delta/quill_delta.dart';
- import 'package:notus/notus.dart';
-
- final boldStyle = new NotusStyle().merge(NotusAttribute.bold);
- final h1Style = new NotusStyle().merge(NotusAttribute.h1);
- final h2Style = new NotusStyle().merge(NotusAttribute.h2);
- final ulStyle = new NotusStyle().merge(NotusAttribute.ul);
- final bqStyle = new NotusStyle().merge(NotusAttribute.bq);
-
- void main() {
- group('$LineNode', () {
- ContainerNode root;
- setUp(() {
- root = new RootNode();
- });
-
- test('empty', () {
- LineNode node = new LineNode();
- expect(node, isEmpty);
- expect(node.length, 1);
- expect(node.style, new NotusStyle());
- expect(node.toDelta().toList(), [new Operation.insert('\n')]);
- });
-
- test('hasEmbed', () {
- LineNode node = new LineNode();
- expect(node.hasEmbed, isFalse);
- node.add(new EmbedNode());
- expect(node.hasEmbed, isTrue);
- });
-
- test('nextLine', () {
- root.insert(
- 0, 'Hello world\nThis is my first multiline\nItem\ndocument.', null);
- root.retain(38, 1, ulStyle);
- root.retain(43, 1, bqStyle);
- LineNode line = root.first;
- expect(line.toPlainText(), 'Hello world\n');
- var next = line.nextLine;
- expect(next.toPlainText(), 'This is my first multiline\n');
- next = next.nextLine;
- expect(next.toPlainText(), 'Item\n');
- next = next.nextLine;
- expect(next.toPlainText(), 'document.\n');
- expect(next.nextLine, isNull);
- });
-
- test('toString', () {
- LineNode node = new LineNode();
- node.insert(0, 'London "Grammar" - Hey Now', null);
- node.retain(0, 16, boldStyle);
- node.applyAttribute(NotusAttribute.h1);
- expect('$node', '¶ ⟨London "Grammar"⟩b → ⟨ - Hey Now⟩ ⏎ {heading: 1}');
- });
-
- test('splitAt with multiple text segments', () {
- root.insert(0, 'This house is a circus', null);
- root.retain(0, 4, boldStyle);
- root.retain(16, 6, boldStyle);
- LineNode line = root.first;
- final newLine = line.splitAt(10);
- expect(line.toPlainText(), 'This house\n');
- expect(newLine.toPlainText(), ' is a circus\n');
- });
-
- test('insert into empty line', () {
- LineNode node = new LineNode();
- node.insert(0, 'London "Grammar" - Hey Now', null);
- expect(node, hasLength(27));
- expect(
- node.toDelta(), new Delta()..insert('London "Grammar" - Hey Now\n'));
- });
-
- test('insert into empty line with styles', () {
- LineNode node = new LineNode();
- node.insert(0, 'London "Grammar" - Hey Now', null);
- node.retain(0, 16, boldStyle);
- node.applyAttribute(NotusAttribute.h1);
- expect(node, hasLength(27));
- expect(node.childCount, 2);
-
- final delta = new Delta()
- ..insert('London "Grammar"', boldStyle.toJson())
- ..insert(' - Hey Now')
- ..insert('\n', NotusAttribute.h1.toJson());
- expect(node.toDelta(), delta);
- });
-
- test('insert into non-empty line', () {
- LineNode node = new LineNode();
- node.insert(0, 'Hello world', null);
- node.insert(11, '!!!', null);
- expect(node, hasLength(15));
- expect(node.childCount, 1);
- expect(node.toDelta(), new Delta()..insert('Hello world!!!\n'));
- });
-
- test('insert text with line-break at the end of line', () {
- root.insert(0, 'Hello world', null);
- root.insert(11, '!!!\n', null);
- expect(root.childCount, 2);
-
- LineNode line = root.first;
- expect(line, hasLength(15));
- expect(line.toDelta(), new Delta()..insert('Hello world!!!\n'));
-
- LineNode line2 = root.last;
- expect(line2, hasLength(1));
- expect(line2.toDelta(), new Delta()..insert('\n'));
- });
-
- test('insert into second text segment', () {
- root.insert(0, 'Hello world', null);
- root.retain(6, 5, boldStyle);
- root.insert(11, '!!!', null);
-
- LineNode line = root.first;
- expect(line, hasLength(15));
- Delta delta = new Delta()
- ..insert('Hello ')
- ..insert('world', boldStyle.toJson())
- ..insert('!!!\n');
- expect(line.toDelta(), delta);
- });
-
- test('format line', () {
- root.insert(0, 'Hello world', null);
- root.retain(11, 1, h1Style);
-
- LineNode line = root.first;
- expect(line, hasLength(12));
-
- Delta delta = new Delta()
- ..insert('Hello world')
- ..insert('\n', NotusAttribute.h1.toJson());
- expect(line.toDelta(), delta);
- });
-
- test('format line with inline attributes', () {
- root.insert(0, 'Hello world', null);
- expect(() {
- root.retain(11, 1, boldStyle);
- }, throwsA(const TypeMatcher<AssertionError>()));
- });
-
- test('format text inside line with block/line attributes', () {
- root.insert(0, 'Hello world', null);
- expect(() {
- root.retain(10, 2, h1Style);
- }, throwsA(const TypeMatcher<AssertionError>()));
- });
-
- test('format root line to unset block style', () {
- final unsetBlock = new NotusStyle().put(NotusAttribute.block.unset);
- root.insert(0, 'Hello world', null);
- root.retain(11, 1, unsetBlock);
- expect(root.childCount, 1);
- expect(root.first, const TypeMatcher<LineNode>());
- LineNode line = root.first;
- expect(line.style.contains(NotusAttribute.block), isFalse);
- });
-
- test('format multiple empty lines', () {
- root.insert(0, 'Hello world\n\n\n', null);
- root.retain(11, 3, ulStyle);
- expect(root.children, hasLength(2));
- BlockNode block = root.first;
- expect(block.children, hasLength(3));
- expect(block.toPlainText(), 'Hello world\n\n\n');
- });
-
- test('delete a line', () {
- root.insert(0, 'Hello world', null);
- root.delete(0, 12);
- expect(root, isEmpty);
- // TODO: this should really enforce at least one empty line.
- });
-
- test('delete from the middle of a line', () {
- root.insert(0, 'Hello world', null);
- root.delete(4, 3);
- root.delete(6, 1);
- expect(root.childCount, 1);
- LineNode line = root.first;
- expect(line, hasLength(8));
- expect(line.childCount, 1);
- Delta lineDelta = new Delta()..insert('Hellord\n');
- expect(line.toDelta(), lineDelta);
- });
-
- test('delete from non-first segment in line', () {
- root.insert(0, 'Hello world, Ab cd ef!', null);
- root.retain(6, 5, boldStyle);
- root.delete(10, 5);
- expect(root.childCount, 1);
- LineNode line = root.first;
- expect(line, hasLength(18));
- Delta lineDelta = new Delta()
- ..insert('Hello ')
- ..insert('worl', boldStyle.toJson())
- ..insert(' cd ef!\n');
- expect(line.toDelta(), lineDelta);
- });
-
- test('delete on multiple lines', () {
- root.insert(0, 'delete\nmultiple\nlines', null);
- root.retain(21, 1, h2Style);
- root.delete(3, 15);
- expect(root.childCount, 1);
- LineNode line = root.first;
- expect(line.childCount, 1);
- final delta = new Delta()
- ..insert('delnes')
- ..insert('\n', h2Style.toJson());
- expect(line.toDelta(), delta);
- });
-
- test('delete empty line', () {
- root.insert(
- 0, 'Hello world\nThis is my first multiline\n\ndocument.', null);
- expect(root.childCount, 4);
- root.delete(39, 1);
- expect(root.childCount, 3);
- });
-
- test('delete line-break of non-empty line', () {
- root.insert(
- 0, 'Hello world\nThis is my first multiline\n\ndocument.', null);
- root.retain(39, 1, h2Style);
- expect(root.childCount, 4);
- root.delete(38, 1);
- expect(root.childCount, 3);
- LineNode line = root.children.elementAt(1);
- expect(line.style.get(NotusAttribute.heading), NotusAttribute.h2);
- });
-
- test('insert at the beginning of a line', () {
- root.insert(
- 0, 'Hello world\nThis is my first multiline\ndocument.', null);
- root.insert(12, 'Boom! ', null);
- expect(root.childCount, 3);
- expect(root.children.elementAt(1), hasLength(33));
- });
-
- test('delete last character of a line', () {
- root.insert(
- 0, 'Hello world\nThis is my first multiline\ndocument.', null);
- root.delete(37, 1);
- expect(root.childCount, 3);
- LineNode line = root.children.elementAt(1);
- expect(
- line.toDelta(), new Delta()..insert('This is my first multilin\n'));
- });
-
- test('collectStyle', () {
- // TODO: need more test cases for collectStyle
- root.insert(
- 0, 'Hello world\nThis is my first multiline\n\ndocument.', null);
- root.retain(38, 1, h2Style);
- root.retain(23, 5, boldStyle);
- var result = root.lookup(20);
- LineNode line = result.node;
- var attrs = line.collectStyle(result.offset, 5);
- expect(attrs, h2Style);
- });
-
- test('collectStyle with embed nodes', () {
- root.insert(0, 'Hello world\n\nMore text.\n', null);
- NotusStyle style = new NotusStyle();
- style = style.put(NotusAttribute.embed.horizontalRule);
- root.insert(12, EmbedNode.kPlainTextPlaceholder, style);
-
- var lookup = root.lookup(0);
- LineNode line = lookup.node;
- var result = line.collectStyle(lookup.offset, 15);
- expect(result, isEmpty);
- });
- });
- }
|