mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge pull request #1229 from enzoftware/main
test: Improve Code Coverage for extensions files
This commit is contained in:
commit
06f1d52cc0
@ -17,9 +17,9 @@ extension NodeAttributesExtensions on Attributes {
|
||||
return containsKey(BuiltInAttributeKey.quote);
|
||||
}
|
||||
|
||||
int? get number {
|
||||
num? get number {
|
||||
if (containsKey(BuiltInAttributeKey.number) &&
|
||||
this[BuiltInAttributeKey.number] is int) {
|
||||
this[BuiltInAttributeKey.number] is num) {
|
||||
return this[BuiltInAttributeKey.number];
|
||||
}
|
||||
return null;
|
||||
@ -27,7 +27,7 @@ extension NodeAttributesExtensions on Attributes {
|
||||
|
||||
bool get code {
|
||||
if (containsKey(BuiltInAttributeKey.code) &&
|
||||
this[BuiltInAttributeKey.code] == true) {
|
||||
this[BuiltInAttributeKey.code] is bool) {
|
||||
return this[BuiltInAttributeKey.code];
|
||||
}
|
||||
return false;
|
||||
@ -63,11 +63,14 @@ extension DeltaAttributesExtensions on Attributes {
|
||||
this[BuiltInAttributeKey.strikethrough] == true);
|
||||
}
|
||||
|
||||
static const whiteInt = 0XFFFFFFFF;
|
||||
|
||||
Color? get color {
|
||||
if (containsKey(BuiltInAttributeKey.color) &&
|
||||
this[BuiltInAttributeKey.color] is String) {
|
||||
return Color(
|
||||
int.parse(this[BuiltInAttributeKey.color]),
|
||||
// If the parse fails returns white by default
|
||||
int.tryParse(this[BuiltInAttributeKey.color]) ?? whiteInt,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@ -77,8 +80,7 @@ extension DeltaAttributesExtensions on Attributes {
|
||||
if (containsKey(BuiltInAttributeKey.backgroundColor) &&
|
||||
this[BuiltInAttributeKey.backgroundColor] is String) {
|
||||
return Color(
|
||||
int.parse(this[BuiltInAttributeKey.backgroundColor]),
|
||||
);
|
||||
int.tryParse(this[BuiltInAttributeKey.backgroundColor]) ?? whiteInt);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import 'package:appflowy_editor/src/document/text_delta.dart';
|
||||
import 'package:appflowy_editor/src/document/built_in_attribute_keys.dart';
|
||||
|
||||
extension TextNodeExtension on TextNode {
|
||||
dynamic getAttributeInSelection(Selection selection, String styleKey) {
|
||||
T? getAttributeInSelection<T>(Selection selection, String styleKey) {
|
||||
final ops = delta.whereType<TextInsert>();
|
||||
final startOffset =
|
||||
selection.isBackward ? selection.start.offset : selection.end.offset;
|
||||
@ -19,8 +19,9 @@ extension TextNodeExtension on TextNode {
|
||||
}
|
||||
final length = op.length;
|
||||
if (start < endOffset && start + length > startOffset) {
|
||||
if (op.attributes?.containsKey(styleKey) == true) {
|
||||
return op.attributes![styleKey];
|
||||
final attributes = op.attributes;
|
||||
if (attributes != null && attributes[styleKey] is T?) {
|
||||
return attributes[styleKey];
|
||||
}
|
||||
}
|
||||
start += length;
|
||||
|
@ -26,6 +26,7 @@ import 'messages_hu-HU.dart' as messages_hu_hu;
|
||||
import 'messages_id-ID.dart' as messages_id_id;
|
||||
import 'messages_it-IT.dart' as messages_it_it;
|
||||
import 'messages_ja-JP.dart' as messages_ja_jp;
|
||||
import 'messages_ml_IN.dart' as messages_ml_in;
|
||||
import 'messages_nl-NL.dart' as messages_nl_nl;
|
||||
import 'messages_pl-PL.dart' as messages_pl_pl;
|
||||
import 'messages_pt-BR.dart' as messages_pt_br;
|
||||
@ -48,6 +49,7 @@ Map<String, LibraryLoader> _deferredLibraries = {
|
||||
'id_ID': () => new Future.value(null),
|
||||
'it_IT': () => new Future.value(null),
|
||||
'ja_JP': () => new Future.value(null),
|
||||
'ml_IN': () => new Future.value(null),
|
||||
'nl_NL': () => new Future.value(null),
|
||||
'pl_PL': () => new Future.value(null),
|
||||
'pt_BR': () => new Future.value(null),
|
||||
@ -82,6 +84,8 @@ MessageLookupByLibrary? _findExact(String localeName) {
|
||||
return messages_it_it.messages;
|
||||
case 'ja_JP':
|
||||
return messages_ja_jp.messages;
|
||||
case 'ml_IN':
|
||||
return messages_ml_in.messages;
|
||||
case 'nl_NL':
|
||||
return messages_nl_nl.messages;
|
||||
case 'pl_PL':
|
||||
|
@ -0,0 +1,45 @@
|
||||
// DO NOT EDIT. This is code generated via package:intl/generate_localized.dart
|
||||
// This is a library that provides messages for a ml_IN locale. All the
|
||||
// messages from the main program should be duplicated here with the same
|
||||
// function name.
|
||||
|
||||
// Ignore issues from commonly used lints in this file.
|
||||
// ignore_for_file:unnecessary_brace_in_string_interps, unnecessary_new
|
||||
// ignore_for_file:prefer_single_quotes,comment_references, directives_ordering
|
||||
// ignore_for_file:annotate_overrides,prefer_generic_function_type_aliases
|
||||
// ignore_for_file:unused_import, file_names, avoid_escaping_inner_quotes
|
||||
// ignore_for_file:unnecessary_string_interpolations, unnecessary_string_escapes
|
||||
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:intl/message_lookup_by_library.dart';
|
||||
|
||||
final messages = new MessageLookup();
|
||||
|
||||
typedef String MessageIfAbsent(String messageStr, List<dynamic> args);
|
||||
|
||||
class MessageLookup extends MessageLookupByLibrary {
|
||||
String get localeName => 'ml_IN';
|
||||
|
||||
final messages = _notInlinedMessages(_notInlinedMessages);
|
||||
static Map<String, Function> _notInlinedMessages(_) => <String, Function>{
|
||||
"bold": MessageLookupByLibrary.simpleMessage("ബോൾഡ്"),
|
||||
"bulletedList":
|
||||
MessageLookupByLibrary.simpleMessage("ബുള്ളറ്റഡ് പട്ടിക"),
|
||||
"checkbox": MessageLookupByLibrary.simpleMessage("ചെക്ക്ബോക്സ്"),
|
||||
"embedCode": MessageLookupByLibrary.simpleMessage("എംബെഡഡ് കോഡ്"),
|
||||
"heading1": MessageLookupByLibrary.simpleMessage("തലക്കെട്ട് 1"),
|
||||
"heading2": MessageLookupByLibrary.simpleMessage("തലക്കെട്ട് 2"),
|
||||
"heading3": MessageLookupByLibrary.simpleMessage("തലക്കെട്ട് 3"),
|
||||
"highlight":
|
||||
MessageLookupByLibrary.simpleMessage("പ്രമുഖമാക്കിക്കാട്ടുക"),
|
||||
"image": MessageLookupByLibrary.simpleMessage("ചിത്രം"),
|
||||
"italic": MessageLookupByLibrary.simpleMessage("ഇറ്റാലിക്"),
|
||||
"link": MessageLookupByLibrary.simpleMessage("ലിങ്ക്"),
|
||||
"numberedList":
|
||||
MessageLookupByLibrary.simpleMessage("അക്കമിട്ട പട്ടിക"),
|
||||
"quote": MessageLookupByLibrary.simpleMessage("ഉദ്ധരണി"),
|
||||
"strikethrough": MessageLookupByLibrary.simpleMessage("സ്ട്രൈക്ക്ത്രൂ"),
|
||||
"text": MessageLookupByLibrary.simpleMessage("വചനം"),
|
||||
"underline": MessageLookupByLibrary.simpleMessage("അടിവരയിടുക")
|
||||
};
|
||||
}
|
@ -229,6 +229,7 @@ class AppLocalizationDelegate
|
||||
Locale.fromSubtags(languageCode: 'id', countryCode: 'ID'),
|
||||
Locale.fromSubtags(languageCode: 'it', countryCode: 'IT'),
|
||||
Locale.fromSubtags(languageCode: 'ja', countryCode: 'JP'),
|
||||
Locale.fromSubtags(languageCode: 'ml', countryCode: 'IN'),
|
||||
Locale.fromSubtags(languageCode: 'nl', countryCode: 'NL'),
|
||||
Locale.fromSubtags(languageCode: 'pl', countryCode: 'PL'),
|
||||
Locale.fromSubtags(languageCode: 'pt', countryCode: 'BR'),
|
||||
|
@ -333,8 +333,10 @@ void showLinkMenu(
|
||||
final textNode = node.first as TextNode;
|
||||
String? linkText;
|
||||
if (textNode.allSatisfyLinkInSelection(selection)) {
|
||||
linkText =
|
||||
textNode.getAttributeInSelection(selection, BuiltInAttributeKey.href);
|
||||
linkText = textNode.getAttributeInSelection<String>(
|
||||
selection,
|
||||
BuiltInAttributeKey.href,
|
||||
);
|
||||
}
|
||||
_linkMenuOverlay = OverlayEntry(builder: (context) {
|
||||
return Positioned(
|
||||
|
@ -33,6 +33,7 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
flutter_lints: ^2.0.1
|
||||
network_image_mock: ^2.1.1
|
||||
mockito: ^5.3.2
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
@ -0,0 +1,201 @@
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('NodeAttributesExtensions::', () {
|
||||
test('heading', () {
|
||||
final Attributes attribute = {
|
||||
'subtype': 'heading',
|
||||
'heading': 'AppFlowy',
|
||||
};
|
||||
expect(attribute.heading, 'AppFlowy');
|
||||
});
|
||||
|
||||
test('heading - text is not String return null', () {
|
||||
final Attributes attribute = {
|
||||
'subtype': 'heading',
|
||||
'heading': 123,
|
||||
};
|
||||
expect(attribute.heading, null);
|
||||
});
|
||||
|
||||
test('heading - subtype is not "heading" return null', () {
|
||||
final Attributes attribute = {
|
||||
'subtype': 'code',
|
||||
'heading': 'Hello World!',
|
||||
};
|
||||
expect(attribute.heading, null);
|
||||
});
|
||||
|
||||
test('quote', () {
|
||||
final Attributes attribute = {
|
||||
'quote': 'quote text',
|
||||
};
|
||||
expect(attribute.quote, true);
|
||||
});
|
||||
|
||||
test('number - int', () {
|
||||
final Attributes attribute = {
|
||||
'number': 99,
|
||||
};
|
||||
expect(attribute.number, 99);
|
||||
});
|
||||
|
||||
test('number - double', () {
|
||||
final Attributes attribute = {
|
||||
'number': 12.34,
|
||||
};
|
||||
expect(attribute.number, 12.34);
|
||||
});
|
||||
|
||||
test('number - return null', () {
|
||||
final Attributes attribute = {
|
||||
'code': 12.34,
|
||||
};
|
||||
expect(attribute.number, null);
|
||||
});
|
||||
|
||||
test('code', () {
|
||||
final Attributes attribute = {
|
||||
'code': true,
|
||||
};
|
||||
expect(attribute.code, true);
|
||||
});
|
||||
|
||||
test('code - return false', () {
|
||||
final Attributes attribute = {
|
||||
'quote': true,
|
||||
};
|
||||
expect(attribute.code, false);
|
||||
});
|
||||
|
||||
test('check', () {
|
||||
final Attributes attribute = {
|
||||
'checkbox': true,
|
||||
};
|
||||
expect(attribute.check, true);
|
||||
});
|
||||
|
||||
test('check - return false', () {
|
||||
final Attributes attribute = {
|
||||
'quote': true,
|
||||
};
|
||||
expect(attribute.check, false);
|
||||
});
|
||||
});
|
||||
|
||||
group('DeltaAttributesExtensions::', () {
|
||||
test('bold', () {
|
||||
final Attributes attribute = {
|
||||
'bold': true,
|
||||
};
|
||||
expect(attribute.bold, true);
|
||||
});
|
||||
|
||||
test('bold - return false', () {
|
||||
final Attributes attribute = {
|
||||
'bold': 123,
|
||||
};
|
||||
expect(attribute.bold, false);
|
||||
});
|
||||
|
||||
test('italic', () {
|
||||
final Attributes attribute = {
|
||||
'italic': true,
|
||||
};
|
||||
expect(attribute.italic, true);
|
||||
});
|
||||
|
||||
test('italic - return false', () {
|
||||
final Attributes attribute = {
|
||||
'italic': 123,
|
||||
};
|
||||
expect(attribute.italic, false);
|
||||
});
|
||||
|
||||
test('underline', () {
|
||||
final Attributes attribute = {
|
||||
'underline': true,
|
||||
};
|
||||
expect(attribute.underline, true);
|
||||
});
|
||||
|
||||
test('underline - return false', () {
|
||||
final Attributes attribute = {
|
||||
'underline': 123,
|
||||
};
|
||||
expect(attribute.underline, false);
|
||||
});
|
||||
|
||||
test('strikethrough', () {
|
||||
final Attributes attribute = {
|
||||
'strikethrough': true,
|
||||
};
|
||||
expect(attribute.strikethrough, true);
|
||||
});
|
||||
|
||||
test('strikethrough - return false', () {
|
||||
final Attributes attribute = {
|
||||
'strikethrough': 123,
|
||||
};
|
||||
expect(attribute.strikethrough, false);
|
||||
});
|
||||
|
||||
test('color', () {
|
||||
final Attributes attribute = {
|
||||
'color': '0xff212fff',
|
||||
};
|
||||
expect(attribute.color, const Color(0XFF212FFF));
|
||||
});
|
||||
|
||||
test('color - return null', () {
|
||||
final Attributes attribute = {
|
||||
'color': 123,
|
||||
};
|
||||
expect(attribute.color, null);
|
||||
});
|
||||
|
||||
test('color - parse failure return white', () {
|
||||
final Attributes attribute = {
|
||||
'color': 'hello123',
|
||||
};
|
||||
expect(attribute.color, const Color(0XFFFFFFFF));
|
||||
});
|
||||
|
||||
test('backgroundColor', () {
|
||||
final Attributes attribute = {
|
||||
'backgroundColor': '0xff678fff',
|
||||
};
|
||||
expect(attribute.backgroundColor, const Color(0XFF678FFF));
|
||||
});
|
||||
|
||||
test('backgroundColor - return null', () {
|
||||
final Attributes attribute = {
|
||||
'backgroundColor': 123,
|
||||
};
|
||||
expect(attribute.backgroundColor, null);
|
||||
});
|
||||
|
||||
test('backgroundColor - parse failure return white', () {
|
||||
final Attributes attribute = {
|
||||
'backgroundColor': 'hello123',
|
||||
};
|
||||
expect(attribute.backgroundColor, const Color(0XFFFFFFFF));
|
||||
});
|
||||
|
||||
test('href', () {
|
||||
final Attributes attribute = {
|
||||
'href': '/app/flowy',
|
||||
};
|
||||
expect(attribute.href, '/app/flowy');
|
||||
});
|
||||
|
||||
test('href - return null', () {
|
||||
final Attributes attribute = {
|
||||
'href': 123,
|
||||
};
|
||||
expect(attribute.href, null);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
import 'package:appflowy_editor/src/extensions/color_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('ColorExtension::', () {
|
||||
const white = Color(0XFFFFFFFF);
|
||||
const black = Color(0XFF000000);
|
||||
const blue = Color(0XFF000FFF);
|
||||
const blueRgba = 'rgba(0, 15, 255, 255)';
|
||||
test('ToRgbaString', () {
|
||||
expect(blue.toRgbaString(), 'rgba(0, 15, 255, 255)');
|
||||
expect(white.toRgbaString(), 'rgba(255, 255, 255, 255)');
|
||||
expect(black.toRgbaString(), 'rgba(0, 0, 0, 255)');
|
||||
});
|
||||
|
||||
test('tryFromRgbaString', () {
|
||||
final color = ColorExtension.tryFromRgbaString(blueRgba);
|
||||
expect(color, const Color.fromARGB(255, 0, 15, 255));
|
||||
});
|
||||
|
||||
test('tryFromRgbaString - wrong rgba format return null', () {
|
||||
const wrongRgba = 'abc(1,2,3,4)';
|
||||
final color = ColorExtension.tryFromRgbaString(wrongRgba);
|
||||
expect(color, null);
|
||||
});
|
||||
|
||||
test('tryFromRgbaString - wrong length return null', () {
|
||||
const wrongRgba = 'rgba(0, 15, 255)';
|
||||
final color = ColorExtension.tryFromRgbaString(wrongRgba);
|
||||
expect(color, null);
|
||||
});
|
||||
|
||||
test('tryFromRgbaString - wrong values return null', () {
|
||||
const wrongRgba = 'rgba(-12, 999, 1234, 619)';
|
||||
final color = ColorExtension.tryFromRgbaString(wrongRgba);
|
||||
expect(color, null);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:appflowy_editor/src/extensions/node_extensions.dart';
|
||||
|
||||
class MockNode extends Mock implements Node {}
|
||||
|
||||
void main() {
|
||||
final mockNode = MockNode();
|
||||
|
||||
group('NodeExtensions::', () {
|
||||
final selection = Selection(
|
||||
start: Position(path: [0]),
|
||||
end: Position(path: [1]),
|
||||
);
|
||||
|
||||
test('rect - renderBox is null', () {
|
||||
when(mockNode.renderBox).thenReturn(null);
|
||||
final result = mockNode.rect;
|
||||
expect(result, Rect.zero);
|
||||
});
|
||||
|
||||
test('inSelection', () {
|
||||
// I use an empty implementation instead of mock, because the mocked
|
||||
// version throws error trying to access the path.
|
||||
|
||||
final subLinkedList = LinkedList<Node>()
|
||||
..addAll([
|
||||
Node(type: 'type', children: LinkedList(), attributes: {}),
|
||||
Node(type: 'type', children: LinkedList(), attributes: {}),
|
||||
Node(type: 'type', children: LinkedList(), attributes: {}),
|
||||
Node(type: 'type', children: LinkedList(), attributes: {}),
|
||||
Node(type: 'type', children: LinkedList(), attributes: {}),
|
||||
]);
|
||||
|
||||
final linkedList = LinkedList<Node>()
|
||||
..addAll([
|
||||
Node(
|
||||
type: 'type',
|
||||
children: subLinkedList,
|
||||
attributes: {},
|
||||
),
|
||||
]);
|
||||
|
||||
final node = Node(
|
||||
type: 'type',
|
||||
children: linkedList,
|
||||
attributes: {},
|
||||
);
|
||||
final result = node.inSelection(selection);
|
||||
expect(result, false);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:appflowy_editor/src/extensions/object_extensions.dart';
|
||||
|
||||
void main() {
|
||||
group('FlowyObjectExtensions::', () {
|
||||
test('unwrapOrNull', () {
|
||||
final result = const TextSpan().unwrapOrNull<HitTestTarget>();
|
||||
assert(result is TextSpan);
|
||||
});
|
||||
|
||||
test('unwrapOrNull - return null', () {
|
||||
final result = const TextSpan().unwrapOrNull<ServerSocket>();
|
||||
expect(result, null);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
group('TextNodeExtension::', () {
|
||||
test('description', () {});
|
||||
});
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:appflowy_editor/src/extensions/text_style_extension.dart';
|
||||
|
||||
void main() {
|
||||
group('TextStyleExtensions::', () {
|
||||
const style = TextStyle(
|
||||
color: Colors.blue,
|
||||
backgroundColor: Colors.white,
|
||||
fontSize: 14,
|
||||
height: 100,
|
||||
wordSpacing: 2,
|
||||
fontWeight: FontWeight.w700,
|
||||
);
|
||||
|
||||
const otherStyle = TextStyle(
|
||||
color: Colors.red,
|
||||
backgroundColor: Colors.black,
|
||||
fontSize: 12,
|
||||
height: 10,
|
||||
wordSpacing: 1,
|
||||
);
|
||||
test('combine', () {
|
||||
final result = style.combine(otherStyle);
|
||||
expect(result.color, Colors.red);
|
||||
expect(result.backgroundColor, Colors.black);
|
||||
expect(result.fontSize, 12);
|
||||
expect(result.height, 10);
|
||||
expect(result.wordSpacing, 1);
|
||||
});
|
||||
|
||||
test('combine - return this', () {
|
||||
final result = style.combine(null);
|
||||
expect(result, style);
|
||||
});
|
||||
|
||||
test('combine - return null with inherit', () {
|
||||
final styleCopy = otherStyle.copyWith(inherit: false);
|
||||
final result = style.combine(styleCopy);
|
||||
expect(result, styleCopy);
|
||||
});
|
||||
});
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
test('safeLaunchUrl without scheme', () async {
|
||||
const href = null;
|
||||
final result = await safeLaunchUrl(href);
|
||||
expect(result, false);
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user