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

// These tests fork a second VM process that runs the script
// ``tools/full-coverage.dart'' and verifies that the tool
// produces the expeced output.

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

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

final String coverageScript =
    Platform.script.resolve('../../tools/full-coverage.dart').toFilePath();
final String packageRoot = Platform.packageRoot;
final List dartBaseArgs = ['--package-root=${packageRoot}', '--checked',];

// With line numbers starting at 0, the list of hits can be understood as
// follows:
// * -1: No coverage data on this line.
// *  0: No hits on this line.
// *  1: ``Some'' hits on this line.
final coverageTests = [
  {
    'name': 'faculty',
    'program': '''
dummy () {
  for (int i = 0; i < 100; i++) {
    print(i);
  }
}

int fac(int n) {
  int f = 1;
  for (int i = 1; i <= n; i++) {
    f *= i;
  }
  return f;
}

main() {
  if (false) {
    dummy(11);
  } else {
    fac(10);
  }
}
''',
    'expectedHits': [-1, 0, 0, -1, -1, -1, -1, -1, 1, 1, -1, -1, -1, -1, 1, -1,
                     0, -1, 1, -1, -1]
  },{
    'name': 'closures',
    'program': '''
main() {
  foo(bar) {
    bar();
  }

  foo(() {
    print("in closure");
  });
}
''',
    'expectedHits': [1, -1, 1, -1, -1, 1, 1, -1, -1]
  }
];


String prepareEnv() {
  Directory testDir = Directory.systemTemp.createTempSync("coverage-");
  for (var coverageProg in coverageTests) {
    var coverageProgDir = new Directory(
        path.join(testDir.path, coverageProg["name"]))
      ..createSync();
    var f = new File(path.join(coverageProgDir.path,
        "${coverageProg['name']}.dart"));
    f.writeAsStringSync(coverageProg["program"], mode: FileMode.WRITE);
  }
  return testDir.path;
}


destroyEnv(base) => new Directory(base).deleteSync(recursive: true);


generateCoverage(String workingDirectory) {
  for (var coverageProg in coverageTests) {
    var progPath = path.join(workingDirectory, coverageProg['name']);
    var script = path.join(progPath, "${coverageProg['name']}.dart");
    var dartArgs = new List.from(dartBaseArgs)
      ..addAll(['--coverage-dir=${progPath}', '${script}']);
    var result = Process.runSync(Platform.executable, dartArgs);
    if (result.exitCode != 0) {
      print("Coverage generator returned exitCode: ${result.exitCode}.");
      print("stderr:\n${result.stderr}\n");
      expect(result.exitCode, 0);
    }
  }
}


Future<Process> convertCoverage(String programDir, String format) {
  var dartArgs = new List.from(dartBaseArgs)
      ..addAll([
        coverageScript,
        '--package-root=${packageRoot}',
        '--in=${programDir}',
        format
      ]);
  return Process.start(Platform.executable, dartArgs);
}


class PrettyPrintDescriptor {
  var _programPath;
  var _validFormat = new RegExp(r"^\s*\d*\|.*$", multiLine: true);
  var _pattern = new RegExp(r"^\s*(\d+)\|", multiLine: true);

  PrettyPrintDescriptor(this._programPath);

  get sectionStart => _programPath;
  get sectionEnd => '/';
  get coverageParameter => '--pretty-print';

  hitData(line) {
    expect(_validFormat.hasMatch(line), isTrue);
    var match = _pattern.firstMatch(line);
    var result = -1;
    if (match != null) {
      result = (int.parse(match.group(1)) != 0) ? 1 : 0;
    }
    return [result];
  }
}


class LcovDescriptor {
  var _pattern = new RegExp(r"^DA:(\d+),(\d+)$", multiLine: true);
  var _programPath;
  var _line_nr = 0;

  LcovDescriptor(this._programPath);

  get sectionStart => 'SF:${_programPath}';
  get sectionEnd => 'end_of_record';
  get coverageParameter => '--lcov';

  hitData(line) {
    expect(_pattern.hasMatch(line), isTrue);
    var match = _pattern.firstMatch(line);
    // Lcov data starts at line 1, we start at 0.
    var out_line = int.parse(match[1]) - 1;
    var hitCount = int.parse(match[2]);
    var result = [];
    for ( ; _line_nr < out_line; _line_nr++) {
      result.add(-1);
    }
    result.add((hitCount != 0) ? 1 : 0);
    _line_nr++;
    return result;
  }
}


Stream filterHitData(input, descriptor) {
  bool in_program_section = false;
  return input.where((line) {
    if (in_program_section) {
      if (line.startsWith(descriptor.sectionEnd)) {
        in_program_section = false;
        return false;
      }
      return true;
    }
    if (line.startsWith(descriptor.sectionStart)) {
      in_program_section = true;
    }
    return false;
  }).map((line) {
    return descriptor.hitData(line);
  });
}


testCoverage(String programDir, String programPath, descriptor,
             List expectedHitMap) {
  var p = convertCoverage(programDir, descriptor.coverageParameter);
  expect(p.then((process) {
    var hitStream = filterHitData(
        process.stdout.transform(UTF8.decoder)
                      .transform(const LineSplitter()),
        descriptor);
    var hitMap = [];
    var subscription = hitStream.listen((data) {
      // Flatten results.
      data.forEach((e) => hitMap.add(e));
    });
    expect(subscription.asFuture().then((_) {
      hitMap.forEach((e) {
        expect(e, expectedHitMap.removeAt(0));
      });
      // Make sure that there are only lines left that do not contain coverage
      // data.
      expectedHitMap.forEach((e) => expect(e, -1));
    }), completes);
  }), completes);
}


main() {
  String testingDirectory;

  setUp(() {
    testingDirectory = prepareEnv();
  });

  tearDown(() => destroyEnv(testingDirectory));

  test('CoverageTests', () {
    generateCoverage(testingDirectory);

    coverageTests.forEach((cTest) {
      String programDir = path.join(testingDirectory, cTest['name']);
      String programPath = path.join(programDir, "${cTest['name']}.dart");
      testCoverage(programDir, programPath,
                   new LcovDescriptor(programPath),
                   new List.from(cTest['expectedHits']));
      testCoverage(programDir, programPath,
                   new PrettyPrintDescriptor(programPath),
                   new List.from(cTest['expectedHits']));
    });
  });
}
