// Copyright (c) 2018, 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 the enqueuers are not dependent upon in which order impacts are
// applied.

import 'package:async_helper/async_helper.dart';
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/common_elements.dart';
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/names.dart';
import 'package:compiler/src/elements/types.dart';
import 'package:compiler/src/enqueue.dart';
import 'package:compiler/src/inferrer/typemasks/masks.dart';
import 'package:compiler/src/universe/call_structure.dart';
import 'package:compiler/src/universe/selector.dart';
import 'package:compiler/src/universe/world_impact.dart';
import 'package:compiler/src/universe/use.dart';
import 'package:compiler/src/universe/world_builder.dart';
import 'package:compiler/src/world.dart';
import 'package:expect/expect.dart';
import '../memory_compiler.dart';

class Test {
  final String name;
  final String code;
  final List<Impact> impacts;
  final Map<String, List<String>> expectedLiveMap;

  const Test({this.name, this.code, this.impacts, this.expectedLiveMap});

  Map<String, List<String>> get expectedLiveResolutionMap {
    Map<String, List<String>> map = {};
    expectedLiveMap.forEach((String clsName, List<String> memberNames) {
      for (String memberName in memberNames) {
        if (memberName.startsWith('?')) {
          memberName = memberName.substring(1);
        }
        map.putIfAbsent(clsName, () => []).add(memberName);
      }
    });
    return map;
  }

  Map<String, List<String>> get expectedLiveCodegenMap {
    Map<String, List<String>> map = {};
    expectedLiveMap.forEach((String clsName, List<String> memberNames) {
      for (String memberName in memberNames) {
        if (memberName.startsWith('?')) {
          // Skip for codegen
          continue;
        }
        map.putIfAbsent(clsName, () => []).add(memberName);
      }
    });
    return map;
  }
}

enum ImpactKind { instantiate, invoke }

class Impact {
  final ImpactKind kind;
  final String clsName;
  final String memberName;

  const Impact.instantiate(this.clsName, [this.memberName = ''])
      : this.kind = ImpactKind.instantiate;
  const Impact.invoke(this.clsName, this.memberName)
      : this.kind = ImpactKind.invoke;

  String toString() =>
      'Impact(kind=$kind,clsName=$clsName,memberName=$memberName)';
}

const List<Test> tests = const <Test>[
  const Test(name: 'Instantiate class', code: '''
class A {
  void method() {}
}
''', impacts: const [
    const Impact.instantiate('A'),
    const Impact.invoke('A', 'method'),
  ], expectedLiveMap: const {
    'A': const ['', 'method'],
  }),
  const Test(name: 'Instantiate subclass', code: '''
class A {
  void method() {}
}
class B extends A {
}
''', impacts: const [
    const Impact.instantiate('B'),
    const Impact.invoke('B', 'method'),
  ], expectedLiveMap: const {
    'A': const ['?', 'method'],
    'B': const [''],
  }),
  const Test(name: 'Instantiate superclass/subclass', code: '''
class A {
  void method() {}
}
class B extends A {
}
''', impacts: const [
    const Impact.instantiate('A'),
    const Impact.instantiate('B'),
    const Impact.invoke('B', 'method'),
  ], expectedLiveMap: const {
    'A': const ['', 'method'],
    'B': const [''],
  }),
];

main() {
  asyncTest(() async {
    for (Test test in tests) {
      await runTest(test);
    }
  });
}

runTest(Test test) async {
  print('====================================================================');
  print('Running test ${test.name}');
  for (List<Impact> permutation in permutations(test.impacts)) {
    print('------------------------------------------------------------------');
    print('Permutation: $permutation');
    await runTestPermutation(test, permutation);
  }
}

Iterable<List<Impact>> permutations(List<Impact> impacts) sync* {
  int length = impacts.length;
  if (length <= 1) {
    yield impacts;
  } else {
    for (int index = 0; index < length; index++) {
      Impact head = impacts[index];
      List<Impact> tail = new List<Impact>.from(impacts)..removeAt(index);
      for (List<Impact> permutation in permutations(tail)) {
        yield [head]..addAll(permutation);
      }
    }
  }
}

