###########################################################
# RapydScript Standard Library
# Author: Alexander Tsepkov
# Copyright 2013 Pyjeon Software LLC
# License: Apache License    2.0
# This library is covered under Apache license, so that
# you can distribute it with your RapydScript applications.
###########################################################


# basic implementation of Python's 'unittest' library


import stdlib


assert = def(result):
    if not result:
        raise AssertionError()

def main():
    num_tests = 0
    bad_tests = 0
    overall = 'OK'
    # NOTE: the timing mechanism is currently naive, this might change in the future if higher accuracy is needed
    start_time = Date()
    for object in Object.getOwnPropertyNames(global):
        if global[object] and isinstance(global[object].prototype, TestCase):
            obj = new global[object]()
            for prop in Object.getOwnPropertyNames(obj):
                if prop[:4] == 'test':
                    num_tests += 1
                    # create a new instance of the test object for each case to ensure independence
                    # TODO: make this case not require 'new' keyword in the future, it needs it because
                    # compiler isn't smart enough to realize that global[object] == object
                    new_obj = new global[object]()
                    if type(new_obj.setUp) is 'function':
                        new_obj.setUp()
                    try:
                        new_obj[prop]()
                        result = 'ok'
                    except AssertionError as e:
                        result = 'FAIL'
                        bad_tests += 1
                    console.log(prop + ' (' + object + ') ... ' + result)
                    if type(new_obj.tearDown) is 'function':
                        new_obj.tearDown()
    elapsed = (Date() - start_time)/1000
    console.log('--------------------------------------------------------------')
    console.log('Ran ' + str(num_tests) + ' tests in ' + elapsed + 's\n')
    if bad_tests:
        overall = 'FAILED (failures=' + str(bad_tests) + ')'
    console.log(overall)

class TestCase:
    def __init__(self):
        pass
    def assertEqual(self, a, b):
        # this function is smart enough to correctly test equality even for arrays
        assert(deep_eq(a, b))
    def assertNotEqual(self, a, b):
        # this function is smart enough to correctly test equality even for arrays
        assert(not deep_eq(a, b))
    def assertTrue(self, a):
        assert(a)
    def assertFalse(self, a):
        assert(not a)
    def assertAlmostEqual(self, a, b, precision):
        epsilon = 1/Math.pow(10, precision)
        assert(Math.abs(a-b) < epsilon)
    def assertNotAlmostEqual(self, a, b, precision):
        try:
            self.assertAlmostEqual(a, b, precision)
        except AssertionError:
            return
        raise AssertionError()
    def assertRaises(self, exception, callable, *args):
        try:
            callable(*args)
        except exception:
            return



#import random
#import unittest
#
#class TestSequenceFunctions(unittest.TestCase):
#
#    def setUp(self):
#        self.seq = range(10)
#
#    def test_shuffle(self):
#        # make sure the shuffled sequence does not lose any elements
#        random.shuffle(self.seq)
#        self.seq.sort()
#        self.assertEqual(self.seq, range(10))
#
#        # should raise an exception for an immutable sequence
#        self.assertRaises(TypeError, random.shuffle, (1,2,3))
#
#    def test_choice(self):
#        element = random.choice(self.seq)
#        self.assertTrue(element in self.seq)
#
#    def test_sample(self):
#        self.assertRaises(ValueError, random.sample, (self.seq, 20))
#        for element in random.sample(self.seq, 5):
#            self.assertTrue(element in self.seq)
#
## there is no way to make this work without explicitly binding it to global scope
#global.TestSequenceFunctions = TestSequenceFunctions
#
#unittest.main()
