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

// Test that dart2js produces the expected static type warnings to ensures that
// the analyzer and dart2js agrees on the tests.

import 'dart:async';
import 'dart:io';
import 'package:expect/expect.dart';
import 'package:async_helper/async_helper.dart';
import 'memory_compiler.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/io/source_file.dart';
import 'package:compiler/src/source_file_provider.dart';
import 'package:compiler/src/util/uri_extras.dart';
import 'dart:convert';

void checkWarnings(Map<String, dynamic> tests, [List<String> arguments]) {
  bool isWindows = Platform.isWindows;
  Uri script = currentDirectory.resolveUri(Platform.script);
  bool warningsMismatch = false;
  bool verbose = arguments != null && arguments.contains('-v');
  asyncTest(() => Future.forEach(tests.keys, (String test) async {
    Uri uri = script.resolve('../../$test');
    String source = UTF8.decode(readAll(uriPathToNative(uri.path)));
    SourceFile file = new StringSourceFile(
        uri, relativize(currentDirectory, uri, isWindows), source);
    Map<int,String> expectedWarnings = {};
    int lineNo = 0;
    for (String line in source.split('\n')) {
      if (line.contains('///') &&
          (line.contains('static type warning') ||
           line.contains('static warning'))) {
        expectedWarnings[lineNo] = line;
      }
      lineNo++;
    }
    Set<int> unseenWarnings = new Set<int>.from(expectedWarnings.keys);
    DiagnosticCollector collector = new DiagnosticCollector();
    await runCompiler(
        entryPoint: uri,
        diagnosticHandler: collector,
        options: [Flags.analyzeOnly],
        showDiagnostics: verbose);
    Map<String, List<int>> statusMap = tests[test];
    // Line numbers with known unexpected warnings.
    List<int> unexpectedStatus = [];
    if (statusMap != null && statusMap.containsKey('unexpected')) {
      unexpectedStatus = statusMap['unexpected'];
    }
    // Line numbers with known missing warnings.
    List<int> missingStatus = [];
    if (statusMap != null && statusMap.containsKey('missing')) {
      missingStatus = statusMap['missing'];
    }
    for (CollectedMessage message in collector.warnings) {
      Expect.equals(uri, message.uri);
      int lineNo = file.getLine(message.begin);
      if (expectedWarnings.containsKey(lineNo)) {
        unseenWarnings.remove(lineNo);
      } else if (!unexpectedStatus.contains(lineNo+1)) {
        warningsMismatch = true;
        print(file.getLocationMessage(
            'Unexpected warning: ${message.message}',
            message.begin, message.end));
      }
    }
    if (!unseenWarnings.isEmpty) {
      for (int lineNo in unseenWarnings) {
        if (!missingStatus.contains(lineNo+1)) {
          warningsMismatch = true;
          String line = expectedWarnings[lineNo];
          print('$uri [${lineNo+1}]: Missing static type warning.');
          print(line);
        }
      }
    }
  }).then((_) {
    Expect.isFalse(warningsMismatch);
  }));
}
