| // Copyright (c) 2014, 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. | |
| // ignore_for_file: prefer_interpolation_to_compose_strings | |
| import 'package:source_span/source_span.dart'; | |
| import 'package:source_span/src/colors.dart' as colors; | |
| import 'package:term_glyph/term_glyph.dart' as glyph; | |
| import 'package:test/test.dart'; | |
| void main() { | |
| late bool oldAscii; | |
| setUpAll(() { | |
| oldAscii = glyph.ascii; | |
| glyph.ascii = true; | |
| }); | |
| tearDownAll(() { | |
| glyph.ascii = oldAscii; | |
| }); | |
| late SourceFile file; | |
| setUp(() { | |
| file = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz bang boom | |
| zip zap zop | |
| '''); | |
| }); | |
| test('points to the span in the source', () { | |
| expect(file.span(4, 7).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| test('gracefully handles a missing source URL', () { | |
| final span = SourceFile.fromString('foo bar baz').span(4, 7); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| group('highlights a point span', () { | |
| test('in the middle of a line', () { | |
| expect(file.location(4).pointSpan().highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^ | |
| '""")); | |
| }); | |
| test('at the beginning of the file', () { | |
| expect(file.location(0).pointSpan().highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^ | |
| '""")); | |
| }); | |
| test('at the beginning of a line', () { | |
| expect(file.location(12).pointSpan().highlight(), equals(""" | |
| , | |
| 2 | whiz bang boom | |
| | ^ | |
| '""")); | |
| }); | |
| test('at the end of a line', () { | |
| expect(file.location(11).pointSpan().highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^ | |
| '""")); | |
| }); | |
| test('at the end of the file', () { | |
| expect(file.location(38).pointSpan().highlight(), equals(""" | |
| , | |
| 3 | zip zap zop | |
| | ^ | |
| '""")); | |
| }); | |
| test('after the end of the file', () { | |
| expect(file.location(39).pointSpan().highlight(), equals(""" | |
| , | |
| 4 | | |
| | ^ | |
| '""")); | |
| }); | |
| test('at the end of the file with no trailing newline', () { | |
| file = SourceFile.fromString('zip zap zop'); | |
| expect(file.location(10).pointSpan().highlight(), equals(""" | |
| , | |
| 1 | zip zap zop | |
| | ^ | |
| '""")); | |
| }); | |
| test('after the end of the file with no trailing newline', () { | |
| file = SourceFile.fromString('zip zap zop'); | |
| expect(file.location(11).pointSpan().highlight(), equals(""" | |
| , | |
| 1 | zip zap zop | |
| | ^ | |
| '""")); | |
| }); | |
| test('in an empty file', () { | |
| expect(SourceFile.fromString('').location(0).pointSpan().highlight(), | |
| equals(""" | |
| , | |
| 1 | | |
| | ^ | |
| '""")); | |
| }); | |
| test('on an empty line', () { | |
| final file = SourceFile.fromString('foo\n\nbar'); | |
| expect(file.location(4).pointSpan().highlight(), equals(""" | |
| , | |
| 2 | | |
| | ^ | |
| '""")); | |
| }); | |
| }); | |
| test('highlights a single-line file without a newline', () { | |
| expect(SourceFile.fromString('foo bar').span(0, 7).highlight(), equals(""" | |
| , | |
| 1 | foo bar | |
| | ^^^^^^^ | |
| '""")); | |
| }); | |
| test('highlights text including a trailing newline', () { | |
| expect(file.span(8, 12).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| test('highlights a single empty line', () { | |
| expect( | |
| SourceFile.fromString('foo\n\nbar').span(4, 5).highlight(), equals(""" | |
| , | |
| 2 | | |
| | ^ | |
| '""")); | |
| }); | |
| test('highlights a trailing newline', () { | |
| expect(file.span(11, 12).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^ | |
| '""")); | |
| }); | |
| group('with a multiline span', () { | |
| test('highlights the middle of the first and last lines', () { | |
| expect(file.span(4, 34).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-------^ | |
| '""")); | |
| }); | |
| test('works when it begins at the end of a line', () { | |
| expect(file.span(11, 34).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,------------^ | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-------^ | |
| '""")); | |
| }); | |
| test('works when it ends at the beginning of a line', () { | |
| expect(file.span(4, 28).highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-^ | |
| '""")); | |
| }); | |
| test('highlights the full first line', () { | |
| expect(file.span(0, 34).highlight(), equals(""" | |
| , | |
| 1 | / foo bar baz | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-------^ | |
| '""")); | |
| }); | |
| test("highlights the full first line even if it's indented", () { | |
| final file = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz bang boom | |
| zip zap zop | |
| '''); | |
| expect(file.span(2, 38).highlight(), equals(""" | |
| , | |
| 1 | / foo bar baz | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-------^ | |
| '""")); | |
| }); | |
| test("highlights the full first line if it's empty", () { | |
| final file = SourceFile.fromString(''' | |
| foo | |
| bar | |
| '''); | |
| expect(file.span(4, 9).highlight(), equals(r""" | |
| , | |
| 2 | / | |
| 3 | \ bar | |
| '""")); | |
| }); | |
| test('highlights the full last line', () { | |
| expect(file.span(4, 27).highlight(), equals(r""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | \ whiz bang boom | |
| '""")); | |
| }); | |
| test('highlights the full last line with no trailing newline', () { | |
| expect(file.span(4, 26).highlight(), equals(r""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | \ whiz bang boom | |
| '""")); | |
| }); | |
| test('highlights the full last line with a trailing Windows newline', () { | |
| final file = SourceFile.fromString(''' | |
| foo bar baz\r | |
| whiz bang boom\r | |
| zip zap zop\r | |
| '''); | |
| expect(file.span(4, 29).highlight(), equals(r""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | \ whiz bang boom | |
| '""")); | |
| }); | |
| test('highlights the full last line at the end of the file', () { | |
| expect(file.span(4, 39).highlight(), equals(r""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| 3 | \ zip zap zop | |
| '""")); | |
| }); | |
| test( | |
| 'highlights the full last line at the end of the file with no trailing ' | |
| 'newline', () { | |
| final file = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz bang boom | |
| zip zap zop'''); | |
| expect(file.span(4, 38).highlight(), equals(r""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| 3 | \ zip zap zop | |
| '""")); | |
| }); | |
| test("highlights the full last line if it's empty", () { | |
| final file = SourceFile.fromString(''' | |
| foo | |
| bar | |
| '''); | |
| expect(file.span(0, 5).highlight(), equals(r""" | |
| , | |
| 1 | / foo | |
| 2 | \ | |
| '""")); | |
| }); | |
| test('highlights multiple empty lines', () { | |
| final file = SourceFile.fromString('foo\n\n\n\nbar'); | |
| expect(file.span(4, 7).highlight(), equals(r""" | |
| , | |
| 2 | / | |
| 3 | | | |
| 4 | \ | |
| '""")); | |
| }); | |
| // Regression test for #32 | |
| test('highlights the end of a line and an empty line', () { | |
| final file = SourceFile.fromString('foo\n\n'); | |
| expect(file.span(3, 5).highlight(), equals(r""" | |
| , | |
| 1 | foo | |
| | ,----^ | |
| 2 | \ | |
| '""")); | |
| }); | |
| }); | |
| group('prints tabs as spaces', () { | |
| group('in a single-line span', () { | |
| test('before the highlighted section', () { | |
| final span = SourceFile.fromString('foo\tbar baz').span(4, 7); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| test('within the highlighted section', () { | |
| final span = SourceFile.fromString('foo bar\tbaz bang').span(4, 11); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz bang | |
| | ^^^^^^^^^^ | |
| '""")); | |
| }); | |
| test('after the highlighted section', () { | |
| final span = SourceFile.fromString('foo bar\tbaz').span(4, 7); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| }); | |
| group('in a multi-line span', () { | |
| test('before the highlighted section', () { | |
| final span = SourceFile.fromString(''' | |
| foo\tbar baz | |
| whiz bang boom | |
| ''').span(4, 21); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,--------^ | |
| 2 | | whiz bang boom | |
| | '---------^ | |
| '""")); | |
| }); | |
| test('within the first highlighted line', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar\tbaz | |
| whiz bang boom | |
| ''').span(4, 21); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| | '---------^ | |
| '""")); | |
| }); | |
| test('at the beginning of the first highlighted line', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar\tbaz | |
| whiz bang boom | |
| ''').span(7, 21); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,--------^ | |
| 2 | | whiz bang boom | |
| | '---------^ | |
| '""")); | |
| }); | |
| test('within a middle highlighted line', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz\tbang boom | |
| zip zap zop | |
| ''').span(4, 34); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| 3 | | zip zap zop | |
| | '-------^ | |
| '""")); | |
| }); | |
| test('within the last highlighted line', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz\tbang boom | |
| ''').span(4, 21); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| | '------------^ | |
| '""")); | |
| }); | |
| test('at the end of the last highlighted line', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz\tbang boom | |
| ''').span(4, 17); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| | '--------^ | |
| '""")); | |
| }); | |
| test('after the highlighted section', () { | |
| final span = SourceFile.fromString(''' | |
| foo bar baz | |
| whiz bang\tboom | |
| ''').span(4, 21); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ,-----^ | |
| 2 | | whiz bang boom | |
| | '---------^ | |
| '""")); | |
| }); | |
| }); | |
| }); | |
| group('supports lines of preceding and following context for a span', () { | |
| test('within a single line', () { | |
| final span = SourceSpanWithContext( | |
| SourceLocation(20, line: 2, column: 5, sourceUrl: 'foo.dart'), | |
| SourceLocation(27, line: 2, column: 12, sourceUrl: 'foo.dart'), | |
| 'foo bar', | |
| 'previous\nlines\n-----foo bar-----\nfollowing line\n'); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | previous | |
| 2 | lines | |
| 3 | -----foo bar----- | |
| | ^^^^^^^ | |
| 4 | following line | |
| '""")); | |
| }); | |
| test('covering a full line', () { | |
| final span = SourceSpanWithContext( | |
| SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'), | |
| SourceLocation(33, line: 3, column: 0, sourceUrl: 'foo.dart'), | |
| '-----foo bar-----\n', | |
| 'previous\nlines\n-----foo bar-----\nfollowing line\n'); | |
| expect(span.highlight(), equals(""" | |
| , | |
| 1 | previous | |
| 2 | lines | |
| 3 | -----foo bar----- | |
| | ^^^^^^^^^^^^^^^^^ | |
| 4 | following line | |
| '""")); | |
| }); | |
| test('covering multiple full lines', () { | |
| final span = SourceSpanWithContext( | |
| SourceLocation(15, line: 2, column: 0, sourceUrl: 'foo.dart'), | |
| SourceLocation(23, line: 4, column: 0, sourceUrl: 'foo.dart'), | |
| 'foo\nbar\n', | |
| 'previous\nlines\nfoo\nbar\nfollowing line\n'); | |
| expect(span.highlight(), equals(r""" | |
| , | |
| 1 | previous | |
| 2 | lines | |
| 3 | / foo | |
| 4 | \ bar | |
| 5 | following line | |
| '""")); | |
| }); | |
| }); | |
| group('colors', () { | |
| test("doesn't colorize if color is false", () { | |
| expect(file.span(4, 7).highlight(color: false), equals(""" | |
| , | |
| 1 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| test('colorizes if color is true', () { | |
| expect(file.span(4, 7).highlight(color: true), equals(''' | |
| ${colors.blue} ,${colors.none} | |
| ${colors.blue}1 |${colors.none} foo ${colors.red}bar${colors.none} baz | |
| ${colors.blue} |${colors.none} ${colors.red} ^^^${colors.none} | |
| ${colors.blue} '${colors.none}''')); | |
| }); | |
| test("uses the given color if it's passed", () { | |
| expect(file.span(4, 7).highlight(color: colors.yellow), equals(''' | |
| ${colors.blue} ,${colors.none} | |
| ${colors.blue}1 |${colors.none} foo ${colors.yellow}bar${colors.none} baz | |
| ${colors.blue} |${colors.none} ${colors.yellow} ^^^${colors.none} | |
| ${colors.blue} '${colors.none}''')); | |
| }); | |
| test('colorizes a multiline span', () { | |
| expect(file.span(4, 34).highlight(color: true), equals(''' | |
| ${colors.blue} ,${colors.none} | |
| ${colors.blue}1 |${colors.none} foo ${colors.red}bar baz${colors.none} | |
| ${colors.blue} |${colors.none} ${colors.red},${colors.none}${colors.red}-----^${colors.none} | |
| ${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none} | |
| ${colors.blue}3 |${colors.none} ${colors.red}|${colors.none} ${colors.red}zip zap${colors.none} zop | |
| ${colors.blue} |${colors.none} ${colors.red}'${colors.none}${colors.red}-------^${colors.none} | |
| ${colors.blue} '${colors.none}''')); | |
| }); | |
| test('colorizes a multiline span that highlights full lines', () { | |
| expect(file.span(0, 39).highlight(color: true), equals(''' | |
| ${colors.blue} ,${colors.none} | |
| ${colors.blue}1 |${colors.none} ${colors.red}/${colors.none} ${colors.red}foo bar baz${colors.none} | |
| ${colors.blue}2 |${colors.none} ${colors.red}|${colors.none} ${colors.red}whiz bang boom${colors.none} | |
| ${colors.blue}3 |${colors.none} ${colors.red}\\${colors.none} ${colors.red}zip zap zop${colors.none} | |
| ${colors.blue} '${colors.none}''')); | |
| }); | |
| }); | |
| group('line numbers have appropriate padding', () { | |
| test('with line number 9', () { | |
| expect( | |
| SourceFile.fromString('\n' * 8 + 'foo bar baz\n') | |
| .span(8, 11) | |
| .highlight(), | |
| equals(""" | |
| , | |
| 9 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| test('with line number 10', () { | |
| expect( | |
| SourceFile.fromString('\n' * 9 + 'foo bar baz\n') | |
| .span(9, 12) | |
| .highlight(), | |
| equals(""" | |
| , | |
| 10 | foo bar baz | |
| | ^^^ | |
| '""")); | |
| }); | |
| }); | |
| } |