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

/// Tests the (probably temporary) API for extracting reified type arguments
/// from an object.

import "package:expect/expect.dart";

// It's weird that a language test is testing code defined in a package. The
// rationale for putting this test here is:
//
// * This package is special and "built-in" to Dart in that the various
//   compilers give it the special privilege of importing "dart:_internal"
//   without error.
//
// * Eventually, the API being tested here may be replaced with an actual
//   language feature, in which case this test will become an actual language
//   test.
//
// * Placing the test here ensures it is tested on all of the various platforms
//   and configurations where we need the API to work.
import "package:dart_internal/extract_type_arguments.dart";

main() {
  testExtractIterableTypeArgument();
  testExtractMapTypeArguments();
}

testExtractIterableTypeArgument() {
  Iterable object = <int>[];

  // Invokes function with iterable's type argument.
  var called = false;
  extractIterableTypeArgument(object, <T>() {
    Expect.equals(T, int);
    called = true;
  });
  Expect.isTrue(called);

  // Returns result of function.
  Object result = extractIterableTypeArgument(object, <T>() => new Set<T>());
  Expect.isTrue(result is Set<int>);
  Expect.isFalse(result is Set<bool>);

  // Accepts user-defined implementations of Iterable.
  object = new CustomIterable();
  result = extractIterableTypeArgument(object, <T>() => new Set<T>());
  Expect.isTrue(result is Set<String>);
  Expect.isFalse(result is Set<bool>);
}

testExtractMapTypeArguments() {
  Map object = <String, int>{};

  // Invokes function with map's type arguments.
  var called = false;
  extractMapTypeArguments(object, <K, V>() {
    Expect.equals(K, String);
    Expect.equals(V, int);
    called = true;
  });
  Expect.isTrue(called);

  // Returns result of function.
  Object result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
  Expect.isTrue(result is Two<String, int>);
  Expect.isFalse(result is Two<int, String>);

  // Accepts user-defined implementations of Map.
  object = new CustomMap();
  result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
  Expect.isTrue(result is Two<int, bool>);
  Expect.isFalse(result is Two<bool, int>);

  // Uses the type parameter order of Map, not any other type in the hierarchy.
  object = new FlippedMap<double, Null>();
  result = extractMapTypeArguments(object, <K, V>() => new Two<K, V>());
  // Order is reversed here:
  Expect.isTrue(result is Two<Null, double>);
  Expect.isFalse(result is Two<double, Null>);
}

class Two<A, B> {}

class CustomIterable implements Iterable<String> {
  noSuchMethod(i) => throw new UnimplementedError();
}

class CustomMap implements Map<int, bool> {
  noSuchMethod(i) => throw new UnimplementedError();
}

// Note: Flips order of type parameters.
class FlippedMap<V, K> implements Map<K, V> {
  noSuchMethod(i) => throw new UnimplementedError();
}
