// Copyright (c) 2016, 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.md file.

library testing.chain;

import 'dart:async' show Future, Stream;

import 'dart:convert' show json, JsonEncoder;

import 'dart:io' show Directory, File, FileSystemEntity, exitCode;

import 'suite.dart' show Suite;

import '../testing.dart' show FileBasedTestDescription, TestDescription;

import 'test_dart/status_file_parser.dart'
    show ReadTestExpectations, TestExpectations;

import 'zone_helper.dart' show runGuarded;

import 'error_handling.dart' show withErrorHandling;

import 'log.dart'
    show
        logMessage,
        logStepComplete,
        logStepStart,
        logSuiteComplete,
        logTestComplete,
        logUnexpectedResult,
        splitLines;

import 'multitest.dart' show MultitestTransformer, isError;

import 'expectation.dart' show Expectation, ExpectationSet;

typedef Future<ChainContext> CreateContext(
    Chain suite, Map<String, String> environment);

/// A test suite for tool chains, for example, a compiler.
class Chain extends Suite {
  final Uri source;

  final Uri uri;

  final List<RegExp> pattern;

  final List<RegExp> exclude;

  final bool processMultitests;

  Chain(String name, String kind, this.source, this.uri, Uri statusFile,
      this.pattern, this.exclude, this.processMultitests)
      : super(name, kind, statusFile);

  factory Chain.fromJsonMap(Uri base, Map json, String name, String kind) {
    Uri source = base.resolve(json["source"]);
    String path = json["path"];
    if (!path.endsWith("/")) {
      path += "/";
    }
    Uri uri = base.resolve(path);
    Uri statusFile = base.resolve(json["status"]);
    List<RegExp> pattern =
        json["pattern"].map<RegExp>((p) => new RegExp(p)).toList();
    List<RegExp> exclude =
        json["exclude"].map<RegExp>((p) => new RegExp(p)).toList();
    bool processMultitests = json["process-multitests"] ?? false;
    return new Chain(name, kind, source, uri, statusFile, pattern, exclude,
        processMultitests);
  }

  void writeImportOn(StringSink sink) {
    sink.write("import '");
    sink.write(source);
    sink.write("' as ");
    sink.write(name);
    sink.writeln(";");
  }

  void writeClosureOn(StringSink sink) {
    sink.write("await runChain(");
    sink.write(name);
    sink.writeln(".createContext, environment, selectors, r'''");
    const String jsonExtraIndent = "    ";
    sink.write(jsonExtraIndent);
    sink.writeAll(splitLines(new JsonEncoder.withIndent("  ").convert(this)),
        jsonExtraIndent);
    sink.writeln("''');");
  }

  Map toJson() {
    return {
      "name": name,
      "kind": kind,
      "source": "$source",
      "path": "$uri",
      "status": "$statusFile",
      "process-multitests": processMultitests,
      "pattern": []..addAll(pattern.map((RegExp r) => r.pattern)),
      "exclude": []..addAll(exclude.map((RegExp r) => r.pattern)),
    };
  }
}

abstract class ChainContext {
  const ChainContext();

  List<Step> get steps;

  ExpectationSet get expectationSet => ExpectationSet.Default;

  Future<Null> run(Chain suite, Set<String> selectors) async {
    List<String> partialSelectors = selectors
        .where((s) => s.endsWith('...'))
        .map((s) => s.substring(0, s.length - 3))
        .toList();
    TestExpectations expectations = await ReadTestExpectations(
        <String>[suite.statusFile.toFilePath()], {}, expectationSet);
    Stream<TestDescription> stream = list(suite);
    if (suite.processMultitests) {
      stream = stream.transform(new MultitestTransformer());
    }
    List<TestDescription> descriptions = await stream.toList();
    descriptions.sort();
    Map<TestDescription, Result> unexpectedResults =
        <TestDescription, Result>{};
    Map<TestDescription, Set<Expectation>> unexpectedOutcomes =
        <TestDescription, Set<Expectation>>{};
    int completed = 0;
    List<Future> futures = <Future>[];
    for (TestDescription description in descriptions) {
      String selector = "${suite.name}/${description.shortName}";
      if (selectors.isNotEmpty &&
          !selectors.contains(selector) &&
          !selectors.contains(suite.name) &&
          !partialSelectors.any((s) => selector.startsWith(s))) {
        continue;
      }
      final Set<Expectation> expectedOutcomes =
          expectations.expectations(description.shortName);
      final StringBuffer sb = new StringBuffer();
      final Step lastStep = steps.isNotEmpty ? steps.last : null;
      final Iterator<Step> iterator = steps.iterator;

      Result result;
      // Records the outcome of the last step that was run.
      Step lastStepRun;

      /// Performs one step of [iterator].
      ///
      /// If `step.isAsync` is true, the corresponding step is said to be
      /// asynchronous.
      ///
      /// If a step is asynchronous the future returned from this function will
      /// complete after the first asynchronous step is scheduled.  This
      /// allows us to start processing the next test while an external process
      /// completes as steps can be interleaved. To ensure all steps are
      /// completed, wait for [futures].
      ///
      /// Otherwise, the future returned will complete when all steps are
      /// completed. This ensures that tests are run in sequence without
      /// interleaving steps.
      Future doStep(dynamic input) async {
        Future future;
        bool isAsync = false;
        if (iterator.moveNext()) {
          Step step = iterator.current;
          lastStepRun = step;
          isAsync = step.isAsync;
          logStepStart(completed, unexpectedResults.length, descriptions.length,
              suite, description, step);
          // TODO(ahe): It's important to share the zone error reporting zone
          // between all the tasks. Otherwise, if a future completes with an
          // error in one zone, and gets stored, it becomes an uncaught error
          // in other zones (this happened in createPlatform).
          future = runGuarded(() async {
            try {
              return await step.run(input, this);
            } catch (error, trace) {
              return step.unhandledError(error, trace);
            }
          }, printLineOnStdout: sb.writeln);
        } else {
          future = new Future.value(null);
        }
        future = future.then((_currentResult) async {
          Result currentResult = _currentResult;
          if (currentResult != null) {
            logStepComplete(completed, unexpectedResults.length,
                descriptions.length, suite, description, lastStepRun);
            result = currentResult;
            if (currentResult.outcome == Expectation.Pass) {
              // The input to the next step is the output of this step.
              return doStep(result.output);
            }
          }
          await cleanUp(description, result);
          result =
              processTestResult(description, result, lastStep == lastStepRun);
          if (!expectedOutcomes.contains(result.outcome) &&
              !expectedOutcomes.contains(result.outcome.canonical)) {
            result.addLog("$sb");
            unexpectedResults[description] = result;
            unexpectedOutcomes[description] = expectedOutcomes;
            logUnexpectedResult(suite, description, result, expectedOutcomes);
            exitCode = 1;
          } else {
            logMessage(sb);
          }
          logTestComplete(++completed, unexpectedResults.length,
              descriptions.length, suite, description);
        });
        if (isAsync) {
          futures.add(future);
          return null;
        } else {
          return future;
        }
      }

      // The input of the first step is [description].
      await doStep(description);
    }
    await Future.wait(futures);
    logSuiteComplete();
    if (unexpectedResults.isNotEmpty) {
      unexpectedResults.forEach((TestDescription description, Result result) {
        logUnexpectedResult(
            suite, description, result, unexpectedOutcomes[description]);
      });
      print("${unexpectedResults.length} failed:");
      unexpectedResults.forEach((TestDescription description, Result result) {
        print("${suite.name}/${description.shortName}: ${result.outcome}");
      });
    }
  }

