1 2# Copyright 2009-2017 Jaap Karssenberg <jaap.karssenberg@gmail.com> 3 4 5 6import tests 7 8from zim.newfs import TmpFile 9from zim.notebook import Path 10 11from zim.gui.customtools import * 12 13 14def clear_customtools(): 15 listfile = XDG_CONFIG_HOME.file('zim/customtools/customtools.list') 16 folder = XDG_CONFIG_HOME.subdir('zim/customtools/') 17 assert 'tests/tmp' in listfile.path.replace('\\', '/') 18 assert 'tests/tmp' in folder.path.replace('\\', '/') 19 listfile.remove() 20 folder.remove_children() 21 22 23class MockStubPageView(StubPageView): 24 25 def get_word(self, format=None): 26 if format: 27 return '**FooBar**' 28 else: 29 return 'FooBar' 30 31 32@tests.slowTest 33class TestCustomTools(tests.TestCase): 34 35 mockConfigManager = False # breaks hack in customtools 36 37 def setUp(self): 38 clear_customtools() 39 40 def testManager(self): 41 '''Test CustomToolManager API''' 42 # initialize the list 43 manager = CustomToolManager() 44 self.assertEqual(list(manager), []) 45 self.assertEqual(list(manager._names), []) 46 47 # add a tool 48 properties = { 49 'Name': 'Foo', 50 'Comment': 'Test 1 2 3', 51 'Icon': '', 52 'X-Zim-ExecTool': 'foo %t "quoted"', 53 'X-Zim-ReadOnly': False, 54 'X-Zim-ShowInToolBar': True, 55 } 56 tool = manager.create(**properties) 57 self.assertEqual(list(manager), [tool]) 58 self.assertEqual(list(manager._names), ['foo-usercreated']) 59 60 self.assertTrue(tool.isvalid) 61 self.assertEqual(tool.name, 'Foo') 62 self.assertEqual(tool.comment, 'Test 1 2 3') 63 self.assertFalse(tool.isreadonly) 64 self.assertTrue(tool.showintoolbar) 65 self.assertTrue(tool.get_pixbuf(Gtk.IconSize.MENU)) 66 self.assertEqual(tool.showincontextmenu, 'Text') # Auto generated 67 68 # test file saved correctly 69 #~ from pprint import pprint 70 #~ pprint(tool) 71 lines = tool.dump() 72 self.assertTrue(len(lines) > 5) 73 lines = tool.file.readlines() 74 self.assertTrue(len(lines) > 5) 75 76 # refresh list 77 manager = CustomToolManager() 78 self.assertEqual(list(manager), [tool]) 79 self.assertEqual(list(manager._names), ['foo-usercreated']) 80 81 # add a second tool 82 tool1 = tool 83 properties = { 84 'Name': 'Foo', 85 'Comment': 'Test 1 2 3', 86 'Icon': None, 87 'X-Zim-ExecTool': 'foo %f', 88 'X-Zim-ReadOnly': False, 89 'X-Zim-ShowInToolBar': True, 90 } 91 tool = manager.create(**properties) 92 self.assertEqual(list(manager), [tool1, tool]) 93 self.assertEqual(list(manager._names), ['foo-usercreated', 'foo-usercreated-1']) 94 95 self.assertTrue(tool.isvalid) 96 self.assertEqual(tool.name, 'Foo') 97 self.assertEqual(tool.comment, 'Test 1 2 3') 98 self.assertFalse(tool.isreadonly) 99 self.assertTrue(tool.showintoolbar) 100 self.assertTrue(tool.get_pixbuf(Gtk.IconSize.MENU)) 101 self.assertEqual(tool.showincontextmenu, 'Page') # Auto generated 102 103 # switch order 104 i = manager.index(tool) 105 self.assertTrue(i == 1) 106 manager.reorder(tool, 0) 107 i = manager.index(tool) 108 self.assertTrue(i == 0) 109 self.assertEqual(list(manager._names), ['foo-usercreated-1', 'foo-usercreated']) 110 111 # delete 112 file = tool1.file 113 self.assertTrue(file.exists()) 114 manager.delete(tool1) 115 self.assertEqual(list(manager._names), ['foo-usercreated-1']) 116 self.assertFalse(file.exists()) 117 118 def testParseExec(self): 119 '''Test parsing of custom tool Exec strings''' 120 # %f for source file as tmp file current page 121 # %d for attachment directory 122 # %s for real source file (if any) 123 # %p for the page name 124 # %n for notebook location (file or directory) 125 # %D for document root 126 # %t for selected text or word under cursor 127 # %T for selected text or word under cursor with wiki format 128 129 notebook = self.setUpNotebook() 130 page = notebook.get_page(Path('Test:Foo')) 131 pageview = MockStubPageView(notebook, page) 132 args = (notebook, page, pageview) 133 134 tmpfile = TmpFile('tmp-page-source.txt').path 135 136 tool = CustomToolDict() 137 tool.update({ 138 'Name': 'Test', 139 'Comment': 'Test 1 2 3', 140 'X-Zim-ExecTool': 'foo', 141 }) 142 for cmd, wanted in ( 143 ('foo %f', ('foo', tmpfile)), 144 ('foo %d', ('foo', notebook.folder.folder('Test/Foo').path)), 145 ('foo %s', ('foo', page.source.path)), 146 ('foo %p', ('foo', 'Test:Foo')), 147 ('foo %n', ('foo', notebook.folder.path)), 148 ('foo %D', ('foo', '')), # no document root 149 ('foo %t', ('foo', 'FooBar')), 150 ('foo %T', ('foo', '**FooBar**')), 151 ): 152 #~ print('>>>', cmd) 153 tool['Desktop Entry']['X-Zim-ExecTool'] = cmd 154 self.assertEqual(tool.parse_exec(args), wanted) 155 156 157class TestCustomToolsUI(tests.TestCase): 158 159 mockConfigManager = False # breaks hack in customtools 160 161 def setUp(self): 162 clear_customtools() 163 164 notebook = self.setUpNotebook(content=('test',)) 165 page = notebook.get_page(Path('test')) 166 167 self.uimanager = Gtk.UIManager() 168 group = Gtk.ActionGroup('test') 169 group.add_actions([('tools_menu', None, '_Tools')]) 170 self.uimanager.insert_action_group(group) 171 172 173 self.pageview = StubPageView(notebook, page) 174 self.customtoolsui = CustomToolManagerUI(self.uimanager, self.pageview) 175 176 def get_action(self, name): 177 for group in self.uimanager.get_action_groups(): 178 action = group.get_action(name) 179 if action: 180 return action 181 else: 182 raise ValueError 183 184 def testMenuUpdatedWhenToolAdded(self): 185 # Key in this test is that the changes happens via a different instance 186 # of the manager - demonstrating the singleton-like behavior 187 self.assertNotIn('edit-usercreated', self.uimanager.get_ui()) 188 mymanager = CustomToolManager() 189 mytool = { 190 'Name': 'Edit', 191 'Comment': 'Test Edit', 192 'X-Zim-ExecTool': 'edit %f', 193 } 194 mymanager.create(**mytool) 195 self.assertIn('edit-usercreated', self.uimanager.get_ui()) 196 197 def testMenuUpdatedWhenToolChanges(self): 198 # Key in this test is that the changes happens via a different instance 199 # of the manager - demonstrating the singleton-like behavior 200 mymanager = CustomToolManager() 201 mytool = { 202 'Name': 'Edit', 203 'Comment': 'Test Edit', 204 'X-Zim-ExecTool': 'edit %f', 205 } 206 mymanager.create(**mytool) 207 self.assertIn('edit-usercreated', self.uimanager.get_ui()) 208 action = self.get_action('edit-usercreated') 209 self.assertEqual(action.get_property('label'), 'Edit') 210 211 tool = mymanager.get_tool('Edit') 212 tool.update({'Name': 'My Editting tool'}) 213 tool.write() 214 self.assertIn('edit-usercreated', self.uimanager.get_ui()) 215 action = self.get_action('edit-usercreated') 216 self.assertEqual(action.get_property('label'), 'My Editting tool') 217 218 def testExecuteCustomToolAction(self): 219 mymanager = CustomToolManager() 220 mytool = { 221 'Name': 'Edit', 222 'Comment': 'Test Edit', 223 'X-Zim-ExecTool': 'edit %f', 224 } 225 mymanager.create(**mytool) 226 action = self.get_action('edit-usercreated') 227 228 def tool_run(args): 229 self.assertIn(args[0], ('edit', b'edit')) 230 231 with tests.ApplicationContext(tool_run): 232 action.activate() 233 234 def testExecuteCustomToolActionModifyPage(self): 235 mymanager = CustomToolManager() 236 mytool = { 237 'Name': 'Edit', 238 'Comment': 'Test Edit', 239 'X-Zim-ExecTool': 'edit %s', 240 'X-Zim-ReadOnly': False, 241 } 242 mymanager.create(**mytool) 243 action = self.get_action('edit-usercreated') 244 245 def tool_run(args): 246 self.assertIn(args[0], ('edit', b'edit')) 247 self.pageview.page.source_file.write('test 123') 248 249 with tests.ApplicationContext(tool_run): 250 action.activate() 251 252 def testExecuteCustomToolActionReplaceSelection(self): 253 mymanager = CustomToolManager() 254 mytool = { 255 'Name': 'Edit', 256 'Comment': 'Test Edit', 257 'X-Zim-ExecTool': 'edit %f', 258 'X-Zim-ReplaceSelection': True, 259 } 260 tool = mymanager.create(**mytool) 261 self.assertTrue(tool.replaceselection) 262 action = self.get_action('edit-usercreated') 263 264 got = [] 265 self.pageview.replace_selection = lambda *a, **kwa: got.append(a) 266 267 def tool_run(args): 268 self.assertIn(args[0], ('edit', b'edit')) 269 return "TEST 123" 270 271 with tests.ApplicationContext(tool_run): 272 action.activate() 273 274 self.assertEqual(got, [('TEST 123',)]) 275 276class TestCustomToolDialog(tests.TestCase): 277 278 mockConfigManager = False # breaks hack in customtools 279 280 def setUp(self): 281 clear_customtools() 282 283 def testAddCustomTool(self): 284 manager = CustomToolManager() 285 mytool = { 286 'Name': 'Add', 287 'Comment': 'Test Add', 288 'X-Zim-ExecTool': 'add %f', 289 'X-Zim-ReadOnly': False, 290 'X-Zim-ShowInToolBar': False, 291 'X-Zim-ReplaceSelection': False, 292 } 293 294 self.assertIsNone(manager.get_tool('Add')) 295 296 def add_tool(dialog): 297 dialog.set_input(**mytool) 298 dialog.assert_response_ok() 299 300 dialog = CustomToolManagerDialog(None) 301 with tests.DialogContext(add_tool): 302 dialog.on_add() 303 dialog.assert_response_ok() 304 305 # XXX listview intialization fails in test ??? 306 #model = dialog.listview.get_model() 307 #self.assertIn('Add', [r[CustomToolList.NAME_COL] for r in model]) 308 309 tool = manager.get_tool('Add') 310 self.assertIsNotNone(tool) 311 for key, value in list(mytool.items()): 312 self.assertEqual(tool['Desktop Entry'][key], value) 313 314 @tests.expectedFailure # Fails because of select_by_name fails - listview initialized ? 315 def testEditCustomTool(self): 316 manager = CustomToolManager() 317 mytool = { 318 'Name': 'Edit', 319 'Comment': 'Test Edit', 320 'X-Zim-ExecTool': 'edit %f', 321 } 322 manager.create(**mytool) 323 self.assertIsNotNone(manager.get_tool('Edit')) 324 325 def edit_tool(dialog): 326 dialog.set_input(Comment='Editted Comment') 327 dialog.assert_response_ok() 328 329 dialog = CustomToolManagerDialog(None) 330 #model = dialog.listview.get_model() 331 #self.assertIn('Edit', [r[CustomToolList.NAME_COL] for r in model]) 332 with tests.DialogContext(edit_tool): 333 dialog.listview.select_by_name('Edit') 334 dialog.on_edit() 335 dialog.assert_response_ok() 336 337 tool = manager.get_tool('Edit') 338 self.assertEqual(tool.comment, 'Editted Comment') 339 340 @tests.expectedFailure 341 def testRemoveCustomTool(self): 342 # Need initialized listview 343 raise NotImplementedError 344 345 @tests.expectedFailure 346 def testMovePositionInList(self): 347 # Need initialized listview 348 raise NotImplementedError 349