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

/**
 * testcase.dart: this file is sourced by unittest.dart. It defines [TestCase]
 * and assumes unittest defines the type [TestFunction].
 */

/** Summarizes information about a single test case. */
class TestCase {
  /** Identifier for this test. */
  final int id;

  /** A description of what the test is specifying. */
  final String description;

  /** The setup function to call before the test, if any. */
  Function _setUp;

  Function get setUp => _setUp;
  set setUp(Function value) => _setUp = value;

  /** The teardown function to call after the test, if any. */
  Function _tearDown;

  Function get tearDown => _tearDown;
  set tearDown(Function value) => _tearDown = value;

  /** The body of the test case. */
  TestFunction test;

  /**
   * Remaining number of callbacks functions that must reach a 'done' state
   * to wait for before the test completes.
   */
  int callbackFunctionsOutstanding;

  /** Error or failure message. */
  String message = '';

  /**
   * One of [PASS], [FAIL], [ERROR], or [null] if the test hasn't run yet.
   */
  String result;

  /** Stack trace associated with this test, or null if it succeeded. */
  String stackTrace;

  /** The group (or groups) under which this test is running. */
  final String currentGroup;

  Date startTime;

  Duration runningTime;

  bool enabled = true;

  bool _doneTeardown = false;

  TestCase(this.id, this.description, this.test,
           this.callbackFunctionsOutstanding)
  : currentGroup = _currentGroup,
    _setUp = _testSetup,
    _tearDown = _testTeardown;

  bool get isComplete => !enabled || result != null;

  void run() {
    if (enabled) {
      result = stackTrace = null;
      message = '';
      _doneTeardown = false;
      if (_setUp != null) {
        _setUp();
      }
      _config.onTestStart(this);
      startTime = new Date.now();
      runningTime = null;
      test();
    }
  }

  void _complete() {
    if (runningTime == null) {
      // TODO(gram): currently the duration measurement code is blocked
      // by issue 4437. When that is fixed replace the line below with:
      //    runningTime = new Date.now().difference(startTime);
      runningTime = new Duration(milliseconds: 0);
    }
    if (!_doneTeardown) {
      if (_tearDown != null) {
        _tearDown();
      }
      _doneTeardown = true;
    }
    _config.onTestResult(this);
  }

  void pass() {
    result = PASS;
    _complete();
  }

  void fail(String messageText, String stack) {
    if (result != null) {
      if (result == PASS) {
        error('Test failed after initially passing: $messageText', stack);
      } else if (result == FAIL) {
        error('Test failed more than once: $messageText', stack);
      }
    } else {
      result = FAIL;
      message = messageText;
      stackTrace = stack;
      _complete();
    }
  }

  void error(String messageText, String stack) {
    result = ERROR;
    message = messageText;
    stackTrace = stack;
    _complete();
  }
}
