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

// @dart = 2.9

import 'package:kernel/kernel.dart';
import 'package:kernel/class_hierarchy.dart';
import 'package:kernel/core_types.dart';
import 'package:test/test.dart';
import 'class_hierarchy_basic.dart';
import 'dart:io';
import 'dart:math';
import 'self_check_util.dart';

main(List<String> args) {
  runSelfCheck(args, (String filename) {
    testClassHierarchyOnComponent(loadComponentFromBinary(filename));
  });
}

void testClassHierarchyOnComponent(Component component, {bool verbose: false}) {
  BasicClassHierarchy basic = new BasicClassHierarchy(component);
  CoreTypes coreTypes = new CoreTypes(component);
  ClosedWorldClassHierarchy classHierarchy =
      new ClassHierarchy(component, coreTypes);
  int total = classHierarchy.numberOfClasses;
  int progress = 0;
  for (var class1 in classHierarchy.classes) {
    for (var class2 in classHierarchy.classes) {
      bool isSubclass = classHierarchy.isSubclassOf(class1, class2);
      bool isSubtype = classHierarchy.isSubtypeOf(class1, class2);
      var asInstance = classHierarchy.getClassAsInstanceOf(class1, class2);
      if (isSubclass != basic.isSubclassOf(class1, class2)) {
        fail('isSubclassOf(${class1.name}, ${class2.name}) returned '
            '$isSubclass but should be ${!isSubclass}');
      }
      if (isSubtype != basic.isSubtypeOf(class1, class2)) {
        fail('isSubtypeOf(${class1.name}, ${class2.name}) returned '
            '$isSubtype but should be ${!isSubtype}');
      }
      if (asInstance != basic.getClassAsInstanceOf(class1, class2)) {
        fail('asInstanceOf(${class1.name}, ${class2.name}) returned '
            '$asInstance but should be '
            '${basic.getClassAsInstanceOf(class1, class2)}');
      }
    }
    ++progress;
    if (verbose) {
      stdout.write('\rSubclass queries ${100 * progress ~/ total}%');
    }
  }
  Set<Name> names = new Set<Name>();
  for (var classNode in classHierarchy.classes) {
    for (var member in classNode.members) {
      names.add(member.name);
    }
  }
  List<Name> nameList = names.toList();
  progress = 0;
  for (var classNode in classHierarchy.classes) {
    Iterable<Name> candidateNames = <Iterable<Name>>[
      basic.gettersAndCalls[classNode].keys,
      basic.setters[classNode].keys,
      pickRandom(nameList, 100)
    ].expand((x) => x);
    for (Name name in candidateNames) {
      Member expectedGetter =
          basic.getDispatchTarget(classNode, name, setter: false);
      Member expectedSetter =
          basic.getDispatchTarget(classNode, name, setter: true);
      Member actualGetter =
          classHierarchy.getDispatchTarget(classNode, name, setter: false);
      Member actualSetter =
          classHierarchy.getDispatchTarget(classNode, name, setter: true);
      if (actualGetter != expectedGetter) {
        fail('lookupGetter($classNode, $name) returned '
            '$actualGetter but should be $expectedGetter');
      }
      if (actualSetter != expectedSetter) {
        fail('lookupSetter($classNode, $name) returned '
            '$actualSetter but should be $expectedSetter');
      }
    }
    ++progress;
    if (verbose) {
      stdout.write('\rDispatch queries ${100 * progress ~/ total}%');
    }
  }
  progress = 0;
  for (var classNode in classHierarchy.classes) {
    Iterable<Name> candidateNames = [
      basic.interfaceGettersAndCalls[classNode].keys,
      basic.interfaceSetters[classNode].keys,
      pickRandom(nameList, 100)
    ].expand((x) => x);
    for (Name name in candidateNames) {
      Member expectedGetter =
          basic.getInterfaceMember(classNode, name, setter: false);
      Member expectedSetter =
          basic.getInterfaceMember(classNode, name, setter: true);
      Member actualGetter =
          classHierarchy.getInterfaceMember(classNode, name, setter: false);
      Member actualSetter =
          classHierarchy.getInterfaceMember(classNode, name, setter: true);
      if (actualGetter != expectedGetter) {
        fail('getInterfaceMember($classNode, $name) returned '
            '$actualGetter but should be $expectedGetter');
      }
      if (actualSetter != expectedSetter) {
        fail('getInterfaceMember($classNode, $name, setter: true) '
            'returned $actualSetter but should be $expectedSetter');
      }
    }
    ++progress;
    if (verbose) {
      stdout.write('\rInterface queries ${100 * progress ~/ total}%');
    }
  }
  for (var classNode in classHierarchy.classes) {
    String getHash(member, superMember, setter) {
      String eq = setter ? '=' : '';
      return '$member$eq overrides $superMember$eq';
    }

    Set<String> expectedOverrides = new Set<String>();
    basic.forEachOverridePair(classNode, (member, superMember, setter) {
      expectedOverrides.add(getHash(member, superMember, setter));
    });
    Set<String> actualOverrides = new Set<String>();
    classHierarchy.forEachOverridePair(classNode,
        (member, superMember, setter) {
      actualOverrides.add(getHash(member, superMember, setter));
    });
    for (var actual in actualOverrides) {
      if (!expectedOverrides.contains(actual)) {
        fail("forEachOverridePair($classNode) should not report that $actual");
      }
    }
    for (var expected in expectedOverrides) {
      if (!actualOverrides.contains(expected)) {
        fail("forEachOverridePair($classNode) did not report that $expected");
      }
    }
  }
  if (verbose) {
    print('\rProgress 100%. Done.');
  }
}

var random = new Random(12345);

List<T> pickRandom<T>(List<T> items, int n) {
  var result = <T>[];
  for (int i = 0; i < n; ++i) {
    result.add(items[random.nextInt(items.length)]);
  }
  return result;
}
