import unittest
from SPYD import SmartDict

class TestSmartDict(unittest.TestCase):

    def test_initialization(self):
        # Test initialization with key-value pairs
        obj = SmartDict(a=1, b=2)
        self.assertEqual(obj['a'], 1)
        self.assertEqual(obj['b'], 2)

    def test_getitem_key_error(self):
        # Test that KeyError is raised if key is not found
        obj = SmartDict(a=1)
        with self.assertRaises(KeyError):
            obj['b']

    def test_setitem(self):
        # Test setting items
        obj = SmartDict()
        obj['a'] = 1
        self.assertEqual(obj['a'], 1)

    def test_delitem_key_error(self):
        # Test that KeyError is raised when deleting a nonexistent key
        obj = SmartDict(a=1)
        with self.assertRaises(KeyError):
            del obj['b']

    def test_contains(self):
        # Test that `in` works as expected
        obj = SmartDict(a=1)
        self.assertTrue('a' in obj)
        self.assertFalse('b' in obj)

    def test_repr(self):
        # Test the __repr__ method
        obj = SmartDict(a=1, b=2)
        self.assertEqual(repr(obj), "SmartDict{'a': 1, 'b': 2}")

    def test_getattr(self):
        # Test the __getattr__ behavior
        obj = SmartDict(a=1)
        obj.b.c = 3  # This should create a nested SmartDict
        self.assertEqual(obj['b']['c'], 3)

    def test_setattr(self):
        # Test setting attributes via __setattr__
        obj = SmartDict()
        obj.some_attr = 'value'
        self.assertEqual(obj.some_attr, 'value')
        self.assertEqual(obj['some_attr'], 'value')

    def test_to_dict(self):
        # Test converting to a regular dict
        obj = SmartDict(a=1, b=SmartDict(c=2))
        expected = {'a': 1, 'b': {'c': 2}}
        self.assertEqual(obj.to_dict(), expected)

    def test_to_json(self):
        # Test converting to JSON string
        obj = SmartDict(a=1, b=2)
        expected = '{"a": 1, "b": 2}'
        self.assertEqual(obj.to_json(), expected)

    def test_from_json(self):
        # Test creating from JSON string
        json_str = '{"a": 1, "b": 2}'
        obj = SmartDict.from_json(json_str)
        self.assertEqual(obj['a'], 1)
        self.assertEqual(obj['b'], 2)

    def test_to_yaml(self):
        # Test converting to YAML string
        obj = SmartDict(a=1, b=2)
        expected = 'a: 1\nb: 2\n'
        self.assertEqual(obj.to_yaml(), expected)

    def test_from_yaml(self):
        # Test creating from YAML string
        yaml_str = 'a: 1\nb: 2\n'
        obj = SmartDict.from_yaml(yaml_str)
        self.assertEqual(obj['a'], 1)
        self.assertEqual(obj['b'], 2)

    def test_flatten(self):
        # Test flattening nested dicts
        obj = SmartDict(a=1, b=SmartDict(c=2, d=3))
        expected = {'a': 1, 'b.c': 2, 'b.d': 3}
        self.assertEqual(obj.flatten(), expected)

    def test_reverse_lookup(self):
        # Test reverse lookup functionality
        obj = SmartDict(a=1, b=2, c=3)
        self.assertEqual(obj.reverse_lookup(2), 'b')
        self.assertEqual(obj.reverse_lookup(4), None)  # Not found

if __name__ == '__main__':
    unittest.main()
