summary refs log tree commit diff stats
path: root/test/tc_directory.py
blob: a43ac89d12f829908021ca6e44f2cfb9c1c1af5b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# 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/>.

import os.path
import sys
rangerpath = os.path.join(os.path.dirname(__file__), '..')
if sys.path[1] != rangerpath:
	sys.path[1:1] = [rangerpath]

from os.path import realpath, join, dirname

from ranger import fsobject
from ranger.fsobject.file import File
from ranger.fsobject.directory import Directory
from ranger.core.shared import SettingsAware

SettingsAware._setup()

TESTDIR = realpath(join(dirname(__file__), 'testdir'))
TESTFILE = join(TESTDIR, 'testfile5234148')
NONEXISTANT_DIR = join(TESTDIR, 'nonexistant')

import unittest
class Test1(unittest.TestCase):
	def test_initial_condition(self):
		# Check for the expected initial condition
		dir = Directory(TESTDIR)

		self.assertEqual(dir.path, TESTDIR)
		self.assertFalse(dir.content_loaded)
		self.assertEqual(dir.filenames, None)
		self.assertEqual(dir.files, None)
		if not sys.flags.optimize:  # asserts are ignored with python -O
			self.assertRaises(AssertionError, len, dir)

	def test_after_content_loaded(self):
		import os
		# Check whether the directory has the correct list of filenames.
		dir = Directory(TESTDIR)
		dir.load_content(schedule=False)

		self.assertTrue(dir.exists)
		self.assertEqual(type(dir.filenames), list)

		# Get the filenames you expect it to have and sort both before
		# comparing. I don't expect any order after only loading the filenames.
		assumed_filenames = os.listdir(TESTDIR)
		assumed_filenames = list(map(lambda str: os.path.join(TESTDIR, str),
			assumed_filenames))
		assumed_filenames.sort()
		dir.filenames.sort()

		self.assertTrue(len(dir) > 0)
		self.assertEqual(dir.filenames, assumed_filenames)

		# build a file object for each file in the list assumed_filenames
		# and find exactly one equivalent in dir.files
		for name in assumed_filenames:
			f = File(name)
			f.load()
			for dirfile in dir.files:
				if (f.path == dirfile.path and f.stat == dirfile.stat):
					break
			else:
				self.fail("couldn't find file {0}".format(name))

	def test_nonexistant_dir(self):
		dir = Directory(NONEXISTANT_DIR)
		dir.load_content(schedule=False)

		self.assertTrue(dir.content_loaded)
		self.assertFalse(dir.exists)
		self.assertFalse(dir.accessible)
		self.assertEqual(dir.filenames, None)
		if not sys.flags.optimize:  # asserts are ignored with python -O
			self.assertRaises(AssertionError, len, dir)

	def test_load_if_outdated(self):
		import os
		import time
		# modify the directory. If the time between the last modification
		# was within the filesystems resolution of mtime, we should have a reload

		def modify_dir():
			open(TESTFILE, 'w').close()
			os.unlink(TESTFILE)

		def mtime():
			return os.stat(TESTDIR).st_mtime

		dir = Directory(TESTDIR)
		dir.load()

		# If the modification happens to be in the same second as the
		# last modification, it will result in mtime having the same
		# integer value. So we wait until the resolution is exceeded
		# and mtime differs.
		old_mtime = mtime()
		for i in range(50):
			modify_dir()
			if old_mtime != mtime(): break
			time.sleep(0.1)
		else:
			# fail after 5 seconds of trying
			self.fail(
					"Cannot perform test: mtime of TESTDIR is not being updated.")

		self.assertTrue(dir.load_if_outdated())

if __name__ == '__main__':
	unittest.main()
