#! /usr/bin/env python
"""Test script for the dbm.sqlite module
   by Skip Montanaro, based on the 3.0 dumbdbm test module.
"""

import io
import os
import unittest
import dbm.sqlite
from test import support

_fname = support.TESTFN

def _delete_files():
    try:
        os.unlink(_fname)
    except OSError:
        pass

class DbmSQLiteTestCase(unittest.TestCase):
    _dict = {'0': b'',
             'a': b'Python:',
             'b': b'Programming',
             'c': b'the',
             'd': b'way',
             'f': b'Guido',
             'g': b'intended',
             }

    def test_sqlite_creation(self):
        f = dbm.sqlite.open(_fname, 'c')
        self.assertEqual(list(f.keys()), [])
        for key in self._dict:
            f[key.encode("ascii")] = self._dict[key]
        self.read_helper(f)
        f.close()

    def test_close_twice(self):
        f = dbm.sqlite.open(_fname)
        f[b'a'] = b'b'
        self.assertEqual(f[b'a'], b'b')
        f.close()
        f.close()

    def test_sqlite_modification(self):
        self.init_db()
        f = dbm.sqlite.open(_fname, 'w')
        self._dict['g'] = f[b'g'] = b"indented"
        self.read_helper(f)
        f.close()

    def test_sqlite_read(self):
        self.init_db()
        f = dbm.sqlite.open(_fname, 'r')
        self.read_helper(f)
        f.close()

    def test_sqlite_keys(self):
        self.init_db()
        f = dbm.sqlite.open(_fname)
        keys = self.keys_helper(f)
        f.close()

    def test_len(self):
        f = dbm.sqlite.open(_fname)
        self.assertEqual(len(f), 0)
        f[b'1'] = b'hello'
        self.assertEqual(len(f), 1)
        f[b'1'] = b'goodbye'
        self.assertEqual(len(f), 1)
        f.close()

    def test_write_contains(self):
        f = dbm.sqlite.open(_fname)
        f[b'1'] = b'hello'
        self.assertTrue(b'1' in f)
        f.close()

    def test_write_write_read(self):
        # test for bug #482460
        f = dbm.sqlite.open(_fname)
        f[b'1'] = b'hello'
        f[b'1'] = b'hello2'
        f.close()
        f = dbm.sqlite.open(_fname)
        self.assertEqual(f[b'1'], b'hello2')
        f.close()

    def test_write_then_read(self):
        # test for bug #482460
        f = dbm.sqlite.open(_fname)
        f[b'1'] = b'hello'
        self.assertEqual(f[b'1'], b'hello')
        f.close()

    def read_helper(self, f):
        keys = self.keys_helper(f)
        for key in self._dict:
            self.assertEqual(self._dict[key], f[key.encode("ascii")])

    def init_db(self):
        f = dbm.sqlite.open(_fname, 'w')
        for k in self._dict:
            f[k.encode("ascii")] = self._dict[k]
        f.close()

    def keys_helper(self, f):
        keys = sorted(k.decode("ascii") for k in f.keys())
        dkeys = sorted(self._dict.keys())
        self.assertEqual(keys, dkeys)
        return keys

    # Perform randomized operations.  This doesn't make assumptions about
    # what *might* fail.
    def test_random(self):
        import random
        d = {}  # mirror the database
        for dummy in range(5):
            f = dbm.sqlite.open(_fname)
            for dummy in range(100):
                k = random.choice('abcdefghijklm')
                if random.random() < 0.2:
                    if k in d:
                        del d[k]
                        del f[k.encode("ascii")]
                else:
                    v = (random.choice((b'a', b'b', b'c')) *
                         random.randrange(100))
                    d[k] = v
                    f[k.encode("ascii")] = v
                    if not (d[k], v == f[k.encode("ascii")] == d[k]):
                        print("v:", v, "f[k]:", f[k.encode("ascii")],
                              "d[k]:")
                    self.assertEqual(f[k.encode("ascii")], v)
            f.close()

            f = dbm.sqlite.open(_fname)
            expected = sorted((k.encode("latin-1"), v) for k, v in d.items())
            got = sorted(f.items())
            self.assertEqual(expected, got)
            f.close()

    def test_keys_values_items(self):
        f = dbm.sqlite.open(_fname, 'c')
        self.assertEqual(list(f.keys()), [])
        for key in self._dict:
            f[key.encode("ascii")] = self._dict[key]
        self.assertEqual(list(zip(f.keys(), f.values())),
                         f.items())
        f.close()
    def tearDown(self):
        _delete_files()

    def setUp(self):
        _delete_files()

def test_main():
    try:
        support.run_unittest(DbmSQLiteTestCase)
    finally:
        _delete_files()

if __name__ == "__main__":
    test_main()