runTestPermutation(Test test, List<Impact> impacts) async {
  Compiler compiler = compilerFor(memorySourceFiles: {
    'main.dart': '''
${test.code}
main() {}
'''
  }, options: [
    Flags.disableInlining,
  ]);

  void checkInvariant(
      Enqueuer enqueuer, ElementEnvironment elementEnvironment) {
    for (MemberEntity member
        in compiler.enqueuer.resolution.processedEntities) {
      Expect.isTrue(
          member == elementEnvironment.mainFunction ||
              member.library != elementEnvironment.mainLibrary,
          "Unexpected member $member in ${enqueuer}.");
    }
  }

  void instantiate(
      Enqueuer enqueuer, ElementEnvironment elementEnvironment, String name) {
    ClassEntity cls =
        elementEnvironment.lookupClass(elementEnvironment.mainLibrary, name);
    ConstructorEntity constructor =
        elementEnvironment.lookupConstructor(cls, '');
    InterfaceType type = elementEnvironment.getRawType(cls);
    WorldImpact impact = new WorldImpactBuilderImpl()
      ..registerStaticUse(new StaticUse.typedConstructorInvoke(
          constructor, constructor.parameterStructure.callStructure, type));
    enqueuer.applyImpact(impact);
  }

  void invoke(
      Enqueuer enqueuer,
      ElementEnvironment elementEnvironment,
      String className,
      String methodName,
      Object Function(ClassEntity cls) createConstraint) {
    ClassEntity cls = elementEnvironment.lookupClass(
        elementEnvironment.mainLibrary, className);
    Selector selector = new Selector.call(
        new Name(methodName, elementEnvironment.mainLibrary),
        CallStructure.NO_ARGS);
    WorldImpact impact = new WorldImpactBuilderImpl()
      ..registerDynamicUse(new ConstrainedDynamicUse(
          selector, createConstraint(cls), const <DartType>[]));
    enqueuer.applyImpact(impact);
  }

  void applyImpact(Enqueuer enqueuer, ElementEnvironment elementEnvironment,
      Impact impact, Object Function(ClassEntity cls) createConstraint) {
    switch (impact.kind) {
      case ImpactKind.instantiate:
        instantiate(enqueuer, elementEnvironment, impact.clsName);
        break;
      case ImpactKind.invoke:
        invoke(enqueuer, elementEnvironment, impact.clsName, impact.memberName,
            createConstraint);
        break;
    }
  }

  void checkLiveMembers(
      Enqueuer enqueuer,
      ElementEnvironment elementEnvironment,
      Map<String, List<String>> expectedLiveMap) {
    Map<String, List<String>> actualLiveMap = {};
    for (MemberEntity member in enqueuer.processedEntities) {
      if (member != elementEnvironment.mainFunction &&
          member.library == elementEnvironment.mainLibrary) {
        actualLiveMap
            .putIfAbsent(member.enclosingClass.name, () => [])
            .add(member.name);
      }
    }

    Expect.setEquals(
        expectedLiveMap.keys,
        actualLiveMap.keys,
        "Unexpected live classes in $enqueuer\n "
        "Expected: ${expectedLiveMap.keys}\n "
        "Actual  : ${actualLiveMap.keys}");
    expectedLiveMap.forEach((String clsName, List<String> expectedMembers) {
      List<String> actualMembers = actualLiveMap[clsName];
      Expect.setEquals(
          expectedMembers,
          actualMembers,
          "Unexpected live members for $clsName in $enqueuer\n "
          "Expected: $expectedMembers\n "
          "Actual  : $actualMembers");
    });
  }

  compiler.onResolutionQueueEmptyForTesting = () {
    Enqueuer enqueuer = compiler.enqueuer.resolution;
    ElementEnvironment elementEnvironment =
        compiler.frontendStrategy.elementEnvironment;
    checkInvariant(enqueuer, elementEnvironment);

    Object createConstraint(ClassEntity cls) {
      return new StrongModeConstraint(cls);
    }

    for (Impact impact in impacts) {
      applyImpact(enqueuer, elementEnvironment, impact, createConstraint);
    }
  };
  compiler.onCodegenQueueEmptyForTesting = () {
    Enqueuer enqueuer = compiler.enqueuer.codegenEnqueuerForTesting;
    JClosedWorld closedWorld = compiler.backendClosedWorldForTesting;
    ElementEnvironment elementEnvironment =
        compiler.backendClosedWorldForTesting.elementEnvironment;
    checkInvariant(enqueuer, elementEnvironment);

    Object createConstraint(ClassEntity cls) {
      return new TypeMask.subtype(cls, closedWorld);
    }

    for (Impact impact in impacts) {
      applyImpact(enqueuer, elementEnvironment, impact, createConstraint);
    }
  };

  await compiler.run(Uri.parse('memory:main.dart'));

  checkLiveMembers(
      compiler.enqueuer.resolution,
      compiler.frontendStrategy.elementEnvironment,
      test.expectedLiveResolutionMap);

  checkLiveMembers(
      compiler.enqueuer.codegenEnqueuerForTesting,
      compiler.backendClosedWorldForTesting.elementEnvironment,
      test.expectedLiveCodegenMap);
}
