summary refs log tree commit diff stats
path: root/src/gifs/blinkies/win10no.gif
blob: 01976de184bbb89f3516d135192d01954b127e39 (plain)
ofshex dumpascii
0000 47 49 46 38 39 61 58 00 1f 00 e7 ff 00 00 01 00 02 00 05 07 00 00 00 01 0e 00 01 13 01 04 00 0c GIF89aX.........................
0020 00 08 02 05 01 10 01 01 03 04 10 16 00 03 12 00 11 0b 04 02 19 00 0c 06 06 12 21 00 00 05 08 04 ..........................!.....
0040 25 00 03 00 0b 05 29 00 00 1b 05 01 19 05 09 05 0b 0e 04 0d 00 2e 01 02 00 0f 00 33 00 00 0d 0a %.....)....................3....
0060 0f 11 0b 0a 00 11 01 3b 00 00 31 01 26 18 0c 0c 31 05 08 31 01 35 49 00 03 40 03 00 05 14 07 38 .......;..1.&...1..1.5I..@.....8
0080 05 06 4b 00 00 14 0f 0e 34 07 03 0f 11 0e 4c 00 0e 54 00 00 4f 02 03 43 06 01 42 06 09 14 16 13 ..K.....4.....L..T..O..C..B.....
00a0 19 15 14 4c 08 0b 3d 0f 0a 20 17 18 6e 00 26 66 02 31 58 0b 0e 1b 1c 1a 23 1a 1a 29 1a 18 20 1d ...L..=.....n.&f.1X.....#..)....
00c0 1c 63 0c 00 5c 0f 02 44 13 37 6b 0c 0d 32 1d 1c 4f 13 32 21 23 21 27 23 14 99 03 05 76 0e 0e 29 .c..\..D.7k..2..O.2!#!'#....v..)
00e0 26 03 7e 0c 12 37 22 0c 3c 1f 1d 7f 0d 0d 70 13 12 82 10 00 b0 03 03 31 26 31 bb 02 01 35 25 31 &.~..7".<.....p........1&1...5%1
0100 2f 28 2c 96 0f 00 2e 2a 29 c6 01 00 d0 00 00 cf 00 04 5e 20 1c d7 00 00 47 2a 0c 2d 2f 2c b1 0a /(,....*).........^.....G*.-/,..
0120 1b 55 25 25 33 33 00 de 01 00 2f 31 2e 30 32 2f 5d 26 23 30 33 27 43 2e 23 3d 33 08 3e 34 01 32 .U%%33..../1.02/]&#03'C.#=3.>4.2
0140 33 31 f0 00 00 40 31 33 77 23 23 3d 33 34 60 2a 2b ff 00 00 67 2a 2e 36 38 36 6a 2b 2b 70 2a 28 31...@13w##=34`*+...g*.686j++p*(
0160 65 2d 2f 64 32 01 60 2f 2e 68 2e 21 9f 1e 20 6e 2e 28 65 34 0b bc 1a 0d b4 1d 11 6b 31 29 67 33 e-/d2.`/.h.!...n.(e4.......k1)g3
0180 28 94 26 27 65 33 32 bd 1c 16 b4 1f 1e 6b 33 34 3f 41 3e 62 38 38 a5 2a 01 e5 16 0b bf 20 1e 98 (.&'e32......k34?A>b88.*........
01a0 2e 0c 66 3e 09 9b 30 00 86 31 34 93 2e 2e 6f 3c 13 43 45 42 9c 31 06 3a 49 39 95 2f 2f 54 44 21 ..f>..0..14...o<.CEB.1.:I9.//TD!
01c0 e6 1a 1e 91 33 34 47 49 36 9b 33 28 d7 23 16 99 33 32 c5 27 28 7d 3e 20 d0 27 13 ea 1f 20 76 40 ....34GI6.3(.#..32.'(}>..'....v@
01e0 34 9a 32 68 54 4b 40 9a 34 59 35 58 2d c4 30 2a a4 3b 2f cc 30 33 94 41 30 4c 54 50 9b 41 33 b8 4.2hTK@.4Y5X-.0*.;/.03.A0LTP.A3.
0200 3c 1a 68 4f 4e 76 4d 47 cd 31 65 fd 2b 2c ad 43 3c 95 4c 2a 54 60 34 cf 39 5e ff 31 35 fa 36 39 <.hONvMG.1e.+,.C<.L*T`4.9^.15.69
0220 ba 4c 27 68 65 30 9b 56 31 d0 4a 2a a5 58 2a 9a 57 59 65 66 64 a2 5c 30 9a 60 36 fe 40 60 96 60 .L'he0.V1.J*.X*.WYefd.\0.`6.@`.`
0240 63 c3 5a 37 c5 5b 32 cb 58 56 98 67 62 ca 5e 2e ae 66 3a d2 5f 2b c0 61 50 d2 60 39 ce 62 32 c1 c.Z7.[2.XV.gb.^..f:._+.aP.`9.b2.
0260 65 41 cd 62 3e cb 65 32 d9 5e 5f 8a 77 51 cb 67 40 f7 5c 2d d7 64 3d cc 65 57 a4 74 3e d4 67 36 eA.b>.e2.^_.wQ.g@.\-.d=.eW.t>.g6
0280 cc 66 5d d8 65 44 cb 66 63 ca 67 68 d2 65 65 fa 5b 5a d5 66 5b de 68 65 fa 65 32 db 6d 42 fe 63 .f].eD.fc.gh.ee.[Z.f[.he.e2.mB.c
02a0 40 ff 64 34 ff 64 3b fd 65 53 f3 66 67 ff 63 67 fc 66 66 ff 6a 36 dc 72 5e ff 6a 63 ff 6d 46 ff @.d4.d;.eS.fg.cg.ff.j6.r^.jc.mF.
02c0 6a 68 ff 6e 58 f0 74 54 ff 72 41 ff 6f 64 ff 73 73 ff 76 67 ce 89 5e ff 7f 3f fe 83 47 d9 8d 64 jh.nX.tT.rA.od.ss.vg..^..?..G..d
02e0 ff 8a 3c f4 8a 60 ff 88 64 ff 8d 5a ff 8d 65 fd 92 67 ff 93 63 fa 95 68 fe 94 94 ff 99 66 be c1 ..<..`..d..Z..e..g..c..h.....f..
0300 bd fe b9 63 ca cc c9 fe ff fc ff ff ff 21 f9 04 01 0a 00 ff 00 2c 00 00 00 00 58 00 1f 00 00 08 ...c.........!.......,....X.....
0320 fe 00 fd 09 1c 48 b0 a0 c1 83 08 13 2a 5c c8 30 61 81 86 10 23 4a 9c b8 b0 c0 43 7f fb 32 6a dc .....H......*\.0a...#J....C..2j.
0340 c8 b1 a3 c7 8f 20 43 8a 1c d9 d1 a2 40 92 fb fa 08 ea 83 0a a5 cb 97 30 37 9a c4 e8 b1 49 c6 24 ......C.....@..........07....I.$
0360 7b c2 94 f9 e0 a2 cd 04 09 63 32 3e 8b f9 d1 22 51 92 33 41 ca d2 00 02 87 90 1e 7d 8a f4 89 b3 {........c2>..."Q.3A.......}....
0380 e4 45 46 36 32 8d 5a 2c 90 51 6b 48 ae 47 8d ee db 9a f5 e4 47 44 28 10 50 50 81 a0 8b 2d 35 71 .EF62.Z,.QkH.G......GD(.PP...-5q
03a0 34 a4 68 c0 c6 0b 47 b0 63 35 e2 fd 7a b4 6b 5e bf 5d 2f 7e d4 70 86 c8 04 1a 42 1e f4 19 71 27 4.h...G.c5..z.k^.]/~.p....B...q'
03c0 8e 1c 14 56 ce 94 e4 4a d9 af d6 ad 60 c9 8e a5 cc 79 33 e6 bb 7f 43 27 ed 98 63 08 95 2a 0f 60 ...V...J....`....y3...C'..c..*.`
03e0 98 11 71 c4 c4 8d 07 27 5a 60 79 e2 b1 72 65 c0 99 ff de de 9d 37 b7 4c d1 7a 05 73 84 34 63 ce ..q....'Z`y..re......7.L.z.s.4c.
0400 a1 2a 59 ec f0 90 d1 e7 0d 92 08 64 42 f0 58 51 fb 32 5e df bc 73 77 ce bc d7 b2 de e0 66 37 fe .*Y........dB.XQ.2^..sw......f7.
0420 b6 88 d3 07 10 20 49 c3 80 e5 02 f4 43 cf a3 10 35 14 a8 28 fa bd be 76 ef ba 71 03 fe 2e f6 ba ......I.....C...5..(...v..q.....
0440 f0 8d 47 e8 a0 81 1c 08 dc e1 cc 2b c8 58 92 07 28 96 d8 60 49 27 28 d0 b7 1f 66 d6 7d 26 56 7e ..G........+.X..(..`I'(...f.}&V~
0460 9e dd 65 5d 59 34 6d c4 c5 0e 69 ad 21 4f 3d fa dc 63 a2 3a ea dc 43 4c 28 1b f4 e5 62 4c a3 6d ..e]Y4m...i.!O=..c.:..CL(...bL.m
0480 d4 ca 3e 15 60 90 8f 36 8b 04 d1 8c 3a ec a4 53 8f 3a f1 18 53 c8 8b 2f b9 d3 57 8c 1c 35 e1 c1 ..>.`..6....:..S.:..S../..W..5..
04a0 31 98 b4 b3 ce 2c a5 60 33 4e 26 7f 50 02 07 1a 2e 62 c5 11 1b 5a 6e 69 64 58 ff 71 04 cb 3e e2 1....,.`3N&.P....b...ZnidX.q..>.
04c0 5c 83 07 38 58 d4 81 ce 2a 8a 58 52 c5 1e fb dc 72 14 97 1c b9 c3 c6 97 1b d9 e9 22 92 1a f9 91 \..8X...*.XR....r.........."....
04e0 91 2a f4 cc 33 8d 28 e0 a4 c1 8f 22 a2 64 73 4a 96 77 6e 44 e7 3e 76 7e f9 28 98 e1 79 54 8c 3a .*..3.(....".dsJ.wnD.>v~.(..yT.:
0500 f3 e8 03 8e 3e 91 d4 63 49 38 dc 04 93 d2 9c 93 ee a3 25 97 8f 96 0a 63 98 1c 11 b2 cd 3b fe f8 ....>..cI8........%....c.....;..
0520 70 23 45 24 e4 d8 63 08 32 df 48 c3 68 a3 90 62 15 29 9d aa ae 5a e9 46 9f 7c c3 0d 34 79 28 52 p#E$..c.2.H.h..b.)...Z.F.|..4y(R
0540 4f 39 95 d8 23 4c 23 bc 28 d1 17 97 76 9e 6a 24 9d 7a 06 0b 13 9f 1a 01 31 0d 33 dd 68 c2 02 3e O9..#L#.(...v.j$.z......1.3.h..>
0560 e6 cc b3 09 30 8a 3c a2 cc b4 19 45 6a 6a af ed 56 8b 27 a5 1d 6e 74 c0 02 d3 fc 72 4e 24 e0 50 ....0.<....Ejj..V.'..nt....rN$.P
0580 03 8e 2f 7c c4 21 ca 20 7d e9 79 15 aa a6 4a da 2e 91 dc ee 13 88 0f d5 78 d2 8b 37 e4 88 73 4f ../|.!..}.y...J.........x..7..sO
05a0 38 ba 5c 52 0b a3 1a c9 6b b0 c1 44 6e 36 ec 3e 6e 7c 11 45 3d c9 58 42 8b 3a f0 2c b3 85 24 74 8.\R....k..Dn6.>n|.E=.XB.:.,..$t
05c0 94 30 c9 b4 f3 52 1b a9 c1 bc ee c9 6a 20 6e 38 61 06 13 dc b8 c2 8a 29 fa 4c 13 0b 2e e1 14 90 .0...R......j.n8a......).L......
05e0 81 00 04 c4 04 b2 46 8d 22 7c d5 bc f4 6e d4 85 45 81 80 c1 c8 2e d1 94 62 49 2a fa cc a3 8e 35 ......F."|...n..E.......bI*....5
0600 08 30 90 00 01 dd 91 44 75 9d 78 ae 4d 54 8c 05 20 20 77 02 60 08 01 46 22 79 f4 61 c6 7d 34 ec .0.....Du.x.MT....w.`..F"y.a.}4.
0620 44 a3 41 01 04 5c 40 40 06 69 87 6c 78 60 27 91 12 c0 00 19 10 20 00 02 16 98 21 84 16 8e 70 d2 D.A..\@@.i.lx`'...........!...p.
0640 c7 15 a3 4c a1 82 45 01 48 50 80 0a 30 1c 2e 3a 78 fe 18 51 80 04 03 30 20 81 01 09 24 c0 81 16 ...L..E.HP..0..:x..Q...0....$...
0660 4e 80 21 06 14 2e c4 e0 80 01 03 08 20 40 01 03 e4 de cf ef c0 07 2f fc f0 c4 17 6f fc f1 c0 43 N.!..........@......../....o...C
0680 00 81 3f ca 37 ef fc f3 d0 47 2f fd f4 d4 57 6f fd f5 d8 67 af fd f6 dc 3f 1f 10 00 3b ..?.7....G/...Wo...g....?...;
9'>349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
# coding=utf-8
# Copyright (C) 2009, 2010  Roman Zimbelmann <romanz@lavabit.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

if __name__ == '__main__': from __init__ import init; init()
from unittest import TestCase, main

from ranger.ext.tree import Tree
from ranger.container.keymap import *

import sys

class PressTestCase(TestCase):
	"""Some useful methods for the actual test"""
	def _mkpress(self, keybuffer, _=0):
		def press(keys):
			keybuffer.clear()
			match = keybuffer.simulate_press(keys)
			self.assertFalse(keybuffer.failure,
					"parsing keys '"+keys+"' did fail!")
			self.assertTrue(keybuffer.done,
					"parsing keys '"+keys+"' did not complete!")
			arg = CommandArgs(None, None, keybuffer)
			self.assert_(match.function, "No function found! " + \
					str(match.__dict__))
			return match.function(arg)
		return press

	def assertPressFails(self, kb, keys):
		kb.clear()
		kb.simulate_press(keys)
		self.assertTrue(kb.failure, "Keypress did not fail as expected")
		kb.clear()

	def assertPressIncomplete(self, kb, keys):
		kb.clear()
		kb.simulate_press(keys)
		self.assertFalse(kb.failure, "Keypress failed, expected incomplete")
		self.assertFalse(kb.done, "Keypress done which was unexpected")
		kb.clear()

class Test(PressTestCase):
	"""The test cases"""
	def test_passive_action(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		def n(value):
			"""return n or value"""
			def fnc(arg=None):
				if arg is None or arg.n is None:
					return value
				return arg.n
			return fnc

		km.map('ppp', n(5))
		km.map('pp<bg>', n(8))
		km.map('pp<dir>', n(2))
		directions.map('j', dir=Direction(down=1))

		press = self._mkpress(kb, km)
		self.assertEqual(5, press('ppp'))
		self.assertEqual(3, press('3ppp'))

		self.assertEqual(2, press('ppj'))

		kb.clear()
		match = kb.simulate_press('pp')
		args = CommandArgs(0, 0, kb)
		self.assert_(match)
		self.assert_(match.function)
		self.assertEqual(8, match.function(args))

	def test_map_collision(self):
		def add_dirs(arg):
			return sum(dir.down() for dir in arg.directions)
		def return5(_):
			return 5


		directions = KeyMap()
		directions.map('gg', dir=Direction(down=1))


		km = KeyMap()
		km.map('gh', return5)
		km.map('agh', return5)
		km.map('a<dir>', add_dirs)

		kb = KeyBuffer(km, directions)
		press = self._mkpress(kb, km)

		self.assertEqual(5, press('gh'))
		self.assertEqual(5, press('agh'))
#		self.assertPressFails(kb, 'agh')
		self.assertEqual(1, press('agg'))


	def test_translate_keys(self):
		def test(string, *args):
			if not args:
				args = (string, )
			self.assertEqual(ordtuple(*args), tuple(translate_keys(string)))

		def ordtuple(*args):
			lst = []
			for arg in args:
				if isinstance(arg, str):
					lst.extend(ord(c) for c in arg)
				else:
					lst.append(arg)
			return tuple(lst)

		# 1 argument means: assume nothing is translated.
		test('k')
		test('kj')
		test('k<dir>', 'k', DIRKEY)
		test('k<ANY>z<any>', 'k', ANYKEY, 'z', ANYKEY)
		test('k<anY>z<dir>', 'k', ANYKEY, 'z', DIRKEY)
		test('<cr>', "\n")
		test('<tab><tab><cr>', "\t\t\n")
		test('<')
		test('>')
		test('<C-a>', 1)
		test('<C-b>', 2)
		for i in range(1, 26):
			test('<C-' + chr(i+ord('a')-1) + '>', i)
		test('<A-x>', 27, ord('x'))
		test('<a-o>', 27, ord('o'))
		test('k<a')
		test('k<anz>')
		test('k<a<nz>')
		test('k<a<nz>')
		test('k<a<>nz>')
		test('>nz>')

	def test_alias(self):
		def add_dirs(arg):
			return sum(dir.down() for dir in arg.directions)
		def return5(_):
			return 5

		directions = KeyMap()
		directions.map('j', dir=Direction(down=1))
		directions.map('k', dir=Direction(down=-1))
		directions.map('<CR>', alias='j')
		directions.map('@', alias='<CR>')

		base = KeyMap()
		base.map('a<dir>', add_dirs)
		base.map('b<dir>', add_dirs)
		base.map('x<dir>x<dir>', add_dirs)
		base.map('f', return5)
		base.map('yy', alias='y')
		base.map('!', alias='!')

		other = KeyMap()
		other.map('b<dir>b<dir>', alias='x<dir>x<dir>')
		other.map('c<dir>', add_dirs)
		other.map('g', alias='f')

		km = base.merge(other, copy=True)
		kb = KeyBuffer(km, directions)

		press = self._mkpress(kb, km)

		self.assertEqual(1, press('aj'))
		self.assertEqual(2, press('bjbj'))
		self.assertEqual(1, press('cj'))
		self.assertEqual(1, press('c<CR>'))

		self.assertEqual(5, press('f'))
		self.assertEqual(5, press('g'))
		self.assertEqual(press('c<CR>'), press('c@'))
		self.assertEqual(press('c<CR>'), press('c@'))
		self.assertEqual(press('c<CR>'), press('c@'))

		for n in range(1, 50):
			self.assertPressIncomplete(kb, 'y' * n)

		for n in range(1, 5):
			self.assertPressFails(kb, '!' * n)

	def test_tree(self):
		t = Tree()
		t.set('abcd', "Yes")
		self.assertEqual("Yes", t.traverse('abcd'))
		self.assertRaises(KeyError, t.traverse, 'abcde')
		self.assertRaises(KeyError, t.traverse, 'xyz')
		self.assert_(isinstance(t.traverse('abc'), Tree))

		t2 = Tree()
		self.assertRaises(KeyError, t2.set, 'axy', "Lol", force=False)
		t2.set('axx', 'ololol')
		t2.set('axyy', "Lol")
		self.assertEqual("Yes", t.traverse('abcd'))
		self.assertRaises(KeyError, t2.traverse, 'abcd')
		self.assertEqual("Lol", t2.traverse('axyy'))
		self.assertEqual("ololol", t2.traverse('axx'))

		t2.unset('axyy')
		self.assertEqual("ololol", t2.traverse('axx'))
		self.assertRaises(KeyError, t2.traverse, 'axyy')
		self.assertRaises(KeyError, t2.traverse, 'axy')

		t2.unset('a')
		self.assertRaises(KeyError, t2.traverse, 'abcd')
		self.assertRaises(KeyError, t2.traverse, 'a')
		self.assert_(t2.empty())

	def test_merge_trees(self):
		def makeTreeA():
			t = Tree()
			t.set('aaaX', 1)
			t.set('aaaY', 2)
			t.set('aaaZ', 3)
			t.set('bbbA', 11)
			t.set('bbbB', 12)
			t.set('bbbC', 13)
			t.set('bbbD', 14)
			t.set('bP', 21)
			t.set('bQ', 22)
			return t

		def makeTreeB():
			u = Tree()
			u.set('aaaX', 0)
			u.set('bbbC', 'Yes')
			u.set('bbbD', None)
			u.set('bbbE', 15)
			u.set('bbbF', 16)
			u.set('bQ', 22)
			u.set('bR', 23)
			u.set('ffff', 1337)
			return u

		# test 1
		t = Tree('a')
		u = Tree('b')
		merged = t.merge(u, copy=True)
		self.assertEqual('b', merged._tree)

		# test 2
		t = Tree('a')
		u = makeTreeA()
		merged = t.merge(u, copy=True)
		self.assertEqual(u._tree, merged._tree)

		# test 3
		t = makeTreeA()
		u = makeTreeB()
		v = t.merge(u, copy=True)

		self.assertEqual(0, v['aaaX'])
		self.assertEqual(2, v['aaaY'])
		self.assertEqual(3, v['aaaZ'])
		self.assertEqual(11, v['bbbA'])
		self.assertEqual('Yes', v['bbbC'])
		self.assertEqual(None, v['bbbD'])
		self.assertEqual(15, v['bbbE'])
		self.assertEqual(16, v['bbbF'])
		self.assertRaises(KeyError, t.__getitem__, 'bbbG')
		self.assertEqual(21, v['bP'])
		self.assertEqual(22, v['bQ'])
		self.assertEqual(23, v['bR'])
		self.assertEqual(1337, v['ffff'])

		# merge shouldn't be destructive
		self.assertEqual(makeTreeA()._tree, t._tree)
		self.assertEqual(makeTreeB()._tree, u._tree)

		v['fff'].replace('Lolz')
		self.assertEqual('Lolz', v['fff'])

		v['aaa'].replace('Very bad')
		v.plow('qqqqqqq').replace('eww.')

		self.assertEqual(makeTreeA()._tree, t._tree)
		self.assertEqual(makeTreeB()._tree, u._tree)

	def test_add(self):
		c = KeyMap()
		c.map('aa', 'b', lambda *_: 'lolz')
		self.assert_(c['aa'].function(), 'lolz')
		@c.map('a', 'c')
		def test():
			return 5
		self.assert_(c['b'].function(), 'lolz')
		self.assert_(c['c'].function(), 5)
		self.assert_(c['a'].function(), 5)

	def test_quantifier(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		def n(value):
			"""return n or value"""
			def fnc(arg=None):
				if arg is None or arg.n is None:
					return value
				return arg.n
			return fnc
		km.map('p', n(5))
		press = self._mkpress(kb, km)
		self.assertEqual(5, press('p'))
		self.assertEqual(3, press('3p'))
		self.assertEqual(6223, press('6223p'))

	def test_direction(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		directions.map('j', dir=Direction(down=1))
		directions.map('k', dir=Direction(down=-1))
		def nd(arg):
			""" n * direction """
			n = arg.n is None and 1 or arg.n
			dir = arg.direction is None and Direction(down=1) \
					or arg.direction
			return n * dir.down()
		km.map('d<dir>', nd)
		km.map('dd', func=nd)

		press = self._mkpress(kb, km)

		self.assertPressIncomplete(kb, 'd')
		self.assertEqual(  1, press('dj'))
		self.assertEqual(  3, press('3ddj'))
		self.assertEqual( 15, press('3d5j'))
		self.assertEqual(-15, press('3d5k'))
		# supporting this kind of key combination would be too confusing:
		# self.assertEqual( 15, press('3d5d'))
		self.assertEqual(  3, press('3dd'))
		self.assertEqual(  33, press('33dd'))
		self.assertEqual(  1, press('dd'))

		km.map('x<dir>', nd)
		km.map('xxxx', func=nd)

		self.assertEqual(1, press('xxxxj'))
		self.assertEqual(1, press('xxxxjsomeinvalitchars'))

		# these combinations should break:
		self.assertPressFails(kb, 'xxxj')
		self.assertPressFails(kb, 'xxj')
		self.assertPressFails(kb, 'xxkldfjalksdjklsfsldkj')
		self.assertPressFails(kb, 'xyj')
		self.assertPressIncomplete(kb, 'x') # direction missing

	def test_any_key(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		directions.map('j', dir=Direction(down=1))
		directions.map('k', dir=Direction(down=-1))

		directions.map('g<any>', dir=Direction(down=-1))

		def cat(arg):
			n = arg.n is None and 1 or arg.n
			return ''.join(chr(c) for c in arg.matches) * n

		km.map('return<any>', cat)
		km.map('cat4<any><any><any><any>', cat)
		km.map('foo<dir><any>', cat)

		press = self._mkpress(kb, km)

		self.assertEqual('x', press('returnx'))
		self.assertEqual('abcd', press('cat4abcd'))
		self.assertEqual('abcdabcd', press('2cat4abcd'))
		self.assertEqual('55555', press('5return5'))

		self.assertEqual('x', press('foojx'))
		self.assertPressFails(kb, 'fooggx')  # ANYKEY forbidden in DIRECTION

		km.map('<any>', lambda _: Ellipsis)
		self.assertEqual('x', press('returnx'))
		self.assertEqual('abcd', press('cat4abcd'))
		self.assertEqual(Ellipsis, press('2cat4abcd'))
		self.assertEqual(Ellipsis, press('5return5'))
		self.assertEqual(Ellipsis, press('g'))
		self.assertEqual(Ellipsis, press('ß'))
		self.assertEqual(Ellipsis, press('ア'))
		self.assertEqual(Ellipsis, press('9'))

	def test_multiple_directions(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		directions.map('j', dir=Direction(down=1))
		directions.map('k', dir=Direction(down=-1))

		def add_dirs(arg):
			return sum(dir.down() for dir in arg.directions)

		km.map('x<dir>y<dir>', add_dirs)
		km.map('four<dir><dir><dir><dir>', add_dirs)

		press = self._mkpress(kb, km)

		self.assertEqual(2, press('xjyj'))
		self.assertEqual(0, press('fourjkkj'))
		self.assertEqual(2, press('four2j4k2j2j'))
		self.assertEqual(10, press('four1j2j3j4j'))
		self.assertEqual(10, press('four1j2j3j4jafslkdfjkldj'))

	def test_corruptions(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		press = self._mkpress(kb, km)
		directions.map('j', dir=Direction(down=1))
		directions.map('k', dir=Direction(down=-1))
		km.map('xxx', lambda _: 1)

		self.assertEqual(1, press('xxx'))

		# corrupt the tree
		tup = tuple(translate_keys('xxx'))
		x = ord('x')
		km._tree[x][x][x] = "Boo"

		self.assertPressFails(kb, 'xxy')
		self.assertPressFails(kb, 'xzy')
		self.assertPressIncomplete(kb, 'xx')
		self.assertPressIncomplete(kb, 'x')
		if not sys.flags.optimize:
			self.assertRaises(AssertionError, kb.simulate_press, 'xxx')
		kb.clear()

	def test_directions_as_functions(self):
		km = KeyMap()
		directions = KeyMap()
		kb = KeyBuffer(km, directions)
		press = self._mkpress(kb, km)

		def move(arg):
			return arg.direction.down()

		directions.map('j', dir=Direction(down=1))
		directions.map('s', alias='j')
		directions.map('k', dir=Direction(down=-1))
		km.map('<dir>', func=move)

		self.assertEqual(1, press('j'))
		self.assertEqual(1, press('j'))
		self.assertEqual(1, press('j'))
		self.assertEqual(1, press('j'))
		self.assertEqual(1, press('j'))
		self.assertEqual(1, press('s'))
		self.assertEqual(1, press('s'))
		self.assertEqual(1, press('s'))
		self.assertEqual(1, press('s'))
		self.assertEqual(1, press('s'))
		self.assertEqual(-1, press('k'))
		self.assertEqual(-1, press('k'))
		self.assertEqual(-1, press('k'))

		km.map('k', func=lambda _: 'love')

		self.assertEqual(1, press('j'))
		self.assertEqual('love', press('k'))

		self.assertEqual(1, press('40j'))
		self.assertEqual(40, kb.quant)

		km.map('<dir><dir><any><any>', func=move)

		self.assertEqual(1, press('40jkhl'))
		self.assertEqual(40, kb.quant)

	def test_tree_deep_copy(self):
		t = Tree()
		s = t.plow('abcd')
		s.replace('X')
		u = t.copy()
		self.assertEqual(t._tree, u._tree)
		s = t.traverse('abc')
		s.replace('Y')
		self.assertNotEqual(t._tree, u._tree)

	def test_keymap_with_context(self):
		def func(arg):
			return 5
		def getdown(arg):
			return arg.direction.down()

		buffer = KeyBuffer(None, None)
		press = self._mkpress(buffer)
		kmc = KeyManager(buffer, ['foo', 'bar'])

		map = kmc.get_context('foo')
		map('a', func)
		map('b', func)
		map = kmc.get_context('bar')
		map('c', func)
		map('<dir>', getdown)

		kmc.map('directions', 'j', dir=Direction(down=1))

		kmc.use_context('foo')
		self.assertEqual(5, press('a'))
		self.assertEqual(5, press('b'))
		self.assertPressFails(buffer, 'c')

		kmc.use_context('bar')
		self.assertPressFails(buffer, 'a')
		self.assertPressFails(buffer, 'b')
		self.assertEqual(5, press('c'))
		self.assertEqual(1, press('j'))
		kmc.use_context('foo')
		kmc.use_context('foo')
		kmc.use_context('foo')
		kmc.use_context('bar')
		kmc.use_context('foo')
		kmc.use_context('bar')
		kmc.use_context('bar')
		self.assertEqual(1, press('j'))

if __name__ == '__main__': main()