
from __future__ import with_statement

import os
import sys
import tempfile
import unittest

import gio
import gobject

def unsplitlines(ls):
    return ''.join([l + '\n' for l in ls])

def code_literal(s):
    lines = s.splitlines()
    i = 1

    while True:
        prefixes = [line[:i] for line in lines if line != '']

        if not all([prefix == prefixes[0] for prefix in prefixes[1:]]):
            break

        i += 1

    return unsplitlines([s[i - 1:] for s in lines])

class ReloadTest(unittest.TestCase):
    def setUp(self):
        (_, self.tmp_path) = tempfile.mkstemp(suffix='.py')
        sys.path.insert(0, tempfile.gettempdir())

        # Avoid generating .pyc files in the temporary directory.
        if hasattr(sys, 'dont_write_bytecode'):
            self.dont_write_bytecode = sys.dont_write_bytecode
            sys.dont_write_bytecode = True

    def tearDown(self):
        os.unlink(self.tmp_path)
        sys.path.pop(0)

        if hasattr(sys, 'dont_write_bytecode'):
            sys.dont_write_bytecode = self.dont_write_bytecode

    def wait_for_file_change(self, path):
        # Wait for the GFileMonitor to notice that the file has
        # changed. Annoyingly, this takes about a second, and setting
        # the rate-limit property doesn't seem to affect it.
        loop = gobject.MainLoop()
        monitor = gio.File(path).monitor()
        monitor.connect('changed', lambda *x: loop.quit())
        loop.run()


    def test(self):
        code1 = code_literal("""
            from glitch.gtk.reload import Reload

            class Foo(Reload):
                def foo(self):
                    return 42
            """)
        code_lines = code1.splitlines()
        code_lines[-2] = "        return 43"
        code2 = unsplitlines(code_lines)

        with file(self.tmp_path, 'w') as fh:
            fh.write(code1)

        mod_name = os.path.splitext(os.path.basename(self.tmp_path))[0]
        mod = __import__(mod_name)

        mod.Foo._rate_limit = 1
        foo = mod.Foo()
        self.assertEquals(42, foo.foo())

        with file(self.tmp_path, 'w') as fh:
            fh.write(code2)

        self.wait_for_file_change(self.tmp_path)
        self.assertEquals(43, foo.foo())

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