ss="n">down=1) map.dir('<up>', up=1) map.dir('<left>', left=1) map.dir('<right>', right=1) map.dir('<home>', down=0, absolute=True) map.dir('<end>', down=-1, absolute=True) map.dir('<pagedown>', down=1, pages=True) map.dir('<pageup>', down=-1, pages=True) map.dir('%', down=50, percentage=True, absolute=True) # =================================================================== # == Define aliases # =================================================================== map = vim_aliases = KeyMapWithDirections() map.dir('j', alias='<down>') map.dir('k', alias='<up>') map.dir('h', alias='<left>') map.dir('l', alias='<right>') map.dir('gg', alias='<home>') map.dir('G', alias='<end>') map.dir('<C-F>', alias='<pagedown>') map.dir('<C-B>', alias='<pageup>') map = readline_aliases = KeyMapWithDirections() map.dir('<C-B>', alias='<left>') map.dir('<C-F>', alias='<right>') map.dir('<C-A>', alias='<home>') map.dir('<C-E>', alias='<end>') map.dir('<C-D>', alias='<delete>') map.dir('<C-H>', alias='<backspace>') map = midnight_commander_fkeys = KeyMapWithDirections() map('<F1>', fm.display_help()) map('<F3>', fm.display_file()) map('<F4>', fm.edit_file()) map('<F5>', fm.copy()) map('<F6>', fm.cut()) map('<F7>', fm.open_console('mkdir ')) map('<F8>', fm.open_console(DELETE_WARNING)) map('<F10>', fm.exit()) # =================================================================== # == Define keys in "browser" context: # =================================================================== map = keymanager.get_context('browser') map.merge(global_keys) map.merge(vim_aliases) map.merge(midnight_commander_fkeys) # -------------------------------------------------------- movement map('gg', fm.move(to=0)) map('<enter>', wdg.move(right=0)) # run with mode=0 map('<C-D>', 'J', fm.move(down=0.5, pages=True)) map('<C-U>', 'K', fm.move(up=0.5, pages=True)) map(']', fm.move_parent(1)) map('[', fm.move_parent(-1)) map('}', fm.traverse()) map('{', fm.history_go(-1)) # --------------------------------------------------------- history map('H', fm.history_go(-1)) map('L', fm.history_go(1)) # ----------------------------------------------- tagging / marking map('t', fm.tag_toggle()) map('T', fm.tag_remove()) map(' ', fm.mark(toggle=True)) map('v', fm.mark(all=True, toggle=True)) map('V', 'uv', fm.mark(all=True, val=False)) map('<C-V><dir>', fm.mark_in_direction(val=True)) map('u<C-V><dir>', fm.mark_in_direction(val=False)) # ------------------------------------------ file system operations map('yy', 'y<dir>', fm.copy()) map('ya', fm.copy(mode='add')) map('yr', fm.copy(mode='remove')) map('dd', 'd<dir>', fm.cut()) map('da', fm.cut(mode='add')) map('dr', fm.cut(mode='remove')) map('pp', fm.paste()) map('po', fm.paste(overwrite=True)) map('pl', fm.paste_symlink()) map('p<bg>', fm.hint('press *p* to confirm pasting' \ ', *o* to overwrite or *l* to create symlinks')) map('u<bg>', fm.hint("un*y*ank, unbook*m*ark, unselect:*v*")) map('ud', 'uy', fm.uncut()) # ---------------------------------------------------- run programs map('S', fm.execute_command(os.environ['SHELL'])) map('E', fm.edit_file()) map('du', fm.execute_console('shell -p du --max-depth=1 -h --apparent-size')) # -------------------------------------------------- toggle options map('z<bg>', fm.hint("[*cdfhimpPs*] show_*h*idden *p*review_files "\ "*P*review_dirs *f*ilter flush*i*nput *m*ouse")) map('zh', '<C-h>', '<backspace>', fm.toggle_boolean_option('show_hidden')) map('zp', fm.toggle_boolean_option('preview_files')) map('zP', fm.toggle_boolean_option('preview_directories')) map('zi', fm.toggle_boolean_option('flushinput')) map('zd', fm.toggle_boolean_option('sort_directories_first')) map('zc', fm.toggle_boolean_option('collapse_preview')) map('zs', fm.toggle_boolean_option('sort_case_insensitive')) map('zm', fm.toggle_boolean_option('mouse_enabled')) map('zf', fm.open_console('filter ')) # ------------------------------------------------------------ sort map('o<bg>', 'O<bg>', fm.hint("*s*ize *b*ase*n*ame *m*time" \ " *t*ype *r*everse")) sort_dict = { 's': 'size', 'b': 'basename', 'n': 'basename', 'm': 'mtime', 't': 'type', } for key, val in sort_dict.items(): for key, is_capital in ((key, False), (key.upper(), True)): # reverse if any of the two letters is capital map('o' + key, fm.sort(func=val, reverse=is_capital)) map('O' + key, fm.sort(func=val, reverse=True)) map('or', 'Or', 'oR', 'OR', lambda arg: \ arg.fm.sort(reverse=not arg.fm.settings.sort_reverse)) # ----------------------------------------------- console shortcuts @map("A") def append_to_filename(arg): command = 'rename ' + arg.fm.env.cf.basename arg.fm.open_console(command) @map("I") def insert_before_filename(arg): command = 'rename ' + arg.fm.env.cf.basename arg.fm.open_console(command, position=len('rename ')) map('cw', fm.open_console('rename ')) map('cd', fm.open_console('cd ')) map('f', fm.open_console('find ')) map('d<bg>', fm.hint('d*u* (disk usage) d*d* (cut)')) map('@', fm.open_console('shell %s', position=len('shell '))) map('#', fm.open_console('shell -p ')) # --------------------------------------------- jump to directories map('gh', fm.cd('~')) map('ge', fm.cd('/etc')) map('gu', fm.cd('/usr')) map('gd', fm.cd('/dev')) map('gl', lambda arg: arg.fm.cd(os.path.realpath(arg.fm.env.cwd.path))) map('gL', lambda arg: arg.fm.cd( os.path.dirname(os.path.realpath(arg.fm.env.cf.path)))) map('go', fm.cd('/opt')) map('gv', fm.cd('/var')) map('gr', 'g/', fm.cd('/')) map('gm', fm.cd('/media')) map('gM', fm.cd('/mnt')) map('gs', fm.cd('/srv')) map('gR', fm.cd(RANGERDIR)) # ------------------------------------------------------------ tabs map('gc', '<C-W>', fm.tab_close()) map('gt', '<TAB>', fm.tab_move(1)) map('gT', '<S-TAB>', fm.tab_move(-1)) @map('gn', '<C-N>') def newtab_and_gohome(arg): arg.fm.tab_new() arg.fm.cd('~') # To return to the original directory, type `` for n in range(1, 10): map('g' + str(n), fm.tab_open(n)) map('<A-' + str(n) + '>', fm.tab_open(n)) # ------------------------------------------------------- searching map('/', fm.open_console('search ')) map('n', fm.search()) map('N', fm.search(forward=False)) map('ct', fm.search(order='tag')) map('cc', fm.search(order='ctime')) map('cm', fm.search(order='mimetype')) map('cs', fm.search(order='size')) map('c<bg>', fm.hint('*c*time *m*imetype *s*ize *t*ag *w*:rename')) # ------------------------------------------------------- bookmarks for key in ALLOWED_BOOKMARK_KEYS: map("`" + key, "'" + key, fm.enter_bookmark(key)) map("m" + key, fm.set_bookmark(key)) map("um" + key, fm.unset_bookmark(key)) map("`<bg>", "'<bg>", "m<bg>", fm.draw_bookmarks()) map('um<bg>', fm.hint("delete which bookmark?")) # ---------------------------------------------------- change views map('i', fm.display_file()) map('W', fm.display_log()) map('?', fm.display_help()) map('w', lambda arg: arg.fm.ui.open_taskview()) # ------------------------------------------------ system functions map('ZZ', 'ZQ', fm.exit()) map('<C-R>', fm.reset()) map('R', fm.reload_cwd()) @map('<C-C>') def ctrl_c(arg): try: item = arg.fm.loader.queue[0] except: arg.fm.notify("Type Q or :quit<Enter> to exit Ranger") else: arg.fm.notify("Aborting: " + item.get_description()) arg.fm.loader.remove(index=0) map(':', ';', fm.open_console('')) map('!', fm.open_console('shell ')) map('s', fm.open_console('shell ')) map('r', fm.open_console('open_with ')) # =================================================================== # == Define keys for the pager # =================================================================== map = pager_keys = KeyMapWithDirections() map.merge(global_keys) map.merge(vim_aliases) # -------------------------------------------------------- movement map('<left>', 'h', wdg.move(left=4)) map('<right>', 'l', wdg.move(right=4)) map('<C-D>', 'd', wdg.move(down=0.5, pages=True)) map('<C-U>', 'u', wdg.move(up=0.5, pages=True)) map('<C-F>', 'f', '<pagedown>', wdg.move(down=1, pages=True)) map('<C-B>', 'b', '<pageup>', wdg.move(up=1, pages=True)) map('<space>', wdg.move(down=0.8, pages=True)) map('<cr>', wdg.move(down=1)) # ---------------------------------------------------------- others map('E', fm.edit_file()) map('?', fm.display_help()) # --------------------------------------------------- bind the keys # There are two different kinds of pagers, each have a different # method for exiting: map = keymanager.get_context('pager') map.merge(pager_keys) map('q', 'i', '<esc>', '<F3>', lambda arg: arg.fm.ui.close_pager()) map = keymanager.get_context('embedded_pager') map.merge(pager_keys) map('q', 'i', '<esc>', '<F3>', lambda arg: arg.fm.ui.close_embedded_pager()) # =================================================================== # == Define keys for the taskview # =================================================================== map = keymanager.get_context('taskview') map.merge(global_keys) map.merge(vim_aliases) map('K', wdg.task_move(0)) map('J', wdg.task_move(-1)) map('dd', wdg.task_remove()) map('?', fm.display_help()) map('w', 'q', ESC, ctrl('d'), ctrl('c'), lambda arg: arg.fm.ui.close_taskview()) # =================================================================== # == Define keys for the console # =================================================================== map = keymanager.get_context('console') map.merge(global_keys) map.merge(readline_aliases) map('<up>', '<C-P>', wdg.history_move(-1)) map('<down>', '<C-N>', wdg.history_move(1)) map('<home>', '<C-A>', wdg.move(right=0, absolute=True)) map('<end>', '<C-E>', wdg.move(right=-1, absolute=True)) map('<tab>', wdg.tab()) map('<s-tab>', wdg.tab(-1)) map('<C-C>', '<C-D>', '<ESC>', wdg.close()) map('<CR>', '<c-j>', wdg.execute()) map('<F1>', lambda arg: arg.fm.display_command_help(arg.wdg)) map('<backspace>', '<C-H>', wdg.delete(-1)) map('<delete>', '<C-D>', wdg.delete(0)) map('<C-W>', wdg.delete_word()) map('<C-K>', wdg.delete_rest(1)) map('<C-U>', wdg.delete_rest(-1)) map('<C-Y>', wdg.paste()) # Any key which is still undefined will simply be typed in. @map('<any>') def type_key(arg): arg.wdg.type_key(arg.match) # Allow typing in numbers: def type_chr(n): return lambda arg: arg.wdg.type_key(str(n)) for number in range(10): map(str(number), type_chr(number)) # Unmap some global keys so we can type them: map.unmap('Q') map.directions.unmap('%')