  Stream<TestDescription> list(Chain suite) async* {
    Directory testRoot = new Directory.fromUri(suite.uri);
    if (await testRoot.exists()) {
      Stream<FileSystemEntity> files =
          testRoot.list(recursive: true, followLinks: false);
      await for (FileSystemEntity entity in files) {
        if (entity is! File) continue;
        String path = entity.uri.path;
        if (suite.exclude.any((RegExp r) => path.contains(r))) continue;
        if (suite.pattern.any((RegExp r) => path.contains(r))) {
          yield new FileBasedTestDescription(suite.uri, entity);
        }
      }
    } else {
      throw "${suite.uri} isn't a directory";
    }
  }

  Result processTestResult(
      TestDescription description, Result result, bool last) {
    if (description is FileBasedTestDescription &&
        description.multitestExpectations != null) {
      if (isError(description.multitestExpectations)) {
        result =
            toNegativeTestResult(result, description.multitestExpectations);
      }
    } else if (last && description.shortName.endsWith("negative_test")) {
      if (result.outcome == Expectation.Pass) {
        result.addLog("Negative test didn't report an error.\n");
      } else if (result.outcome == Expectation.Fail) {
        result.addLog("Negative test reported an error as expeceted.\n");
      }
      result = toNegativeTestResult(result);
    }
    return result;
  }

  Result toNegativeTestResult(Result result, [Set<String> expectations]) {
    Expectation outcome = result.outcome;
    if (outcome == Expectation.Pass) {
      if (expectations == null) {
        outcome = Expectation.Fail;
      } else if (expectations.contains("compile-time error")) {
        outcome = expectationSet["MissingCompileTimeError"];
      } else if (expectations.contains("runtime error") ||
          expectations.contains("dynamic type error")) {
        outcome = expectationSet["MissingRuntimeError"];
      } else {
        outcome = Expectation.Fail;
      }
    } else if (outcome == Expectation.Fail) {
      outcome = Expectation.Pass;
    }
    return result.copyWithOutcome(outcome);
  }

  void cleanUp(TestDescription description, Result result) {}
}

abstract class Step<I, O, C extends ChainContext> {
  const Step();

  String get name;

  bool get isAsync => false;

  bool get isCompiler => false;

  bool get isRuntime => false;

  Future<Result<O>> run(I input, C context);

  Result<O> unhandledError(error, StackTrace trace) {
    return new Result<O>.crash(error, trace);
  }

  Result<O> pass(O output) => new Result<O>.pass(output);

  Result<O> crash(error, StackTrace trace) => new Result<O>.crash(error, trace);

  Result<O> fail(O output, [error, StackTrace trace]) {
    return new Result<O>.fail(output, error, trace);
  }
}

class Result<O> {
  final O output;

  final Expectation outcome;

  final error;

  final StackTrace trace;

  final List<String> logs = <String>[];

  Result(this.output, this.outcome, this.error, this.trace);

  Result.pass(O output) : this(output, Expectation.Pass, null, null);

  Result.crash(error, StackTrace trace)
      : this(null, Expectation.Crash, error, trace);

  Result.fail(O output, [error, StackTrace trace])
      : this(output, Expectation.Fail, error, trace);

  String get log => logs.join();

  void addLog(String log) {
    logs.add(log);
  }

  Result<O> copyWithOutcome(Expectation outcome) {
    return new Result<O>(output, outcome, error, trace)..logs.addAll(logs);
  }
}

/// This is called from generated code.
Future<Null> runChain(CreateContext f, Map<String, String> environment,
    Set<String> selectors, String jsonText) {
  return withErrorHandling(() async {
    Chain suite = new Suite.fromJsonMap(Uri.base, json.decode(jsonText));
    print("Running ${suite.name}");
    ChainContext context = await f(suite, environment);
    return context.run(suite, selectors);
  });
}
