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

import 'package:test_reflective_loader/test_reflective_loader.dart';

import 'driver_resolution.dart';
import 'resolution.dart';
import 'task_resolution.dart';

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(ClassAliasDriverResolutionTest);
    defineReflectiveTests(ClassAliasTaskResolutionTest);
  });
}

@reflectiveTest
class ClassAliasDriverResolutionTest extends DriverResolutionTest
    with ClassAliasResolutionMixin {}

abstract class ClassAliasResolutionMixin implements ResolutionTest {
  test_defaultConstructor() async {
    addTestFile(r'''
class A {}
class M {}
class X = A with M;
''');
    await resolveTestFile();
    assertNoTestErrors();
    assertConstructors(findElement.class_('X'), ['X() → X']);
  }

  test_element() async {
    addTestFile(r'''
class A {}
class B {}
class C {}

class X = A with B implements C;
''');
    await resolveTestFile();
    assertNoTestErrors();

    var x = findElement.class_('X');

    assertTypeName(findNode.typeName('A with'), findElement.class_('A'), 'A');
    assertTypeName(findNode.typeName('B impl'), findElement.class_('B'), 'B');
    assertTypeName(findNode.typeName('C;'), findElement.class_('C'), 'C');

    assertElementTypeString(x.supertype, 'A');
    assertElementTypeStrings(x.mixins, ['B']);
    assertElementTypeStrings(x.interfaces, ['C']);
  }

  @failingTest
  test_implicitConstructors_const() async {
    addTestFile(r'''
class A {
  const A();
}

class M {}

class C = A with M;

const x = const C();
''');
    await resolveTestFile();
    assertNoTestErrors();
    // TODO(scheglov) add also negative test with fields
  }

  test_implicitConstructors_dependencies() async {
    addTestFile(r'''
class A {
  A(int i);
}
class M1 {}
class M2 {}

class C2 = C1 with M2;
class C1 = A with M1;
''');
    await resolveTestFile();
    assertNoTestErrors();

    assertConstructors(findElement.class_('C1'), ['C1(int i) → C1']);
    assertConstructors(findElement.class_('C2'), ['C2(int i) → C2']);
  }

  test_implicitConstructors_optionalParameters() async {
    addTestFile(r'''
class A {
  A.c1(int a);
  A.c2(int a, [int b, int c]);
  A.c3(int a, {int b, int c});
}

class M {}

class C = A with M;
''');
    await resolveTestFile();
    assertNoTestErrors();

    assertConstructors(
      findElement.class_('C'),
      [
        'C.c1(int a) → C',
        'C.c2(int a, [int b, int c]) → C',
        'C.c3(int a, {int b, int c}) → C'
      ],
    );
  }

  test_implicitConstructors_requiredParameters() async {
    addTestFile(r'''
class A<T extends num> {
  A(T x, T y);
}

class M {}

class B<E extends num> = A<E> with M;
''');
    await resolveTestFile();
    assertNoTestErrors();

    assertConstructors(findElement.class_('B'), ['B(E x, E y) → B<E>']);
  }
}

@reflectiveTest
class ClassAliasTaskResolutionTest extends TaskResolutionTest
    with ClassAliasResolutionMixin {}
