// Copyright (c) 2013, 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.
// Second dart test program.

// VMOptions=--optimization-counter-threshold=90

import "package:expect/expect.dart";

class EqualsNotCalled {
  int get hashCode => throw "And don't warn!";
  bool operator ==(Object other) {
    throw "SHOULD NOT GET HERE";
  }
}

class Generic<T> {
  bool test(o) => o is T;
  T cast(o) => o as T;
  Type get type => T;
}

class Generic2<T, S> {
  bool test(o) => new Generic<T>().test(o);
  T cast(o) => new Generic<T>().cast(o);
  Type get type => new Generic<T>().type;
}

// Magic incantation to avoid the compiler recognizing the constant values
// at compile time. If the result is computed at compile time, the dynamic code
// will not be tested.
confuse(x) {
  try {
    if (new DateTime.now().millisecondsSinceEpoch == 42) x = 42;
    throw [x];
  } on dynamic catch (e) {
    return e[0];
  }
  return 42;
}

void main() {
  for (int i = 0; i < 100; i++) {
    test();
  }
}

void test() {
  void foo(var obj) {
    Expect.equals(null, obj);
  }

  bool compareToNull(var value) {
    return null == value;
  }

  bool compareWithNull(var value) {
    return value == null;
  }

  var val = 1;
  var obj = confuse(null); // Null value that isn't known at compile-time.
  Expect.isTrue(identical(obj, null), "identical");

  Expect.isTrue(null == null);
  Expect.isTrue(null == obj);
  Expect.isTrue(obj == null);
  Expect.isTrue(obj == obj);

  // Using  == null  or  null ==  will not call any equality method.
  Expect.isFalse(new EqualsNotCalled() == null);
  Expect.isFalse(null == new EqualsNotCalled());
  Expect.isFalse(new EqualsNotCalled() == obj);
  Expect.isFalse(obj == new EqualsNotCalled());

  Expect.isFalse(null == false);
  Expect.isFalse(null == 0);
  Expect.isFalse(null == "");
  Expect.isFalse(null == []);
  Expect.isFalse(null == 0.0);
  Expect.isFalse(null == -0.0);
  Expect.isFalse(null == double.nan);

  Expect.isFalse(obj == false);
  Expect.isFalse(obj == 0);
  Expect.isFalse(obj == "");
  Expect.isFalse(obj == []);
  Expect.isFalse(obj == 0.0);
  Expect.isFalse(obj == -0.0);
  Expect.isFalse(obj == double.nan);

  // Explicit constant expressions.
  const t1 = null == null;
  const t2 = null == 0;
  const t3 = false == null;
  Expect.isTrue(t1);
  Expect.isFalse(t2);
  Expect.isFalse(t3);

  foo(obj);
  foo(null);
  if (obj != null) {
    foo(null);
  } else {
    foo(obj);
  }

  // Test "is" operator.
  Expect.isTrue(null is Null);
  Expect.isTrue(obj is Null);
  Expect.isFalse(null is Object);
  Expect.isFalse(obj is Object);
  Expect.isTrue(null is Object?);
  Expect.isTrue(obj is Object?);
  Expect.isTrue(null is dynamic);
  Expect.isTrue(obj is dynamic);
  Expect.isFalse(null is String);
  Expect.isFalse(obj is String);
  Expect.isFalse(0 is Null); // It's only assignable.
  Expect.isFalse(null is! Null);
  Expect.isFalse(obj is! Null);
  Expect.isTrue(null is! Object);
  Expect.isTrue(obj is! Object);
  Expect.isFalse(null is! Object?);
  Expect.isFalse(obj is! Object?);
  Expect.isFalse(null is! dynamic);
  Expect.isFalse(obj is! dynamic);
  Expect.isTrue(null is! String);
  Expect.isTrue(obj is! String);
  Expect.isTrue(0 is! Null); // It's only assignable.

  // Test "is" operator with generic type variable.
  Expect.isTrue(new Generic<Null>().test(null));
  Expect.isFalse(new Generic<Null>().test(42));
  Expect.isTrue(new Generic2<Null, int>().test(null));
  Expect.isFalse(new Generic2<Null, int>().test(42));

  // Test cast, "as", operator.
  Expect.equals(null, null as Null);
  if (hasSoundNullSafety) {
    Expect.throwsTypeError(() => null as Object);
  } else {
    Expect.equals(null, null as Object);
  }
  Expect.equals(null, null as Object?);
  if (hasSoundNullSafety) {
    Expect.throwsTypeError(() => null as int);
  } else {
    Expect.equals(null, null as int);
  }
  Expect.equals(null, null as int?);
  Expect.throwsTypeError(() => 42 as Null);
  Expect.equals(null, new Generic<Null>().cast(null));
  Expect.equals(null, new Generic<Object?>().cast(null));
  Expect.equals(null, new Generic<int?>().cast(null));

  Expect.equals(null, obj as Null);
  if (hasSoundNullSafety) {
    Expect.throwsTypeError(() => obj as Object);
  } else {
    Expect.equals(null, obj as Object);
  }
  Expect.equals(null, obj as Object?);
  if (hasSoundNullSafety) {
    Expect.throwsTypeError(() => obj as int);
  } else {
    Expect.equals(null, obj as int);
  }
  Expect.equals(null, obj as int?);
  Expect.equals(null, new Generic<Null>().cast(obj));
  Expect.equals(null, new Generic<Object?>().cast(obj));
  Expect.equals(null, new Generic<int?>().cast(obj));

  Expect.equals("null", null.toString());
  Expect.equals("null", "${null}");
  Expect.equals("null", obj.toString());
  Expect.equals("null", "${obj}");

  Expect.equals(Null, null.runtimeType);
  Expect.equals(Null, obj.runtimeType);
  Expect.equals(Null, new Generic<Null>().type);
  Expect.equals(Null, new Generic2<Null, int>().type);

  Expect.isFalse(compareToNull(val));
  Expect.isTrue(compareToNull(obj));
  Expect.isFalse(compareWithNull(val));
  Expect.isTrue(compareWithNull(obj));

  // Re-initialize obj to cancel promotion from previous "as" operators.
  obj = confuse(null);

  // Method/value extraction. The runtimeType was checked above, and operator==
  // cannot be extracted.
  // Currently fails in VM.
  Expect.equals(null.toString, obj.toString);
  Expect.equals(null.noSuchMethod, obj.noSuchMethod);
  Expect.equals(null.hashCode, obj.hashCode);

  var toString = null.toString;
  Expect.equals("null", toString());
  Expect.equals("null", Function.apply(toString, []));

  Expect.throws(() => obj.notDeclared());
  var noSuchMethod = null.noSuchMethod;
  // Assign to "dynamic" to prevent compile-time error.
  dynamic capture = new CaptureInvocationMirror();
  var mirror = capture.notDeclared();
  Expect.throws(() => noSuchMethod(mirror));
  Expect.throws(() => Function.apply(noSuchMethod, [mirror]));
}

class CaptureInvocationMirror {
  noSuchMethod(mirror) => mirror;
}
