// Copyright (c) 2011, 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 basic classes and methods.
class ClassTest {
  ClassTest() {}

  static testMain() {
    var test = new ClassTest();
    test.testSuperCalls();
    test.testVirtualCalls();
    test.testStaticCalls();
    test.testInheritedField();
    test.testMemberRefInClosure();
    test.testFactory();
    test.testNamedConstructors();
    test.testDefaultImplementation();
    test.testFunctionParameter((int a) { return a;});
  }

  testFunctionParameter(int func(int a)) {
    Expect.equals(1, func(1));
  }

  testSuperCalls() {
    var sub = new Sub();
    Expect.equals(43, sub.methodX());
    Expect.equals(84, sub.methodK());
  }

  testVirtualCalls() {
    var sub = new Sub();
    Expect.equals(41, sub.method2());
    Expect.equals(41, sub.method3());
  }

  testStaticCalls() {
    var sub = new Sub();
    Expect.equals(-42, Sub.method4());
    Expect.equals(-41, sub.method5());
  }

  testInheritedField() {
    var sub  = new Sub();
    Expect.equals(42, sub.method6());
  }

  testMemberRefInClosure() {
    var sub = new Sub();
    Expect.equals(1, sub.closureRef());
    Expect.equals(2, sub.closureRef());
    // Make sure it is actually on the object, not the global 'this'.
    sub = new Sub();
    Expect.equals(1, sub.closureRef());
    Expect.equals(2, sub.closureRef());
  }

  testFactory() {
    var sup = new Sup.named();
    Expect.equals(43, sup.methodX());
    Expect.equals(84, sup.methodK());
  }

  testNamedConstructors() {
    var sup = new Sup.fromInt(4);
    Expect.equals(4, sup.methodX());
    Expect.equals(0, sup.methodK());
  }

  testDefaultImplementation() {
    var x = new Inter(4);
    Expect.equals(4, x.methodX());
    Expect.equals(8, x.methodK());

    x = new Inter.fromInt(4);
    Expect.equals(4, x.methodX());
    Expect.equals(0, x.methodK());

    x = new Inter.named();
    Expect.equals(43, x.methodX());
    Expect.equals(84, x.methodK());

    x = new Inter.factory();
    Expect.equals(43, x.methodX());
    Expect.equals(84, x.methodK());
  }
}

interface Inter default Sup {
  Inter.named();
  Inter.fromInt(int x);
  Inter(int x);
  Inter.factory();
  int methodX();
  int methodK();
  int x_;
}

class Sup implements Inter {
  int x_;
  int k_;

  factory Sup.named() {
    return new Sub();
  }

  factory Sup.factory() {
    return new Sub();
  }

  Sup.fromInt(int x) {
    x_ = x;
    k_ = 0;
  }

  int methodX() {
    return x_;
  }

  int methodK() {
    return k_;
  }

  Sup(int x) : this.x_ = x {
    k_ = x * 2;
  }

  int method2() {
    return x_ - 1;
  }
}

class Sub extends Sup {
  int y_;

  // Override
  int methodX() {
    return super.methodX() + 1;
  }

  int method3() {
    return method2();
  }

  static int method4() {
    return -42;
  }

  int method5() {
    return method4() + 1;
  }

  int method6() {
    return x_ + y_;
  }

  int closureRef() {
    var f = () {y_ += 1; return y_;};
    return f();
  }

  Sub() : super(42) {
    y_ = 0;
  }
}

main() {
  ClassTest.testMain();
}
