1# Copyright 2021 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Tests for pw_console.console_app""" 15 16import logging 17import unittest 18from unittest.mock import MagicMock 19 20from prompt_toolkit.application import create_app_session 21from prompt_toolkit.output import ColorDepth 22# inclusive-language: ignore 23from prompt_toolkit.output import DummyOutput as FakeOutput 24 25from pw_console.console_app import ConsoleApp 26from pw_console.console_prefs import ConsolePrefs 27from pw_console.window_manager import _WINDOW_SPLIT_ADJUST 28from pw_console.window_list import _WINDOW_HEIGHT_ADJUST, DisplayMode 29 30 31def _create_console_app(logger_count=2): 32 console_app = ConsoleApp(color_depth=ColorDepth.DEPTH_8_BIT, 33 prefs=ConsolePrefs(project_file=False, 34 project_user_file=False, 35 user_file=False)) 36 console_app.focus_on_container = MagicMock() 37 38 loggers = {} 39 for i in range(logger_count): 40 loggers['Log{}'.format(i)] = [ 41 logging.getLogger('test_log{}'.format(i)) 42 ] 43 for window_title, logger_instances in loggers.items(): 44 console_app.add_log_handler(window_title, logger_instances) 45 return console_app 46 47 48_WINDOW_MANAGER_WIDTH = 80 49_WINDOW_MANAGER_HEIGHT = 30 50_DEFAULT_WINDOW_WIDTH = 10 51_DEFAULT_WINDOW_HEIGHT = 10 52 53 54def _window_list_widths(window_manager): 55 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 56 _WINDOW_MANAGER_HEIGHT) 57 58 return [ 59 window_list.width.preferred 60 for window_list in window_manager.window_lists 61 ] 62 63 64def _window_list_heights(window_manager): 65 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 66 _WINDOW_MANAGER_HEIGHT) 67 68 return [ 69 window_list.height.preferred 70 for window_list in window_manager.window_lists 71 ] 72 73 74def _window_pane_widths(window_manager, window_list_index=0): 75 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 76 _WINDOW_MANAGER_HEIGHT) 77 78 return [ 79 pane.width.preferred 80 for pane in window_manager.window_lists[window_list_index].active_panes 81 ] 82 83 84def _window_pane_heights(window_manager, window_list_index=0): 85 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 86 _WINDOW_MANAGER_HEIGHT) 87 88 return [ 89 pane.height.preferred 90 for pane in window_manager.window_lists[window_list_index].active_panes 91 ] 92 93 94def _window_pane_counts(window_manager): 95 return [ 96 len(window_list.active_panes) 97 for window_list in window_manager.window_lists 98 ] 99 100 101def window_pane_titles(window_manager): 102 return [[ 103 pane.pane_title() + ' - ' + pane.pane_subtitle() 104 for pane in window_list.active_panes 105 ] for window_list in window_manager.window_lists] 106 107 108def target_list_and_pane(window_manager, list_index, pane_index): 109 # pylint: disable=protected-access 110 # Bypass prompt_toolkit has_focus() 111 window_manager._get_active_window_list_and_pane = ( 112 MagicMock( # type: ignore 113 return_value=( 114 window_manager.window_lists[list_index], 115 window_manager.window_lists[list_index]. 116 active_panes[pane_index], 117 ))) 118 119 120class TestWindowManager(unittest.TestCase): 121 # pylint: disable=protected-access 122 """Tests for window management functions.""" 123 def setUp(self): 124 self.maxDiff = None # pylint: disable=invalid-name 125 126 def test_find_window_list_and_pane(self) -> None: 127 """Test getting the window list for a given pane.""" 128 with create_app_session(output=FakeOutput()): 129 console_app = _create_console_app(logger_count=3) 130 131 window_manager = console_app.window_manager 132 self.assertEqual([4], _window_pane_counts(window_manager)) 133 134 # Move 2 windows to the right into their own splits 135 target_list_and_pane(window_manager, 0, 0) 136 window_manager.move_pane_right() 137 target_list_and_pane(window_manager, 0, 0) 138 window_manager.move_pane_right() 139 target_list_and_pane(window_manager, 1, 0) 140 window_manager.move_pane_right() 141 # 3 splits, first split has 2 windows 142 self.assertEqual([2, 1, 1], _window_pane_counts(window_manager)) 143 144 # Move the first window in the first split left 145 target_list_and_pane(window_manager, 0, 0) 146 window_manager.move_pane_left() 147 # 4 splits, each with their own window 148 self.assertEqual([1, 1, 1, 1], _window_pane_counts(window_manager)) 149 150 # Move the first window to the right 151 target_list_and_pane(window_manager, 0, 0) 152 window_manager.move_pane_right() 153 # 3 splits, first split has 2 windows 154 self.assertEqual([2, 1, 1], _window_pane_counts(window_manager)) 155 156 target_pane = window_manager.window_lists[2].active_panes[0] 157 158 result_window_list, result_pane_index = ( 159 window_manager._find_window_list_and_pane_index(target_pane)) 160 self.assertEqual( 161 (result_window_list, result_pane_index), 162 (window_manager.window_lists[2], 0), 163 ) 164 window_manager.remove_pane(target_pane) 165 self.assertEqual([2, 1], _window_pane_counts(window_manager)) 166 167 def test_window_list_moving_and_resizing(self) -> None: 168 """Test window split movement resizing.""" 169 with create_app_session(output=FakeOutput()): 170 console_app = _create_console_app(logger_count=3) 171 172 window_manager = console_app.window_manager 173 174 target_list_and_pane(window_manager, 0, 0) 175 # Should have one window list split of size 50. 176 self.assertEqual( 177 _window_list_widths(window_manager), 178 [_WINDOW_MANAGER_WIDTH], 179 ) 180 181 # Move one pane to the right, creating a new window_list split. 182 window_manager.move_pane_right() 183 184 self.assertEqual(_window_list_widths(window_manager), [ 185 int(_WINDOW_MANAGER_WIDTH / 2), 186 int(_WINDOW_MANAGER_WIDTH / 2), 187 ]) 188 189 # Move another pane to the right twice, creating a third 190 # window_list split. 191 target_list_and_pane(window_manager, 0, 0) 192 window_manager.move_pane_right() 193 194 # Above window pane is at a new location 195 target_list_and_pane(window_manager, 1, 0) 196 window_manager.move_pane_right() 197 198 # Should have 3 splits now 199 self.assertEqual( 200 _window_list_widths(window_manager), 201 [ 202 int(_WINDOW_MANAGER_WIDTH / 3), 203 int(_WINDOW_MANAGER_WIDTH / 3), 204 int(_WINDOW_MANAGER_WIDTH / 3), 205 ], 206 ) 207 208 # Total of 4 active panes 209 self.assertEqual(len(list(window_manager.active_panes())), 4) 210 211 # Target the middle split 212 target_list_and_pane(window_manager, 1, 0) 213 # Shrink the middle split twice 214 window_manager.shrink_split() 215 window_manager.shrink_split() 216 self.assertEqual( 217 _window_list_widths(window_manager), 218 [ 219 int(_WINDOW_MANAGER_WIDTH / 3), 220 int(_WINDOW_MANAGER_WIDTH / 3) - 221 (2 * _WINDOW_SPLIT_ADJUST), 222 int(_WINDOW_MANAGER_WIDTH / 3) + 223 (2 * _WINDOW_SPLIT_ADJUST), 224 ], 225 ) 226 227 # Target the first split 228 target_list_and_pane(window_manager, 0, 0) 229 window_manager.reset_split_sizes() 230 # Shrink the first split twice 231 window_manager.shrink_split() 232 self.assertEqual( 233 _window_list_widths(window_manager), 234 [ 235 int(_WINDOW_MANAGER_WIDTH / 3) - 236 (1 * _WINDOW_SPLIT_ADJUST), 237 int(_WINDOW_MANAGER_WIDTH / 3) + 238 (1 * _WINDOW_SPLIT_ADJUST), 239 int(_WINDOW_MANAGER_WIDTH / 3), 240 ], 241 ) 242 243 # Target the third (last) split 244 target_list_and_pane(window_manager, 2, 0) 245 window_manager.reset_split_sizes() 246 # Shrink the third split once 247 window_manager.shrink_split() 248 self.assertEqual( 249 _window_list_widths(window_manager), 250 [ 251 int(_WINDOW_MANAGER_WIDTH / 3), 252 int(_WINDOW_MANAGER_WIDTH / 3) + 253 (1 * _WINDOW_SPLIT_ADJUST), 254 int(_WINDOW_MANAGER_WIDTH / 3) - 255 (1 * _WINDOW_SPLIT_ADJUST), 256 ], 257 ) 258 259 window_manager.reset_split_sizes() 260 # Enlarge the third split a few times. 261 window_manager.enlarge_split() 262 window_manager.enlarge_split() 263 window_manager.enlarge_split() 264 self.assertEqual( 265 _window_list_widths(window_manager), 266 [ 267 int(_WINDOW_MANAGER_WIDTH / 3), 268 int(_WINDOW_MANAGER_WIDTH / 3) - 269 (3 * _WINDOW_SPLIT_ADJUST), 270 int(_WINDOW_MANAGER_WIDTH / 3) + 271 (3 * _WINDOW_SPLIT_ADJUST), 272 ], 273 ) 274 275 # Target the middle split 276 target_list_and_pane(window_manager, 1, 0) 277 # Move the middle window pane left 278 window_manager.move_pane_left() 279 # This is called on the next render pass 280 window_manager.rebalance_window_list_sizes() 281 # Middle split should be removed 282 self.assertEqual( 283 _window_list_widths(window_manager), 284 [ 285 int(_WINDOW_MANAGER_WIDTH / 2) - 286 (3 * _WINDOW_SPLIT_ADJUST), 287 # This split is removed 288 int(_WINDOW_MANAGER_WIDTH / 2) + 289 (2 * _WINDOW_SPLIT_ADJUST), 290 ], 291 ) 292 293 # Revert sizes to default 294 window_manager.reset_split_sizes() 295 self.assertEqual( 296 _window_list_widths(window_manager), 297 [ 298 int(_WINDOW_MANAGER_WIDTH / 2), 299 int(_WINDOW_MANAGER_WIDTH / 2), 300 ], 301 ) 302 303 def test_get_pane_titles(self) -> None: 304 """Test window resizing.""" 305 with create_app_session(output=FakeOutput()): 306 console_app = _create_console_app(logger_count=3) 307 308 window_manager = console_app.window_manager 309 list_pane_titles = [ 310 # Remove mouse click handler partials in tup[2] 311 [(tup[0], tup[1]) for tup in window_list.get_pane_titles()] 312 for window_list in window_manager.window_lists 313 ] 314 self.assertEqual( 315 list_pane_titles[0], 316 [('', ' '), ('class:window-tab-inactive', ' Log2 test_log2 '), 317 ('', ' '), ('class:window-tab-inactive', ' Log1 test_log1 '), 318 ('', ' '), ('class:window-tab-inactive', ' Log0 test_log0 '), 319 ('', ' '), ('class:window-tab-inactive', ' Python Repl '), 320 ('', ' ')], 321 ) 322 323 def test_window_pane_movement_resizing(self) -> None: 324 """Test window resizing.""" 325 with create_app_session(output=FakeOutput()): 326 console_app = _create_console_app(logger_count=3) 327 328 window_manager = console_app.window_manager 329 330 # 4 panes, 3 for the loggers and 1 for the repl. 331 self.assertEqual( 332 len(window_manager.first_window_list().active_panes), 4) 333 334 def target_window_pane(index: int): 335 # Bypass prompt_toolkit has_focus() 336 window_manager._get_active_window_list_and_pane = ( 337 MagicMock( # type: ignore 338 return_value=( 339 window_manager.window_lists[0], 340 window_manager.window_lists[0].active_panes[index], 341 ))) 342 window_list = console_app.window_manager.first_window_list() 343 window_list.get_current_active_pane = ( 344 MagicMock( # type: ignore 345 return_value=window_list.active_panes[index])) 346 347 # Target the first window pane 348 target_window_pane(0) 349 350 # Shrink the first pane 351 window_manager.shrink_pane() 352 self.assertEqual( 353 _window_pane_heights(window_manager), 354 [ 355 _DEFAULT_WINDOW_HEIGHT - (1 * _WINDOW_HEIGHT_ADJUST), 356 _DEFAULT_WINDOW_HEIGHT + (1 * _WINDOW_HEIGHT_ADJUST), 357 _DEFAULT_WINDOW_HEIGHT, 358 _DEFAULT_WINDOW_HEIGHT, 359 ], 360 ) 361 362 # Reset pane sizes 363 window_manager.window_lists[0].current_window_list_height = ( 364 4 * _DEFAULT_WINDOW_HEIGHT) 365 window_manager.reset_pane_sizes() 366 self.assertEqual( 367 _window_pane_heights(window_manager), 368 [ 369 _DEFAULT_WINDOW_HEIGHT, 370 _DEFAULT_WINDOW_HEIGHT, 371 _DEFAULT_WINDOW_HEIGHT, 372 _DEFAULT_WINDOW_HEIGHT, 373 ], 374 ) 375 376 # Shrink last pane 377 target_window_pane(3) 378 379 window_manager.shrink_pane() 380 self.assertEqual( 381 _window_pane_heights(window_manager), 382 [ 383 _DEFAULT_WINDOW_HEIGHT, 384 _DEFAULT_WINDOW_HEIGHT, 385 _DEFAULT_WINDOW_HEIGHT + (1 * _WINDOW_HEIGHT_ADJUST), 386 _DEFAULT_WINDOW_HEIGHT - (1 * _WINDOW_HEIGHT_ADJUST), 387 ], 388 ) 389 390 # Enlarge second pane 391 target_window_pane(1) 392 window_manager.reset_pane_sizes() 393 394 window_manager.enlarge_pane() 395 window_manager.enlarge_pane() 396 self.assertEqual( 397 _window_pane_heights(window_manager), 398 [ 399 _DEFAULT_WINDOW_HEIGHT, 400 _DEFAULT_WINDOW_HEIGHT + (2 * _WINDOW_HEIGHT_ADJUST), 401 _DEFAULT_WINDOW_HEIGHT - (2 * _WINDOW_HEIGHT_ADJUST), 402 _DEFAULT_WINDOW_HEIGHT, 403 ], 404 ) 405 406 # Check window pane ordering 407 self.assertEqual( 408 window_pane_titles(window_manager), 409 [ 410 [ 411 'Log2 - test_log2', 412 'Log1 - test_log1', 413 'Log0 - test_log0', 414 'Python Repl - ', 415 ], 416 ], 417 ) 418 419 target_window_pane(0) 420 window_manager.move_pane_down() 421 self.assertEqual( 422 window_pane_titles(window_manager), 423 [ 424 [ 425 'Log1 - test_log1', 426 'Log2 - test_log2', 427 'Log0 - test_log0', 428 'Python Repl - ', 429 ], 430 ], 431 ) 432 target_window_pane(2) 433 window_manager.move_pane_up() 434 target_window_pane(1) 435 window_manager.move_pane_up() 436 self.assertEqual( 437 window_pane_titles(window_manager), 438 [ 439 [ 440 'Log0 - test_log0', 441 'Log1 - test_log1', 442 'Log2 - test_log2', 443 'Python Repl - ', 444 ], 445 ], 446 ) 447 target_window_pane(0) 448 window_manager.move_pane_up() 449 self.assertEqual( 450 window_pane_titles(window_manager), 451 [ 452 [ 453 'Log0 - test_log0', 454 'Log1 - test_log1', 455 'Log2 - test_log2', 456 'Python Repl - ', 457 ], 458 ], 459 ) 460 461 def test_focus_next_and_previous_pane(self) -> None: 462 """Test switching focus to next and previous window panes.""" 463 with create_app_session(output=FakeOutput()): 464 console_app = _create_console_app(logger_count=4) 465 466 window_manager = console_app.window_manager 467 self.assertEqual( 468 window_pane_titles(window_manager), 469 [ 470 [ 471 'Log3 - test_log3', 472 'Log2 - test_log2', 473 'Log1 - test_log1', 474 'Log0 - test_log0', 475 'Python Repl - ', 476 ], 477 ], 478 ) 479 480 # Scenario: Move between panes with a single stacked window list. 481 482 # Set the first pane in focus. 483 target_list_and_pane(window_manager, 0, 0) 484 # Switch focus to the next pane 485 window_manager.focus_next_pane() 486 # Pane index 1 should now be focused. 487 console_app.focus_on_container.assert_called_once_with( 488 window_manager.window_lists[0].active_panes[1]) 489 console_app.focus_on_container.reset_mock() 490 491 # Set the first pane in focus. 492 target_list_and_pane(window_manager, 0, 0) 493 # Switch focus to the previous pane 494 window_manager.focus_previous_pane() 495 # Previous pane should wrap around to the last pane in the first 496 # window_list. 497 console_app.focus_on_container.assert_called_once_with( 498 window_manager.window_lists[0].active_panes[-1]) 499 console_app.focus_on_container.reset_mock() 500 501 # Set the last pane in focus. 502 target_list_and_pane(window_manager, 0, 4) 503 # Switch focus to the next pane 504 window_manager.focus_next_pane() 505 # Next pane should wrap around to the first pane in the first 506 # window_list. 507 console_app.focus_on_container.assert_called_once_with( 508 window_manager.window_lists[0].active_panes[0]) 509 console_app.focus_on_container.reset_mock() 510 511 # Scenario: Move between panes with a single tabbed window list. 512 513 # Switch to Tabbed view mode 514 window_manager.window_lists[0].set_display_mode(DisplayMode.TABBED) 515 # The set_display_mode call above will call focus_on_container once. 516 console_app.focus_on_container.reset_mock() 517 518 # Setup the switch_to_tab mock 519 window_manager.window_lists[0].switch_to_tab = MagicMock( 520 wraps=window_manager.window_lists[0].switch_to_tab) 521 522 # Set the first pane/tab in focus. 523 target_list_and_pane(window_manager, 0, 0) 524 # Switch focus to the next pane/tab 525 window_manager.focus_next_pane() 526 # Check switch_to_tab is called 527 window_manager.window_lists[ 528 0].switch_to_tab.assert_called_once_with(1) 529 # And that focus_on_container is called only once 530 console_app.focus_on_container.assert_called_once_with( 531 window_manager.window_lists[0].active_panes[1]) 532 console_app.focus_on_container.reset_mock() 533 window_manager.window_lists[0].switch_to_tab.reset_mock() 534 535 # Set the last pane/tab in focus. 536 target_list_and_pane(window_manager, 0, 4) 537 # Switch focus to the next pane/tab 538 window_manager.focus_next_pane() 539 # Check switch_to_tab is called 540 window_manager.window_lists[ 541 0].switch_to_tab.assert_called_once_with(0) 542 # And that focus_on_container is called only once 543 console_app.focus_on_container.assert_called_once_with( 544 window_manager.window_lists[0].active_panes[0]) 545 console_app.focus_on_container.reset_mock() 546 window_manager.window_lists[0].switch_to_tab.reset_mock() 547 548 # Set the first pane/tab in focus. 549 target_list_and_pane(window_manager, 0, 0) 550 # Switch focus to the prev pane/tab 551 window_manager.focus_previous_pane() 552 # Check switch_to_tab is called 553 window_manager.window_lists[ 554 0].switch_to_tab.assert_called_once_with(4) 555 # And that focus_on_container is called only once 556 console_app.focus_on_container.assert_called_once_with( 557 window_manager.window_lists[0].active_panes[4]) 558 console_app.focus_on_container.reset_mock() 559 window_manager.window_lists[0].switch_to_tab.reset_mock() 560 561 # Scenario: Move between multiple window lists with mixed stacked 562 # and tabbed view modes. 563 564 # Setup: Move two panes to the right into their own stacked 565 # window_list. 566 target_list_and_pane(window_manager, 0, 4) 567 window_manager.move_pane_right() 568 target_list_and_pane(window_manager, 0, 3) 569 window_manager.move_pane_right() 570 self.assertEqual( 571 window_pane_titles(window_manager), 572 [ 573 [ 574 'Log3 - test_log3', 575 'Log2 - test_log2', 576 'Log1 - test_log1', 577 ], 578 [ 579 'Log0 - test_log0', 580 'Python Repl - ', 581 ], 582 ], 583 ) 584 585 # Setup the switch_to_tab mock on the second window_list 586 window_manager.window_lists[1].switch_to_tab = MagicMock( 587 wraps=window_manager.window_lists[1].switch_to_tab) 588 589 # Set Log1 in focus 590 target_list_and_pane(window_manager, 0, 2) 591 window_manager.focus_next_pane() 592 # Log0 should now have focus 593 console_app.focus_on_container.assert_called_once_with( 594 window_manager.window_lists[1].active_panes[0]) 595 console_app.focus_on_container.reset_mock() 596 597 # Set Log0 in focus 598 target_list_and_pane(window_manager, 1, 0) 599 window_manager.focus_previous_pane() 600 # Log1 should now have focus 601 console_app.focus_on_container.assert_called_once_with( 602 window_manager.window_lists[0].active_panes[2]) 603 # The first window list is in tabbed mode so switch_to_tab should be 604 # called once. 605 window_manager.window_lists[ 606 0].switch_to_tab.assert_called_once_with(2) 607 # Reset 608 window_manager.window_lists[0].switch_to_tab.reset_mock() 609 console_app.focus_on_container.reset_mock() 610 611 # Set Python Repl in focus 612 target_list_and_pane(window_manager, 1, 1) 613 window_manager.focus_next_pane() 614 # Log3 should now have focus 615 console_app.focus_on_container.assert_called_once_with( 616 window_manager.window_lists[0].active_panes[0]) 617 window_manager.window_lists[ 618 0].switch_to_tab.assert_called_once_with(0) 619 # Reset 620 window_manager.window_lists[0].switch_to_tab.reset_mock() 621 console_app.focus_on_container.reset_mock() 622 623 # Set Log3 in focus 624 target_list_and_pane(window_manager, 0, 0) 625 window_manager.focus_next_pane() 626 # Log2 should now have focus 627 console_app.focus_on_container.assert_called_once_with( 628 window_manager.window_lists[0].active_panes[1]) 629 window_manager.window_lists[ 630 0].switch_to_tab.assert_called_once_with(1) 631 # Reset 632 window_manager.window_lists[0].switch_to_tab.reset_mock() 633 console_app.focus_on_container.reset_mock() 634 635 # Set Python Repl in focus 636 target_list_and_pane(window_manager, 1, 1) 637 window_manager.focus_previous_pane() 638 # Log0 should now have focus 639 console_app.focus_on_container.assert_called_once_with( 640 window_manager.window_lists[1].active_panes[0]) 641 # The second window list is in stacked mode so switch_to_tab should 642 # not be called. 643 window_manager.window_lists[1].switch_to_tab.assert_not_called() 644 # Reset 645 window_manager.window_lists[1].switch_to_tab.reset_mock() 646 console_app.focus_on_container.reset_mock() 647 648 def test_resize_vertical_splits(self) -> None: 649 """Test resizing window splits.""" 650 with create_app_session(output=FakeOutput()): 651 console_app = _create_console_app(logger_count=4) 652 window_manager = console_app.window_manager 653 654 # Required before moving windows 655 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 656 _WINDOW_MANAGER_HEIGHT) 657 window_manager.create_root_container() 658 659 # Vertical split by default 660 self.assertTrue(window_manager.vertical_window_list_spliting()) 661 662 # Move windows to create 3 splits 663 target_list_and_pane(window_manager, 0, 0) 664 window_manager.move_pane_right() 665 target_list_and_pane(window_manager, 0, 0) 666 window_manager.move_pane_right() 667 target_list_and_pane(window_manager, 1, 1) 668 window_manager.move_pane_right() 669 670 # Check windows are where expected 671 self.assertEqual( 672 window_pane_titles(window_manager), 673 [ 674 [ 675 'Log1 - test_log1', 676 'Log0 - test_log0', 677 'Python Repl - ', 678 ], 679 [ 680 'Log2 - test_log2', 681 ], 682 [ 683 'Log3 - test_log3', 684 ], 685 ], 686 ) 687 688 # Check initial split widths 689 widths = [ 690 int(_WINDOW_MANAGER_WIDTH / 3), 691 int(_WINDOW_MANAGER_WIDTH / 3), 692 int(_WINDOW_MANAGER_WIDTH / 3), 693 ] 694 self.assertEqual(_window_list_widths(window_manager), widths) 695 696 # Decrease size of first split 697 window_manager.adjust_split_size(window_manager.window_lists[0], 698 -4) 699 widths = [ 700 widths[0] - (4 * _WINDOW_SPLIT_ADJUST), 701 widths[1] + (4 * _WINDOW_SPLIT_ADJUST), 702 widths[2], 703 ] 704 self.assertEqual(_window_list_widths(window_manager), widths) 705 706 # Increase size of last split 707 widths = [ 708 widths[0], 709 widths[1] - (4 * _WINDOW_SPLIT_ADJUST), 710 widths[2] + (4 * _WINDOW_SPLIT_ADJUST), 711 ] 712 window_manager.adjust_split_size(window_manager.window_lists[2], 4) 713 self.assertEqual(_window_list_widths(window_manager), widths) 714 715 # Check heights are all the same 716 window_manager.rebalance_window_list_sizes() 717 heights = [ 718 int(_WINDOW_MANAGER_HEIGHT), 719 int(_WINDOW_MANAGER_HEIGHT), 720 int(_WINDOW_MANAGER_HEIGHT), 721 ] 722 self.assertEqual(_window_list_heights(window_manager), heights) 723 724 def test_resize_horizontal_splits(self) -> None: 725 """Test resizing window splits.""" 726 with create_app_session(output=FakeOutput()): 727 console_app = _create_console_app(logger_count=4) 728 window_manager = console_app.window_manager 729 730 # We want horizontal window splits 731 window_manager.vertical_window_list_spliting = (MagicMock( 732 return_value=False)) 733 self.assertFalse(window_manager.vertical_window_list_spliting()) 734 735 # Required before moving windows 736 window_manager.update_window_manager_size(_WINDOW_MANAGER_WIDTH, 737 _WINDOW_MANAGER_HEIGHT) 738 window_manager.create_root_container() 739 740 # Move windows to create 3 splits 741 target_list_and_pane(window_manager, 0, 0) 742 window_manager.move_pane_right() 743 target_list_and_pane(window_manager, 0, 0) 744 window_manager.move_pane_right() 745 target_list_and_pane(window_manager, 1, 1) 746 window_manager.move_pane_right() 747 748 # Check windows are where expected 749 self.assertEqual( 750 window_pane_titles(window_manager), 751 [ 752 [ 753 'Log1 - test_log1', 754 'Log0 - test_log0', 755 'Python Repl - ', 756 ], 757 [ 758 'Log2 - test_log2', 759 ], 760 [ 761 'Log3 - test_log3', 762 ], 763 ], 764 ) 765 766 # Check initial split widths 767 heights = [ 768 int(_WINDOW_MANAGER_HEIGHT / 3), 769 int(_WINDOW_MANAGER_HEIGHT / 3), 770 int(_WINDOW_MANAGER_HEIGHT / 3), 771 ] 772 self.assertEqual(_window_list_heights(window_manager), heights) 773 774 # Decrease size of first split 775 window_manager.adjust_split_size(window_manager.window_lists[0], 776 -4) 777 heights = [ 778 heights[0] - (4 * _WINDOW_SPLIT_ADJUST), 779 heights[1] + (4 * _WINDOW_SPLIT_ADJUST), 780 heights[2], 781 ] 782 self.assertEqual(_window_list_heights(window_manager), heights) 783 784 # Increase size of last split 785 heights = [ 786 heights[0], 787 heights[1] - (4 * _WINDOW_SPLIT_ADJUST), 788 heights[2] + (4 * _WINDOW_SPLIT_ADJUST), 789 ] 790 window_manager.adjust_split_size(window_manager.window_lists[2], 4) 791 self.assertEqual(_window_list_heights(window_manager), heights) 792 793 # Check widths are all the same 794 window_manager.rebalance_window_list_sizes() 795 widths = [ 796 int(_WINDOW_MANAGER_WIDTH), 797 int(_WINDOW_MANAGER_WIDTH), 798 int(_WINDOW_MANAGER_WIDTH), 799 ] 800 self.assertEqual(_window_list_widths(window_manager), widths) 801 802 803if __name__ == '__main__': 804 unittest.main() 805