// Copyright (c) 2017, 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.

import 'dart:async';

import 'package:analysis_server/protocol/protocol_generated.dart';
import 'package:analysis_server/src/computer/computer_closingLabels.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../../abstract_context.dart';

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(ClosingLabelsComputerTest);
    defineReflectiveTests(ClosingLabelsComputerTest_UseCFE);
  });
}

@reflectiveTest
class ClosingLabelsComputerTest extends AbstractContextTest {
  String sourcePath;

  setUp() {
    super.setUp();
    sourcePath = resourceProvider.convertPath('/p/lib/source.dart');
  }

  test_adjacentLinesExcluded() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/new Thing(1,
      2)/*2:Thing*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  /// When constructors span many like this, the node's start position is on the first line
  /// of the expression and not where the opening paren is, so this test ensures we
  /// don't end up with lots of unwanted labels on each line here.
  test_chainedConstructorOverManyLines() async {
    String content = """
main() {
  return new thing
    .whatIsSplit
    .acrossManyLines(1, 2);
}
    """;

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 0);
  }

  /// When chaining methods like this, the node's start position is on the first line
  /// of the expression and not where the opening paren is, so this test ensures we
  /// don't end up with lots of unwanted labels on each line here.
  test_chainedMethodsOverManyLines() async {
    String content = """
List<ClosingLabel> compute() {
  _unit.accept(new _DartUnitClosingLabelsComputerVisitor(this));
  return _closingLabelsByEndLine.values
      .where((l) => l.any((cl) => cl.spannedLines >= 2))
      .expand((cls) => cls)
      .map((clwlc) => clwlc.label)
      .toList();
}
    """;

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 0);
  }

  test_constConstructor() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/const Class(
      1,
      2
    )/*2:Class*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_constNamedConstructor() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/const Class.fromThing(
      1,
      2
    )/*2:Class.fromThing*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_knownBadCode1() async {
    // This code crashed during testing when I accidentally inserted a test snippet.
    String content = """
@override
Widget build(BuildContext context) {
  new SliverGrid(
            gridDelegate: gridDelegate,
            delegate: myMethod(<test('', () {
              
            });>[
              "a",
              'b',
              "c",
            ]),
          ),
        ),
      ],
    ),
  );
}
""";

    // TODO(dantup) Results here are currently bad so this test is just checking
    // that we don't crash. Need to confirm what to do here; the bad labels
    // might not be fixed until the code is using the new shared parser.
    // https://github.com/dart-lang/sdk/issues/30370
    await _computeElements(content);
  }

  test_labelsShownForMultipleElements() async {
    String content = """
Widget build(BuildContext context) {
  return /*1*/new Row(
    child: new RaisedButton(),
  )/*1:Row*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 1);
  }

  test_labelsShownForMultipleElements_2() async {
    String content = """
Widget build(BuildContext context) {
  return /*1*/new Row(
    child: /*2*/new RaisedButton(
      onPressed: increment,
    )/*2:RaisedButton*/,
  )/*1:Row*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_listLiterals() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    Widget.createWidget(/*2*/<Widget>[
      1,
      2
    ]/*2:<Widget>[]*/)
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  /// When a line contains the end of a label, we need to ensure we also include any
  /// other labels that end on the same line, even if they are 1-2 lines, otherwise
  /// it isn't obvious which closing bracket goes with the label.
  test_mixedLineSpanning() async {
    String content = """
main() {
    /*1*/new Foo((m) {
      /*2*/new Bar(
          labels,
          /*3*/new Padding(
              new ClosingLabel(expectedStart, expectedLength, expectedLabel))/*3:Padding*/)/*2:Bar*/;
    })/*1:Foo*/;
  }
}
  """;

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 3);
  }

  test_multipleNested() async {
    String content = """
Widget build(BuildContext context) {
  return /*1*/new Row(
    children: /*2*/<Widget>[
      /*3*/new RaisedButton(
        onPressed: increment,
        child: /*4*/new Text(
          'Increment'
        )/*4:Text*/,
      )/*3:RaisedButton*/,
      _makeWidget(
        'a',
        'b'
      ),
      new Text('Count: \$counter'),
    ]/*2:<Widget>[]*/,
  )/*1:Row*/;
}
""";
    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 4);
  }

  test_newConstructor() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/new Class(
      1,
      2
    )/*2:Class*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_newNamedConstructor() async {
    String content = """
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/new Class.fromThing(
      1,
      2
    )/*2:Class.fromThing*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_noLabelsForOneElement() async {
    String content = """
Widget build(BuildContext context) {
  return new Row(
  );
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 0);
  }

  test_NoLabelsFromInterpolatedStrings() async {
    String content = """
void main(HighlightRegionType type, int offset, int length) {
  /*1*/new Wrapper(
    /*2*/new Fail(
        'Not expected to find (offset=\$offset; length=\$length; type=\$type) in\\n'
        '\${regions.join('\\n')}')/*2:Fail*/
      )/*1:Wrapper*/;
}
    """;

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_prefixedConstConstructor() async {
    String content = """
