// 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.

import 'dart:async';
import 'dart:io';

import 'package:package_resolver/package_resolver.dart';
import 'package:path/path.dart' as p;
import 'package:test_descriptor/test_descriptor.dart' as d;
import 'package:test_process/test_process.dart';

import 'package:test/test.dart';

/// The path to the root directory of the `test` package.
final Future<String> packageDir = PackageResolver.current.packagePath('test');

/// The path to the `pub` executable in the current Dart SDK.
final _pubPath = p.absolute(p.join(p.dirname(Platform.resolvedExecutable),
    Platform.isWindows ? 'pub.bat' : 'pub'));

/// The platform-specific message emitted when a nonexistent file is loaded.
final String noSuchFileMessage = Platform.isWindows
    ? 'The system cannot find the file specified.'
    : 'No such file or directory';

/// A regular expression that matches the output of "pub serve".
final _servingRegExp =
    RegExp(r'^Serving myapp [a-z]+ on http://localhost:(\d+)$');

/// An operating system name that's different than the current operating system.
final otherOS = Platform.isWindows ? 'mac-os' : 'windows';

/// The port of a pub serve instance run via [runPubServe].
///
/// This is only set after [runPubServe] is called.
int get pubServePort => _pubServePort;
int _pubServePort;

/// Expects that the entire stdout stream of [test] equals [expected].
void expectStdoutEquals(TestProcess test, String expected) =>
    _expectStreamEquals(test.stdoutStream(), expected);

/// Expects that the entire stderr stream of [test] equals [expected].
void expectStderrEquals(TestProcess test, String expected) =>
    _expectStreamEquals(test.stderrStream(), expected);

/// Expects that the entirety of the line stream [stream] equals [expected].
void _expectStreamEquals(Stream<String> stream, String expected) {
  expect((() async {
    var lines = await stream.toList();
    expect(lines.join('\n').trim(), equals(expected.trim()));
  })(), completes);
}

/// Returns a [StreamMatcher] that asserts that the stream emits strings
/// containing each string in [strings] in order.
///
/// This expects each string in [strings] to match a different string in the
/// stream.
StreamMatcher containsInOrder(Iterable<String> strings) =>
    emitsInOrder(strings.map((string) => emitsThrough(contains(string))));

/// Runs the test executable with the package root set properly.
Future<TestProcess> runTest(Iterable<String> args,
    {String reporter,
    String fileReporter,
    int concurrency,
    Map<String, String> environment,
    bool forwardStdio = false}) async {
  concurrency ??= 1;

  var allArgs = [
    p.absolute(p.join(await packageDir, 'bin/test.dart')),
    '--concurrency=$concurrency',
    if (reporter != null) '--reporter=$reporter',
    if (fileReporter != null) '--file-reporter=$fileReporter',
    ...?args,
  ];

  environment ??= {};
  environment.putIfAbsent('_DART_TEST_TESTING', () => 'true');

  return await runDart(allArgs,
      environment: environment,
      description: 'dart bin/test.dart',
      forwardStdio: forwardStdio);
}

/// Runs Dart.
Future<TestProcess> runDart(Iterable<String> args,
    {Map<String, String> environment,
    String description,
    bool forwardStdio = false}) async {
  var allArgs = <String>[
    ...Platform.executableArguments.where((arg) =>
        !arg.startsWith('--package-root=') && !arg.startsWith('--packages=')),
    await PackageResolver.current.processArgument,
    ...args
  ];

  return await TestProcess.start(
      p.absolute(Platform.resolvedExecutable), allArgs,
      workingDirectory: d.sandbox,
      environment: environment,
      description: description,
      forwardStdio: forwardStdio);
}

/// Runs Pub.
Future<TestProcess> runPub(Iterable<String> args,
    {Map<String, String> environment}) {
  return TestProcess.start(_pubPath, args,
      workingDirectory: d.sandbox,
      environment: environment,
      description: 'pub ${args.first}');
}

/// Runs "pub serve".
///
/// This returns assigns [_pubServePort] to a future that will complete to the
/// port of the "pub serve" instance.
Future<TestProcess> runPubServe(
    {Iterable<String> args,
    String workingDirectory,
    Map<String, String> environment}) async {
  var allArgs = ['serve', '--port', '0'];
  if (args != null) allArgs.addAll(args);

  var pub = await runPub(allArgs, environment: environment);

  Match match;
  while (match == null) {
    match = _servingRegExp.firstMatch(await pub.stdout.next);
  }
  _pubServePort = int.parse(match[1]);

  return pub;
}
