// 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/types/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.strongMode,
    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;
    ClosedWorld 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);
}