import 'dart:async' as a;
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/const a.Future(
      1,
      2
    )/*2:a.Future*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_prefixedConstNamedConstructor() async {
    String content = """
import 'dart:async' as a;
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/const a.Future.delayed(
      1,
      2
    )/*2:a.Future.delayed*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_prefixedNewConstructor() async {
    String content = """
import 'dart:async' as a;
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/new a.Future(
      1,
      2
    )/*2:a.Future*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_prefixedNewNamedConstructor() async {
    String content = """
import 'dart:async' as a;
void myMethod() {
  return /*1*/new Wrapper(
    /*2*/new a.Future.delayed(
      1,
      2
    )/*2:a.Future.delayed*/
  )/*1:Wrapper*/;
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 2);
  }

  test_sameLineExcluded() async {
    String content = """
void myMethod() {
  return new Thing();
}
""";

    var labels = await _computeElements(content);
    _compareLabels(labels, content, expectedLabelCount: 0);
  }

  /// Compares provided closing labels with expected
  /// labels extracted from the comments in the provided content.
  void _compareLabels(List<ClosingLabel> labels, String content,
      {int expectedLabelCount}) {
    // Require the test pass us the expected count to guard
    // against expected annotations being mistyped and not
    // extracted by the regex.
    expect(labels, hasLength(expectedLabelCount));

    // Find all numeric markers for label starts.
    var regex = new RegExp("/\\*(\\d+)\\*/");
    var expectedLabels = regex.allMatches(content);

    // Check we didn't get more than expected, since the loop below only
    // checks for the presence of matches, not absence.
    expect(labels, hasLength(expectedLabels.length));

    // Go through each marker, find the expected label/end and
    // ensure it's in the results.
    expectedLabels.forEach((m) {
      var i = m.group(1);
      // Find the end marker.
      var endMatch = new RegExp("/\\*$i:(.+?)\\*/").firstMatch(content);

      var expectedStart = m.end;
      var expectedLength = endMatch.start - expectedStart;
      var expectedLabel = endMatch.group(1);

      expect(
          labels,
          contains(
              new ClosingLabel(expectedStart, expectedLength, expectedLabel)));
    });
  }

  Future<List<ClosingLabel>> _computeElements(String sourceContent) async {
    newFile(sourcePath, content: sourceContent);
    ResolveResult result = await driver.getResult(sourcePath);
    DartUnitClosingLabelsComputer computer =
        new DartUnitClosingLabelsComputer(result.lineInfo, result.unit);
    return computer.compute();
  }
}

@reflectiveTest
class ClosingLabelsComputerTest_UseCFE extends ClosingLabelsComputerTest {
  @override
  bool get useCFE => true;

  @failingTest
  @override
  test_knownBadCode1() => super.test_knownBadCode1();
}
