diff --git a/packages/rfw/CHANGELOG.md b/packages/rfw/CHANGELOG.md index 63852acf2444..dc78140b693c 100644 --- a/packages/rfw/CHANGELOG.md +++ b/packages/rfw/CHANGELOG.md @@ -1,3 +1,8 @@ +## NEXT + +* Adds more testing to restore coverage to 100%. +* Removes some dead code. + ## 1.0.11 * Adds more documentation in the README.md file! diff --git a/packages/rfw/lib/src/dart/text.dart b/packages/rfw/lib/src/dart/text.dart index 34ca06991b93..bebb22e6ad60 100644 --- a/packages/rfw/lib/src/dart/text.dart +++ b/packages/rfw/lib/src/dart/text.dart @@ -738,13 +738,12 @@ enum _TokenizerMode { quoteEscapeUnicode2, quoteEscapeUnicode3, quoteEscapeUnicode4, - endQuote, doubleQuoteEscape, doubleQuoteEscapeUnicode1, doubleQuoteEscapeUnicode2, doubleQuoteEscapeUnicode3, doubleQuoteEscapeUnicode4, - endDoubleQuote, + endQuote, slash, comment, } @@ -1821,36 +1820,6 @@ Iterable<_Token> _tokenize(String file) sync* { } break; - case _TokenizerMode.endQuote: - switch (current) { - case -1: - yield _EofToken(line, column); - return; - case 0x0A: // U+000A LINE FEED (LF) - case 0x20: // U+0020 SPACE character - mode = _TokenizerMode.main; - break; - case 0x28: // U+0028 LEFT PARENTHESIS character (() - case 0x29: // U+0029 RIGHT PARENTHESIS character ()) - case 0x2C: // U+002C COMMA character (,) - case 0x3A: // U+003A COLON character (:) - case 0x3B: // U+003B SEMICOLON character (;) - case 0x3D: // U+003D EQUALS SIGN character (=) - case 0x5B: // U+005B LEFT SQUARE BRACKET character ([) - case 0x5D: // U+005D RIGHT SQUARE BRACKET character (]) - case 0x7B: // U+007B LEFT CURLY BRACKET character ({) - case 0x7D: // U+007D RIGHT CURLY BRACKET character (}) - yield _SymbolToken(current, line, column); - mode = _TokenizerMode.main; - break; - case 0x2E: // U+002E FULL STOP character (.) - mode = _TokenizerMode.dot1; - break; - default: - throw ParserException('Unexpected character ${_describeRune(current)} after end quote', line, column); - } - break; - case _TokenizerMode.doubleQuote: switch (current) { case -1: @@ -2048,7 +2017,7 @@ Iterable<_Token> _tokenize(String file) sync* { } break; - case _TokenizerMode.endDoubleQuote: + case _TokenizerMode.endQuote: switch (current) { case -1: yield _EofToken(line, column); @@ -2074,7 +2043,7 @@ Iterable<_Token> _tokenize(String file) sync* { mode = _TokenizerMode.dot1; break; default: - throw ParserException('Unexpected character ${_describeRune(current)} after end doublequote', line, column); + throw ParserException('Unexpected character ${_describeRune(current)} after end quote', line, column); } break; diff --git a/packages/rfw/test/argument_decoders_test.dart b/packages/rfw/test/argument_decoders_test.dart index ff0af89e7637..41f60aec83f1 100644 --- a/packages/rfw/test/argument_decoders_test.dart +++ b/packages/rfw/test/argument_decoders_test.dart @@ -5,16 +5,19 @@ // This file is hand-formatted. import 'dart:io' show Platform; +import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:rfw/formats.dart' show parseLibraryFile; import 'package:rfw/rfw.dart'; +final bool masterChannel = + !Platform.environment.containsKey('CHANNEL') || + Platform.environment['CHANNEL'] == 'master'; + // See Contributing section of README.md file. -final bool runGoldens = Platform.isLinux && - (!Platform.environment.containsKey('CHANNEL') || - Platform.environment['CHANNEL'] == 'master'); +final bool runGoldens = Platform.isLinux && masterChannel; void main() { testWidgets('String example', (WidgetTester tester) async { @@ -238,6 +241,7 @@ void main() { ..update(const LibraryName(['core']), createCoreWidgets()) ..update(const LibraryName(['test']), parseLibraryFile('import core; widget root = SizedBox();')); final DynamicContent data = DynamicContent(); + final List eventLog = []; await tester.pumpWidget( Directionality( textDirection: TextDirection.rtl, @@ -245,6 +249,9 @@ void main() { runtime: runtime, data: data, widget: const FullyQualifiedWidgetName(LibraryName(['test']), 'root'), + onEvent: (String eventName, DynamicMap eventArguments) { + eventLog.add('$eventName $eventArguments'); + }, ), ), ); @@ -256,6 +263,20 @@ void main() { insets: ArgumentDecoders.edgeInsets(source, ['insets']) ?? EdgeInsets.zero, ); }; + ArgumentDecoders.gradientDecoders['custom'] = (DataSource source, List key) { + return const RadialGradient( + center: Alignment(0.7, -0.6), + radius: 0.2, + colors: [ Color(0xFFFFFF00), Color(0xFF0099FF) ], + stops: [0.4, 1.0], + ); + }; + ArgumentDecoders.shapeBorderDecoders['custom'] = (DataSource source, List key) { + return StarBorder( + side: ArgumentDecoders.borderSide(source, [...key, 'side']) ?? const BorderSide(width: 2.0, color: Color(0xFFFFFFFF)), + points: source.v([...key, 'points']) ?? 5.0, + ); + }; runtime.update(const LibraryName(['test']), parseLibraryFile(''' import core; @@ -297,6 +318,7 @@ void main() { color: 0xFF8811FF, blendMode: "xor", }, + onError: event 'image-error-event' { }, }, gradient: { type: 'linear', @@ -338,7 +360,7 @@ void main() { { type: 'continuous', borderRadius: [ { x: 60.0 }, { x: 80.0 }, { x: 0.0 }, { x: 20.0, y: 50.0 } ], side: { width: 10.0, color: 0xFFEEFF33 } }, { type: 'rounded', borderRadius: [ { x: 20.0 } ], side: { width: 10.0, color: 0xFF00CCFF } }, { type: 'stadium', side: { width: 10.0, color: 0xFF00FFFF } }, - { type: 'custom', side: { width: 100.0, color: 0xFFFF0000 } }, // should not render + { type: 'custom', side: { width: 5.0, color: 0xFFFFFF00 }, points: 6 }, // star ], gradient: { type: 'radial', @@ -349,10 +371,13 @@ void main() { ); ''')); await tester.pump(); + expect(eventLog, hasLength(1)); + expect(eventLog.first, startsWith('image-error-event {exception: HTTP request failed, statusCode: 400, x-invalid:')); + eventLog.clear(); await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/argument_decoders_test.containers.png'), - skip: 'https://github.com/flutter/flutter/issues/106205' + skip: !runGoldens, ); expect(find.byType(DecoratedBox), findsNWidgets(6)); expect( @@ -368,6 +393,16 @@ void main() { 'opacity 1.0, FilterQuality.low)', ); + ArgumentDecoders.colorFilterDecoders['custom'] = (DataSource source, List key) { + return const ColorFilter.mode(Color(0x12345678), BlendMode.xor); + }; + ArgumentDecoders.maskFilterDecoders['custom'] = (DataSource source, List key) { + return const MaskFilter.blur(BlurStyle.outer, 0.5); + }; + ArgumentDecoders.shaderDecoders['custom'] = (DataSource source, List key) { + return ui.Gradient.linear(Offset.zero, const Offset(100.0, 100.0), const [Color(0xFFFFFF00), Color(0xFF00FFFF)]); + }; + runtime.update(const LibraryName(['test']), parseLibraryFile(''' import core; widget root = Column( @@ -428,7 +463,7 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/argument_decoders_test.text.png'), - skip: 'https://github.com/flutter/flutter/issues/106205' + skip: !runGoldens, ); runtime.update(const LibraryName(['test']), parseLibraryFile(''' @@ -451,7 +486,7 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/argument_decoders_test.gridview.fixed.png'), - skip: 'https://github.com/flutter/flutter/issues/106205' + skip: !runGoldens, ); runtime.update(const LibraryName(['test']), parseLibraryFile(''' @@ -474,7 +509,7 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/argument_decoders_test.gridview.max.png'), - skip: 'https://github.com/flutter/flutter/issues/106205' + skip: !runGoldens, ); int sawGridDelegateDecoder = 0; @@ -504,7 +539,9 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/argument_decoders_test.gridview.custom.png'), - skip: 'https://github.com/flutter/flutter/issues/106205' + skip: !runGoldens, ); - }, skip: !runGoldens); + + expect(eventLog, isEmpty); + }, skip: !masterChannel); // https://github.com/flutter/flutter/pull/129851 } diff --git a/packages/rfw/test/goldens/argument_decoders_test.containers.png b/packages/rfw/test/goldens/argument_decoders_test.containers.png index 01d4ef7a8b64..12695d219f16 100644 Binary files a/packages/rfw/test/goldens/argument_decoders_test.containers.png and b/packages/rfw/test/goldens/argument_decoders_test.containers.png differ diff --git a/packages/rfw/test/goldens/argument_decoders_test.gridview.fixed.png b/packages/rfw/test/goldens/argument_decoders_test.gridview.fixed.png index 687b9c2f322a..85db60e14a5e 100644 Binary files a/packages/rfw/test/goldens/argument_decoders_test.gridview.fixed.png and b/packages/rfw/test/goldens/argument_decoders_test.gridview.fixed.png differ diff --git a/packages/rfw/test/goldens/argument_decoders_test.text.png b/packages/rfw/test/goldens/argument_decoders_test.text.png index 9dbc9aa93631..6dd313c3a249 100644 Binary files a/packages/rfw/test/goldens/argument_decoders_test.text.png and b/packages/rfw/test/goldens/argument_decoders_test.text.png differ diff --git a/packages/rfw/test/material_widgets_test.dart b/packages/rfw/test/material_widgets_test.dart index 1742ec42f1c6..6aecc3c00a13 100644 --- a/packages/rfw/test/material_widgets_test.dart +++ b/packages/rfw/test/material_widgets_test.dart @@ -140,6 +140,7 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/material_test.scaffold.png'), + skip: !runGoldens, ); await tester.tapAt(const Offset(20.0, 20.0)); await tester.pump(); @@ -147,6 +148,7 @@ void main() { await expectLater( find.byType(RemoteWidget), matchesGoldenFile('goldens/material_test.drawer.png'), + skip: !runGoldens, ); - }, skip: !runGoldens); + }); } diff --git a/packages/rfw/test/text_test.dart b/packages/rfw/test/text_test.dart index 3ab1ca9ae0c4..bee5f8bd65fc 100644 --- a/packages/rfw/test/text_test.dart +++ b/packages/rfw/test/text_test.dart @@ -3,6 +3,7 @@ // found in the LICENSE file. // This file is hand-formatted. +// ignore_for_file: use_raw_strings, avoid_escaping_inner_quotes import 'package:flutter_test/flutter_test.dart'; import 'package:rfw/formats.dart'; @@ -54,6 +55,94 @@ void main() { test('{ a: a }', 'Unexpected a at line 1 column 7.'); test('{ ... }', 'Expected symbol "}" but found … at line 1 column 5.'); test('{ a: ... }', 'Unexpected … at line 1 column 8.'); + test('{ a: -', 'Unexpected end of file after minus sign at line 1 column 6.'); + test('{ a: -a', 'Unexpected character U+0061 ("a") after minus sign (expected digit) at line 1 column 7.'); + test('{ a: 0', 'Expected symbol "}" but found at line 1 column 6.'); + test('{ a: 0e', 'Unexpected end of file after exponent separator at line 1 column 7.'); + test('{ a: 0ee', 'Unexpected character U+0065 ("e") after exponent separator at line 1 column 8.'); + test('{ a: 0e-', 'Unexpected end of file after exponent separator and minus sign at line 1 column 8.'); + test('{ a: 0e-e', 'Unexpected character U+0065 ("e") in exponent at line 1 column 9.'); + test('{ a: 0e-f', 'Unexpected character U+0066 ("f") in exponent at line 1 column 9.'); + test('{ a: 0e-.', 'Unexpected character U+002E (".") in exponent at line 1 column 9.'); + test('{ a: 0e- ', 'Unexpected character U+0020 in exponent at line 1 column 9.'); + test('{ a: 0e-0', 'Expected symbol "}" but found at line 1 column 9.'); + test('{ a: 0e-0{', 'Expected symbol "}" but found { at line 1 column 10.'); + test('{ a: 0e-0;', 'Expected symbol "}" but found ; at line 1 column 10.'); + test('{ a: 0e-0e', 'Unexpected character U+0065 ("e") in exponent at line 1 column 10.'); + test('{ a: 0 ', 'Expected symbol "}" but found at line 1 column 7.'); + test('{ a: 0.', 'Unexpected end of file after decimal point at line 1 column 7.'); + test('{ a: 0.e', 'Unexpected character U+0065 ("e") in fraction component at line 1 column 8.'); + test('{ a: 0. ', 'Unexpected character U+0020 in fraction component at line 1 column 8.'); + test('{ a: 00', 'Expected symbol "}" but found at line 1 column 7.'); + test('{ a: 00e', 'Unexpected end of file after exponent separator at line 1 column 8.'); + test('{ a: 00ee', 'Unexpected character U+0065 ("e") after exponent separator at line 1 column 9.'); + test('{ a: 00e-', 'Unexpected end of file after exponent separator and minus sign at line 1 column 9.'); + test('{ a: 00 ', 'Expected symbol "}" but found at line 1 column 8.'); + test('{ a: -0', 'Expected symbol "}" but found at line 1 column 7.'); + test('{ a: -0.', 'Unexpected end of file after decimal point at line 1 column 8.'); + test('{ a: -0. ', 'Unexpected character U+0020 in fraction component at line 1 column 9.'); + test('{ a: -0.0', 'Expected symbol "}" but found at line 1 column 9.'); + test('{ a: -0.0 ', 'Expected symbol "}" but found at line 1 column 10.'); + test('{ a: -0.0e', 'Unexpected end of file after exponent separator at line 1 column 10.'); + test('{ a: -0.0ee', 'Unexpected character U+0065 ("e") after exponent separator at line 1 column 11.'); + test('{ a: -0.0e-', 'Unexpected end of file after exponent separator and minus sign at line 1 column 11.'); + test('{ a: -0.0f', 'Unexpected character U+0066 ("f") in fraction component at line 1 column 10.'); + test('{ a: -00', 'Expected symbol "}" but found at line 1 column 8.'); + test('{ a: 0f', 'Unexpected character U+0066 ("f") after zero at line 1 column 7.'); + test('{ a: -0f', 'Unexpected character U+0066 ("f") after negative zero at line 1 column 8.'); + test('{ a: 00f', 'Unexpected character U+0066 ("f") at line 1 column 8.'); + test('{ a: -00f', 'Unexpected character U+0066 ("f") at line 1 column 9.'); + test('{ a: test.0', 'Unexpected test at line 1 column 10.'); + test('{ a: test.0 ', 'Unexpected test at line 1 column 10.'); + test('{ a: 0x', 'Unexpected end of file after 0x prefix at line 1 column 7.'); + test('{ a: 0xg', 'Unexpected character U+0067 ("g") after 0x prefix at line 1 column 8.'); + test('{ a: 0xx', 'Unexpected character U+0078 ("x") after 0x prefix at line 1 column 8.'); + test('{ a: 0x}', 'Unexpected character U+007D ("}") after 0x prefix at line 1 column 8.'); + test('{ a: 0x0', 'Expected symbol "}" but found at line 1 column 8.'); + test('{ a: 0xff', 'Expected symbol "}" but found at line 1 column 9.'); + test('{ a: 0xfg', 'Unexpected character U+0067 ("g") in hex literal at line 1 column 9.'); + test('{ a: ."hello"', 'Unexpected . at line 1 column 7.'); + test('{ a: "hello"."hello"', 'Expected symbol "}" but found . at line 1 column 14.'); + test('{ a: "hello"', 'Expected symbol "}" but found at line 1 column 12.'); + test('{ a: "\n"', 'Unexpected end of line inside string at line 2 column 0.'); + test('{ a: "hello\n"', 'Unexpected end of line inside string at line 2 column 0.'); + test('{ a: "\\', 'Unexpected end of file inside string at line 1 column 7.'); + test('{ a: ."hello"', 'Unexpected . at line 1 column 7.'); + test('{ "a": \'hello\'.\'hello\'', 'Expected symbol "}" but found . at line 1 column 16.'); + test('{ "a": \'hello\'', 'Expected symbol "}" but found at line 1 column 14.'); + test('{ "a": \'hello\'h', 'Unexpected character U+0068 ("h") after end quote at line 1 column 15.'); + test('{ "a": \'\n\'', 'Unexpected end of line inside string at line 2 column 0.'); + test('{ "a": \'hello\n\'', 'Unexpected end of line inside string at line 2 column 0.'); + test('{ "a": \'\\', 'Unexpected end of file inside string at line 1 column 9.'); + test('{ "a": \'\\\'', 'Unexpected end of file inside string at line 1 column 10.'); + test('{ "a": \'\\u', 'Unexpected end of file inside Unicode escape at line 1 column 10.'); + test('{ "a": \'\\u0', 'Unexpected end of file inside Unicode escape at line 1 column 11.'); + test('{ "a": \'\\u00', 'Unexpected end of file inside Unicode escape at line 1 column 12.'); + test('{ "a": \'\\u000', 'Unexpected end of file inside Unicode escape at line 1 column 13.'); + test('{ "a": \'\\u0000', 'Unexpected end of file inside string at line 1 column 14.'); + test('{ "a": \'\\u|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 11.'); + test('{ "a": \'\\u0|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 12.'); + test('{ "a": \'\\u00|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 13.'); + test('{ "a": \'\\u000|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 14.'); + test('{ "a": \'\\u0000|', 'Unexpected end of file inside string at line 1 column 15.'); + test('{ "a": \'\\U263A\' }', 'Unexpected character U+0055 ("U") after backslash in string at line 1 column 10.'); + test('{ "a": "\\', 'Unexpected end of file inside string at line 1 column 9.'); + test('{ "a": "\\"', 'Unexpected end of file inside string at line 1 column 10.'); + test('{ "a": "\\u', 'Unexpected end of file inside Unicode escape at line 1 column 10.'); + test('{ "a": "\\u0', 'Unexpected end of file inside Unicode escape at line 1 column 11.'); + test('{ "a": "\\u00', 'Unexpected end of file inside Unicode escape at line 1 column 12.'); + test('{ "a": "\\u000', 'Unexpected end of file inside Unicode escape at line 1 column 13.'); + test('{ "a": "\\u0000', 'Unexpected end of file inside string at line 1 column 14.'); + test('{ "a": "\\u|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 11.'); + test('{ "a": "\\u0|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 12.'); + test('{ "a": "\\u00|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 13.'); + test('{ "a": "\\u000|', 'Unexpected character U+007C ("|") in Unicode escape at line 1 column 14.'); + test('{ "a": "\\u0000|', 'Unexpected end of file inside string at line 1 column 15.'); + test('{ "a": "\\U263A" }', 'Unexpected character U+0055 ("U") after backslash in string at line 1 column 10.'); + test('{ "a": ', 'Unexpected at line 1 column 7.'); + test('{ "a": /', 'Unexpected end of file inside comment delimiter at line 1 column 8.'); + test('{ "a": /.', 'Unexpected character U+002E (".") inside comment delimiter at line 1 column 9.'); + test('{ "a": //', 'Unexpected at line 1 column 9.'); }); testWidgets('valid values in parseDataFile', (WidgetTester tester) async { @@ -65,7 +154,80 @@ void main() { expect(parseDataFile('{ a: true }'), { 'a': true }); expect(parseDataFile('{ a: false }'), { 'a': false }); expect(parseDataFile('{ "a": 0 }'), { 'a': 0 }); + expect(parseDataFile('{ "a": -0, b: "x" }'), { 'a': 0, 'b': 'x' }); expect(parseDataFile('{ "a": null }'), { }); + expect(parseDataFile('{ "a": -6 }'), { 'a': -6 }); + expect(parseDataFile('{ "a": -7 }'), { 'a': -7 }); + expect(parseDataFile('{ "a": -8 }'), { 'a': -8 }); + expect(parseDataFile('{ "a": -9 }'), { 'a': -9 }); + expect(parseDataFile('{ "a": 01 }'), { 'a': 1 }); + expect(parseDataFile('{ "a": 0e0 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": 0e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": 0e8 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": 1e9 }'), { 'a': 1000000000.0 }); + expect(parseDataFile('{ "a": -0e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": 00e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": -00e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": 00.0e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": -00.0e1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": -00.0e-1 }'), { 'a': 0.0 }); + expect(parseDataFile('{ "a": -1e-1 }'), { 'a': -0.1 }); + expect(parseDataFile('{ "a": -1e-2 }'), { 'a': -0.01 }); + expect(parseDataFile('{ "a": -1e-3 }'), { 'a': -0.001 }); + expect(parseDataFile('{ "a": -1e-4 }'), { 'a': -0.0001 }); + expect(parseDataFile('{ "a": -1e-5 }'), { 'a': -0.00001 }); + expect(parseDataFile('{ "a": -1e-6 }'), { 'a': -0.000001 }); + expect(parseDataFile('{ "a": -1e-7 }'), { 'a': -0.0000001 }); + expect(parseDataFile('{ "a": -1e-8 }'), { 'a': -0.00000001 }); + expect(parseDataFile('{ "a": -1e-9 }'), { 'a': -0.000000001 }); + expect(parseDataFile('{ "a": -1e-10 }'), { 'a': -0.0000000001 }); + expect(parseDataFile('{ "a": -1e-11 }'), { 'a': -0.00000000001 }); + expect(parseDataFile('{ "a": -1e-12 }'), { 'a': -0.000000000001 }); + expect(parseDataFile('{ "a": -1e-13 }'), { 'a': -0.0000000000001 }); + expect(parseDataFile('{ "a": -1e-14 }'), { 'a': -0.00000000000001 }); + expect(parseDataFile('{ "a": -1e-15 }'), { 'a': -0.000000000000001 }); + expect(parseDataFile('{ "a": -1e-16 }'), { 'a': -0.0000000000000001 }); + expect(parseDataFile('{ "a": -1e-17 }'), { 'a': -0.00000000000000001 }); + expect(parseDataFile('{ "a": -1e-18 }'), { 'a': -0.000000000000000001 }); + expect(parseDataFile('{ "a": -1e-19 }'), { 'a': -0.0000000000000000001 }); + expect(parseDataFile('{ "a": 0x0 }'), { 'a': 0 }); + expect(parseDataFile('{ "a": 0x1 }'), { 'a': 1 }); + expect(parseDataFile('{ "a": 0x01 }'), { 'a': 1 }); + expect(parseDataFile('{ "a": 0xa }'), { 'a': 10 }); + expect(parseDataFile('{ "a": 0xb }'), { 'a': 11 }); + expect(parseDataFile('{ "a": 0xc }'), { 'a': 12 }); + expect(parseDataFile('{ "a": 0xd }'), { 'a': 13 }); + expect(parseDataFile('{ "a": 0xe }'), { 'a': 14 }); + expect(parseDataFile('{ "a": 0xfa }'), { 'a': 250 }); + expect(parseDataFile('{ "a": 0xfb }'), { 'a': 251 }); + expect(parseDataFile('{ "a": 0xfc }'), { 'a': 252 }); + expect(parseDataFile('{ "a": 0xfd }'), { 'a': 253 }); + expect(parseDataFile('{ "a": 0xfe }'), { 'a': 254 }); + expect(parseDataFile('{ "a": "\\"\\/\\\'\\b\\f\\n\\r\\t\\\\" }'), { 'a': '\x22\x2F\x27\x08\x0C\x0A\x0D\x09\x5C' }); + expect(parseDataFile('{ "a": \'\\"\\/\\\'\\b\\f\\n\\r\\t\\\\\' }'), { 'a': '\x22\x2F\x27\x08\x0C\x0A\x0D\x09\x5C' }); + expect(parseDataFile('{ "a": \'\\u263A\' }'), { 'a': '☺' }); + expect(parseDataFile('{ "a": \'\\u0000\' }'), { 'a': '\x00' }); + expect(parseDataFile('{ "a": \'\\u1111\' }'), { 'a': 'ᄑ' }); + expect(parseDataFile('{ "a": \'\\u2222\' }'), { 'a': '∢' }); + expect(parseDataFile('{ "a": \'\\u3333\' }'), { 'a': '㌳' }); + expect(parseDataFile('{ "a": \'\\u4444\' }'), { 'a': '䑄' }); + expect(parseDataFile('{ "a": \'\\u5555\' }'), { 'a': '啕' }); + expect(parseDataFile('{ "a": \'\\u6666\' }'), { 'a': '晦' }); + expect(parseDataFile('{ "a": \'\\u7777\' }'), { 'a': '睷' }); + expect(parseDataFile('{ "a": \'\\u8888\' }'), { 'a': '袈' }); + expect(parseDataFile('{ "a": \'\\u9999\' }'), { 'a': '香' }); + expect(parseDataFile('{ "a": \'\\uaaaa\' }'), { 'a': 'ꪪ' }); + expect(parseDataFile('{ "a": \'\\ubbbb\' }'), { 'a': '뮻' }); + expect(parseDataFile('{ "a": \'\\ucccc\' }'), { 'a': '쳌' }); + expect(parseDataFile('{ "a": \'\\udddd\' }'), { 'a': '\u{dddd}' }); // low surragate + expect(parseDataFile('{ "a": \'\\ueeee\' }'), { 'a': '\u{eeee}' }); // private use area + expect(parseDataFile('{ "a": \'\\uffff\' }'), { 'a': '\u{ffff}' }); // not technically a valid Unicode character + expect(parseDataFile('{ "a": \'\\uAAAA\' }'), { 'a': 'ꪪ' }); + expect(parseDataFile('{ "a": \'\\uBBBB\' }'), { 'a': '뮻' }); + expect(parseDataFile('{ "a": \'\\uCCCC\' }'), { 'a': '쳌' }); + expect(parseDataFile('{ "a": \'\\uDDDD\' }'), { 'a': '\u{dddd}' }); + expect(parseDataFile('{ "a": \'\\uEEEE\' }'), { 'a': '\u{eeee}' }); + expect(parseDataFile('{ "a": \'\\uFFFF\' }'), { 'a': '\u{ffff}' }); }); testWidgets('error handling in parseLibraryFile', (WidgetTester tester) async { @@ -87,14 +249,28 @@ void main() { test('import foo+', 'Unexpected character U+002B ("+") inside identifier at line 1 column 11.'); test('import foo.1', 'Expected string but found 1 at line 1 column 12.'); test('import foo.+', 'Unexpected character U+002B ("+") after period at line 1 column 12.'); + test('import foo."', 'Unexpected end of file inside string at line 1 column 12.'); + test('import foo. "', 'Unexpected end of file inside string at line 1 column 13.'); + test('import foo.\'', 'Unexpected end of file inside string at line 1 column 12.'); + test('import foo. \'', 'Unexpected end of file inside string at line 1 column 13.'); test('widget a = b(c: [ ...for args in []: "e" ]);', 'args is a reserved word at line 1 column 30.'); test('widget a = switch 0 { 0: a(), 0: b() };', 'Switch has duplicate cases for key 0 at line 1 column 32.'); test('widget a = switch 0 { default: a(), default: b() };', 'Switch has multiple default cases at line 1 column 44.'); test('widget a = b(c: args)', 'Expected symbol "." but found ) at line 1 column 21.'); test('widget a = b(c: args.=)', 'Unexpected = at line 1 column 22.'); + test('widget a = b(c: args.0', 'Expected symbol ")" but found at line 1 column 22.'); + test('widget a = b(c: args.0 ', 'Expected symbol ")" but found at line 1 column 23.'); + test('widget a = b(c: args.0)', 'Expected symbol ";" but found at line 1 column 23.'); + test('widget a = b(c: args.0f', 'Unexpected character U+0066 ("f") in integer at line 1 column 23.'); + test('widget a = b(c: [ ..', 'Unexpected end of file inside "..." symbol at line 1 column 20.'); + test('widget a = b(c: [ .. ]);', 'Unexpected character U+0020 inside "..." symbol at line 1 column 21.'); test('widget a = b(c: [ ... ]);', 'Expected identifier but found ] at line 1 column 23.'); test('widget a = b(c: [ ...baa ]);', 'Expected for but found baa at line 1 column 25.'); test('widget a = 0;', 'Expected identifier but found 0 at line 1 column 13.'); + test('widget a = a.', 'Expected symbol "(" but found . at line 1 column 13.'); + test('widget a = a. ', 'Expected symbol "(" but found . at line 1 column 14.'); + test('widget a = a.0', 'Expected symbol "(" but found . at line 1 column 14.'); + test('widget a = a.0 ', 'Expected symbol "(" but found . at line 1 column 14.'); }); testWidgets('parseLibraryFile: imports', (WidgetTester tester) async { @@ -131,6 +307,18 @@ void main() { expect(parseLibraryFile('widget a = b(c:data.foo.9);').toString(), 'widget a = b({c: data.foo.9});'); expect(parseLibraryFile('widget a = b(c:state.foo.9);').toString(), 'widget a = b({c: state.foo.9});'); expect(parseLibraryFile('widget a = b(c: [...for d in []: d.9]);').toString(), 'widget a = b({c: [...for loop in []: loop0.9]});'); + expect(parseLibraryFile('widget a = b(c:args.foo.12);').toString(), 'widget a = b({c: args.foo.12});'); + expect(parseLibraryFile('widget a = b(c:data.foo.12);').toString(), 'widget a = b({c: data.foo.12});'); + expect(parseLibraryFile('widget a = b(c:state.foo.12);').toString(), 'widget a = b({c: state.foo.12});'); + expect(parseLibraryFile('widget a = b(c: [...for d in []: d.12]);').toString(), 'widget a = b({c: [...for loop in []: loop0.12]});'); + expect(parseLibraryFile('widget a = b(c:args.foo.98);').toString(), 'widget a = b({c: args.foo.98});'); + expect(parseLibraryFile('widget a = b(c:data.foo.98);').toString(), 'widget a = b({c: data.foo.98});'); + expect(parseLibraryFile('widget a = b(c:state.foo.98);').toString(), 'widget a = b({c: state.foo.98});'); + expect(parseLibraryFile('widget a = b(c: [...for d in []: d.98]);').toString(), 'widget a = b({c: [...for loop in []: loop0.98]});'); + expect(parseLibraryFile('widget a = b(c:args.foo.000);').toString(), 'widget a = b({c: args.foo.0});'); + expect(parseLibraryFile('widget a = b(c:data.foo.000);').toString(), 'widget a = b({c: data.foo.0});'); + expect(parseLibraryFile('widget a = b(c:state.foo.000);').toString(), 'widget a = b({c: state.foo.0});'); + expect(parseLibraryFile('widget a = b(c: [...for d in []: d.000]);').toString(), 'widget a = b({c: [...for loop in []: loop0.0]});'); }); testWidgets('parseLibraryFile: event handlers', (WidgetTester tester) async { diff --git a/packages/rfw/test_coverage/bin/test_coverage.dart b/packages/rfw/test_coverage/bin/test_coverage.dart index 488da7c3f5d0..a1acbac8fbd6 100644 --- a/packages/rfw/test_coverage/bin/test_coverage.dart +++ b/packages/rfw/test_coverage/bin/test_coverage.dart @@ -8,12 +8,20 @@ import 'dart:io'; import 'package:lcov_parser/lcov_parser.dart' as lcov; +// After you run this script, `.../rfw/coverage/lcov.info` will represent the +// latest coverage information for the package. Load that file into your IDE's +// coverage mode to see what lines need coverage. +// In Emacs, that's `M-x coverlay-load-file`, for example. +// (If you're using Emacs, you may need to set the variable `coverlay:base-path` +// first (make sure it has a trailing slash), then load the overlay file, and +// once it is loaded you can call `M-x coverlay-display-stats` to get a summary +// of the files to look at.) + // Please update these targets when you update this package. // Please ensure that test coverage continues to be 100%. -const int targetLines = 2127; -const String targetPercent = '64'; -// TODO(Hixie): Update tests to return coverage to 100%, https://github.com/flutter/packages/pull/2493 -const String lastUpdate = '2021-08-30'; +const int targetLines = 3114; +const String targetPercent = '100'; +const String lastUpdate = '2023-06-29'; Future main(List arguments) async { // This script is mentioned in the README.md file. @@ -36,9 +44,11 @@ Future main(List arguments) async { exit(1); } - if (Platform.environment['CHANNEL'] != 'master') { + if (Platform.environment.containsKey('CHANNEL') && + Platform.environment['CHANNEL'] != 'master' && + Platform.environment['CHANNEL'] != 'main') { print( - 'Tests passed. (Coverage verification skipped; not on master channel.)', + 'Tests passed. (Coverage verification skipped; currently on ${Platform.environment['CHANNEL']} channel.)', ); coverageDirectory.deleteSync(recursive: true); exit(0);