"""Unit tests for models and capabilities"""

import unittest

class ModelsTestCase(unittest.TestCase):
    """Unit tests for the sciunit module"""

    def setUp(self):
        from sciunit.models.examples import UniformModel
        self.M = UniformModel

    def test_get_model_state(self):
        from sciunit import Model

        m = Model()
        state = m.__getstate__()
        self.assertEqual(m.__dict__, state)

    def test_get_model_capabilities(self):
        from sciunit.capabilities import ProducesNumber

        m = self.M(2, 3)
        self.assertEqual(m.capabilities, [ProducesNumber])

    def test_get_model_description(self):
        m = self.M(2, 3)
        m.describe()
        m.description = "Lorem Ipsum"
        m.describe()

    def test_check_model_capabilities(self):
        from sciunit.tests import RangeTest
        t = RangeTest([2,3])
        m = self.M(2,3)
        t.check(m)
        
    def test_check_missing_capabilities_1(self):
        from sciunit.capabilities import Runnable
        from sciunit.errors import CapabilityNotImplementedError
        
        m = self.M(2, 3, name='Not actually runnable due to lack of capability provision')
        try:
            m.run()
        except AttributeError as e:
            pass
        else:
            self.fail("Unprovided capability was called and not caught")
    
    def test_check_missing_capabilities_2(self):
        from sciunit.capabilities import Runnable
        from sciunit.errors import CapabilityNotImplementedError
        
        class MyModel(self.M, Runnable):
            pass
        
        m = MyModel(2, 3, name='Not actually runnable due to lack of capability implementation')
        try:
            m.run()
        except CapabilityNotImplementedError as e:
            pass
        else:
            self.fail("Unimplemented capability was called and not caught")
        
    def test_check_missing_capabilities_3(self):
        from sciunit.capabilities import Runnable
        from sciunit.errors import CapabilityNotImplementedError
        
        class MyModel(self.M, Runnable):
            def run(self):
                print("Actually running!")
        
        m = MyModel(2, 3, name='Now actually runnable')
        m.run()
        
    def test_regular_models(self):
        from sciunit.models.examples\
            import ConstModel, UniformModel, SharedModel, PersistentUniformModel

        m = ConstModel(3)
        self.assertEqual(m.produce_number(),3)

        m = UniformModel(3,4)
        self.assertTrue(3 < m.produce_number() < 4)

        m = PersistentUniformModel(3, 4)
        m.run()
        self.assertTrue(3 < m.produce_number() < 4)

    def test_irregular_models(self):
        from sciunit.models.examples\
            import CacheByInstancePersistentUniformModel,\
            CacheByValuePersistentUniformModel

        a = CacheByInstancePersistentUniformModel(2,3)
        a1 = a.produce_number()
        a2 = a.produce_number()
        self.assertEqual(a1,a2)
        b = CacheByInstancePersistentUniformModel(2,3)
        b1 = b.produce_number()
        self.assertNotEqual(b1,a2)

        c = CacheByValuePersistentUniformModel(2,3)
        c1 = c.produce_number()
        c2 = c.produce_number()
        self.assertEqual(c1,c2)
        d = CacheByValuePersistentUniformModel(2,3)
        d1 = d.produce_number()
        self.assertEqual(d1,c2)
        


class CapabilitiesTestCase(unittest.TestCase):
    """Unit tests for sciunit Capability classes"""

    def test_capabilities(self):
        from sciunit import Model
        from sciunit.capabilities import ProducesNumber
        from sciunit.models import Model
        from sciunit.models.examples import UniqueRandomNumberModel,\
            RepeatedRandomNumberModel

        class MyModel(Model,ProducesNumber):
            def produce_number(self):
                return 3.14
        m = MyModel()
        self.assertEqual(m.produce_number(),3.14)

        m = UniqueRandomNumberModel()
        self.assertNotEqual(m.produce_number(),m.produce_number())

        m = RepeatedRandomNumberModel()
        self.assertEqual(m.produce_number(),m.produce_number())

@@ -247,24 +247,477 @@
 iformModel%0A%0A
+    def test_failed_extra_capabilities(self):%0A        from sciunit import Model%0A%0A        class TestModel(Model):%0A            def test_return_none_function(self):%0A                return None%0A        %0A        m = TestModel()%0A        m.extra_capability_checks = %7BTestModel : %22test_return_none_function%22%7D%0A        test_list = m.failed_extra_capabilities%0A        %0A        self.assertEqual(test_list%5B0%5D, TestModel)%0A        self.assertEqual(len(test_list), 1)%0A%0A
     def test
@@ -4629,28 +4629,75 @@
 umber(),m.produce_number())%0A
+%0Aif __name__ == '__main__':%0A    unittest.main()

Add test cases for failed_extra_capabilities func.