// Copyright (c) 2020, 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 'dart:async';
import 'dart:io';

import 'package:path/path.dart' as p;

import 'package:test_descriptor/test_descriptor.dart' as d;

import 'package:test/test.dart';
import 'package:test_core/src/util/exit_codes.dart' as exit_codes;

import '../io.dart';
import 'json_reporter_utils.dart';

void main() {
  test('runs successful tests with a stdout reporter and file reporter', () {
    return _expectReports('''
      test('success 1', () {});
      test('success 2', () {});
      test('success 3', () {});
    ''', '''
      +0: success 1
      +1: success 2
      +2: success 3
      +3: All tests passed!''', [
      [
        suiteJson(0),
        testStartJson(1, 'loading test.dart', groupIDs: []),
        testDoneJson(1, hidden: true),
      ],
      [
        groupJson(2, testCount: 3),
        testStartJson(3, 'success 1', line: 6, column: 7),
        testDoneJson(3),
        testStartJson(4, 'success 2', line: 7, column: 7),
        testDoneJson(4),
        testStartJson(5, 'success 3', line: 8, column: 7),
        testDoneJson(5),
      ]
    ], doneJson());
  });

  test('runs failing tests with a stdout reporter and file reporter', () {
    return _expectReports('''
      test('failure 1', () => throw new TestFailure('oh no'));
      test('failure 2', () => throw new TestFailure('oh no'));
      test('failure 3', () => throw new TestFailure('oh no'));
    ''', '''
      +0: failure 1
      +0 -1: failure 1 [E]
        oh no
        test.dart 6:31  main.<fn>

      +0 -1: failure 2
      +0 -2: failure 2 [E]
        oh no
        test.dart 7:31  main.<fn>

      +0 -2: failure 3
      +0 -3: failure 3 [E]
        oh no
        test.dart 8:31  main.<fn>

      +0 -3: Some tests failed.''', [
      [
        suiteJson(0),
        testStartJson(1, 'loading test.dart', groupIDs: []),
        testDoneJson(1, hidden: true),
      ],
      [
        groupJson(2, testCount: 3),
        testStartJson(3, 'failure 1', line: 6, column: 7),
        errorJson(3, 'oh no', isFailure: true),
        testDoneJson(3, result: 'failure'),
        testStartJson(4, 'failure 2', line: 7, column: 7),
        errorJson(4, 'oh no', isFailure: true),
        testDoneJson(4, result: 'failure'),
        testStartJson(5, 'failure 3', line: 8, column: 7),
        errorJson(5, 'oh no', isFailure: true),
        testDoneJson(5, result: 'failure'),
      ]
    ], doneJson(success: false));
  });

  group('reports an error if --file-reporter', () {
    test('is not in the form <reporter>:<filepath>', () async {
      var test = await runTest(['--file-reporter=json']);
      expect(test.stderr,
          emits(contains('option must be in the form <reporter>:<filepath>')));
      await test.shouldExit(exit_codes.usage);
    });

    test('targets a non-existent reporter', () async {
      var test = await runTest(['--file-reporter=nope:output.txt']);
      expect(
          test.stderr, emits(contains('"nope" is not a supported reporter')));
      await test.shouldExit(exit_codes.usage);
    });
  });
}

Future _expectReports(String tests, String stdoutExpected,
    List<List<dynamic /*Map|Matcher*/ >> jsonFileExpected, Map jsonFileDone,
    {List<String> args}) async {
  await d.file('test.dart', '''
    import 'dart:async';

    import 'package:test/test.dart';

    void main() {
$tests
    }
  ''').create();

  var test = await runTest(['test.dart', ...?args],
      // Write to a file within a dir that doesn't yet exist to verify that the
      // file is created recursively.
      fileReporter: 'json:reports/tests.json');
  await test.shouldExit();

  // ---- stdout reporter verification ----
  var stdoutLines = await test.stdoutStream().toList();

  // Remove excess trailing whitespace and trim off timestamps.
  var actual = stdoutLines.map((line) {
    if (line.startsWith('  ') || line.isEmpty) return line.trimRight();
    return line.trim().replaceFirst(RegExp('^[0-9]{2}:[0-9]{2} '), '');
  }).join('\n');

  // Un-indent the expected string.
  var indentation = stdoutExpected.indexOf(RegExp('[^ ]'));
  stdoutExpected = stdoutExpected.split('\n').map((line) {
    if (line.isEmpty) return line;
    return line.substring(indentation);
  }).join('\n');

  expect(actual, equals(stdoutExpected));

  // ---- file reporter verification ----
  var fileOutputLines =
      File(p.join(d.sandbox, 'reports', 'tests.json')).readAsLinesSync();
  await expectJsonReport(
      fileOutputLines, test.pid, jsonFileExpected, jsonFileDone);
}
