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