| // Copyright (c) 2015, the Dart 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. |
| // |
| // @dart=2.7 |
| |
| @TestOn('vm') |
| import 'package:analyzer/dart/analysis/utilities.dart'; |
| import 'package:analyzer/dart/ast/ast.dart'; |
| import 'package:test/test.dart'; |
| import 'package:test_core/src/util/string_literal_iterator.dart'; |
| |
| final _offset = 'final str = '.length; |
| |
| void main() { |
| group('returns simple characters in', () { |
| test('a single simple string', () { |
| var iter = _parse('"abc"'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 1)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + 2)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('c')); |
| expect(iter.offset, equals(_offset + 3)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 4)); |
| }); |
| |
| test('a raw string', () { |
| var iter = _parse('r"abc"'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 1)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 2)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + 3)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('c')); |
| expect(iter.offset, equals(_offset + 4)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 5)); |
| }); |
| |
| test('a multiline string', () { |
| var iter = _parse('"""ab\ncd"""'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 2)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 3)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + 4)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('\n')); |
| expect(iter.offset, equals(_offset + 5)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('c')); |
| expect(iter.offset, equals(_offset + 6)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('d')); |
| expect(iter.offset, equals(_offset + 7)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 8)); |
| }); |
| |
| test('a raw multiline string', () { |
| var iter = _parse('r"""ab\ncd"""'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 3)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 4)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + 5)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('\n')); |
| expect(iter.offset, equals(_offset + 6)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('c')); |
| expect(iter.offset, equals(_offset + 7)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('d')); |
| expect(iter.offset, equals(_offset + 8)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 9)); |
| }); |
| |
| test('adjacent strings', () { |
| var iter = _parse('"ab" r"cd" """ef\ngh"""'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 1)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + 2)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('c')); |
| expect(iter.offset, equals(_offset + 7)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('d')); |
| expect(iter.offset, equals(_offset + 8)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('e')); |
| expect(iter.offset, equals(_offset + 14)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('f')); |
| expect(iter.offset, equals(_offset + 15)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('\n')); |
| expect(iter.offset, equals(_offset + 16)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('g')); |
| expect(iter.offset, equals(_offset + 17)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('h')); |
| expect(iter.offset, equals(_offset + 18)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + 19)); |
| }); |
| }); |
| |
| group('parses an escape sequence for', () { |
| test('a newline', () => _expectEscape(r'\n', '\n')); |
| test('a carriage return', () => _expectEscape(r'\r', '\r')); |
| test('a form feed', () => _expectEscape(r'\f', '\f')); |
| test('a backspace', () => _expectEscape(r'\b', '\b')); |
| test('a tab', () => _expectEscape(r'\t', '\t')); |
| test('a vertical tab', () => _expectEscape(r'\v', '\v')); |
| test('a quote', () => _expectEscape(r'\"', '"')); |
| test('a backslash', () => _expectEscape(r'\\', '\\')); |
| |
| test('a hex character', () { |
| _expectEscape(r'\x62', 'b'); |
| _expectEscape(r'\x7A', 'z'); |
| _expectEscape(r'\x7a', 'z'); |
| }); |
| |
| test('a fixed-length unicode character', |
| () => _expectEscape(r'\u0062', 'b')); |
| |
| test('a short variable-length unicode character', |
| () => _expectEscape(r'\u{62}', 'b')); |
| |
| test('a long variable-length unicode character', |
| () => _expectEscape(r'\u{000062}', 'b')); |
| }); |
| |
| group('throws an ArgumentError for', () { |
| test('interpolation', () { |
| expect(() => _parse(r'"$foo"'), throwsArgumentError); |
| }); |
| |
| test('interpolation in an adjacent string', () { |
| expect(() => _parse(r'"foo" "$bar" "baz"'), throwsArgumentError); |
| }); |
| }); |
| } |
| |
| /// Asserts that [escape] is parsed as [value]. |
| void _expectEscape(String escape, String value) { |
| var iter = _parse('"a${escape}b"'); |
| |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('a')); |
| expect(iter.offset, equals(_offset + 1)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune(value)); |
| expect(iter.offset, equals(_offset + 2)); |
| |
| expect(iter.moveNext(), isTrue); |
| expect(iter.current, _isRune('b')); |
| expect(iter.offset, equals(_offset + escape.length + 2)); |
| |
| expect(iter.moveNext(), isFalse); |
| expect(iter.current, isNull); |
| expect(iter.offset, equals(_offset + escape.length + 3)); |
| } |
| |
| /// Returns a matcher that asserts that the given rune is the rune for [char]. |
| Matcher _isRune(String char) { |
| return predicate((rune) { |
| return rune is int && String.fromCharCode(rune) == char; |
| }, 'is the rune "$char"'); |
| } |
| |
| /// Parses [dart], which should be a string literal, into a |
| /// [StringLiteralIterator]. |
| StringLiteralIterator _parse(String dart) { |
| var declaration = parseString(content: 'final str = $dart;') |
| .unit |
| .declarations |
| .single as TopLevelVariableDeclaration; |
| var literal = declaration.variables.variables.single.initializer; |
| return StringLiteralIterator(literal as StringLiteral); |
| } |