# -*- coding: utf-8 -*-

from __future__ import with_statement
import unittest
import os, os.path
import skk
import nicola
from ibus import modifier

class TestSKK(unittest.TestCase):
    def setUp(self):
        # Make sure to start with new empty usrdict.
        usrdict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    ".skk-ibus-jisyo")
        try:
            os.unlink(usrdict_path)
        except:
            pass

        sysdict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    "skk-ibus-jisyo")
        s_dict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                   "SKK-JISYO.S")
        if not os.path.exists(sysdict_path):
            if not os.path.exists(s_dict_path):
                raise RuntimeError('SKK-JISYO.S not found; do "wget http://openlab.ring.gr.jp/skk/skk/dic/SKK-JISYO.S"')
            with open(sysdict_path, 'a') as tp:
                with open(s_dict_path, 'r') as fp:
                    for line in fp:
                        tp.write(line)
                        if line.startswith(';; okuri-nasi'):
                            tp.write(u'#/# /#0月#0日/#1／#1/#1月#1日/\n'.encode('EUC-JP'))
                            tp.write(u'#ひき /#1匹/#3匹/#0匹/#2匹/\n'.encode('EUC-JP'))
                            tp.write(u'>し /氏/\n'.encode('EUC-JP'))
                        if line.startswith('greek '):
                            tp.write(u'request /リクエスト/\n'.encode('EUC-JP'))
                        if line.startswith(u'ちょう '.encode('EUC-JP')):
                            tp.write(u'ちょう> /超/\n'.encode('EUC-JP'))

        self.__skk = skk.Context(usrdict=skk.UsrDict(usrdict_path),
                                 sysdict=skk.SysDict(sysdict_path),
                                 candidate_selector=skk.CandidateSelector())

    def testusrdict(self):
        usrdict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                    ".skk-ibus-jisyo-corrupted")
        with open(usrdict_path, 'w+') as fp:
            fp.write(u'あい /愛/\n'.encode('EUC-JP'))
        try:
            usrdict = skk.UsrDict(usrdict_path, 'UTF-8')
            self.assertNotEqual(usrdict, None)
            self.assertTrue(usrdict.read_only)
        except Exception, e:
            self.fail("can't open user dictionary: %s" % e.message)
        finally:
            os.unlink(usrdict_path)

    def testinputmodechange(self):
        self.__skk.reset()
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_DEFAULT)
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        # catch ctrl-j in HIRAGANA
        handled, output = self.__skk.press_key(u'ctrl+j')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        # HIRAGANA to KATAKANA
        handled, output = self.__skk.press_key(u'q')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_KATAKANA)
        # catch ctrl-j in KATAKANA, and be still in KATAKANA
        self.__skk.press_key(u'ctrl+j')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_KATAKANA)
        # KATAKANA to HIRAGANA
        handled, output = self.__skk.press_key(u'q')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        # HIRAGANA to LATIN
        handled, output = self.__skk.press_key(u'l')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_LATIN)
        # 'q' letter in LATIN
        handled, output = self.__skk.press_key(u'q')
        self.assert_(handled)
        self.assertEqual(output, u'q')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_LATIN)
        # LATIN to HIRAGANA
        handled, output = self.__skk.press_key(u'ctrl+j')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        # HIRAGANA to WIDE-LATIN
        handled, output = self.__skk.press_key(u'L')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_WIDE_LATIN)
        # 'q' letter in WIDE-LATIN
        handled, output = self.__skk.press_key(u'q')
        self.assert_(handled)
        self.assertEqual(output, u'ｑ')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_WIDE_LATIN)
        # WIDE-LATIN to HIRAGANA
        handled, output = self.__skk.press_key(u'ctrl+j')
        self.assert_(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        # wwl -> っ and HIRAGANA to LATIN
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'w')
        handled, output = self.__skk.press_key(u'w')
        self.assertTrue(handled)
        self.assertEqual(output, u'っ')
        self.assertEqual(self.__skk.preedit, u'w')
        handled, output = self.__skk.press_key(u'l')
        self.assertTrue(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_LATIN)

    def testromkana(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        # ka -> か
        self.assertEqual(self.__skk.press_key(u'k'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'k')
        self.assertEqual(self.__skk.press_key(u'a'), (True, u'か'))
        self.assertEqual(self.__skk.preedit, u'')
        # myo -> みょ
        self.assertEqual(self.__skk.press_key(u'm'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'm')
        self.assertEqual(self.__skk.press_key(u'y'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'my')
        self.assertEqual(self.__skk.press_key(u'o'), (True, u'みょ'))
        self.assertEqual(self.__skk.preedit, u'')
        # toggle submode to katakana
        self.assertEqual(self.__skk.press_key(u'q'), (True, u''))
        # ka -> カ
        self.assertEqual(self.__skk.press_key(u'k'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'k')
        self.assertEqual(self.__skk.press_key(u'a'), (True, u'カ'))
        self.assertEqual(self.__skk.preedit, u'')
        # nX -> ンX
        self.__skk.press_key(u'n')
        self.assertEqual(self.__skk.press_key(u'.'), (True, u'ン。'))
        # ww -> っw, etc.  Issue#33.
        for c in (u'h', u'm', u'w'):
            self.__skk.reset()
            self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
            self.__skk.press_key(c)
            handled, output = self.__skk.press_key(c)
            self.assertTrue(handled)
            self.assertEqual(output, u'っ')
            self.assertEqual(self.__skk.preedit, c)
        # zl -> →
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'z')
        self.assertEqual(self.__skk.press_key(u'l'), (True, u'→'))
        # cancel rom-kana conversion
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'm')
        self.__skk.press_key(u'y')
        self.assertEqual(self.__skk.press_key(u'ctrl+g'), (True, u''))
        self.__skk.press_key(u'm')
        self.__skk.press_key(u'y')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.press_key(u'ctrl+g'), (False, u''))

    def testhiraganakatakana(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_START)
        self.__skk.press_key(u'i')
        self.assertEqual(self.__skk.press_key(u'q'), (True, u'アイ'))
        self.assertEqual(self.__skk.preedit, u'')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'q')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_KATAKANA)
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_START)
        self.__skk.press_key(u'i')
        self.assertEqual(self.__skk.press_key(u'q'), (True, u'あい'))
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_KATAKANA)
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_NONE)
        self.assertEqual(self.__skk.preedit, u'')
        # う゛-> ヴ
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'V')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽う゛')
        self.assertEqual(self.__skk.press_key(u'q'), (True, u'ヴ'))
        # ヴ -> う゛
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_KATAKANA)
        self.__skk.press_key(u'V')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽ヴ')
        self.assertEqual(self.__skk.press_key(u'q'), (True, u'う゛'))
        # ▽nq -> ン
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'Q')
        self.__skk.press_key(u'n')
        handled, output = self.__skk.press_key(u'q')
        self.assertTrue(handled)
        self.assertEqual(output, u'ン')
        # Wo -> ▽を (Issue#36)
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'W')
        self.__skk.press_key(u'o')
        self.assertEqual(self.__skk.preedit, u'▽を')

    def testokurinasi(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.assertEqual(self.__skk.press_key(u'A'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.assertEqual(self.__skk.press_key(u'i'), (True, u''))
        self.assertEqual(self.__skk.preedit, u'▽あい')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼愛')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼哀')
        # NA -> ▽な, NAN -> ▽な*n, NANA -> [DictEdit] な*んあ
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'N')
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽な')
        self.__skk.press_key(u'N')
        self.assertEqual(self.__skk.preedit, u'▽な*n')
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] な*んあ ')
        self.__skk.press_key(u'ctrl+g')
        self.__skk.press_key(u'return')
        # NA -> ▽な, NAN -> ▽な*n, NANa -> [DictEdit] な*な
        self.__skk.press_key(u'N')
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽な')
        self.__skk.press_key(u'N')
        self.assertEqual(self.__skk.preedit, u'▽な*n')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] な*な ')

    def testegglikenewline(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        # CONV_STATE_START
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'i')
        self.__skk.egg_like_newline = False
        self.assertEqual(self.__skk.press_key(u'return'), (True, u'あい\n'))
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'i')
        self.__skk.egg_like_newline = True
        self.assertEqual(self.__skk.press_key(u'return'), (True, u'あい'))
        # CONV_STATE_SELECT
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.__skk.egg_like_newline = False
        self.assertEqual(self.__skk.press_key(u'return'), (True, u'愛\n'))
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.__skk.egg_like_newline = True
        self.assertEqual(self.__skk.press_key(u'return'), (True, u'愛'))

    def testokuriari(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'g')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'E')
        self.assertEqual(self.__skk.preedit, u'▼考え')
        self.assertEqual(self.__skk.press_key(u'r'), (True, u'考え'))
        self.assertEqual(self.__skk.preedit, u'r')
        self.assertEqual(self.__skk.press_key(u'u'), (True, u'る'))

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'H')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'Z')
        self.assertEqual(self.__skk.preedit, u'▽は*z')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▼恥ず')

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'T')
        self.__skk.press_key(u'u')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'T')
        self.__skk.press_key(u't')
        self.assertEqual(self.__skk.preedit, u'▽つか*っt')

        # Debian Bug#591052
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'J')
        self.assertEqual(self.__skk.preedit, u'▽かん*j')

        # Issue#10
        self.__skk.debug = True
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'F')
        self.__skk.press_key(u'u')
        self.__skk.press_key(u'N')
        self.__skk.press_key(u'd')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'▼踏んだ')
        self.__skk.debug = False

        # Issue#19
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'z')
        self.__skk.press_key(u'u')
        self.__skk.press_key(u'm')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼東')
        self.__skk.press_key(u'>')
        self.assertEqual(self.__skk.preedit, u'▽>')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'h')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼氏')
        self.__skk.kakutei()
        self.__skk.press_key(u'T')
        self.__skk.press_key(u'y')
        self.__skk.press_key(u'o')
        self.__skk.press_key(u'u')
        self.__skk.press_key(u'>')
        self.assertEqual(self.__skk.preedit, u'▼超')

        # Issue#28
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'S')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'S')
        self.assertEqual(self.__skk.preedit, u'▽さっ*s')

    def testcompletion(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'\t')
        self.assertEqual(self.__skk.preedit, u'▽あい')
        self.__skk.press_key(u'\t')
        self.assertEqual(self.__skk.preedit, u'▽あいさつ')
        self.__skk.press_key(u' ')
        self.__skk.kakutei()
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'\t')
        self.assertEqual(self.__skk.preedit, u'▽あいさつ')
        self.__skk.press_key(u' ')
        self.__skk.kakutei()
        self.assertEqual(self.__skk.preedit, u'')
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'ctrl+i')
        self.assertEqual(self.__skk.preedit, u'▽あいさつ')

    def testautoconvesion(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'i')
        self.assertEqual(self.__skk.preedit, u'▽あい')
        self.__skk.press_key(u',')
        self.assertEqual(self.__skk.preedit, u'▼愛、')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼哀、')
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u'w')
        self.__skk.press_key(u'o')
        self.assertEqual(self.__skk.preedit, u'▼愛を')

    def testdelete(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        handled, output = self.__skk.press_key(u'backspace')
        self.assertTrue(handled)
        self.assertEqual(self.__skk.preedit, u'▽')
        handled, output = self.__skk.press_key(u'backspace')
        self.assertTrue(handled)
        self.assertEqual(self.__skk.preedit, u'')

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u't')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽あいさつ')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼挨拶')
        handled, output = self.__skk.press_key(u'backspace')
        self.assertTrue(handled)
        self.assertEqual(output, u'挨')
        handled, output = self.__skk.press_key(u'backspace')
        self.assertFalse(handled)

    def testdeleteshortcut(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        handled, output = self.__skk.press_key(u'ctrl+h')
        self.assertTrue(handled)
        self.assertEqual(self.__skk.preedit, u'▽')
        handled, output = self.__skk.press_key(u'ctrl+h')
        self.assertTrue(handled)
        self.assertEqual(self.__skk.preedit, u'')

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'A')
        self.assertEqual(self.__skk.preedit, u'▽あ')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u't')
        self.__skk.press_key(u's')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽あいさつ')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼挨拶')
        handled, output = self.__skk.press_key(u'ctrl+h')
        self.assertTrue(handled)
        self.assertEqual(output, u'挨')
        handled, output = self.__skk.press_key(u'ctrl+h')
        self.assertFalse(handled)

    def testnumeric(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'Q')
        self.assertEqual(self.__skk.preedit, u'▽')
        self.__skk.press_key(u'5')
        self.__skk.press_key(u'/')
        self.__skk.press_key(u'1')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼5月1日')

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'Q')
        self.__skk.press_key(u'5')
        self.__skk.press_key(u'h')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼５匹')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼五匹')

        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'Q')
        self.assertEqual(self.__skk.preedit, u'▽')
        self.__skk.press_key(u'5')
        self.__skk.press_key(u'0')
        self.__skk.press_key(u'0')
        self.__skk.press_key(u'0')
        self.__skk.press_key(u'0')
        self.__skk.press_key(u'h')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼五万匹')

    def testkzik(self):
        self.__skk.reset()
        self.__skk.rom_kana_rule = skk.ROM_KANA_KZIK
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'b')
        self.__skk.press_key(u'g')
        handled, output = self.__skk.press_key(u'd')
        self.assertTrue(handled)
        self.assertEqual(output, u'びぇん')
        self.__skk.press_key(u's')
        handled, output = self.__skk.press_key(u'q')
        self.assertTrue(handled)
        self.assertEqual(output, u'さい')
        self.__skk.press_key(u'd')
        handled, output = self.__skk.press_key(u'l')
        self.assertTrue(handled)
        self.assertEqual(output, u'どん')
        self.__skk.rom_kana_rule = skk.ROM_KANA_NORMAL
        self.__skk.reset()

    def testdictedit(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'p')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ あ')
        self.__skk.press_key(u'backspace')
        self.__skk.press_key(u'A')
        self.__skk.press_key(u'ctrl+j')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ あ')
        self.__skk.press_key(u'backspace')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ▽か')
        self.__skk.press_key(u'return')
        self.__skk.press_key(u'backspace')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'p')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'[[DictEdit]] かぱ ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ▽かぱ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ')
        # Don't register empty string (Debian Bug#590191)
        self.__skk.press_key(u'return')
        self.assertEqual(self.__skk.preedit, u'▽かぱ')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ▽か')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ▼下')
        self.__skk.press_key(u'H')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u'return')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'backspace')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ 下破')
        self.assertEqual(self.__skk.press_key(u'return'), (True, u'下破'))
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'p')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼下破')
        # Purge "下破" from the user dictionary (Debian Bug#590188).
        self.__skk.press_key(u'X')
        self.assertEqual(self.__skk.preedit, u'')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'p')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'▽かぱ')
        self.__skk.press_key(u' ')
        # Should enter dict-edit since "下破" is purged above.
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かぱ ')
        self.__skk.press_key(u'ctrl+g')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'j')
        self.__skk.press_key(u'i')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'▼幹事')
        self.__skk.press_key(u'return')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'g')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'E')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かんが*え ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'▼考え')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'▽かんがえ')
        self.__skk.press_key(u'E')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かんがえ*え ')
        self.__skk.press_key(u'ctrl+g')
        self.assertEqual(self.__skk.preedit, u'▽かんがええ')
        self.__skk.press_key(u'ctrl+h')
        self.assertEqual(self.__skk.preedit, u'▽かんがえ')
        self.__skk.press_key(u'ctrl+h')
        self.assertEqual(self.__skk.preedit, u'▽かんが')
        self.__skk.press_key(u'ctrl+g')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u't')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u' ')
        self.__skk.press_key(u'K')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u't')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'q')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かたかな カタカナ')
        self.__skk.press_key(u'backspace')
        self.__skk.press_key(u'l')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'a')
        self.assertEqual(self.__skk.preedit, u'[DictEdit] かたかな カタカna')
        # http://github.com/ueno/ibus-skk/issues/#issue/4
        handled, output = self.__skk.press_key(u'ctrl+m')
        self.assertEqual(output, u'カタカna')

    def testhankaku(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_KATAKANA)
        self.__skk.press_key(u'ctrl+q')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HANKAKU_KATAKANA)
        self.__skk.press_key(u'Z')
        self.__skk.press_key(u'e')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽ｾﾞﾝｶｸ')
        handled, output = self.__skk.press_key(u'ctrl+q')
        self.assertTrue(handled)
        self.assertEqual(output, u'ゼンカク')
        self.__skk.press_key(u'Z')
        self.__skk.press_key(u'e')
        self.__skk.press_key(u'n')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'k')
        self.__skk.press_key(u'u')
        self.assertEqual(self.__skk.preedit, u'▽ｾﾞﾝｶｸ')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼全角')

    def testabbrev(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'/')
        self.__skk.press_key(u'r')
        self.__skk.press_key(u'e')
        self.__skk.press_key(u'q')
        self.__skk.press_key(u'u')
        self.__skk.press_key(u'e')
        self.__skk.press_key(u's')
        self.__skk.press_key(u't')
        self.assertEqual(self.__skk.preedit, u'▽request')
        self.__skk.press_key(u' ')
        self.assertEqual(self.__skk.preedit, u'▼リクエスト')
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'z')
        handled, output = self.__skk.press_key(u'/')
        self.assertTrue(handled)
        self.assertEqual(output, u'・')

        self.__skk.reset();
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'/')
        handled, output = self.__skk.press_key(u']')
        self.assertTrue(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.preedit, u'▽]')

        # Ignore "" in abbrev mode (Issue#16).
        self.__skk.reset();
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'/')
        handled, output = self.__skk.press_key(u'(')
        self.assertTrue(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.preedit, u'▽(')

        self.__skk.reset();
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'/')
        handled, output = self.__skk.press_key(u'A')
        self.assertTrue(handled)
        self.assertEqual(output, u'')
        self.assertEqual(self.__skk.preedit, u'▽A')

        # Convert hankaku to zenkaku with ctrl+q (Issue#17).
        self.__skk.reset();
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'/')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'a')
        handled, output = self.__skk.press_key(u'ctrl+q')
        self.assertTrue(handled)
        self.assertEqual(output, u'ａａ')

    def testkuten(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'\\')
        self.assertEqual(self.__skk.preedit, u'Kuten([MM]KKTT) ')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'backspace')
        self.assertEqual(self.__skk.preedit, u'Kuten([MM]KKTT) ')
        self.__skk.press_key(u'backspace')
        self.assertEqual(self.__skk.preedit, u'')
        self.__skk.press_key(u'\\')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'1')
        self.__skk.press_key(u'a')
        self.__skk.press_key(u'2')
        handled, output = self.__skk.press_key(u'return')
        self.assertTrue(handled)
        self.assertEqual(output, u'、')
        # Don't start KUTEN input on {wide,}latin input mode.
        self.__skk.activate_input_mode(skk.INPUT_MODE_LATIN)
        handled, output = self.__skk.press_key(u'\\')
        self.assertTrue(handled)
        self.assertEqual(output, u'\\')
        self.__skk.activate_input_mode(skk.INPUT_MODE_WIDE_LATIN)
        handled, output = self.__skk.press_key(u'\\')
        self.assertTrue(handled)
        self.assertEqual(output, u'＼')

    def testnicola(self):
        class Counter(object):
            def __init__(self):
                self.__counter = 0

            def time(self):
                return self.__counter

            def incr(self, amount):
                self.__counter += amount

        t = Counter()
        n = nicola.Nicola(time_func=t.time)
        # single key - timeout
        n.queue('a')
        result = n.dispatch()
        self.assertEqual(result.output, tuple())
        t.incr(0.2)
        result = n.dispatch()
        self.assertEqual(result.output, ('a',))
        # single key - release
        n.queue('a')
        n.queue('release+a')
        result = n.dispatch()
        self.assertEqual(result.output, ('a',))
        # single key - overlap
        n.queue('a')
        t.incr(0.05)
        n.queue('b')
        result = n.dispatch()
        self.assertEqual(result.output, ('a',))
        t.incr(0.2)
        result = n.dispatch()
        self.assertEqual(result.output, ('b',))
        # double key - shifted
        n.queue('a')
        t.incr(0.01)
        n.queue('lshift')
        t.incr(0.2)
        result = n.dispatch()
        self.assertEqual(result.output, ('lshift+a',))
        # double key - shifted reverse
        n.queue('lshift')
        t.incr(0.01)
        n.queue('a')
        t.incr(0.2)
        result = n.dispatch()
        self.assertEqual(result.output, ('lshift+a',))
        # double key - shifted expired
        n.queue('a')
        t.incr(0.06)
        n.queue('lshift')
        result = n.dispatch()
        self.assertNotEqual(result.output, ('lshift+a',))
        t.incr(0.2)
        result = n.dispatch()
        # double key - skk-nicola
        n.queue('f')
        t.incr(0.03)
        n.queue('j')
        result = n.dispatch()
        self.assertEqual(result.output, ('[fj]',))
        t.incr(0.2)
        # double key - skk-nicola (reverse)
        n.queue('j')
        t.incr(0.03)
        n.queue('f')
        result = n.dispatch()
        self.assertEqual(result.output, ('[fj]',))
        t.incr(0.2)
        result = n.dispatch()
        # double key - skk-nicola (lshift+rshift)
        n.queue('lshift')
        t.incr(0.03)
        n.queue('rshift')
        result = n.dispatch()
        self.assertEqual(result.output, ('[LR]',))
        t.incr(0.2)
        # triple key t1 <= t2
        n.queue('a')
        t.incr(0.01)
        n.queue('lshift')
        t.incr(0.02)
        n.queue('b')
        result = n.dispatch()
        self.assertEqual(result.output, ('lshift+a',))
        result = n.dispatch()
        self.assertEqual(result.output, tuple())
        t.incr(0.2)
        result = n.dispatch()
        self.assertEqual(result.output, ('b',))
        # triple key t1 > t2
        n.queue('a')
        t.incr(0.02)
        n.queue('lshift')
        t.incr(0.01)
        n.queue('b')
        result = n.dispatch()
        self.assertEqual(result.output, ('a', 'lshift+b'))

    def testnicolaskk(self):
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'nicola+[fj]')
        self.assertEqual(self.__skk.conv_state, skk.CONV_STATE_START)
        self.__skk.press_key(u'nicola+w')        # か
        self.__skk.press_key(u'nicola+;')        # ん
        self.__skk.press_key(u'nicola+rshift+w') # が
        self.assertEqual(self.__skk.preedit, u'▽かんが')
        self.__skk.press_key(u'nicola+[fj]')     # start okuri-ari conversion
        self.__skk.press_key(u'nicola+lshift+w') # え
        self.assertEqual(self.__skk.preedit, u'▼考え')
        self.__skk.reset()
        self.__skk.activate_input_mode(skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'nicola+[LR]')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_LATIN)
        self.__skk.press_key(u'nicola+[LR]')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        self.__skk.activate_input_mode(skk.INPUT_MODE_LATIN)
        self.__skk.press_key(u'nicola+ctrl+j')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        self.__skk.press_key(u'nicola+Z')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_WIDE_LATIN)
        self.__skk.press_key(u'nicola+ctrl+j')
        self.assertEqual(self.__skk.input_mode, skk.INPUT_MODE_HIRAGANA)
        # latin mode input test
        self.__skk.activate_input_mode(skk.INPUT_MODE_LATIN)
        handled, output = self.__skk.press_key(u'nicola+[fj]')
        self.assertEqual(output, 'fj')
        handled, output = self.__skk.press_key(u'nicola+[')
        self.assertEqual(output, '[')
        handled, output = self.__skk.press_key(u'nicola+[LR]')
        self.assertEqual(output, '')
        self.__skk.activate_input_mode(skk.INPUT_MODE_WIDE_LATIN)
        handled, output = self.__skk.press_key(u'nicola+[fj]')
        self.assertEqual(output, u'ｆｊ')

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