├── .gitignore ├── README.md ├── examples ├── session_demo ├── session_practical ├── session_test ├── session_unsupported └── session_yaml ├── screenshots └── screenshot_example.png ├── setup.py ├── tmuxomatic └── windowgram ├── __init__.py ├── windowgram.py └── windowgram_test.py /.gitignore: -------------------------------------------------------------------------------- 1 | # tmuxomatic untracked files 2 | 3 | # PyPI, build with: pandoc -f markdown -t rst README.md -o README.rst 4 | /README.rst 5 | 6 | # build files 7 | /build/ 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # tmuxomatic [![](http://img.shields.io/pypi/v/tmuxomatic.svg?style=flat)](https://pypi.python.org/pypi/tmuxomatic) 4 | 5 | 6 | 7 | A completely different kind of tmux session manager. 8 | 9 | 1. [Introduction](https://github.com/oxidane/tmuxomatic#introduction) 10 | 2. [One Example](https://github.com/oxidane/tmuxomatic#one-example) 11 | 3. [Managerless Mode](https://github.com/oxidane/tmuxomatic#managerless-mode) ... *New in 2.19* 12 | 4. [Flex](https://github.com/oxidane/tmuxomatic#flex) ... ( i. [Concepts](https://github.com/oxidane/tmuxomatic#flex-concepts), ii. [Demo #1](https://github.com/oxidane/tmuxomatic#flex-demonstration-1----create-new-windowgram), iii. [Demo #2](https://github.com/oxidane/tmuxomatic#flex-demonstration-2----extend-previous-windowgram) ) 13 | 5. [Installation](https://github.com/oxidane/tmuxomatic#installation) ... ( i. [Requirements](https://github.com/oxidane/tmuxomatic#installation-requirements), ii. [Guide](https://github.com/oxidane/tmuxomatic#installation-guide), iii. [Optional Packages](https://github.com/oxidane/tmuxomatic#optional-packages) ) 14 | 6. [Using tmux](https://github.com/oxidane/tmuxomatic#using-tmux) 15 | 7. [Legal](https://github.com/oxidane/tmuxomatic#legal) ... ( i. [Copyright](https://github.com/oxidane/tmuxomatic#copyright), ii. [License](https://github.com/oxidane/tmuxomatic#license), iii. [Contributor Agreement](https://github.com/oxidane/tmuxomatic#contributor-agreement) ) 16 | 17 | 18 | 19 | ## Introduction 20 | 21 | Other tmux session managers require pages of documentation for basic use, and define windows using a complicated nesting of pane splits. Instead, tmuxomatic is so easy that anyone could use it after just one example. Yet tmuxomatic is more flexible and more powerful than other tmux session managers. 22 | 23 | At the heart of tmuxomatic is the **windowgram**, a better way of arranging tmux windows. The windowgram is a rectangle comprised of alphanumeric characters (0-9, a-z, A-Z). Each character grouping identifies the name, position, size, and shape of a pane. It should take only **one example** to demonstrate the power and flexibility of the windowgram. 24 | 25 | 26 | 27 | ## One Example 28 | 29 | Take the following window definition from the `session_demo` file (located in the `examples` folder): 30 | 31 | window example_one # A new window begins like this, spaces in names allowed 32 | 33 | AAAAAAvvvvvXXXXXTTTT # The windowgram, defines the shapes and positions of panes 34 | jjjQQQQQQQuuuuuuTTTT # Make your own, any size and arrangement, 62 panes maximum 35 | jjjQQQQQQQuuuuuuTTTT 36 | jjjQQQQQQQuuuuuuTTTT 37 | 0000llllllllllaaaaaa 38 | 1234llllllllllaaaaaa 39 | 40 | foc # Only three 3-letter commands: Focus, Directory, Run 41 | dir ~ # Unlinked directory is the default for all undefined panes 42 | A run figlet "A" # Linked command to pane A, in this case prints a large "A" 43 | Q run figlet "Q" 44 | A foc 45 | 46 | And compare it to the resulting screenshot after running `tmuxomatic session_demo`: 47 | 48 | 49 | ![](https://raw.githubusercontent.com/oxidane/tmuxomatic/41114a3e93b3093ad397b754c109c666705b4db6/screenshots/screenshot_example.png) 50 | 51 | With tmuxomatic, you'll never have to manually split, position, or size a pane again. And linking the panes to actions is so simple and logical that you probably won't forget it. There are no other file format rules to remember, and typically no command line arguments will be necessary. 52 | 53 | Additional examples may be found in the `examples` folder. If you have installed with PyPI, use `tmuxomatic --files` to find the location for these examples on your local filesystem. 54 | 55 | For a list of command line arguments, run `tmuxomatic --help`. For additional features, see the documentation and/or source code. 56 | 57 | 58 | 59 | ## Managerless Mode 60 | 61 | As of ***2.19***, tmuxomatic may be used to add windows to an existing session without having to restart it. This is called *managerless mode*. It works with any tmux session, even those created by other session managers. 62 | 63 | Simply use tmuxomatic from within tmux, and any windows in the specified file that are not already named by the current session will be added. 64 | 65 | If you are new to tmuxomatic and already using tmux, managerless mode is a convenient way to explore the features of tmuxomatic without disrupting your current session. 66 | 67 | **While 2.19 is in development, you will have to `git clone` or `git pull` to use managerless mode** 68 | 69 | 70 | 71 | ## Flex 72 | 73 | Windowgrams are a neat way of arranging workspaces. For simpler layouts, a windowgram can be typed up quickly. But if you need detail, you may find yourself doing a lot of ASCII art. 74 | 75 | In tmuxomatic 2, a new feature named Flex has been added to automate the construction and modification of the windowgram itself. 76 | 77 | Flex is an object-oriented windowgram editor. It is visually expressive, naturally worded, logically ordered, minimal, and powerful. Its short command set may be combined to make any conceivable windowgram -- likely more quickly and more easily than crafting by hand. Flex is intended for power users who desire detailed windowgrams without the tedium of manual entry. 78 | 79 | #### Flex Concepts 80 | 81 | Before proceeding with the flex demonstration, take a moment to review key concepts used by the commands. 82 | 83 | * **Pane**: Single character pane identifier, represents one pane in a windowgram 84 | * **Group**: String of one or more panes, usually forming a complete rectangle without gaps 85 | * **Edge**: String of one or more panes that border one or more edges (imaginary line between panes) 86 | * **Direction**: Expresses movement, or specifies an edge: up, down, left, right, vertical, horizontal 87 | * **Size**: Either an absolute number of characters, or contextually as a percentage or a multiplier 88 | 89 | In the demonstrations that follow, the flex shell is represented in short form by the `flex>` prompt. For a list of flex commands with example usage, type `help` from the shell at any time. 90 | 91 | #### Flex Demonstration #1 -- Create New Windowgram 92 | 93 | Let's use flex to build a windowgram that would otherwise require repetitious typing and/or careful editing. 94 | 95 | The following windowgram is what we'll create in this demonstration. This windowgram is intended for managing cryptocurrency nodes, specifically bitcoin, litecoin, and namecoin. There are panes for a general use shell (`1`), a disk monitor (`z`); and for each currency: a title with keep-alive loop on top (`B`, `L`, `N`), and blockchain information on bottom (`b`, `l`, `n`). 96 | 97 | 1111111111111111111111111zzzzzzzzzzzz 98 | 1111111111111111111111111zzzzzzzzzzzz 99 | 1111111111111111111111111BBBBLLLLNNNN 100 | 1111111111111111111111111BBBBLLLLNNNN 101 | 1111111111111111111111111BBBBLLLLNNNN 102 | 1111111111111111111111111BBBBLLLLNNNN 103 | 1111111111111111111111111bbbbllllnnnn 104 | 1111111111111111111111111bbbbllllnnnn 105 | 1111111111111111111111111bbbbllllnnnn 106 | 1111111111111111111111111bbbbllllnnnn 107 | 108 | Begin by opening the flex shell on the session file `session_flexample`. Flex will create the session file for you if it does not already exist. 109 | 110 | % tmuxomatic session_flexample --flex 111 | 112 | flex> 113 | 114 | First use the `new` command to create a new window named `wallets`. By default, it will create a single pane window represented by the single character `1`. 115 | 116 | flex> new wallets 117 | 118 | 1 119 | 120 | From here it takes only four flex commands to complete the envisioned windowgram. 121 | 122 | **Scale**: 123 | 124 | To make the window easier to work with, let's `scale` this windowgram to `25` characters wide, by `10` characters high. Many flex parameters are flexible, instead of characters we could have used multipliers or percentages. 125 | 126 | flex> scale 25x10 127 | 128 | 1111111111111111111111111 129 | 1111111111111111111111111 130 | 1111111111111111111111111 131 | 1111111111111111111111111 132 | 1111111111111111111111111 133 | 1111111111111111111111111 134 | 1111111111111111111111111 135 | 1111111111111111111111111 136 | 1111111111111111111111111 137 | 1111111111111111111111111 138 | 139 | **Add**: 140 | 141 | Now let's `add` a new pane on the `right` edge, and make it `50%` of the size of the base windowgram (or `12` characters, if you prefer). 142 | 143 | flex> add right 50% 144 | 145 | 1111111111111111111111111000000000000 146 | 1111111111111111111111111000000000000 147 | 1111111111111111111111111000000000000 148 | 1111111111111111111111111000000000000 149 | 1111111111111111111111111000000000000 150 | 1111111111111111111111111000000000000 151 | 1111111111111111111111111000000000000 152 | 1111111111111111111111111000000000000 153 | 1111111111111111111111111000000000000 154 | 1111111111111111111111111000000000000 155 | 156 | There are only two commands left to complete this, and two ways to do it. One way uses `split` and `break`, the other uses `break` and `join`. We'll use break and join, because split is shown in the next demonstration. 157 | 158 | **Break**: 159 | 160 | So let's `break` pane `0` into a grid, `3` panes wide by `5` panes high. For readability, we'll make use of the optional parameter so that new panes to start at `A`. 161 | 162 | flex> break 0 3x5 A 163 | 164 | 1111111111111111111111111AAAABBBBCCCC 165 | 1111111111111111111111111AAAABBBBCCCC 166 | 1111111111111111111111111DDDDEEEEFFFF 167 | 1111111111111111111111111DDDDEEEEFFFF 168 | 1111111111111111111111111GGGGHHHHIIII 169 | 1111111111111111111111111GGGGHHHHIIII 170 | 1111111111111111111111111JJJJKKKKLLLL 171 | 1111111111111111111111111JJJJKKKKLLLL 172 | 1111111111111111111111111MMMMNNNNOOOO 173 | 1111111111111111111111111MMMMNNNNOOOO 174 | 175 | **Join**: 176 | 177 | Finally we complete the envisioned layout using just one `join` command. Each parameter represents a group of panes to be joined together. By default, the first pane in the group becomes the joined name. But we'll be using the optional rename, by appending `.` followed by the new pane id. 178 | 179 | flex> join ABC.z DG.B EH.L FI.N JM.b KN.l LO.n 180 | 181 | 1111111111111111111111111zzzzzzzzzzzz 182 | 1111111111111111111111111zzzzzzzzzzzz 183 | 1111111111111111111111111BBBBLLLLNNNN 184 | 1111111111111111111111111BBBBLLLLNNNN 185 | 1111111111111111111111111BBBBLLLLNNNN 186 | 1111111111111111111111111BBBBLLLLNNNN 187 | 1111111111111111111111111bbbbllllnnnn 188 | 1111111111111111111111111bbbbllllnnnn 189 | 1111111111111111111111111bbbbllllnnnn 190 | 1111111111111111111111111bbbbllllnnnn 191 | 192 | That's it. Our windowgram is ready to use. 193 | 194 | Either type `done` and flex will open this session file in tmux, or type `exit` and add some directions (run commands, home directories, and focus state) to the session file. For more information on directions, see the example session at the start of this readme. 195 | 196 | #### Flex Demonstration #2 -- Extend Previous Windowgram 197 | 198 | For this demonstration, we modify the windowgram from the previous demonstration, using a different set of flex commands. The commands in this demonstration are described in summary form. For more information on these or any other flex commands, type `help ` at the flex prompt. 199 | 200 | > Open the windowgram that we created in the above demonstration 201 | 202 | flex> use wallets 203 | 204 | 1111111111111111111111111zzzzzzzzzzzz 205 | 1111111111111111111111111zzzzzzzzzzzz 206 | 1111111111111111111111111BBBBLLLLNNNN 207 | 1111111111111111111111111BBBBLLLLNNNN 208 | 1111111111111111111111111BBBBLLLLNNNN 209 | 1111111111111111111111111BBBBLLLLNNNN 210 | 1111111111111111111111111bbbbllllnnnn 211 | 1111111111111111111111111bbbbllllnnnn 212 | 1111111111111111111111111bbbbllllnnnn 213 | 1111111111111111111111111bbbbllllnnnn 214 | 215 | **Split**: 216 | 217 | > Split pane `1`, along `bottom`, exactly `3` characters, name the new pane `s` 218 | 219 | flex> split 1 bottom 3 s 220 | 221 | 1111111111111111111111111zzzzzzzzzzzz 222 | 1111111111111111111111111zzzzzzzzzzzz 223 | 1111111111111111111111111BBBBLLLLNNNN 224 | 1111111111111111111111111BBBBLLLLNNNN 225 | 1111111111111111111111111BBBBLLLLNNNN 226 | 1111111111111111111111111BBBBLLLLNNNN 227 | 1111111111111111111111111bbbbllllnnnn 228 | sssssssssssssssssssssssssbbbbllllnnnn 229 | sssssssssssssssssssssssssbbbbllllnnnn 230 | sssssssssssssssssssssssssbbbbllllnnnn 231 | 232 | **Rename**: 233 | 234 | > Rename the panes `N` and `n`, to `D` and `d` respectively 235 | 236 | flex> rename Nn Dd 237 | 238 | 1111111111111111111111111zzzzzzzzzzzz 239 | 1111111111111111111111111zzzzzzzzzzzz 240 | 1111111111111111111111111BBBBLLLLDDDD 241 | 1111111111111111111111111BBBBLLLLDDDD 242 | 1111111111111111111111111BBBBLLLLDDDD 243 | 1111111111111111111111111BBBBLLLLDDDD 244 | 1111111111111111111111111bbbblllldddd 245 | sssssssssssssssssssssssssbbbblllldddd 246 | sssssssssssssssssssssssssbbbblllldddd 247 | sssssssssssssssssssssssssbbbblllldddd 248 | 249 | **Swap**: 250 | 251 | > Swap pane `z` with `s`, also swap panes `Ll` with `Dd`. 252 | 253 | flex> swap z s Ll Dd 254 | 255 | 1111111111111111111111111ssssssssssss 256 | 1111111111111111111111111ssssssssssss 257 | 1111111111111111111111111BBBBDDDDLLLL 258 | 1111111111111111111111111BBBBDDDDLLLL 259 | 1111111111111111111111111BBBBDDDDLLLL 260 | 1111111111111111111111111BBBBDDDDLLLL 261 | 1111111111111111111111111bbbbddddllll 262 | zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 263 | zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 264 | zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 265 | 266 | **Drag**: 267 | 268 | > Drag the `left` edge of group `BDLbdl`, to the `left`, about `50%` of the available space. 269 | 270 | flex> drag left BDLbdl left 50% 271 | 272 | 1111111111111ssssssssssssssssssssssss 273 | 1111111111111ssssssssssssssssssssssss 274 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 275 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 276 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 277 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 278 | 1111111111111bbbbbbbbddddddddllllllll 279 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll 280 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll 281 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll 282 | 283 | **Insert**: 284 | 285 | > Insert a pane to the `left` of pane `s` (while scaling group `BDLbdl`) and make it `6` characters wide 286 | 287 | flex> insert left s:BDLbdl 6 288 | 289 | 1111111111111000000ssssssssssssssssssssssss 290 | 1111111111111000000ssssssssssssssssssssssss 291 | 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 292 | 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 293 | 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 294 | 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 295 | 1111111111111bbbbbbbbbbddddddddddllllllllll 296 | zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 297 | zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 298 | zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 299 | 300 | **Clone**: 301 | 302 | **Delete**: 303 | 304 | **Mirror**: 305 | 306 | **Flip**: 307 | 308 | **Rotate**: 309 | 310 | *Flex is in development, these commands will be added in 2.x* 311 | 312 | 313 | 314 | ## Installation 315 | 316 | #### Installation Requirements 317 | 318 | This application requires the following: 319 | 320 | * [Python 3](http://www.python.org/getit/) + 321 | * [tmux 1.8](http://tmux.github.io/) + 322 | 323 | #### Installation Guide 324 | 325 | There are three ways to install tmuxomatic, in order of convenience: 326 | 327 | * **Automatically** (pip) 328 | 329 | * May require an empty pip cache, ``rm -rf /tmp/pip[-_]build[-_]`whoami`/tmuxomatic`` 330 | * `pip-python3 install tmuxomatic --upgrade` 331 | 332 | * **Manually** (python) 333 | 334 | * Download and extract the archive file from https://pypi.python.org/pypi/tmuxomatic 335 | * `cd tmuxomatic` 336 | * `python3 setup.py install` 337 | 338 | * **From Development** (git) 339 | 340 | * Visit https://github.com/oxidane/tmuxomatic for up-to-date installation instructions 341 | * Additional requirement for build [pandoc 1.12](http://johnmacfarlane.net/pandoc/) + 342 | * `git clone git://github.com/oxidane/tmuxomatic.git` 343 | * `cd tmuxomatic` 344 | * `pandoc -f markdown -t rst README.md -o README.rst` 345 | * `python3 setup.py install` 346 | 347 | Verify that the version reported by `tmuxomatic -V` matches or exceeds the latest release. [![](http://img.shields.io/pypi/v/tmuxomatic.svg?style=flat)](https://pypi.python.org/pypi/tmuxomatic) 348 | 349 | #### Optional Packages 350 | 351 | The following packages are optional; install if you want the additional features. 352 | 353 | * `pip-python3 install pyyaml` ... YAML session file support 354 | 355 | 356 | 357 | ## Using tmux 358 | 359 | To use tmuxomatic, you don't have to know everything about [how to use tmux](http://net.tutsplus.com/tutorials/tools-and-tips/intro-to-tmux/), but the knowledge is useful for [customizing the tmux status bar](http://me.veekun.com/blog/2012/03/21/tmux-is-sweet-as-heck/), or [changing the default key bindings](https://wiki.archlinux.org/index.php/tmux#Key_bindings). These are tmux user preferences, and typically placed in a personal `.tmux.conf` file. 360 | 361 | 362 | 363 | ## Legal 364 | 365 | By downloading, copying, installing or using the software you agree to the license. If you do not agree to the license, do not download, copy, install, or use the software. 366 | 367 | #### Copyright 368 | 369 | Copyright 2013-2016, Oxidane. All rights reserved. 370 | 371 | #### License 372 | 373 | The `windowgram` module is presently not licensed for use outside the tmuxomatic project. For more information, including future plans for an open source license, please see the file `windowgram.py`. 374 | 375 | The `tmuxomatic` source is distributed under the [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause). The copyright and license must be included with any use, modification, or redistribution. See the license for details. 376 | 377 | #### Contributor Agreement 378 | 379 | Contributions must be comprised of original source, and/or properly attributed public domain source. By submitting, you agree that your contribution will inherit the current copyright and license, and will be subject to future changes in tmuxomatic and any officially-related projects. 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /examples/session_demo: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------------- 2 | # 3 | # Simple two window example (session_demo) 4 | # 5 | #-------------------------------------------------------------------------------------- 6 | 7 | window example_one # A new window begins like this, spaces in names allowed 8 | 9 | AAAAAAvvvvvXXXXXTTTT # The windowgram, defines the shapes and positions of panes 10 | jjjQQQQQQQuuuuuuTTTT # Make your own, any size and arrangement, 62 panes maximum 11 | jjjQQQQQQQuuuuuuTTTT 12 | jjjQQQQQQQuuuuuuTTTT 13 | 0000llllllllllaaaaaa 14 | 1234llllllllllaaaaaa 15 | 16 | foc # Only three 3-letter commands: Focus, Directory, Run 17 | dir ~ # Unlinked directory is the default for all undefined panes 18 | A run figlet "A" # Linked command to pane A, in this case prints a large "A" 19 | Q run figlet "Q" 20 | A foc 21 | 22 | #-------------------------------------------------------------------------------------- 23 | 24 | window example_two # Multiple windows per session 25 | 26 | 111XYZ # Try scaling this window in --flex with "scale 5x 4x" 27 | 000000 28 | 000000 29 | 30 | dir ~ 31 | X run echo "X" 32 | Y run echo "Y" 33 | Z run echo "Z" 34 | 0 foc 35 | 0 dir /tmp 36 | 0 run ls -la 37 | 1 run htop 38 | 39 | #-------------------------------------------------------------------------------------- 40 | 41 | -------------------------------------------------------------------------------- /examples/session_practical: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------------- 2 | # 3 | # Practical example (session_practical) 4 | # 5 | # This is a more practical example of how one might use tmuxomatic. Three example 6 | # windows, each for a specific purpose. 7 | # 8 | # All windowgrams are unique, so make your own exactly as you want it to appear. 9 | # 10 | # If you need large windowgrams for small panes, try the new --flex console. 11 | # 12 | #-------------------------------------------------------------------------------------- 13 | 14 | #session new_name # Session rename (optional) is only valid at top of file 15 | 16 | #-------------------------------------------------------------------------------------- 17 | # 18 | # First window: Administrative overview. Host name, network addresses, process list, 19 | # some log tails, package installation, service summaries, etc. 20 | # 21 | #-------------------------------------------------------------------------------------- 22 | 23 | window system monitor 24 | 25 | HHHmmmmm 26 | TTTmmmmm 27 | TTTsssss 28 | TTTsssss 29 | 11112222 30 | 11112222 31 | 11112222 32 | 33334444 33 | 33334444 34 | 33334444 35 | 36 | foc 37 | dir ~ 38 | H run clear ; figlet -c $HOSTNAME -w "\`stty size | cut -f2 -d' '\`" -f standard ; echo "" ; figlet -c "\`hostname --all-ip-addresses | sed 's/ / /g' | sed 's/ *$//g'\`" -w "\`stty size | cut -f2 -d' '\`" -f term ; sleep 1000d 39 | T run htop 40 | m run tail --follow=name /var/log/messages 41 | s run tail --follow=name /var/log/secure 42 | 1 run echo "you're focused on this pane" 43 | 1 foc 44 | 2 run echo "another summary here" 45 | 3 run echo "another log file here" 46 | 4 run echo "a service overview here" 47 | 48 | #-------------------------------------------------------------------------------------- 49 | # 50 | # Second window: An irc client that you want to take up most of the screen, but maybe 51 | # you also want tickers and scrollers for various feeds like twitter, news, financial 52 | # monitoring, etc. 53 | # 54 | #-------------------------------------------------------------------------------------- 55 | 56 | window irc 57 | 58 | 1122abc 59 | iiiiiii 60 | iiiiiii 61 | iiiiiii 62 | iiiiiii 63 | iiiiiii 64 | TTTTTTT 65 | 66 | dir ~ 67 | T run echo "running feed here" 68 | 1 run echo "chart 1" 69 | 2 run echo "chart 2" 70 | a run echo "graph 1" 71 | b run echo "graph 2" 72 | c run echo "graph 3" 73 | dir ~/irc 74 | i foc 75 | i run echo "you'd run irc here" 76 | 77 | #-------------------------------------------------------------------------------------- 78 | # 79 | # Third window: A few cryptocurrency peers, the panes are set to take little space 80 | # compared to a shell where you perform installations, check logs, etc. 81 | # 82 | #-------------------------------------------------------------------------------------- 83 | 84 | window wallets 85 | abcX 86 | abcX 87 | ABCX 88 | 1111 89 | 1111 90 | 1111 91 | 1111 92 | 1111 93 | 1111 94 | 95 | dir /cc/bitcoin 96 | a run figlet bitcoin 97 | A run keepup 98 | dir /cc/litecoin 99 | b run figlet litecoin 100 | B run keepup 101 | dir /cc/namecoin 102 | c run figlet namecoin 103 | C run keepup 104 | dir /cc 105 | X run echo "disk monitor" 106 | 1 run echo "work here" 107 | 1 run ls -la 108 | 109 | -------------------------------------------------------------------------------- /examples/session_test: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------------- 2 | # 3 | # Test windowgram (session_test) 4 | # 5 | # * Makes use of all 62 panes (the maximum) 6 | # * Demonstrates multiple panes per run command 7 | # * Resolution 193x60 recommended (or 4:3 pixels, or 3:1 characters) 8 | # 9 | # Builds text using filled panes that should look like this: 10 | # 11 | # ....................................................... 12 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 13 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 14 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 15 | # ....................................................... 16 | # ..@@@@@@.@@@@@@....@@@@@@.@@@@@@.@@@@@@.@@@@@@.@@@@@@.. 17 | # ..@@.........@@....@@..@@.....@@.@@..@@.@@..@@.@@...... 18 | # ..@@@@@@.@@@@@@....@@@@@@.@@@@@@.@@..@@.@@@@@@.@@@@@@.. 19 | # ..@@..@@.@@........@@.....@@..@@.@@..@@.@@.........@@.. 20 | # ..@@@@@@.@@@@@@....@@.....@@@@@@.@@..@@.@@@@@@.@@@@@@.. 21 | # ....................................................... 22 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 23 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 24 | # ..@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@.. 25 | # ....................................................... 26 | # 27 | #-------------------------------------------------------------------------------------- 28 | 29 | window test 30 | 31 | 0000000000000000000000000000000000000000000000000000000 32 | 1122222222222222222222222222222222222222222222222222233 33 | 1122222222222222222222222222222222222222222222222222233 34 | 1122222222222222222222222222222222222222222222222222233 35 | 1144444444444444444444444444444444444444444444444444433 36 | 1155666678888889999aaaaaabccccccdeeeeeefgggggghiiiiii33 37 | 1155jjjj7kkkkll9999mmnnoobppppqqdrrssttfuuvvwwhxxyyyy33 38 | 1155zzAA7BBBBBB9999CCCCCCbDDDDDDdrrssttfEEEEEEhFFFFFF33 39 | 1155GGAA7HHIIII9999JJKKKKbLLMMNNdrrssttfOOPPPPhQQQQRR33 40 | 1155SSAA7TTTTTT9999JJKKKKbUUUUUUdrrssttfVVVVVVhWWWWWW33 41 | 11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX33 42 | 11YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY33 43 | 11YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY33 44 | 11YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY33 45 | ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 46 | 47 | 2568acegilmoqrtuwxzABCDEFHJLNORSTUVWY run ln=\`echo \\\`stty size | cut -f2 -d' '\\\`*100 | bc\` ; printf '@%.0s' \$(eval 'echo {1..'\$((\$ln))'}') ; sleep 99999 48 | 013479bdfhjknpsvyGIKMPQXZ run clear ; sleep 99999 # Note that "sleep 1d" doesn't work on OS X 49 | 50 | -------------------------------------------------------------------------------- /examples/session_unsupported: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------------- 2 | # 3 | # Unsupported layouts (session_unsupported) 4 | # 5 | # These unsupported layouts have to do with the way tmux itself works. The window 6 | # layout mechanism in tmux is basically the nested arrangement of vertical and 7 | # horizontal splits. If such a split cannot be found, the layout cannot be supported. 8 | # See "session_unsupported" in source for more details. 9 | # 10 | # Follow the clean split rule, and you won't have a problem with unsupported layouts. 11 | # 12 | #-------------------------------------------------------------------------------------- 13 | 14 | window tmux_incompatibility # The following layout is not possible in tmux 15 | 122 # This is the tmux edge case that is mentioned in the source 16 | 154 # The problem with this layout is that there are no clean splits 17 | 334 # If tmux supports new layout mechanics, this could be fixed 18 | 19 | window overlap_not_supported # Overlapping panes are not supported by tmuxomatic or tmux 20 | 12 # This is an inherent limitation of the tmux split arrangement 21 | 11 # Pane 2 overlaps with pane 1 22 | 23 | -------------------------------------------------------------------------------- /examples/session_yaml: -------------------------------------------------------------------------------- 1 | #-------------------------------------------------------------------------------------- 2 | # 3 | # YAML session file example (session_yaml) 4 | # 5 | # This demonstrates a tmuxomatic session file in YAML format only. For configuration 6 | # in general, see the other session examples. 7 | # 8 | # Using YAML as the format for tmuxomatic sessions has one minor limitation, the first 9 | # line of a YAML block literal cannot be indented. This affects indenting the unlinked 10 | # commands in the directions section (used in the other examples for readability). 11 | # 12 | # IMPORTANT: ALL comments will be lost when tmuxomatic writes to a YAML session file 13 | # (for example, when using flex). If you need to comment your session configurations, 14 | # use shorthand, and don't comment on the same lines as the windowgram. 15 | # 16 | #-------------------------------------------------------------------------------------- 17 | 18 | --- 19 | 20 | #- session: new_name # Session rename (optional) may be placed anywhere in file 21 | 22 | - name: one 23 | windowgram: | 24 | 12 25 | 34 26 | directions: | 27 | dir ~ # Applies to any undefined panes that follow 28 | foc 29 | 1 run pwd 30 | dir /tmp # Example of changing the default directory 31 | 2 run pwd 32 | 33 | - name: two 34 | windowgram: | 35 | 1aaaaa 36 | 2AAAAA 37 | 3AAAAA 38 | directions: | 39 | dir ~ 40 | a dir /tmp 41 | A foc 42 | 43 | -------------------------------------------------------------------------------- /screenshots/screenshot_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oxidane/tmuxomatic/5ea10f383702c4d8e864889f0f66f4da388c5877/screenshots/screenshot_example.png -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | ##---------------------------------------------------------------------------------------------------------------------- 5 | ## 6 | ## Installer for tmuxomatic 7 | ## 8 | ## The distutils is the only standard packaging library included with Python 3.x 9 | ## 10 | ##---------------------------------------------------------------------------------------------------------------------- 11 | 12 | from distutils.core import setup 13 | from distutils import sysconfig 14 | import re, os, sys 15 | 16 | lines = open("tmuxomatic", "r").read().split("\n") 17 | extract = lambda what: [re.search(r'"([^"]*)"', line).group() for line in lines if line.startswith(what)][0][1:-1] 18 | def fullfile(filename): f = open(filename, "r") ; text = f.read() ; f.close() ; return text 19 | 20 | version = extract("VERSION") 21 | homepage = extract("HOMEPAGE") 22 | hashtags = "#tmux" 23 | description = extract("DESCRIPTION") + " ... " + hashtags 24 | long_description = fullfile("README.md") 25 | 26 | KEYWORDS = "tmux, session manager, screen, shell, command line, iterm, xterm, split, windowgram" 27 | keywords = [ key.strip() for key in KEYWORDS.split(",") ] # "1, 2, 3" -> ["1", "2", "3"] 28 | 29 | examples = "examples" # Build the list of example files to install: "examples" -> [ "examples/session_demo", ... ] 30 | examples = [ os.path.join(examples, f) for f in os.listdir(examples) if os.path.isfile(os.path.join(examples, f)) ] 31 | 32 | packages = [ "windowgram" ] 33 | package_dir = {} 34 | package_data = {} 35 | data_files = [ 36 | ( "bin", [ "tmuxomatic" ] ), 37 | ( sysconfig.get_python_lib() + "/tmuxomatic", [ "README.md" ] ), 38 | ( sysconfig.get_python_lib() + "/tmuxomatic/examples", examples ), 39 | ] 40 | 41 | classifiers = [ 42 | "Development Status :: 5 - Production/Stable", 43 | "Environment :: Console", 44 | "Environment :: Other Environment", 45 | "Intended Audience :: Developers", 46 | "Intended Audience :: End Users/Desktop", 47 | "Intended Audience :: System Administrators", 48 | "License :: OSI Approved :: BSD License", 49 | "Natural Language :: English", 50 | "Operating System :: MacOS :: MacOS X", 51 | "Operating System :: POSIX :: BSD", 52 | "Operating System :: POSIX :: Linux", 53 | "Operating System :: Unix", 54 | "Programming Language :: Python", 55 | "Programming Language :: Python :: 3", 56 | "Topic :: Desktop Environment", 57 | "Topic :: Internet", 58 | "Topic :: Internet :: Log Analysis", 59 | "Topic :: System", 60 | "Topic :: System :: Shells", 61 | "Topic :: System :: Systems Administration", 62 | "Topic :: System :: System Shells", 63 | "Topic :: Terminals", 64 | "Topic :: Terminals :: Terminal Emulators/X Terminals", 65 | "Topic :: Utilities", 66 | ] 67 | 68 | setup( 69 | 70 | name="tmuxomatic", 71 | version=version, 72 | 73 | description=description, 74 | long_description=long_description, 75 | license="BSD 3-Clause (tmuxomatic), Other (windowgram)", 76 | url=homepage, 77 | download_url="https://pypi.python.org/pypi/tmuxomatic", 78 | 79 | author="Oxidane", 80 | author_email="", 81 | 82 | packages=packages, 83 | package_dir=package_dir, 84 | package_data=package_data, 85 | data_files=data_files, 86 | 87 | keywords=keywords, 88 | classifiers=classifiers, 89 | 90 | ) 91 | 92 | # Fix the chmod for the executable if installing 93 | # Setup imposes 644, but it should be 755 94 | # Note: Using a manifest file would probably make this step unnecessary 95 | 96 | if "install" in sys.argv: 97 | for path in os.environ["PATH"].split(os.pathsep): 98 | path = path.strip('"') 99 | exe_file = os.path.join(path, "tmuxomatic") 100 | if os.path.isfile(exe_file): 101 | os.chmod( exe_file, 0o755 ) 102 | 103 | -------------------------------------------------------------------------------- /windowgram/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | __version__ = "1.0" 4 | __author__ = "Oxidane" 5 | __copyright__ = "Copyright 2013-2016" 6 | __license__ = "All rights reserved, not for redistribution, see windowgram source" 7 | 8 | from .windowgram import * 9 | from .windowgram_test import * 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /windowgram/windowgram_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | 6 | Copyright 2013-2016, Oxidane 7 | All rights reserved 8 | 9 | This source has NOT yet been licensed for redistribution, modification, or inclusion in other projects. 10 | 11 | An exception has been granted to the official tmuxomatic project, originating from the following addresses: 12 | 13 | https://github.com/oxidane/tmuxomatic 14 | https://pypi.python.org/pypi/tmuxomatic 15 | 16 | A proper open source license is expected to be applied sometime after the release of this windowgram module as a 17 | separate project. Please check this source at a later date for these changes. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | 27 | """ 28 | 29 | ##---------------------------------------------------------------------------------------------------------------------- 30 | ## 31 | ## Windowgram Unit Testing 32 | ## 33 | ##---------------------------------------------------------------------------------------------------------------------- 34 | ## 35 | ## These tests are ordered; both the test classes and their test methods are run in the order they appear. This is 36 | ## processed automatically using the wrapper class (see code). 37 | ## 38 | ## Classes with names starting with "Test", processed in the order they appear 39 | ## 40 | ## From these recognized classes, methods with names starting with "test_", processed in the order they appear 41 | ## 42 | ##---------------------------------------------------------------------------------------------------------------------- 43 | ## 44 | ## Tests are ordered lowest level to highest level: 45 | ## 46 | ## Windowgram Convert 47 | ## WindowgramGroup Convert 48 | ## Flex Cores 49 | ## Flex Modifiers 50 | ## Readme Demonstrations 51 | ## 52 | ## TODO: 53 | ## 54 | ## Windowgram 55 | ## Windowgram_Mask 56 | ## PaneList 57 | ## 58 | ##---------------------------------------------------------------------------------------------------------------------- 59 | ## 60 | ## Notes: 61 | ## 62 | ## Hashes should not be used in place of windowgrams, they're needed for comparison in case of failure in testing. 63 | ## 64 | ## A change of indentation of the windowgram groups in this source will cause tests to fail because multiline 65 | ## strings are widely used. 66 | ## 67 | ##---------------------------------------------------------------------------------------------------------------------- 68 | 69 | import unittest, io, inspect, sys 70 | 71 | from windowgram import * 72 | 73 | 74 | 75 | ##---------------------------------------------------------------------------------------------------------------------- 76 | ## 77 | ## Keeps the flex modifier unit test producer and validator in sync 78 | ## 79 | ##---------------------------------------------------------------------------------------------------------------------- 80 | 81 | FLEXUNIT_MAXWIDTH = 120 82 | FLEXUNIT_INDENT = 12 83 | FLEXUNIT_SPACE = 1 84 | 85 | 86 | 87 | ##---------------------------------------------------------------------------------------------------------------------- 88 | ## 89 | ## Unit Testing :: Main 90 | ## 91 | ##---------------------------------------------------------------------------------------------------------------------- 92 | 93 | def Flex_UnitTests(): 94 | # Sense test classes 95 | classes = inspect.getmembers(sys.modules[__name__]) 96 | classes = [ classobj for classname, classobj in classes if classname.startswith("Test") ] 97 | # Pair with line numbers 98 | classes = [ (classobj, inspect.getsourcelines(classobj)[1]) for classobj in classes ] 99 | # Sort by line numbers 100 | classes = sorted(classes, key=lambda tup: tup[1]) 101 | # Run tests in the order they appear 102 | stream = io.StringIO() 103 | runner = unittest.TextTestRunner( stream=stream ) 104 | error = "" 105 | for tup in classes: 106 | result = runner.run( tup[0]() ) 107 | if not result.wasSuccessful(): 108 | if not error: error = "\n" 109 | if result.failures: error = error + result.failures[0][1] 110 | else: error = error + "Unspecified error" 111 | return error if error else None 112 | 113 | 114 | 115 | ##---------------------------------------------------------------------------------------------------------------------- 116 | ## 117 | ## Wrapper class, includes a runTest() that automatically senses tests and executes them 118 | ## 119 | ##---------------------------------------------------------------------------------------------------------------------- 120 | 121 | class SenseTestCase(unittest.TestCase): 122 | 123 | def runTest(self): 124 | try: 125 | # Sense test methods 126 | methods = inspect.getmembers(self.__class__(), predicate=inspect.ismethod) 127 | methods = [ method for method in methods if method[0].startswith("test_") ] 128 | # Pair with line numbers 129 | methods = [ (method[1], inspect.getsourcelines(method[1])[1]) for method in methods ] 130 | # Sort by line numbers 131 | methods = sorted(methods, key=lambda tup: tup[1]) 132 | # Execute tests in the order they appear 133 | for method in methods: 134 | method[0]() 135 | except AssertionError as e: 136 | raise e # Forward 137 | except Exception as e: 138 | error = "An error occurred during testing: " + repr(e) # Show the error in case of failure during test 139 | raise AssertionError( e ) # Forward the exception to properly halt because of failure 140 | 141 | ##---------------------------------------------------------------------------------------------------------- 142 | ## 143 | ## Performs flex commands and compares the resulting windowgrams with those specified 144 | ## 145 | ## Commands List of strings, each string may have multiple commands but corresponds to one windowgram 146 | ## Pattern Windowgram pattern, where they are ordered left to right, top to bottom, with first line 1-N 147 | ## 148 | ##---------------------------------------------------------------------------------------------------------- 149 | 150 | def assertFlexSequence(self, commands, pattern, noticesok=False): 151 | windowgramgroup_list = WindowgramGroup_Convert.Pattern_To_List( pattern ) 152 | cmdlen, ptnlen = len(commands), len(windowgramgroup_list) 153 | if cmdlen != ptnlen: 154 | raise Exception( "Mismatch: commands (" + str(cmdlen) + ") and windowgrams (" + str(ptnlen) + ")" ) 155 | wg = Windowgram( NEW_WINDOWGRAM ) # Specified in case the default changes 156 | wlist = [] 157 | for ix, (command, windowgram) in enumerate( zip( commands, windowgramgroup_list ) ): 158 | errors = flex_processor( wg, command, noticesok ) 159 | self.assertTrue( not errors, errors ) 160 | self.assertTrue( wg.Export_String() == windowgram, 161 | "The resulting windowgram for sequence #" + str(ix+1) + " does not match: \n\n" + wg.Export_String() ) 162 | wlist.append( wg.Export_String() ) 163 | pattern_produced = WindowgramGroup_Convert.List_To_Pattern( \ 164 | wlist, FLEXUNIT_MAXWIDTH, FLEXUNIT_INDENT, FLEXUNIT_SPACE ) 165 | pattern_produced = pattern_produced.rstrip(" \t\n").lstrip("\n") 166 | pattern = pattern.rstrip(" \t\n").lstrip("\n") 167 | self.assertTrue( pattern_produced == pattern, 168 | "The resulting pattern does not match specification: \n\n" + pattern_produced + "\n!=\n" + pattern ) 169 | 170 | 171 | 172 | ##---------------------------------------------------------------------------------------------------------------------- 173 | ## 174 | ## Unit Testing :: Windowgram_Convert 175 | ## 176 | ##---------------------------------------------------------------------------------------------------------------------- 177 | 178 | class Test_Windowgram_Convert(SenseTestCase): 179 | 180 | ##---------------------------------------------------------------------------------------------------------- 181 | ## 182 | ## Windowgram_Convert class 183 | ## 184 | ##---------------------------------------------------------------------------------------------------------- 185 | 186 | def test_Windowgram_Convert_StringToLines(self): 187 | data_i = "1135\n1145\n2245\n" 188 | data_o = [ "1135", "1145", "2245" ] 189 | data_x = Windowgram_Convert.String_To_Lines( data_i ) 190 | self.assertTrue( data_x == data_o ) 191 | 192 | def test_Windowgram_Convert_LinesToString(self): 193 | data_i = [ "1135", "1145", "2245" ] 194 | data_o = "1135\n1145\n2245\n" 195 | data_x = Windowgram_Convert.Lines_To_String( data_i ) 196 | self.assertTrue( data_x == data_o ) 197 | 198 | def test_Windowgram_Convert_StringToChars(self): 199 | data_i = "1135\n1145\n2245\n" 200 | data_o = [ [ "1", "1", "3", "5" ], [ "1", "1", "4", "5" ], [ "2", "2", "4", "5" ] ] 201 | data_x = Windowgram_Convert.String_To_Chars( data_i ) 202 | self.assertTrue( data_x == data_o ) 203 | 204 | def test_Windowgram_Convert_CharsToString(self): 205 | data_i = [ [ "1", "1", "3", "5" ], [ "1", "1", "4", "5" ], [ "2", "2", "4", "5" ] ] 206 | data_o = "1135\n1145\n2245\n" 207 | data_x = Windowgram_Convert.Chars_To_String( data_i ) 208 | self.assertTrue( data_x == data_o ) 209 | 210 | def test_Windowgram_Convert_StringToParsed(self): 211 | data_i = "1135\n1145\n2245\n" 212 | data_o = { 213 | '1': {'y': 1, 'x': 1, 'w': 2, 'n': '1', 'h': 2}, 214 | '2': {'y': 3, 'x': 1, 'w': 2, 'n': '2', 'h': 1}, 215 | '3': {'y': 1, 'x': 3, 'w': 1, 'n': '3', 'h': 1}, 216 | '4': {'y': 2, 'x': 3, 'w': 1, 'n': '4', 'h': 2}, 217 | '5': {'y': 1, 'x': 4, 'w': 1, 'n': '5', 'h': 3}, } 218 | data_x, error_string, error_line = Windowgram_Convert.String_To_Parsed( data_i ) 219 | self.assertTrue( error_string is None ) 220 | self.assertTrue( error_line is None ) 221 | self.assertTrue( data_x == data_o ) 222 | 223 | def test_Windowgram_Convert_ParsedToString(self): 224 | data_i = { 225 | '1': {'y': 1, 'x': 1, 'w': 2, 'n': '1', 'h': 2}, 226 | '2': {'y': 3, 'x': 1, 'w': 2, 'n': '2', 'h': 1}, 227 | '3': {'y': 1, 'x': 3, 'w': 1, 'n': '3', 'h': 1}, 228 | '4': {'y': 2, 'x': 3, 'w': 1, 'n': '4', 'h': 2}, 229 | '5': {'y': 1, 'x': 4, 'w': 1, 'n': '5', 'h': 3}, } 230 | data_o = "1135\n1145\n2245\n" 231 | data_x = Windowgram_Convert.Parsed_To_String( data_i ) 232 | self.assertTrue( data_x == data_o ) 233 | 234 | def test_Windowgram_Convert_StringToMosaic(self): 235 | data_i = "1135\n1145\n2245\n" 236 | data_m = [ 237 | "@@::\n@@::\n::::\n", 238 | "::::\n::::\n@@::\n", 239 | "::@:\n::::\n::::\n", 240 | "::::\n::@:\n::@:\n", 241 | ":::@\n:::@\n:::@\n", 242 | ] 243 | data_o = ( 244 | Windowgram("1135\n1145\n2245\n"), 245 | [ 246 | [ Windowgram("11..\n11..\n....\n"), Windowgram("@@::\n@@::\n::::\n") ], 247 | [ Windowgram("....\n....\n22..\n"), Windowgram("::::\n::::\n@@::\n") ], 248 | [ Windowgram("..3.\n....\n....\n"), Windowgram("::@:\n::::\n::::\n") ], 249 | [ Windowgram("....\n..4.\n..4.\n"), Windowgram("::::\n::@:\n::@:\n") ], 250 | [ Windowgram("...5\n...5\n...5\n"), Windowgram(":::@\n:::@\n:::@\n") ], 251 | ], 252 | ) 253 | data_x = Windowgram_Convert.String_To_Mosaic( data_i, data_m ) 254 | self.assertTrue( Mosaics_Equal( data_x, data_o ) ) 255 | 256 | def test_Windowgram_Convert_MosaicToString(self): 257 | data_i = ( 258 | Windowgram("xxxx\nxxxx\nxxxx\n"), # This will be completely overwritten by the following mask pairs 259 | [ 260 | [ Windowgram("11..\n11..\n....\n"), Windowgram("@@::\n@@::\n::::\n") ], 261 | [ Windowgram("....\n....\n22..\n"), Windowgram("::::\n::::\n@@::\n") ], 262 | [ Windowgram("..3.\n....\n....\n"), Windowgram("::@:\n::::\n::::\n") ], 263 | [ Windowgram("....\n..4.\n..4.\n"), Windowgram("::::\n::@:\n::@:\n") ], 264 | [ Windowgram("...5\n...5\n...5\n"), Windowgram(":::@\n:::@\n:::@\n") ], 265 | ], 266 | ) 267 | data_o = "1135\n1145\n2245\n" 268 | data_x = Windowgram_Convert.Mosaic_To_String( data_i ) 269 | self.assertTrue( data_x == data_o ) 270 | 271 | def test_Windowgram_Convert_PurifyString(self): 272 | data_i = "\n\n1135 \n1145 # etc\n2245\n\n" 273 | data_o = "1135\n1145\n2245\n" 274 | data_x = Windowgram_Convert.PurifyString( data_i ) 275 | self.assertTrue( data_x == data_o ) 276 | 277 | def test_Windowgram_Convert_TransposeCharacters(self): 278 | data_i = [ [ "1", "1", "3", "5" ], 279 | [ "1", "1", "4", "5" ], 280 | [ "2", "2", "4", "5" ] ] 281 | data_o = [ [ "1", "1", "2" ], 282 | [ "1", "1", "2" ], 283 | [ "3", "4", "4" ], 284 | [ "5", "5", "5" ] ] 285 | data_x = Windowgram_Convert.Transpose_Chars( data_i ) 286 | self.assertTrue( data_x == data_o ) 287 | 288 | 289 | 290 | ##---------------------------------------------------------------------------------------------------------------------- 291 | ## 292 | ## Unit Testing :: WindowgramGroup_Convert 293 | ## 294 | ##---------------------------------------------------------------------------------------------------------------------- 295 | 296 | class Test_WindowgramGroup_Convert(SenseTestCase): 297 | 298 | def test_WindowgramGroup_Convert_ListToPattern(self): 299 | 300 | # Inclusion of blank lines 301 | group_i = ['1\n', '2\n2\n'] 302 | group_o = """ 303 | 1 2 304 | 2 305 | """ 306 | group_x = WindowgramGroup_Convert.List_To_Pattern( group_i, 32, 12, 1, testmode=8 ) 307 | self.assertTrue( group_o == group_x ) 308 | 309 | # Fitting pattern #1 310 | group_i = [ '111\n'*3, '2\n'*2, '3333333333\n'*5, 'aaaaaaaaaaaaaaaaa\n'*10, 'bbbbbbbbbbbbbbbbb\n'*5 ] 311 | group_o = """ 312 | 111 2 3333333333 313 | 111 2 3333333333 314 | 111 3333333333 315 | 3333333333 316 | 3333333333 317 | 318 | aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 319 | aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 320 | aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 321 | aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 322 | aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 323 | aaaaaaaaaaaaaaaaa 324 | aaaaaaaaaaaaaaaaa 325 | aaaaaaaaaaaaaaaaa 326 | aaaaaaaaaaaaaaaaa 327 | aaaaaaaaaaaaaaaaa 328 | """ 329 | group_x = WindowgramGroup_Convert.List_To_Pattern( group_i, 50, 12, 4, testmode=8 ) 330 | self.assertTrue( group_o == group_x ) 331 | 332 | # Fitting pattern #2 333 | group_i = [ '111\n'*3, '2\n'*2, '3333333333\n'*5, 'aaaaaaaaaaaaaaaaa\n'*10, 'bbbbbbbbbbbbbbbbb\n'*5 ] 334 | group_o = """ 335 | 111 2 3333333333 aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 336 | 111 2 3333333333 aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 337 | 111 3333333333 aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 338 | 3333333333 aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 339 | 3333333333 aaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbb 340 | aaaaaaaaaaaaaaaaa 341 | aaaaaaaaaaaaaaaaa 342 | aaaaaaaaaaaaaaaaa 343 | aaaaaaaaaaaaaaaaa 344 | aaaaaaaaaaaaaaaaa 345 | """ 346 | group_x = WindowgramGroup_Convert.List_To_Pattern( group_i, 100, 12, 1, testmode=8 ) 347 | self.assertTrue( group_o == group_x ) 348 | 349 | def test_WindowgramGroup_Convert_PatternToList(self): 350 | 351 | # Test basic height differences 352 | group_i = """ 353 | 1 2 354 | 2 355 | """ 356 | group_o = ['1\n', '2\n2\n'] 357 | group_x = WindowgramGroup_Convert.Pattern_To_List( group_i ) 358 | self.assertTrue( group_o == group_x ) 359 | 360 | # Test special characters like transparency 361 | group_i = """ 362 | 1.. ... 363 | ... ..2 364 | """ 365 | group_o = ['1..\n...\n', '...\n..2\n'] 366 | group_x = WindowgramGroup_Convert.Pattern_To_List( group_i ) 367 | self.assertTrue( group_o == group_x ) 368 | 369 | # More comprehensive test, including windowgram width mismatch, and '0' as out-of-bounds windowgram 370 | group_i = """ 371 | 1 22 33 aa bb XX Y ZZ 372 | 1 22 aa bb Y 0 373 | 1 bb 0 374 | bbb 375 | """ 376 | group_o = ['1\n1\n1\n', '22\n22\n', '33\n', 'aa\naa\n', 'bb\nbb\nbb\nbbb\n', 'XX\n', 'Y\nY\n', 'ZZ\n'] 377 | group_x = WindowgramGroup_Convert.Pattern_To_List( group_i ) 378 | self.assertTrue( group_o == group_x ) 379 | 380 | # Test misaligned windowgram lines (second line of second window should be clipped, see expected result) 381 | group_i = """ 382 | 111 222 333 383 | 111 222 333 384 | 111 385 | """ 386 | group_o = ['111\n111\n111\n', '222\n', '333\n333\n'] 387 | group_x = WindowgramGroup_Convert.Pattern_To_List( group_i ) 388 | self.assertTrue( group_o == group_x ) 389 | 390 | 391 | 392 | ##---------------------------------------------------------------------------------------------------------------------- 393 | ## 394 | ## Unit Testing :: Flex Cores 395 | ## 396 | ##---------------------------------------------------------------------------------------------------------------------- 397 | 398 | class Test_FlexCores(SenseTestCase): 399 | 400 | ## Scale Core 401 | 402 | def test_ScaleCore(self): 403 | group_i = """ 404 | 111223 405 | 111223 406 | 111223 407 | xxxyyz 408 | xxxyyz 409 | XXXYYZ 410 | """ 411 | group_o = Windowgram_Convert.Lines_To_String( [ "111111222233", "111111222233", "xxxxxxyyyyzz" ] ) 412 | group_x = scalecore( group_i, 12, 3 ) 413 | self.assertTrue( group_o == group_x ) 414 | 415 | ## Enforces the use of scale core v1, and will fail if v2 is reactivated 416 | 417 | def test_ScaleCore_VersionAssert(self): 418 | # break 1 2x2 ; scale 3x3 ; scale 2x2 419 | wg_i = "01\n23\n" 420 | wg_o = scalecore( wg_i, 3, 3 ) 421 | wg_o = scalecore( wg_o, 2, 2 ) 422 | self.assertTrue( wg_o == wg_i ) 423 | 424 | ## Tests the need for retries in the scale core 425 | 426 | def test_ScaleCore_ScaleRetries(self): 427 | # break 1 11x1 ; scale 46 1 ; break 5 7x1 428 | wg_x = "00000001111111222222222333333344444445555555666666677777778888888889999999aaaaaaa\n" 429 | wg_o = scalecore( "000011112222233334444555566667777888889999aaaa\n", 80, 1, ( "5", 7, 1 ) ) 430 | self.assertTrue( wg_o == wg_x ) 431 | 432 | ## Group Core 433 | 434 | def test_GroupCore_Sufficient(self): 435 | wg = Windowgram( """ 436 | qqwwee 437 | qqwwee 438 | rrttyy 439 | rrttyy 440 | uuiioo 441 | uuiioo 442 | """ ) 443 | result, suggestions = groupcore( wg, "qwrt" ) 444 | self.assertTrue( result == GroupStatus.Success ) 445 | self.assertTrue( suggestions == "" ) 446 | 447 | def test_GroupCore_Insufficient(self): 448 | wg = Windowgram( """ 449 | 1122xx 450 | 1122yy 451 | 33zzzz 452 | 33zzzz 453 | rrzzzz 454 | rrsstt 455 | """ ) 456 | result, suggestions = groupcore( wg, "123" ) 457 | self.assertTrue( result == GroupStatus.Insufficient_Panes ) 458 | self.assertTrue( suggestions == PaneList_AssimilatedSorted( "rstxyz", "" ) ) 459 | 460 | ## Edge Core 461 | 462 | def test_EdgeCore_Merger(self): 463 | # 464 | # The merger algorithm should be obvious. Required to merge the results of SwipeSide algorithm. 465 | # 466 | self.assertTrue( edgecore_merger( [[3, 3, 5], [9, 0, 2], [9, 3, 5], [9, 6, 8]] ) == [[3, 3, 5], [9, 0, 8]] ) 467 | self.assertTrue( edgecore_merger( [[9, 6, 8], [9, 3, 5], [3, 3, 5], [9, 0, 2]] ) == [[3, 3, 5], [9, 0, 8]] ) 468 | 469 | def test_EdgeCore_SideSwipe(self): 470 | # 471 | # SideSwipe algorithm (not to be confused with SwipeSide) 472 | # 473 | # This algorithm is axis-agnostic; illustrated tests are vertical, i.e., horizontal swaps parameters. 474 | # To produce new tests, interject the respective windowgram into edgecore(), print the results, then exit. 475 | # 476 | # Successful Successful Fail Fail 477 | # @A @B @C @D @E @F @G @H @I @J @K @L 478 | # .2 1. .2 1. .1 2. .1 2. .2 1. 2. .1 479 | # .2 1. 12 12 .1 2. 21 21 .2 1. 2. .. 480 | # 12 1. 12 12 21 2. 21 21 .2 .. 2. 2. 481 | # 12 12 12 12 21 21 21 21 .2 .. .1 2. 482 | # 12 12 12 .2 21 21 21 .1 .2 .2 .1 2. 483 | # 12 12 .2 .2 21 21 .1 .1 1. .2 .1 2. 484 | # 1. 1. .2 .2 2. 2. .1 .1 1. .2 .1 2. 485 | # p1x p2x p1y p2y 486 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 3, 7, 1, 6 ) == [ 1, 2, 5 ] ) # @A 487 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 1, 7, 4, 6 ) == [ 1, 3, 5 ] ) # @B 488 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 2, 5, 1, 7 ) == [ 1, 1, 4 ] ) # @C 489 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 1, 4, 2, 7 ) == [ 1, 1, 3 ] ) # @D 490 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 1, 6, 3, 7 ) == [ 1, 2, 5 ] ) # @E 491 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 4, 6, 1, 7 ) == [ 1, 3, 5 ] ) # @F 492 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 1, 7, 2, 5 ) == [ 1, 1, 4 ] ) # @G 493 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 2, 7, 1, 4 ) == [ 1, 1, 3 ] ) # @H 494 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 6, 7, 1, 5 ) == None ) # @I 495 | self.assertTrue( edgecore_sideswipe( 1, 1, 2, 2, 1, 2, 5, 7 ) == None ) # @J 496 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 4, 7, 1, 3 ) == None ) # @K 497 | self.assertTrue( edgecore_sideswipe( 2, 2, 1, 1, 1, 1, 3, 7 ) == None ) # @L 498 | 499 | def test_EdgeCore_SwipeSide(self): 500 | # 501 | # SwipeSide algorithm (not to be confused with SideSwipe) 502 | # 503 | # This algorithm is axis-agnostic; when using X major, the windowgram and pane must be transposed. 504 | # 505 | wg = Windowgram( """ 506 | xx000yyyy # xxx111333 (original, transposed) 507 | xx000yyyy # xxx111333 508 | xx000yyyy # 000zzz444 509 | 11zzz2222 # 000zzz444 510 | 11zzz2222 # 000zzz444 511 | 11zzz2222 # yyy444555 512 | 334445555 # yyy444555 513 | 334445555 # yyy444555 514 | 334445555 # yyy444555 515 | """ ) 516 | windowgram_chars_yx = wg.Export_Chars() 517 | windowgram_chars_xy = Windowgram_Convert.Transpose_Chars( windowgram_chars_yx ) 518 | windowgram_parsed = wg.Export_Parsed() 519 | group = "012345" 520 | # For cleaner processing 521 | def edgescan_q(axis, direction, windowgram_parsed, group, windowgram_chars): 522 | runs = [] 523 | for pane in list(group): 524 | parsedpane = windowgram_parsed[pane] 525 | if not axis: parsedpane = Windowgram_Convert.Transpose_ParsedPane( parsedpane ) 526 | this_runs = edgecore_swipeside( direction, parsedpane, group, windowgram_chars ) 527 | for run in this_runs: runs.append( run ) 528 | return edgecore_merger( runs ) 529 | def edgescan_v(direction): 530 | return edgescan_q( True, direction, windowgram_parsed, group, windowgram_chars_yx ) 531 | def edgescan_h(direction): 532 | return edgescan_q( False, direction, windowgram_parsed, group, windowgram_chars_xy ) 533 | # TBLR 534 | self.assertTrue( edgescan_v( True ) == [[0, 2, 4], [3, 0, 1], [3, 5, 8], [6, 2, 4]] ) 535 | self.assertTrue( edgescan_v( False ) == [[3, 2, 4], [9, 0, 8]] ) 536 | self.assertTrue( edgescan_h( True ) == [[0, 3, 8], [2, 0, 2], [5, 3, 5]] ) 537 | self.assertTrue( edgescan_h( False ) == [[2, 3, 5], [5, 0, 2], [9, 3, 8]] ) 538 | 539 | def test_EdgeCore_Invalid(self): 540 | wg = Windowgram( """ 541 | W11YY 542 | XX22Z 543 | """ ) 544 | # Irrational (W does not border Z) 545 | status, axis, minimal, optimal = edgecore( wg, "WZ" ) 546 | self.assertTrue( status is EdgeStatus.Irrational ) 547 | self.assertTrue( axis is None ) 548 | self.assertTrue( minimal is None ) 549 | self.assertTrue( optimal is None ) 550 | # Ambiguous (vertical edge W1 and X, horizontal edge W and 1) 551 | status, axis, minimal, optimal = edgecore( wg, "WX1" ) 552 | self.assertTrue( status is EdgeStatus.Ambiguous ) 553 | self.assertTrue( axis is None ) 554 | self.assertTrue( minimal is None ) 555 | self.assertTrue( optimal is None ) 556 | # Noncontiguous (a gap exists in the minimal edge between 1 and 2) 557 | status, axis, minimal, optimal = edgecore( wg, "WXYZ" ) 558 | self.assertTrue( status is EdgeStatus.Noncontiguous ) 559 | self.assertTrue( axis is None ) 560 | self.assertTrue( minimal is None ) 561 | self.assertTrue( optimal is None ) 562 | 563 | def test_EdgeCore_Group_Vertical(self): 564 | wg = Windowgram( """ 565 | WX 566 | 1X 567 | 12 568 | Y2 569 | YZ 570 | """ ) 571 | status, axis, minimal, optimal = edgecore( wg, "12" ) # Implicit vertical 572 | self.assertTrue( status is EdgeStatus.Valid ) 573 | self.assertTrue( axis == "v" ) 574 | self.assertTrue( minimal == [ [1, 2, 3] ] ) 575 | self.assertTrue( optimal == [ [1, 0, 5] ] ) 576 | 577 | def test_EdgeCore_Group_Horizontal(self): 578 | wg = Windowgram( """ 579 | 1AA22 580 | 1AA22 581 | 33BB4 582 | 33BB4 583 | """ ) 584 | status, axis, minimal, optimal = edgecore( wg, "AB" ) # Implicit horizontal 585 | self.assertTrue( status is EdgeStatus.Valid ) 586 | self.assertTrue( axis == "h" ) 587 | self.assertTrue( minimal == [ [2, 2, 3] ] ) 588 | self.assertTrue( optimal == [ [2, 0, 5] ] ) 589 | 590 | def test_EdgeCore_GroupDirection_Vertical(self): 591 | wg = Windowgram( """ 592 | OWbo 593 | O1Xo 594 | O12o 595 | OY2o 596 | OqZo 597 | """ ) 598 | status, axis, minimal, optimal = edgecore( wg, "2", "left" ) 599 | self.assertTrue( status is EdgeStatus.Valid ) 600 | self.assertTrue( axis == "v" ) 601 | self.assertTrue( minimal == [ [2, 2, 4] ] ) 602 | self.assertTrue( optimal == [ [2, 1, 4] ] ) 603 | status, axis, minimal, optimal = edgecore( wg, "X", "right" ) 604 | self.assertTrue( status is EdgeStatus.Valid ) 605 | self.assertTrue( axis == "v" ) 606 | self.assertTrue( minimal == [ [3, 1, 2] ] ) 607 | self.assertTrue( optimal == [ [3, 0, 5] ] ) 608 | 609 | def test_EdgeCore_GroupDirection_Horizontal(self): 610 | wg = Windowgram( """ 611 | 1AA22 612 | 33BB4 613 | """ ) 614 | status, axis, minimal, optimal = edgecore( wg, "A", "bottom" ) 615 | self.assertTrue( status is EdgeStatus.Valid ) 616 | self.assertTrue( axis == "h" ) 617 | self.assertTrue( minimal == [ [1, 1, 3] ] ) 618 | self.assertTrue( optimal == [ [1, 0, 5] ] ) 619 | status, axis, minimal, optimal = edgecore( wg, "3", "top" ) 620 | self.assertTrue( status is EdgeStatus.Valid ) 621 | self.assertTrue( axis == "h" ) 622 | self.assertTrue( minimal == [ [1, 0, 2] ] ) 623 | self.assertTrue( optimal == [ [1, 0, 5] ] ) 624 | 625 | def test_EdgeCore_WindowgramEdge(self): 626 | # All edges here will have equal minimal and optimal since there are no neighboring panes 627 | wg = Windowgram( """ 628 | 011222 629 | 344555 630 | 344555 631 | 677888 632 | 677888 633 | 677888 634 | """ ) 635 | status, axis, minimal, optimal = edgecore( wg, "5", "right" ) 636 | self.assertTrue( status is EdgeStatus.Valid ) 637 | self.assertTrue( axis is "v" ) 638 | self.assertTrue( minimal == [ [6, 1, 3] ] ) 639 | self.assertTrue( optimal == [ [6, 1, 3] ] ) 640 | status, axis, minimal, optimal = edgecore( wg, "0", "left" ) 641 | self.assertTrue( status is EdgeStatus.Valid ) 642 | self.assertTrue( axis is "v" ) 643 | self.assertTrue( minimal == [ [0, 0, 1] ] ) 644 | self.assertTrue( optimal == [ [0, 0, 1] ] ) 645 | status, axis, minimal, optimal = edgecore( wg, "8", "bottom" ) 646 | self.assertTrue( status is EdgeStatus.Valid ) 647 | self.assertTrue( axis is "h" ) 648 | self.assertTrue( minimal == [ [6, 3, 6] ] ) 649 | self.assertTrue( optimal == [ [6, 3, 6] ] ) 650 | status, axis, minimal, optimal = edgecore( wg, "1", "top" ) 651 | self.assertTrue( status is EdgeStatus.Valid ) 652 | self.assertTrue( axis is "h" ) 653 | self.assertTrue( minimal == [ [0, 1, 3] ] ) 654 | self.assertTrue( optimal == [ [0, 1, 3] ] ) 655 | 656 | def test_EdgeCore_Nuances(self): 657 | # This is noncontiguous, for now. It's possible to support, but callers must be rigorously tested, since they 658 | # assume a single run in the edgecore result. 659 | wg = Windowgram( """ 660 | 1122AABB 661 | aabbxxyy 662 | XXYY3344 663 | """ ) 664 | status, axis, minimal, optimal = edgecore( wg, "1234", "right" ) 665 | self.assertTrue( status is EdgeStatus.Noncontiguous ) 666 | self.assertTrue( axis is None ) 667 | self.assertTrue( minimal is None ) 668 | self.assertTrue( optimal is None ) 669 | 670 | def test_EdgeCore_Examples(self): 671 | wg = Windowgram( """ 672 | # E.1 673 | aaabbb # 674 | 111222 # = 675 | zzzyyy # 676 | """ ) 677 | status, axis, minimal, optimal = edgecore( wg, "12" ) 678 | self.assertTrue( status is EdgeStatus.Valid ) 679 | self.assertTrue( axis is "v" ) 680 | self.assertTrue( minimal == [ [3, 1, 2] ] ) 681 | self.assertTrue( optimal == [ [3, 1, 2] ] ) 682 | wg = Windowgram( """ 683 | # E.2 684 | qqqxxx # o 685 | 111xxx # o 686 | 111222 # m 687 | 111rrr # o 688 | wwwrrr # o 689 | """ ) 690 | status, axis, minimal, optimal = edgecore( wg, "12" ) 691 | self.assertTrue( status is EdgeStatus.Valid ) 692 | self.assertTrue( axis is "v" ) 693 | self.assertTrue( minimal == [ [3, 2, 3] ] ) 694 | self.assertTrue( optimal == [ [3, 0, 5] ] ) 695 | wg = Windowgram( """ 696 | # E.3 697 | MMMNNN # 698 | 111OOO # o 699 | 111222 # m 700 | PPP222 # o 701 | QQQRRR # 702 | """ ) 703 | status, axis, minimal, optimal = edgecore( wg, "12" ) 704 | self.assertTrue( status is EdgeStatus.Valid ) 705 | self.assertTrue( axis is "v" ) 706 | self.assertTrue( minimal == [ [3, 2, 3] ] ) 707 | self.assertTrue( optimal == [ [3, 1, 4] ] ) 708 | 709 | ## Smudge Core 710 | 711 | def test_SmudgeCore_Basic(self): 712 | wg_i = Windowgram( """ 713 | 12345 714 | abcde 715 | fghij 716 | ABCDE 717 | FGHIJ 718 | """ ) 719 | group_o = """ 720 | 2345 11345 1234 12355 721 | bcde aacde abcd abcee 722 | ghij ffhij fghi fghjj 723 | BCDE AACDE ABCD ABCEE 724 | GHIJ FFHIJ FGHI FGHJJ 725 | 726 | abcde 12345 12345 12345 727 | fghij 12345 abcde abcde 728 | ABCDE fghij fghij fghij 729 | FGHIJ ABCDE ABCDE FGHIJ 730 | FGHIJ FGHIJ 731 | 732 | 345 12345 123 12555 733 | cde abcde abc abeee 734 | hij fffij fgh fgjjj 735 | CDE AAADE ABC ABCDE 736 | HIJ FFFIJ FGH FGHIJ 737 | 738 | fghij 12345 12345 12345 739 | ABCDE ab345 abcde abcde 740 | FGHIJ fg345 fghij FGHij 741 | ABCDE FGHDE 742 | FGHIJ FGHIJ 743 | """ 744 | wg_o_list = WindowgramGroup_Convert.Pattern_To_List( group_o ) 745 | wg_x_list = [ 746 | smudgecore( wg_i, 0, "v", 1, "" ).Export_String(), 747 | smudgecore( wg_i, 1, "v", 1, "" ).Export_String(), 748 | smudgecore( wg_i, 5, "v", 1, "-" ).Export_String(), 749 | smudgecore( wg_i, 4, "v", 1, "-" ).Export_String(), 750 | smudgecore( wg_i, 0, "h", 1, "" ).Export_String(), 751 | smudgecore( wg_i, 1, "h", 1, "" ).Export_String(), 752 | smudgecore( wg_i, 5, "h", 1, "-" ).Export_String(), 753 | smudgecore( wg_i, 4, "h", 1, "-" ).Export_String(), 754 | smudgecore( wg_i, 0, "v", 2, "" , [0, 1, 4] ).Export_String(), # Edge discarded with transparency 755 | smudgecore( wg_i, 1, "v", 2, "" , [1, 2, 5] ).Export_String(), 756 | smudgecore( wg_i, 5, "v", 2, "-" , [5, 1, 4] ).Export_String(), # Edge discarded with transparency 757 | smudgecore( wg_i, 4, "v", 2, "-" , [4, 0, 3] ).Export_String(), 758 | smudgecore( wg_i, 0, "h", 2, "" , [0, 1, 4] ).Export_String(), # Edge discarded with transparency 759 | smudgecore( wg_i, 1, "h", 2, "" , [1, 2, 5] ).Export_String(), 760 | smudgecore( wg_i, 5, "h", 2, "-" , [5, 1, 4] ).Export_String(), # Edge discarded with transparency 761 | smudgecore( wg_i, 4, "h", 2, "-" , [4, 0, 3] ).Export_String(), 762 | ] 763 | for wg_o, wg_x in zip( wg_o_list, wg_x_list ): 764 | self.assertTrue( wg_x == wg_o, "\nwg_o\n" + wg_o + "\nwg_x\n" + wg_x ) 765 | 766 | 767 | 768 | ##---------------------------------------------------------------------------------------------------------------------- 769 | ## 770 | ## Unit Testing :: Flex Modifier :: Reset 771 | ## 772 | ##---------------------------------------------------------------------------------------------------------------------- 773 | 774 | class Test_FlexModifier_Reset(SenseTestCase): 775 | 776 | def test_Reset(self): 777 | self.assertFlexSequence( [ 778 | "reset", 779 | ], """ 780 | 1 781 | """ ) 782 | 783 | 784 | 785 | ##---------------------------------------------------------------------------------------------------------------------- 786 | ## 787 | ## Unit Testing :: Flex Modifier :: Scale 788 | ## 789 | ##---------------------------------------------------------------------------------------------------------------------- 790 | 791 | class Test_FlexModifier_Scale(SenseTestCase): 792 | 793 | def test_Scale_One_DupCharacters(self): # Created in flex using "new unittest Scale_One_DupCharacters" 794 | self.assertFlexSequence( [ 795 | "scale 1", 796 | "scale 19", 797 | "scale 3", 798 | "scale 20", 799 | ], """ 800 | 1 1111111111111111111 111 11111111111111111111 801 | 1111111111111111111 111 11111111111111111111 802 | 1111111111111111111 111 11111111111111111111 803 | 1111111111111111111 11111111111111111111 804 | 1111111111111111111 11111111111111111111 805 | 1111111111111111111 11111111111111111111 806 | 1111111111111111111 11111111111111111111 807 | 1111111111111111111 11111111111111111111 808 | 1111111111111111111 11111111111111111111 809 | 1111111111111111111 11111111111111111111 810 | 1111111111111111111 11111111111111111111 811 | 1111111111111111111 11111111111111111111 812 | 1111111111111111111 11111111111111111111 813 | 1111111111111111111 11111111111111111111 814 | 1111111111111111111 11111111111111111111 815 | 1111111111111111111 11111111111111111111 816 | 1111111111111111111 11111111111111111111 817 | 1111111111111111111 11111111111111111111 818 | 1111111111111111111 11111111111111111111 819 | 11111111111111111111 820 | """ ) 821 | 822 | def test_Scale_One_DupPercentages(self): # Created in flex using "new unittest Scale_One_DupPercentages" 823 | self.assertFlexSequence( [ 824 | "scale 200%", 825 | "scale 400%", 826 | "scale 25%", 827 | "scale 400%", 828 | "scale 75%", 829 | "scale 33.4%", 830 | "scale 100%", 831 | "scale 100.99%", 832 | "scale 50%", 833 | "scale 1000%", 834 | "scale 050.000%", 835 | ], """ 836 | 11 11111111 11 11111111 111111 11 11 11 1 1111111111 11111 837 | 11 11111111 11 11111111 111111 11 11 11 1111111111 11111 838 | 11111111 11111111 111111 1111111111 11111 839 | 11111111 11111111 111111 1111111111 11111 840 | 11111111 11111111 111111 1111111111 11111 841 | 11111111 11111111 111111 1111111111 842 | 11111111 11111111 1111111111 843 | 11111111 11111111 1111111111 844 | 1111111111 845 | 1111111111 846 | """ ) 847 | 848 | def test_Scale_One_DupMultipliers(self): # Created in flex using "new unittest Scale_One_DupMultipliers" 849 | self.assertFlexSequence( [ 850 | "scale 2x", 851 | "scale 1x", 852 | "scale .5x", 853 | "scale 5x", 854 | "scale 2.5x", 855 | "scale 1.25x", 856 | "scale .2x", 857 | "scale 5.34x", 858 | "scale 0.25x", 859 | "scale 00000.25000x", 860 | ], """ 861 | 11 11 1 11111 111111111111 111111111111111 111 1111111111111111 1111 1 862 | 11 11 11111 111111111111 111111111111111 111 1111111111111111 1111 863 | 11111 111111111111 111111111111111 111 1111111111111111 1111 864 | 11111 111111111111 111111111111111 1111111111111111 1111 865 | 11111 111111111111 111111111111111 1111111111111111 866 | 111111111111 111111111111111 1111111111111111 867 | 111111111111 111111111111111 1111111111111111 868 | 111111111111 111111111111111 1111111111111111 869 | 111111111111 111111111111111 1111111111111111 870 | 111111111111 111111111111111 1111111111111111 871 | 111111111111 111111111111111 1111111111111111 872 | 111111111111 111111111111111 1111111111111111 873 | 111111111111111 1111111111111111 874 | 111111111111111 1111111111111111 875 | 111111111111111 1111111111111111 876 | 1111111111111111 877 | """ ) 878 | 879 | def test_Scale_One_MixedJoin1(self): # Created in flex using "new unittest Scale_One_MixedJoin1" 880 | self.assertFlexSequence( [ 881 | "scale 5:10", 882 | "scale 10:5", 883 | "scale 2x:2x", 884 | "scale 50%:50%", 885 | "scale .5x:5", 886 | "scale 5:200%", 887 | "scale 200%:.5x", 888 | ], """ 889 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 890 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 891 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 892 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 893 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 894 | 11111 11111111111111111111 11111 895 | 11111 11111111111111111111 11111 896 | 11111 11111111111111111111 11111 897 | 11111 11111111111111111111 11111 898 | 11111 11111111111111111111 11111 899 | """ ) 900 | 901 | def test_Scale_One_MixedJoin2(self): # Created in flex using "new unittest Scale_One_MixedJoin2" 902 | self.assertFlexSequence( [ 903 | "scale 5x10", 904 | "scale 10x5", 905 | "scale 2xx2x", 906 | "scale 50%x50%", 907 | "scale .5xx5", 908 | "scale 5x200%", 909 | "scale 200%x.5x", 910 | ], """ 911 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 912 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 913 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 914 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 915 | 11111 1111111111 11111111111111111111 1111111111 11111 11111 1111111111 916 | 11111 11111111111111111111 11111 917 | 11111 11111111111111111111 11111 918 | 11111 11111111111111111111 11111 919 | 11111 11111111111111111111 11111 920 | 11111 11111111111111111111 11111 921 | """ ) 922 | 923 | def test_Scale_Two_Mixed(self): # Created in flex using "new unittest Scale_Two_Mixed" 924 | self.assertFlexSequence( [ 925 | "scale 5 10", 926 | "scale 10 5", 927 | "scale 10 2x", 928 | "scale 2x 200%", 929 | "scale 50% 10", 930 | "scale 50% 1.5x", 931 | "scale 2.5x 10", 932 | "scale 10 50%", 933 | ], """ 934 | 11111 1111111111 1111111111 11111111111111111111 1111111111 11111 111111111111 1111111111 935 | 11111 1111111111 1111111111 11111111111111111111 1111111111 11111 111111111111 1111111111 936 | 11111 1111111111 1111111111 11111111111111111111 1111111111 11111 111111111111 1111111111 937 | 11111 1111111111 1111111111 11111111111111111111 1111111111 11111 111111111111 1111111111 938 | 11111 1111111111 1111111111 11111111111111111111 1111111111 11111 111111111111 1111111111 939 | 11111 1111111111 11111111111111111111 1111111111 11111 111111111111 940 | 11111 1111111111 11111111111111111111 1111111111 11111 111111111111 941 | 11111 1111111111 11111111111111111111 1111111111 11111 111111111111 942 | 11111 1111111111 11111111111111111111 1111111111 11111 111111111111 943 | 11111 1111111111 11111111111111111111 1111111111 11111 111111111111 944 | 11111111111111111111 11111 945 | 11111111111111111111 11111 946 | 11111111111111111111 11111 947 | 11111111111111111111 11111 948 | 11111111111111111111 11111 949 | 11111111111111111111 950 | 11111111111111111111 951 | 11111111111111111111 952 | 11111111111111111111 953 | 11111111111111111111 954 | """ ) 955 | 956 | 957 | 958 | ##---------------------------------------------------------------------------------------------------------------------- 959 | ## 960 | ## Unit Testing :: Flex Modifier :: Add 961 | ## 962 | ##---------------------------------------------------------------------------------------------------------------------- 963 | 964 | class Test_FlexModifier_Add(SenseTestCase): 965 | 966 | def test_Add_Characters(self): # Created in flex using "new unittest Add_Characters" 967 | self.assertFlexSequence( [ 968 | "scale 5x2 ; rename 1 0 ; add left 1 L", 969 | "add right 2 R", 970 | "add top 3 T", 971 | "add bottom 4 B", 972 | ], """ 973 | L00000 L00000RR TTTTTTTT TTTTTTTT 974 | L00000 L00000RR TTTTTTTT TTTTTTTT 975 | TTTTTTTT TTTTTTTT 976 | L00000RR L00000RR 977 | L00000RR L00000RR 978 | BBBBBBBB 979 | BBBBBBBB 980 | BBBBBBBB 981 | BBBBBBBB 982 | """ ) 983 | 984 | def test_Add_Percentages(self): # Created in flex using "new unittest Add_Percentages" 985 | self.assertFlexSequence( [ 986 | "scale 5 ; rename 1 0 ; add left 100% L", 987 | "add right 50% R", 988 | "add top 20% T", 989 | "add bottom 17% B", 990 | ], """ 991 | LLLLL00000 LLLLL00000RRRRR TTTTTTTTTTTTTTT TTTTTTTTTTTTTTT 992 | LLLLL00000 LLLLL00000RRRRR LLLLL00000RRRRR LLLLL00000RRRRR 993 | LLLLL00000 LLLLL00000RRRRR LLLLL00000RRRRR LLLLL00000RRRRR 994 | LLLLL00000 LLLLL00000RRRRR LLLLL00000RRRRR LLLLL00000RRRRR 995 | LLLLL00000 LLLLL00000RRRRR LLLLL00000RRRRR LLLLL00000RRRRR 996 | LLLLL00000RRRRR LLLLL00000RRRRR 997 | BBBBBBBBBBBBBBB 998 | """ ) 999 | 1000 | def test_Add_Multipliers(self): # Created in flex using "new unittest Add_Multipliers" 1001 | self.assertFlexSequence( [ 1002 | "scale 2 ; rename 1 0 ; add left 3x L", 1003 | "add right .25x R", 1004 | "add top .5x T", 1005 | "add bottom 1x B", 1006 | ], """ 1007 | LLLLLL00 LLLLLL00RR TTTTTTTTTT TTTTTTTTTT 1008 | LLLLLL00 LLLLLL00RR LLLLLL00RR LLLLLL00RR 1009 | LLLLLL00RR LLLLLL00RR 1010 | BBBBBBBBBB 1011 | BBBBBBBBBB 1012 | BBBBBBBBBB 1013 | """ ) 1014 | 1015 | def test_Add_DefaultNames(self): # Created in flex using "new unittest Add_DefaultNames" 1016 | self.assertFlexSequence( [ 1017 | "add left 1", 1018 | "add right 1", 1019 | "add right 1", 1020 | "add right 1", 1021 | "add right 1", 1022 | "add right 1", 1023 | "add right 1", 1024 | "add right 1", 1025 | "add right 1", 1026 | "add top 1", 1027 | "add bottom 1", 1028 | ], """ 1029 | 01 012 0123 01234 012345 0123456 01234567 012345678 0123456789 aaaaaaaaaa aaaaaaaaaa 1030 | 0123456789 0123456789 1031 | bbbbbbbbbb 1032 | """ ) 1033 | 1034 | 1035 | 1036 | ##---------------------------------------------------------------------------------------------------------------------- 1037 | ## 1038 | ## Unit Testing :: Flex Modifier :: Break 1039 | ## 1040 | ##---------------------------------------------------------------------------------------------------------------------- 1041 | 1042 | class Test_FlexModifier_Break(SenseTestCase): 1043 | 1044 | def test_Break_Recursive(self): # Created in flex using "new unittest Break_Recursive" 1045 | self.assertFlexSequence( [ 1046 | "break 1 3x2 Q", 1047 | "break R 3x2 q", 1048 | "break r 3x2 1", 1049 | "break 2 2x2 e", 1050 | ], """ 1051 | QRS QQQqrsSSS QQQQQQQQQqqq123sssSSSSSSSSS QQQQQQQQQQQQQQQQQQqqqqqq11ef33ssssssSSSSSSSSSSSSSSSSSS 1052 | TUV QQQtuvSSS QQQQQQQQQqqq456sssSSSSSSSSS QQQQQQQQQQQQQQQQQQqqqqqq11gh33ssssssSSSSSSSSSSSSSSSSSS 1053 | TTTUUUVVV QQQQQQQQQtttuuuvvvSSSSSSSSS QQQQQQQQQQQQQQQQQQqqqqqq445566ssssssSSSSSSSSSSSSSSSSSS 1054 | TTTUUUVVV QQQQQQQQQtttuuuvvvSSSSSSSSS QQQQQQQQQQQQQQQQQQqqqqqq445566ssssssSSSSSSSSSSSSSSSSSS 1055 | TTTTTTTTTUUUUUUUUUVVVVVVVVV QQQQQQQQQQQQQQQQQQttttttuuuuuuvvvvvvSSSSSSSSSSSSSSSSSS 1056 | TTTTTTTTTUUUUUUUUUVVVVVVVVV QQQQQQQQQQQQQQQQQQttttttuuuuuuvvvvvvSSSSSSSSSSSSSSSSSS 1057 | TTTTTTTTTUUUUUUUUUVVVVVVVVV QQQQQQQQQQQQQQQQQQttttttuuuuuuvvvvvvSSSSSSSSSSSSSSSSSS 1058 | TTTTTTTTTUUUUUUUUUVVVVVVVVV QQQQQQQQQQQQQQQQQQttttttuuuuuuvvvvvvSSSSSSSSSSSSSSSSSS 1059 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1060 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1061 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1062 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1063 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1064 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1065 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1066 | TTTTTTTTTTTTTTTTTTUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVV 1067 | """ ) 1068 | 1069 | def test_Break_Scale(self): # Created in flex using "new unittest Break_Scale" 1070 | self.assertFlexSequence( [ 1071 | "break 1 4x2 G ; scale 2x", 1072 | "break G 3x1 a", 1073 | "break H 4x1 d", 1074 | "break I 5x1 h", 1075 | "break J 3x1 m", 1076 | "break K 1x3 x", 1077 | "break L 1x3 X", 1078 | "break a 1x3 Q", 1079 | ], """ 1080 | GGHHIIJJ abcHHHIIIJJJ abbcdefgIIIIJJJJ abbbcdeefghijklJJJJJ abbbbcdeeefghijjklmmnnoo 1081 | GGHHIIJJ abcHHHIIIJJJ abbcdefgIIIIJJJJ abbbcdeefghijklJJJJJ abbbbcdeeefghijjklmmnnoo 1082 | KKLLMMNN KKKLLLMMMNNN KKKKLLLLMMMMNNNN KKKKKLLLLLMMMMMNNNNN KKKKKKLLLLLLMMMMMMNNNNNN 1083 | KKLLMMNN KKKLLLMMMNNN KKKKLLLLMMMMNNNN KKKKKLLLLLMMMMMNNNNN KKKKKKLLLLLLMMMMMMNNNNNN 1084 | 1085 | abbbbcdeeefghijjklmmnnoo abbbbcdeeefghijjklmmnnoo Qbbbbcdeeefghijjklmmnnoo 1086 | abbbbcdeeefghijjklmmnnoo abbbbcdeeefghijjklmmnnoo Rbbbbcdeeefghijjklmmnnoo 1087 | abbbbcdeeefghijjklmmnnoo abbbbcdeeefghijjklmmnnoo Sbbbbcdeeefghijjklmmnnoo 1088 | xxxxxxLLLLLLMMMMMMNNNNNN xxxxxxXXXXXXMMMMMMNNNNNN xxxxxxXXXXXXMMMMMMNNNNNN 1089 | yyyyyyLLLLLLMMMMMMNNNNNN yyyyyyYYYYYYMMMMMMNNNNNN yyyyyyYYYYYYMMMMMMNNNNNN 1090 | zzzzzzLLLLLLMMMMMMNNNNNN zzzzzzZZZZZZMMMMMMNNNNNN zzzzzzZZZZZZMMMMMMNNNNNN 1091 | """ ) 1092 | 1093 | def test_Break_Various(self): # Created in flex using "new unittest Break_Various" 1094 | self.assertFlexSequence( [ 1095 | "break 1 7x4 a", 1096 | "break A 3x3 0", 1097 | "break B 5x2 A", 1098 | "break J 1x1 Z", 1099 | "break k 3x2 OQSUWY", 1100 | ], """ 1101 | abcdefg aaabbbcccdddeeefffggg aaaaabbbbbcccccdddddeeeeefffffggggg aaaaabbbbbcccccdddddeeeeefffffggggg 1102 | hijklmn aaabbbcccdddeeefffggg aaaaabbbbbcccccdddddeeeeefffffggggg aaaaabbbbbcccccdddddeeeeefffffggggg 1103 | opqrstu aaabbbcccdddeeefffggg aaaaabbbbbcccccdddddeeeeefffffggggg aaaaabbbbbcccccdddddeeeeefffffggggg 1104 | vwxyzAB hhhiiijjjkkklllmmmnnn aaaaabbbbbcccccdddddeeeeefffffggggg aaaaabbbbbcccccdddddeeeeefffffggggg 1105 | hhhiiijjjkkklllmmmnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn 1106 | hhhiiijjjkkklllmmmnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn 1107 | ooopppqqqrrrssstttuuu hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn 1108 | ooopppqqqrrrssstttuuu hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn hhhhhiiiiijjjjjkkkkklllllmmmmmnnnnn 1109 | ooopppqqqrrrssstttuuu ooooopppppqqqqqrrrrrssssstttttuuuuu ooooopppppqqqqqrrrrrssssstttttuuuuu 1110 | vvvwwwxxxyyyzzz012BBB ooooopppppqqqqqrrrrrssssstttttuuuuu ooooopppppqqqqqrrrrrssssstttttuuuuu 1111 | vvvwwwxxxyyyzzz345BBB ooooopppppqqqqqrrrrrssssstttttuuuuu ooooopppppqqqqqrrrrrssssstttttuuuuu 1112 | vvvwwwxxxyyyzzz678BBB ooooopppppqqqqqrrrrrssssstttttuuuuu ooooopppppqqqqqrrrrrssssstttttuuuuu 1113 | vvvvvwwwwwxxxxxyyyyyzzzzz00122ABCDE vvvvvwwwwwxxxxxyyyyyzzzzz00122ABCDE 1114 | vvvvvwwwwwxxxxxyyyyyzzzzz33455ABCDE vvvvvwwwwwxxxxxyyyyyzzzzz33455ABCDE 1115 | vvvvvwwwwwxxxxxyyyyyzzzzz33455FGHIJ vvvvvwwwwwxxxxxyyyyyzzzzz33455FGHIZ 1116 | vvvvvwwwwwxxxxxyyyyyzzzzz66788FGHIJ vvvvvwwwwwxxxxxyyyyyzzzzz66788FGHIZ 1117 | 1118 | aaaaaabbbbbbccccccddddddeeeeeeffffffgggggg 1119 | aaaaaabbbbbbccccccddddddeeeeeeffffffgggggg 1120 | aaaaaabbbbbbccccccddddddeeeeeeffffffgggggg 1121 | aaaaaabbbbbbccccccddddddeeeeeeffffffgggggg 1122 | hhhhhhiiiiiijjjjjjOOQQSSllllllmmmmmmnnnnnn 1123 | hhhhhhiiiiiijjjjjjOOQQSSllllllmmmmmmnnnnnn 1124 | hhhhhhiiiiiijjjjjjUUWWYYllllllmmmmmmnnnnnn 1125 | hhhhhhiiiiiijjjjjjUUWWYYllllllmmmmmmnnnnnn 1126 | ooooooppppppqqqqqqrrrrrrssssssttttttuuuuuu 1127 | ooooooppppppqqqqqqrrrrrrssssssttttttuuuuuu 1128 | ooooooppppppqqqqqqrrrrrrssssssttttttuuuuuu 1129 | ooooooppppppqqqqqqrrrrrrssssssttttttuuuuuu 1130 | vvvvvvwwwwwwxxxxxxyyyyyyzzzzzz001122ABCCDE 1131 | vvvvvvwwwwwwxxxxxxyyyyyyzzzzzz334455ABCCDE 1132 | vvvvvvwwwwwwxxxxxxyyyyyyzzzzzz334455FGHHIZ 1133 | vvvvvvwwwwwwxxxxxxyyyyyyzzzzzz667788FGHHIZ 1134 | """ ) 1135 | 1136 | def test_Break_Naming(self): # Created in flex using "new unittest Break_Naming" 1137 | self.assertFlexSequence( [ 1138 | "break 1 6x2 Z", 1139 | "break a 13x2", 1140 | "break Z 13x2", 1141 | ], """ 1142 | Z01234 ZZZZZZZZZZZZZ00000000000001111111111111222222222222233333333333334444444444444 1143 | 56789a ZZZZZZZZZZZZZ00000000000001111111111111222222222222233333333333334444444444444 1144 | 55555555555556666666666666777777777777788888888888889999999999999abcdefghijklm 1145 | 55555555555556666666666666777777777777788888888888889999999999999nopqrstuvwxyz 1146 | 1147 | ABCDEFGHIJKLM00000000000001111111111111222222222222233333333333334444444444444 1148 | NOPQRSTUVWXYZ00000000000001111111111111222222222222233333333333334444444444444 1149 | 55555555555556666666666666777777777777788888888888889999999999999abcdefghijklm 1150 | 55555555555556666666666666777777777777788888888888889999999999999nopqrstuvwxyz 1151 | """ ) 1152 | 1153 | 1154 | 1155 | ##---------------------------------------------------------------------------------------------------------------------- 1156 | ## 1157 | ## Unit Testing :: Flex Modifier :: Drag 1158 | ## 1159 | ##---------------------------------------------------------------------------------------------------------------------- 1160 | 1161 | class Test_FlexModifier_Drag(SenseTestCase): 1162 | 1163 | def test_Drag_EdgeModify_Example1(self): # Created in flex using "new unittest_ignore Drag_EdgeModify_Example1" 1164 | self.assertFlexSequence( [ 1165 | "break 1 6x5 a ; join Au.0 Bvp.1 Cwqk.2 Dxrlf.3 s.w t.Q mn.x o.R ghi.y j.S abcd.z e.T y.X z.Y", 1166 | "drag XY right 5", 1167 | ], """ 1168 | zzzzT3 zzzzTT 1169 | yyyS23 yyySSS 1170 | xxR123 xxRRRR 1171 | wQ0123 wQQQQQ 1172 | XY0123 XXXXXX 1173 | """, True ) # Ignore notices 1174 | 1175 | def test_Drag_EdgeModify_Example2(self): # Created in flex using "new unittest_ignore Drag_EdgeModify_Example2" 1176 | self.assertFlexSequence( [ 1177 | "break 1 6x5 a ; join Au.0 Bvp.1 Cwqk.2 Dxrlf.3 s.w t.Q mn.x o.R ghi.y j.S abcd.z e.T y.X z.Y", 1178 | "drag right XY right 4", 1179 | ], """ 1180 | zzzzT3 zzzzTT 1181 | yyyS23 yyySSS 1182 | xxR123 xxRRRR 1183 | wQ0123 wQQQQQ 1184 | XY0123 XXXYYY 1185 | """, True ) # Ignore notices 1186 | 1187 | def test_Drag_EdgeModify_WithScale(self): # Created in flex using "new unittest_ignore Drag_EdgeModify_WithScale" 1188 | self.assertFlexSequence( [ 1189 | "break 1 9x6 ; join RIzqh8 QHypg PGxo OFw NE", 1190 | "drag right ABCJKL right 6", 1191 | "drag top * down 100%", 1192 | "drag left * right 100%", 1193 | ], """ 1194 | 01234567R 012345677 ijklmnnnn m 1195 | 9abcdefQR 9abcdefff 1196 | ijklmnPQR ijklmnnnn 1197 | rstuvOPQR rstuvvvvv 1198 | ABCDNOPQR AAABBBCCC 1199 | JKLMNOPQR JJJKKKLLL 1200 | """, True ) # Ignore notices 1201 | 1202 | def test_Drag_EdgeModify_NoScale(self): # Created in flex using "new unittest_ignore Drag_EdgeModify_NoScale" 1203 | self.assertFlexSequence( [ 1204 | "break 1 7x7 ; join 18fm 29g 3a MFyrkd6 LExqjc KDwpi JCvo IBu HA", 1205 | "drag right l right 10", 1206 | "drag bottom * up 100%", 1207 | "drag right * left 100%", 1208 | ], """ 1209 | 012345M 00000000000 lllllllllll l 1210 | 7123bLM 77777777777 1211 | e12hKLM eeeeeeeeeee 1212 | l1nJKLM lllllllllll 1213 | stIJKLM stIIIIIIIII 1214 | zHIJKLM zHIIIIIIIII 1215 | GHIJKLM GHIIIIIIIII 1216 | """, True ) # Ignore notices 1217 | 1218 | def test_Drag_Expansion_Right(self): # Created in flex using "new unittest_ignore Drag_Expansion_Right" 1219 | self.assertFlexSequence( [ 1220 | "break 1 2x3 o ; scale 2x:1x", 1221 | "drag right q right 5", 1222 | ], """ 1223 | oopp ooppppp 1224 | qqrr qqqqqqq 1225 | sstt ssttttt 1226 | """, True ) # Ignore notices 1227 | 1228 | # Released 2.16 without sufficient unit testing; found and fixed the following bugs 1229 | 1230 | def test_Drag_Fixed1(self): # Created in flex using "new unittest_ignore Drag_Fixed1" 1231 | self.assertFlexSequence( [ 1232 | "break 1 2x2 1 ; scale 5x", 1233 | "drag horizontal 1234 down 4", 1234 | "drag horizontal 1234 down 3", 1235 | ], """ 1236 | 1111122222 1111122222 1111122222 1237 | 1111122222 1111122222 1111122222 1238 | 1111122222 1111122222 1111122222 1239 | 1111122222 1111122222 1111122222 1240 | 1111122222 1111122222 1111122222 1241 | 3333344444 1111122222 1111122222 1242 | 3333344444 1111122222 1111122222 1243 | 3333344444 1111122222 1111122222 1244 | 3333344444 1111122222 1111122222 1245 | 3333344444 3333344444 1111122222 1246 | 1111122222 1247 | 1111122222 1248 | """, True ) # Ignore notices 1249 | 1250 | def test_Drag_Fixed2(self): # Created in flex using "new unittest Drag_Fixed2" 1251 | self.assertFlexSequence( [ 1252 | "break 1 2x2 1 ; scale 5x", 1253 | "drag horizontal 1234 down 4", 1254 | "drag horizontal 1234 up 2", 1255 | ], """ 1256 | 1111122222 1111122222 1111122222 1257 | 1111122222 1111122222 1111122222 1258 | 1111122222 1111122222 1111122222 1259 | 1111122222 1111122222 1111122222 1260 | 1111122222 1111122222 1111122222 1261 | 3333344444 1111122222 1111122222 1262 | 3333344444 1111122222 1111122222 1263 | 3333344444 1111122222 3333344444 1264 | 3333344444 1111122222 3333344444 1265 | 3333344444 3333344444 3333344444 1266 | """ ) 1267 | 1268 | def test_Drag_Fixed3(self): # Created in flex using "new unittest Drag_Fixed3" 1269 | self.assertFlexSequence( [ 1270 | "scale 36x10 ; break 1 6x2 defghiDEFGHI ; drag r iI l 3", 1271 | "drag bottom ghi down 4", 1272 | "drag horizontal ghiGHI up 1", 1273 | ], """ 1274 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1275 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1276 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1277 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1278 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1279 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1280 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1281 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1282 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII 1283 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII 1284 | """ ) 1285 | 1286 | # Enforce required sorted() of edge overlap in the edgemagnet() function to prevent careless removal 1287 | 1288 | def test_Drag_Overlap(self): # Created in flex using "new unittest Drag_Overlap" 1289 | self.assertFlexSequence( [ 1290 | "scale 36x10 ; break 1 6x2 defghiDEFGHI ; drag r iI l 3", 1291 | "drag bottom ghi down 4", 1292 | "drag bottom ghi up 1", 1293 | ], """ 1294 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1295 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1296 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1297 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1298 | ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii ddddddeeeeeeffffffgggggghhhhhhiii 1299 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1300 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1301 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFgggggghhhhhhiii 1302 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFgggggghhhhhhiii DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII 1303 | DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII DDDDDDEEEEEEFFFFFFGGGGGGHHHHHHIII 1304 | """ ) 1305 | 1306 | # Mixing edgegroup with scalegroup to make sure the intended edge is dragged when multiple panes factor 1307 | 1308 | def test_Drag_EdgeScaleMixing(self): # Created in flex using "new unittest Drag_EdgeScaleMixing" 1309 | self.assertFlexSequence( [ 1310 | "scale 12x4 ; break 1 4x2 wxyzWXYZ", 1311 | "drag bottom x:yXY down 1", 1312 | "drag top Y:Xxy up 2", 1313 | "drag horizontal XYxy down 2", 1314 | "drag top XY:xy up 1 ; drag left Z:xyzXY right 2", 1315 | "drag right wW:xyXY left 2", 1316 | "drag vertical ZY:ZYxXyz left 2", 1317 | "drag vertical wxWX:wxWXyY right 2", 1318 | ], """ 1319 | wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxxyyyyz wxxxxxyyyyyz wxxxxyyyyzzz wwwxxxyyyzzz 1320 | wwwxxxyyyzzz wwwxxxyyyzzz wwwXXXYYYzzz wwwxxxyyyzzz wwwxxxxyyyyz wxxxxxyyyyyz wxxxxyyyyzzz wwwxxxyyyzzz 1321 | WWWXXXYYYZZZ WWWxxxyyyZZZ WWWXXXYYYZZZ WWWxxxyyyZZZ WWWXXXXYYYYZ WXXXXXYYYYYZ WXXXXYYYYZZZ WWWXXXYYYZZZ 1322 | WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXXYYYYZ WXXXXXYYYYYZ WXXXXYYYYZZZ WWWXXXYYYZZZ 1323 | """ ) 1324 | 1325 | # Other tests 1326 | 1327 | def test_Drag_ExpandAndContract(self): # Created in flex using "new unittest Drag_ExpandAndContract" 1328 | self.assertFlexSequence( [ 1329 | "scale 12x4 ; break 1 4x2 wxyzWXYZ", 1330 | "drag bottom X:* down 2", 1331 | "drag right z:* right 4", 1332 | "drag top y:* down 2", 1333 | "drag left w:* right 4", 1334 | "drag bottom * up 2", 1335 | "drag right * left 8", 1336 | "drag top * up 2", 1337 | "drag left * left 8", 1338 | ], """ 1339 | wwwxxxyyyzzz wwwxxxyyyzzz wwwwxxxxyyyyzzzz wwwwxxxxyyyyzzzz wwwxxxyyyzzz wwwxxxyyyzzz wxyz wxyz wwwxxxyyyzzz 1340 | wwwxxxyyyzzz wwwxxxyyyzzz wwwwxxxxyyyyzzzz wwwwxxxxyyyyzzzz wwwxxxyyyzzz WWWXXXYYYZZZ WXYZ wxyz wwwxxxyyyzzz 1341 | WWWXXXYYYZZZ wwwxxxyyyzzz wwwwxxxxyyyyzzzz WWWWXXXXYYYYZZZZ WWWXXXYYYZZZ WXYZ WWWXXXYYYZZZ 1342 | WWWXXXYYYZZZ WWWXXXYYYZZZ WWWWXXXXYYYYZZZZ WWWWXXXXYYYYZZZZ WWWXXXYYYZZZ WXYZ WWWXXXYYYZZZ 1343 | WWWXXXYYYZZZ WWWWXXXXYYYYZZZZ 1344 | WWWXXXYYYZZZ WWWWXXXXYYYYZZZZ 1345 | """ ) 1346 | 1347 | def test_Drag_ExpandAndContract_Rel(self): # Created in flex using "new unittest_ignore Drag_ExpandAndContract_Rel" 1348 | self.assertFlexSequence( [ 1349 | "scale 12x4 ; break 1 4x2 wxyzWXYZ", 1350 | "drag top y up 100%", 1351 | "drag bottom X down 100%", 1352 | "drag left w left 100%", 1353 | "drag right Z right 100%", 1354 | "drag top y down 25%", 1355 | "drag bottom X up 35%", 1356 | "drag left w right 17%", 1357 | "drag right Z left 25%", 1358 | ], """ 1359 | wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wxxxyyyzzz 1360 | wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz wwwxxxyyyzzz WWWXXXYYYZZZ WWWXXXYYYZZZ WXXXYYYZZZ 1361 | WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ 1362 | WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ WWWXXXYYYZZZ 1363 | 1364 | wxxxyyyz 1365 | WXXXYYYZ 1366 | """, True ) # Ignore notices 1367 | 1368 | def test_Drag_WithAndWithoutScalegroup(self): # Created in flex using "new unittest Drag_WithAndWithoutScalegroup" 1369 | self.assertFlexSequence( [ 1370 | "break 1 4x4 A ; scale 4x", 1371 | "drag left G:* left 4", 1372 | "drag bottom G:* down 4", 1373 | "drag left G left 1", 1374 | "drag bottom G down 1", 1375 | "drag right G right 2", 1376 | ], """ 1377 | AAAABBBBCCCCDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1378 | AAAABBBBCCCCDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1379 | AAAABBBBCCCCDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1380 | AAAABBBBCCCCDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1381 | EEEEFFFFGGGGHHHH EEFFGGGGGGHHHHHH AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1382 | EEEEFFFFGGGGHHHH EEFFGGGGGGHHHHHH AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD AABBCCCCCCDDDDDD 1383 | EEEEFFFFGGGGHHHH EEFFGGGGGGHHHHHH EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1384 | EEEEFFFFGGGGHHHH EEFFGGGGGGHHHHHH EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1385 | IIIIJJJJKKKKLLLL IIJJKKKKKKLLLLLL EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1386 | IIIIJJJJKKKKLLLL IIJJKKKKKKLLLLLL EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1387 | IIIIJJJJKKKKLLLL IIJJKKKKKKLLLLLL EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1388 | IIIIJJJJKKKKLLLL IIJJKKKKKKLLLLLL EEFFGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGHHHHHH EEFGGGGGGGGGHHHH 1389 | MMMMNNNNOOOOPPPP MMNNOOOOOOPPPPPP IIJJKKKKKKLLLLLL IIJJKKKKKKLLLLLL IIFGGGGGGGLLLLLL IIFGGGGGGGGGLLLL 1390 | MMMMNNNNOOOOPPPP MMNNOOOOOOPPPPPP IIJJKKKKKKLLLLLL IIJJKKKKKKLLLLLL IIJJKKKKKKLLLLLL IIJJKKKKKKKKLLLL 1391 | MMMMNNNNOOOOPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP 1392 | MMMMNNNNOOOOPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP MMNNOOOOOOPPPPPP 1393 | """ ) 1394 | 1395 | def test_Drag_AcrossWindowgramEdge(self): # Created in flex using "new unittest_ignore Drag_AcrossWindowgramEdge" 1396 | self.assertFlexSequence( [ 1397 | "scale 12 ; break 1 4x4 A", 1398 | "drag right F left 150%", 1399 | "reset ; scale 12 ; break 1 4x4 A ; drag right F right 150%", 1400 | "reset ; scale 12 ; break 1 4x4 A ; drag bottom G up 150%", 1401 | "reset ; scale 12 ; break 1 4x4 A ; drag bottom G down 150%", 1402 | ], """ 1403 | AAABBBCCCDDD AAAAAABBBCCCDDD AAABBBCCCDDDDDD AAABBBKKKDDD AAABBBCCCDDD 1404 | AAABBBCCCDDD AAAAAABBBCCCDDD AAABBBCCCDDDDDD AAABBBKKKDDD AAABBBCCCDDD 1405 | AAABBBCCCDDD AAAAAABBBCCCDDD AAABBBCCCDDDDDD AAABBBKKKDDD AAABBBCCCDDD 1406 | EEEFFFGGGHHH GGGGGGGGGGGGHHH EEEFFFFFFFFFFFF AAABBBKKKDDD EEEFFFGGGHHH 1407 | EEEFFFGGGHHH GGGGGGGGGGGGHHH EEEFFFFFFFFFFFF AAABBBKKKDDD EEEFFFGGGHHH 1408 | EEEFFFGGGHHH GGGGGGGGGGGGHHH EEEFFFFFFFFFFFF AAABBBKKKDDD EEEFFFGGGHHH 1409 | IIIJJJKKKLLL IIIIIIJJJKKKLLL IIIJJJKKKLLLLLL EEEFFFKKKHHH IIIJJJGGGLLL 1410 | IIIJJJKKKLLL IIIIIIJJJKKKLLL IIIJJJKKKLLLLLL EEEFFFKKKHHH IIIJJJGGGLLL 1411 | IIIJJJKKKLLL IIIIIIJJJKKKLLL IIIJJJKKKLLLLLL EEEFFFKKKHHH IIIJJJGGGLLL 1412 | MMMNNNOOOPPP MMMMMMNNNOOOPPP MMMNNNOOOPPPPPP IIIJJJKKKLLL MMMNNNGGGPPP 1413 | MMMNNNOOOPPP MMMMMMNNNOOOPPP MMMNNNOOOPPPPPP IIIJJJKKKLLL MMMNNNGGGPPP 1414 | MMMNNNOOOPPP MMMMMMNNNOOOPPP MMMNNNOOOPPPPPP IIIJJJKKKLLL MMMNNNGGGPPP 1415 | MMMNNNOOOPPP MMMNNNGGGPPP 1416 | MMMNNNOOOPPP MMMNNNGGGPPP 1417 | MMMNNNOOOPPP MMMNNNGGGPPP 1418 | """, True ) # Ignore notices 1419 | 1420 | def test_Drag_Scalegroups(self): # Created in flex using "new unittest Drag_Scalegroups" 1421 | self.assertFlexSequence( [ 1422 | "reset ; scale 16x12 ; break 1 4x4 a ; drag ab:efgh:mnop right 3", 1423 | "reset ; scale 16x12 ; break 1 4x4 a ; drag ab:ijkl:mnop:abcd left 3", 1424 | "reset ; scale 16x12 ; break 1 4x4 a ; drag fj:aei:gko:hl up 2", 1425 | "reset ; scale 16x12 ; break 1 4x4 a ; drag gk:abefij:hlp down 2", 1426 | ], """ 1427 | aaaaaaabccccdddd abbbbbcccccddddd aaaabbbbccccdddd aaaabbbbccccdddd 1428 | aaaaaaabccccdddd abbbbbcccccddddd aaaabbbbccccdddd aaaabbbbccccdddd 1429 | aaaaaaabccccdddd abbbbbcccccddddd eeeebbbbccccdddd aaaabbbbccccdddd 1430 | eeeeeeefffggghhh eeeeffffgggghhhh eeeeffffgggghhhh aaaabbbbgggghhhh 1431 | eeeeeeefffggghhh eeeeffffgggghhhh iiiijjjjkkkkllll eeeeffffgggghhhh 1432 | eeeeeeefffggghhh eeeeffffgggghhhh iiiijjjjkkkkllll eeeeffffgggghhhh 1433 | iiiijjjjkkkkllll ijjjjjkkkkklllll iiiijjjjkkkkllll eeeeffffgggghhhh 1434 | iiiijjjjkkkkllll ijjjjjkkkkklllll iiiijjjjkkkkllll eeeeffffgggghhhh 1435 | iiiijjjjkkkkllll ijjjjjkkkkklllll iiiijjjjoooollll iiiijjjjkkkkllll 1436 | mmmmmmmnnnoooppp mnnnnnoooooppppp mmmmnnnnoooopppp mmmmnnnnoooollll 1437 | mmmmmmmnnnoooppp mnnnnnoooooppppp mmmmnnnnoooopppp mmmmnnnnoooopppp 1438 | mmmmmmmnnnoooppp mnnnnnoooooppppp mmmmnnnnoooopppp mmmmnnnnoooopppp 1439 | """ ) 1440 | 1441 | def test_Drag_Scalegroups_Empty(self): # Created in flex using "new unittest Drag_Scalegroups_Empty" 1442 | self.assertFlexSequence( [ 1443 | "reset ; scale 15x9 ; break 1 3x3 m ; drag pq:mno: right 2", 1444 | "reset ; scale 15x9 ; break 1 3x3 m ; drag pq:: left 2", 1445 | "reset ; scale 15x9 ; break 1 3x3 m ; drag ru: down 2", 1446 | "reset ; scale 15x9 ; break 1 3x3 m ; drag mp::oru up 2", 1447 | ], """ 1448 | mmmmmmmnnnnoooo mmmmmnnnnnooooo mmmmmnnnnnooooo mmmmmnnnnnooooo 1449 | mmmmmmmnnnnoooo mmmmmnnnnnooooo mmmmmnnnnnooooo pppppnnnnnrrrrr 1450 | mmmmmmmnnnnoooo mmmmmnnnnnooooo mmmmmnnnnnooooo pppppnnnnnrrrrr 1451 | pppppppqqqrrrrr pppqqqqqqqrrrrr pppppqqqqqrrrrr pppppqqqqqrrrrr 1452 | pppppppqqqrrrrr pppqqqqqqqrrrrr pppppqqqqqrrrrr pppppqqqqqrrrrr 1453 | pppppppqqqrrrrr pppqqqqqqqrrrrr pppppqqqqqrrrrr pppppqqqqquuuuu 1454 | ssssstttttuuuuu ssssstttttuuuuu ssssstttttrrrrr ssssstttttuuuuu 1455 | ssssstttttuuuuu ssssstttttuuuuu ssssstttttrrrrr ssssstttttuuuuu 1456 | ssssstttttuuuuu ssssstttttuuuuu ssssstttttuuuuu ssssstttttuuuuu 1457 | """ ) 1458 | 1459 | def test_Drag_Scalegroups_Errors(self): # Created in flex using "new unittest_ignore Drag_Scalegroups_Errors" 1460 | self.assertFlexSequence( [ 1461 | "reset ; scale 15x6 ; break 1 5x2 V ; drag WX:01234z right 1", 1462 | "reset ; scale 15x6 ; break 1 5x2 V ; drag WX:z right 1", 1463 | ], """ 1464 | VVVWWWXXXYYYZZZ VVVWWWXXXYYYZZZ 1465 | VVVWWWXXXYYYZZZ VVVWWWXXXYYYZZZ 1466 | VVVWWWXXXYYYZZZ VVVWWWXXXYYYZZZ 1467 | 000111222333444 000111222333444 1468 | 000111222333444 000111222333444 1469 | 000111222333444 000111222333444 1470 | """, True ) # Ignore notices 1471 | 1472 | # This still needs to be implemented: Automatic splitting of scalegroups when they are combined 1473 | # At the moment this will work as "drag b D:DdGg:FfIi", but that's already been tested in the above 1474 | 1475 | # def test_Drag_MultipleEdges(self): # Created in flex using "new unittest Drag_MultipleEdges" 1476 | # self.assertFlexSequence( [ 1477 | # "scale 15x8 ; break 1 3x4 defDEFGHIghi", 1478 | # "drag b D:DdGgFfIi down 2", 1479 | # ], """ 1480 | # dddddeeeeefffff dddddeeeeefffff 1481 | # dddddeeeeefffff dddddeeeeefffff 1482 | # DDDDDEEEEEFFFFF dddddEEEEEfffff 1483 | # DDDDDEEEEEFFFFF DDDDDEEEEEFFFFF 1484 | # GGGGGHHHHHIIIII DDDDDHHHHHFFFFF 1485 | # GGGGGHHHHHIIIII DDDDDHHHHHFFFFF 1486 | # ggggghhhhhiiiii GGGGGhhhhhIIIII 1487 | # ggggghhhhhiiiii ggggghhhhhiiiii 1488 | # """ ) 1489 | 1490 | 1491 | 1492 | ##---------------------------------------------------------------------------------------------------------------------- 1493 | ## 1494 | ## Unit Testing :: Flex Modifier :: Insert 1495 | ## 1496 | ##---------------------------------------------------------------------------------------------------------------------- 1497 | 1498 | class Test_FlexModifier_Insert(SenseTestCase): 1499 | 1500 | def test_Insert_SpreadFavorsTopLeft_50(self): # Created in flex using "new unittest Insert_SpreadFavorsTopLeft_50" 1501 | self.assertFlexSequence( [ 1502 | "reset ; break 1 2x2 w", 1503 | "reset ; break 1 2x2 w ; insert xz 1", 1504 | "reset ; break 1 2x2 w ; insert xz 2", 1505 | "reset ; break 1 2x2 w ; insert xz 3", 1506 | "reset ; break 1 2x2 w ; insert xz 4", 1507 | "reset ; break 1 2x2 w ; insert xz 5", 1508 | "reset ; break 1 2x2 w ; insert xz 6", 1509 | "reset ; break 1 2x2 w", 1510 | "reset ; break 1 2x2 w ; insert yz 1", 1511 | "reset ; break 1 2x2 w ; insert yz 2", 1512 | "reset ; break 1 2x2 w ; insert yz 3", 1513 | "reset ; break 1 2x2 w ; insert yz 4", 1514 | "reset ; break 1 2x2 w ; insert yz 5", 1515 | "reset ; break 1 2x2 w ; insert yz 6", 1516 | ], """ 1517 | wx wx wx wx wx wx wx wx wwx wwxx wwwxx wwwxxx wwwwxxx wwwwxxxx 1518 | yz w0 w0 w0 w0 w0 w0 yz y0z y00z y000z y0000z y00000z y000000z 1519 | yz y0 w0 w0 w0 w0 1520 | yz y0 y0 w0 w0 1521 | yz y0 y0 y0 1522 | yz y0 y0 1523 | yz y0 1524 | yz 1525 | """ ) 1526 | 1527 | def test_Insert_SpreadTests(self): # Created in flex using "new unittest Insert_SpreadTests" 1528 | self.assertFlexSequence( [ 1529 | "reset ; break 1 2x2 w", 1530 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 0%", 1531 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 25%", 1532 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 50%", 1533 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 75%", 1534 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 100%", 1535 | "reset ; break 1 2x2 w ; insert vertical wx 10 0 0x", 1536 | "reset ; break 1 2x2 w ; insert vertical wx 10 0 .2x", 1537 | "reset ; break 1 2x2 w ; insert vertical wx 10 0 .5x", 1538 | "reset ; break 1 2x2 w ; insert vertical wx 10 0 .8x", 1539 | "reset ; break 1 2x2 w ; insert vertical wx 10 0 1x", 1540 | ], """ 1541 | wx w0000x w0000x w0000x w0000x w0000x w0000000000x w0000000000x w0000000000x w0000000000x w0000000000x 1542 | yz yzzzzz yyzzzz yyyzzz yyyyzz yyyyyz yzzzzzzzzzzz yyyzzzzzzzzz yyyyyyzzzzzz yyyyyyyyyzzz yyyyyyyyyyyz 1543 | """ ) 1544 | 1545 | def test_Insert_SpreadFails(self): # Created in flex using "new unittest_ignore Insert_SpreadFails" 1546 | self.assertFlexSequence( [ 1547 | "reset ; break 1 2x2 w", 1548 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -0.0001%", 1549 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -1%", 1550 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 100.0001%", 1551 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 101%", 1552 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -0.1x", 1553 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -1x", 1554 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -1.0001x", 1555 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -1.1x", 1556 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 -1", 1557 | "reset ; break 1 2x2 w ; insert vertical wx 4 0 5", 1558 | ], """ 1559 | wx wx wx wx wx wx wx wx wx wx wx 1560 | yz yz yz yz yz yz yz yz yz yz yz 1561 | """, True ) # Ignore notices 1562 | 1563 | def test_Insert_LockTest_Edge(self): # Created in flex using "new unittest Insert_LockTest_Edge" 1564 | self.assertFlexSequence( [ 1565 | "reset ; break 1 3x3 a ; scale 14x:5x ; drag top h:be up 2", 1566 | "insert right g 5 X", 1567 | "reset ; break 1 3x3 a ; scale 14x:5x ; drag right d:ef right 2", 1568 | "insert bottom a 5 X", 1569 | ], """ 1570 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1571 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1572 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1573 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1574 | aaaaaaaaaaaaaaeeeeeeeeeeeeeecccccccccccccc aaaaaaaaaaaaaaaaaaaeeeeeeeeeeeeeecccccccccccccc 1575 | ddddddddddddddeeeeeeeeeeeeeeffffffffffffff dddddddddddddddddddeeeeeeeeeeeeeeffffffffffffff 1576 | ddddddddddddddeeeeeeeeeeeeeeffffffffffffff dddddddddddddddddddeeeeeeeeeeeeeeffffffffffffff 1577 | ddddddddddddddeeeeeeeeeeeeeeffffffffffffff dddddddddddddddddddeeeeeeeeeeeeeeffffffffffffff 1578 | ddddddddddddddhhhhhhhhhhhhhhffffffffffffff dddddddddddddddddddhhhhhhhhhhhhhhffffffffffffff 1579 | ddddddddddddddhhhhhhhhhhhhhhffffffffffffff dddddddddddddddddddhhhhhhhhhhhhhhffffffffffffff 1580 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ggggggggggggggXXXXXhhhhhhhhhhhhhhiiiiiiiiiiiiii 1581 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ggggggggggggggXXXXXhhhhhhhhhhhhhhiiiiiiiiiiiiii 1582 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ggggggggggggggXXXXXhhhhhhhhhhhhhhiiiiiiiiiiiiii 1583 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ggggggggggggggXXXXXhhhhhhhhhhhhhhiiiiiiiiiiiiii 1584 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ggggggggggggggXXXXXhhhhhhhhhhhhhhiiiiiiiiiiiiii 1585 | 1586 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1587 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1588 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1589 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1590 | aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc aaaaaaaaaaaaaabbbbbbbbbbbbbbcccccccccccccc 1591 | ddddddddddddddddeeeeeeeeeeeeefffffffffffff XXXXXXXXXXXXXXbbbbbbbbbbbbbbcccccccccccccc 1592 | ddddddddddddddddeeeeeeeeeeeeefffffffffffff XXXXXXXXXXXXXXbbbbbbbbbbbbbbcccccccccccccc 1593 | ddddddddddddddddeeeeeeeeeeeeefffffffffffff XXXXXXXXXXXXXXbbbbbbbbbbbbbbcccccccccccccc 1594 | ddddddddddddddddeeeeeeeeeeeeefffffffffffff XXXXXXXXXXXXXXbbbbbbbbbbbbbbcccccccccccccc 1595 | ddddddddddddddddeeeeeeeeeeeeefffffffffffff XXXXXXXXXXXXXXbbbbbbbbbbbbbbcccccccccccccc 1596 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ddddddddddddddddeeeeeeeeeeeeefffffffffffff 1597 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ddddddddddddddddeeeeeeeeeeeeefffffffffffff 1598 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ddddddddddddddddeeeeeeeeeeeeefffffffffffff 1599 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ddddddddddddddddeeeeeeeeeeeeefffffffffffff 1600 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii ddddddddddddddddeeeeeeeeeeeeefffffffffffff 1601 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii 1602 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii 1603 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii 1604 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii 1605 | gggggggggggggghhhhhhhhhhhhhhiiiiiiiiiiiiii 1606 | """ ) 1607 | 1608 | def test_Insert_LockTest_Center(self): # Created in flex using "new unittest Insert_LockTest_Center" 1609 | self.assertFlexSequence( [ 1610 | "reset ; break 1 2x2 W ; scale 10x:5x ; drag WY up 1 ; drag XZ down 1", 1611 | "insert XY 4", 1612 | "reset ; break 1 2x2 W ; scale 10x:5x ; drag WY down 1 ; drag XZ up 1", 1613 | "insert WZ 4", 1614 | "reset ; break 1 2x2 W ; scale 10x:5x ; drag WX right 1 ; drag YZ left 1", 1615 | "insert WZ 2", 1616 | "reset ; break 1 2x2 W ; scale 10x:5x ; drag WX left 1 ; drag YZ right 1", 1617 | "insert XY 2", 1618 | ], """ 1619 | WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXXXXXX 1620 | WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXXXXXX 1621 | WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXXXXXX 1622 | WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXX WWWWWWWWWWXXXXXXXXXXXXXX 1623 | YYYYYYYYYYXXXXXXXXXX YYYYYYYYYY0000XXXXXXXXXX WWWWWWWWWWZZZZZZZZZZ WWWWWWWWWW0000ZZZZZZZZZZ 1624 | YYYYYYYYYYXXXXXXXXXX YYYYYYYYYY0000XXXXXXXXXX WWWWWWWWWWZZZZZZZZZZ WWWWWWWWWW0000ZZZZZZZZZZ 1625 | YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYYYYYZZZZZZZZZZ 1626 | YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYYYYYZZZZZZZZZZ 1627 | YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYYYYYZZZZZZZZZZ 1628 | YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZZZZZ YYYYYYYYYYZZZZZZZZZZ YYYYYYYYYYYYYYZZZZZZZZZZ 1629 | 1630 | WWWWWWWWWWWXXXXXXXXX WWWWWWWWWWWXXXXXXXXX WWWWWWWWWXXXXXXXXXXX WWWWWWWWWXXXXXXXXXXX 1631 | WWWWWWWWWWWXXXXXXXXX WWWWWWWWWWWXXXXXXXXX WWWWWWWWWXXXXXXXXXXX WWWWWWWWWXXXXXXXXXXX 1632 | WWWWWWWWWWWXXXXXXXXX WWWWWWWWWWWXXXXXXXXX WWWWWWWWWXXXXXXXXXXX WWWWWWWWWXXXXXXXXXXX 1633 | WWWWWWWWWWWXXXXXXXXX WWWWWWWWWWWXXXXXXXXX WWWWWWWWWXXXXXXXXXXX WWWWWWWWWXXXXXXXXXXX 1634 | WWWWWWWWWWWXXXXXXXXX WWWWWWWWWWWXXXXXXXXX WWWWWWWWWXXXXXXXXXXX WWWWWWWWWXXXXXXXXXXX 1635 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYY00XXXXXXXXX YYYYYYYYYYYZZZZZZZZZ WWWWWWWWW00ZZZZZZZZZ 1636 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYY00XXXXXXXXX YYYYYYYYYYYZZZZZZZZZ WWWWWWWWW00ZZZZZZZZZ 1637 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ 1638 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ 1639 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ 1640 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ 1641 | YYYYYYYYYZZZZZZZZZZZ YYYYYYYYYYYZZZZZZZZZ 1642 | """ ) 1643 | 1644 | def test_Insert_LockTest_Mixed(self): # Created in flex using "new unittest Insert_LockTest_Mixed" 1645 | self.assertFlexSequence( [ 1646 | "reset ; break 1 6x4 a ; scale 5x:3x", 1647 | "drag ag:agms up 2 ; drag ou:ouci down 2 ; drag xw:xwv left 2 ; drag jk:jkl right 2", 1648 | "insert ni 1", 1649 | "insert ij 1", 1650 | "insert wp 1", 1651 | "insert mn 1", 1652 | "insert fk 1", 1653 | "insert ba 1", 1654 | "insert gh 1", 1655 | "insert left m 1", 1656 | "insert kr 1", 1657 | "insert right x 1", 1658 | ], """ 1659 | aaaaabbbbbcccccdddddeeeeefffff aaaaabbbbbcccccdddddeeeeefffff aaaaabbbbbbcccccdddddeeeeefffff 1660 | aaaaabbbbbcccccdddddeeeeefffff gggggbbbbbcccccdddddeeeeefffff gggggbbbbbbcccccdddddeeeeefffff 1661 | aaaaabbbbbcccccdddddeeeeefffff gggggbbbbbcccccdddddeeeeefffff gggggbbbbbbcccccdddddeeeeefffff 1662 | ggggghhhhhiiiiijjjjjkkkkklllll ggggghhhhhcccccjjjjjjjkkkkllll ggggghhhhhhcccccjjjjjjjkkkkllll 1663 | ggggghhhhhiiiiijjjjjkkkkklllll ggggghhhhhiiiiijjjjjjjkkkkllll ggggghhhhhhiiiiijjjjjjjkkkkllll 1664 | ggggghhhhhiiiiijjjjjkkkkklllll mmmmmhhhhhiiiiijjjjjjjkkkkllll mmmmmhhhhhhiiiiijjjjjjjkkkkllll 1665 | mmmmmnnnnnooooopppppqqqqqrrrrr mmmmmnnnnniiiiipppppqqqqqrrrrr mmmmmnnnnn0iiiiipppppqqqqqrrrrr 1666 | mmmmmnnnnnooooopppppqqqqqrrrrr mmmmmnnnnnooooopppppqqqqqrrrrr mmmmmnnnnnoooooopppppqqqqqrrrrr 1667 | mmmmmnnnnnooooopppppqqqqqrrrrr sssssnnnnnooooopppppqqqqqrrrrr sssssnnnnnoooooopppppqqqqqrrrrr 1668 | ssssstttttuuuuuvvvvvwwwwwxxxxx ssssstttttooooovvvvwwwwxxxxxxx ssssstttttoooooovvvvwwwwxxxxxxx 1669 | ssssstttttuuuuuvvvvvwwwwwxxxxx ssssstttttooooovvvvwwwwxxxxxxx ssssstttttoooooovvvvwwwwxxxxxxx 1670 | ssssstttttuuuuuvvvvvwwwwwxxxxx ssssstttttuuuuuvvvvwwwwxxxxxxx ssssstttttuuuuuuvvvvwwwwxxxxxxx 1671 | 1672 | aaaaabbbbbbccccccdddddeeeeefffff aaaaabbbbbbccccccdddddeeeeefffff aaaaabbbbbbbccccccdddddeeeeefffff 1673 | gggggbbbbbbccccccdddddeeeeefffff gggggbbbbbbccccccdddddeeeeefffff gggggbbbbbbbccccccdddddeeeeefffff 1674 | gggggbbbbbbccccccdddddeeeeefffff gggggbbbbbbccccccdddddeeeeefffff gggggbbbbbbbccccccdddddeeeeefffff 1675 | ggggghhhhhhccccccjjjjjjjkkkkllll ggggghhhhhhccccccjjjjjjjkkkkllll ggggghhhhhhhccccccjjjjjjjkkkkllll 1676 | ggggghhhhhhiiiii1jjjjjjjkkkkllll ggggghhhhhhiiiii1jjjjjjjkkkkllll ggggghhhhhhhiiiii1jjjjjjjkkkkllll 1677 | mmmmmhhhhhhiiiii1jjjjjjjkkkkllll mmmmmhhhhhhiiiii1jjjjjjjkkkkllll mmmmmhhhhhhhiiiii1jjjjjjjkkkkllll 1678 | mmmmmnnnnn0iiiiippppppqqqqqrrrrr mmmmmnnnnn0iiiiippppppqqqqqrrrrr mmmmm3nnnnn0iiiiippppppqqqqqrrrrr 1679 | mmmmmnnnnnooooooppppppqqqqqrrrrr mmmmmnnnnnooooooppppppqqqqqrrrrr mmmmm3nnnnnooooooppppppqqqqqrrrrr 1680 | sssssnnnnnooooooppppppqqqqqrrrrr sssssnnnnnooooooppppppqqqqqrrrrr ssssssnnnnnooooooppppppqqqqqrrrrr 1681 | ssssstttttoooooovvvvvwwwwxxxxxxx sssssnnnnnoooooovvvvv2qqqqqrrrrr ssssssnnnnnoooooovvvvv2qqqqqrrrrr 1682 | ssssstttttoooooovvvvvwwwwxxxxxxx ssssstttttoooooovvvvvwwwwxxxxxxx sssssstttttoooooovvvvvwwwwxxxxxxx 1683 | ssssstttttuuuuuuvvvvvwwwwxxxxxxx ssssstttttoooooovvvvvwwwwxxxxxxx sssssstttttoooooovvvvvwwwwxxxxxxx 1684 | ssssstttttuuuuuuvvvvvwwwwxxxxxxx sssssstttttuuuuuuvvvvvwwwwxxxxxxx 1685 | 1686 | aaaaabbbbbbbccccccdddddeeeeefffff aaaaa5bbbbbbbccccccdddddeeeeefffff aaaaa5bbbbbbbbccccccdddddeeeeefffff 1687 | gggggbbbbbbbccccccdddddeeeeefffff ggggggbbbbbbbccccccdddddeeeeefffff ggggggbbbbbbbbccccccdddddeeeeefffff 1688 | gggggbbbbbbbccccccdddddeeeeefffff ggggggbbbbbbbccccccdddddeeeeefffff ggggggbbbbbbbbccccccdddddeeeeefffff 1689 | gggggbbbbbbbccccccdddddeeeee4llll ggggggbbbbbbbccccccdddddeeeee4llll ggggggbbbbbbbbccccccdddddeeeee4llll 1690 | ggggghhhhhhhccccccjjjjjjjkkkkllll gggggghhhhhhhccccccjjjjjjjkkkkllll gggggg6hhhhhhhccccccjjjjjjjkkkkllll 1691 | ggggghhhhhhhiiiii1jjjjjjjkkkkllll gggggghhhhhhhiiiii1jjjjjjjkkkkllll gggggg6hhhhhhhiiiii1jjjjjjjkkkkllll 1692 | mmmmmhhhhhhhiiiii1jjjjjjjkkkkllll mmmmmmhhhhhhhiiiii1jjjjjjjkkkkllll mmmmmmmhhhhhhhiiiii1jjjjjjjkkkkllll 1693 | mmmmm3nnnnn0iiiiippppppqqqqqrrrrr mmmmmm3nnnnn0iiiiippppppqqqqqrrrrr mmmmmmm3nnnnn0iiiiippppppqqqqqrrrrr 1694 | mmmmm3nnnnnooooooppppppqqqqqrrrrr mmmmmm3nnnnnooooooppppppqqqqqrrrrr mmmmmmm3nnnnnooooooppppppqqqqqrrrrr 1695 | ssssssnnnnnooooooppppppqqqqqrrrrr sssssssnnnnnooooooppppppqqqqqrrrrr ssssssssnnnnnooooooppppppqqqqqrrrrr 1696 | ssssssnnnnnoooooovvvvv2qqqqqrrrrr sssssssnnnnnoooooovvvvv2qqqqqrrrrr ssssssssnnnnnoooooovvvvv2qqqqqrrrrr 1697 | sssssstttttoooooovvvvvwwwwxxxxxxx ssssssstttttoooooovvvvvwwwwxxxxxxx sssssssstttttoooooovvvvvwwwwxxxxxxx 1698 | sssssstttttoooooovvvvvwwwwxxxxxxx ssssssstttttoooooovvvvvwwwwxxxxxxx sssssssstttttoooooovvvvvwwwwxxxxxxx 1699 | sssssstttttuuuuuuvvvvvwwwwxxxxxxx ssssssstttttuuuuuuvvvvvwwwwxxxxxxx sssssssstttttuuuuuuvvvvvwwwwxxxxxxx 1700 | 1701 | aaaaaa5bbbbbbbbccccccdddddeeeeefffff aaaaaa5bbbbbbbbccccccdddddeeeeefffff 1702 | gggggggbbbbbbbbccccccdddddeeeeefffff gggggggbbbbbbbbccccccdddddeeeeefffff 1703 | gggggggbbbbbbbbccccccdddddeeeeefffff gggggggbbbbbbbbccccccdddddeeeeefffff 1704 | gggggggbbbbbbbbccccccdddddeeeee4llll gggggggbbbbbbbbccccccdddddeeeee4llll 1705 | ggggggg6hhhhhhhccccccjjjjjjjkkkkllll ggggggg6hhhhhhhccccccjjjjjjjkkkkllll 1706 | ggggggg6hhhhhhhiiiii1jjjjjjjkkkkllll ggggggg6hhhhhhhiiiii1jjjjjjjkkkkllll 1707 | 7mmmmmmmhhhhhhhiiiii1jjjjjjjkkkkllll 7mmmmmmmhhhhhhhiiiii1jjjjjjjkkkkllll 1708 | 7mmmmmmm3nnnnn0iiiiippppppqqqqqrrrrr 7mmmmmmmhhhhhhhiiiiippppppqqqqq8llll 1709 | 7mmmmmmm3nnnnnooooooppppppqqqqqrrrrr 7mmmmmmm3nnnnn0iiiiippppppqqqqqrrrrr 1710 | sssssssssnnnnnooooooppppppqqqqqrrrrr 7mmmmmmm3nnnnnooooooppppppqqqqqrrrrr 1711 | sssssssssnnnnnoooooovvvvv2qqqqqrrrrr sssssssssnnnnnooooooppppppqqqqqrrrrr 1712 | ssssssssstttttoooooovvvvvwwwwxxxxxxx sssssssssnnnnnoooooovvvvv2qqqqqrrrrr 1713 | ssssssssstttttoooooovvvvvwwwwxxxxxxx ssssssssstttttoooooovvvvvwwwwxxxxxxx 1714 | ssssssssstttttuuuuuuvvvvvwwwwxxxxxxx ssssssssstttttoooooovvvvvwwwwxxxxxxx 1715 | ssssssssstttttuuuuuuvvvvvwwwwxxxxxxx 1716 | 1717 | aaaaaa5bbbbbbbbccccccdddddeeeeeffffff 1718 | gggggggbbbbbbbbccccccdddddeeeeeffffff 1719 | gggggggbbbbbbbbccccccdddddeeeeeffffff 1720 | gggggggbbbbbbbbccccccdddddeeeee4lllll 1721 | ggggggg6hhhhhhhccccccjjjjjjjkkkklllll 1722 | ggggggg6hhhhhhhiiiii1jjjjjjjkkkklllll 1723 | 7mmmmmmmhhhhhhhiiiii1jjjjjjjkkkklllll 1724 | 7mmmmmmmhhhhhhhiiiiippppppqqqqq8lllll 1725 | 7mmmmmmm3nnnnn0iiiiippppppqqqqqrrrrrr 1726 | 7mmmmmmm3nnnnnooooooppppppqqqqqrrrrrr 1727 | sssssssssnnnnnooooooppppppqqqqqrrrrrr 1728 | sssssssssnnnnnoooooovvvvv2qqqqqrrrrrr 1729 | ssssssssstttttoooooovvvvvwwwwxxxxxxx9 1730 | ssssssssstttttoooooovvvvvwwwwxxxxxxx9 1731 | ssssssssstttttuuuuuuvvvvvwwwwxxxxxxx9 1732 | """ ) 1733 | 1734 | def test_Insert_LockTest_Small(self): # Created in flex using "new unittest Insert_LockTest_Small" 1735 | self.assertFlexSequence( [ 1736 | "reset ; break 1 2x3 1", 1737 | "insert 34 2", 1738 | "reset ; break 1 2x3 1 ; join 24 35 ; rename 6 4", 1739 | "insert 32 2", 1740 | "reset ; break 1 3x2 1 ; join 12 56 ; rename 345 234", 1741 | "insert 14 2", 1742 | ], """ 1743 | 12 1122 12 1112 112 112 1744 | 34 3004 32 3002 344 302 1745 | 56 5566 34 3444 302 1746 | 344 1747 | """ ) 1748 | 1749 | def test_Insert_WindowgramEdge_Full(self): # Created in flex using "new unittest Insert_WindowgramEdge_Full" 1750 | self.assertFlexSequence( [ 1751 | "break 1 2x2 ; scale 20x10", 1752 | "insert left * 1 L", 1753 | "insert right * 1 R", 1754 | "insert top * 1 T", 1755 | "insert bottom * 1 B", 1756 | ], """ 1757 | 00000000001111111111 L00000000001111111111 L00000000001111111111R TTTTTTTTTTTTTTTTTTTTTT 1758 | 00000000001111111111 L00000000001111111111 L00000000001111111111R L00000000001111111111R 1759 | 00000000001111111111 L00000000001111111111 L00000000001111111111R L00000000001111111111R 1760 | 00000000001111111111 L00000000001111111111 L00000000001111111111R L00000000001111111111R 1761 | 00000000001111111111 L00000000001111111111 L00000000001111111111R L00000000001111111111R 1762 | 22222222223333333333 L22222222223333333333 L22222222223333333333R L00000000001111111111R 1763 | 22222222223333333333 L22222222223333333333 L22222222223333333333R L22222222223333333333R 1764 | 22222222223333333333 L22222222223333333333 L22222222223333333333R L22222222223333333333R 1765 | 22222222223333333333 L22222222223333333333 L22222222223333333333R L22222222223333333333R 1766 | 22222222223333333333 L22222222223333333333 L22222222223333333333R L22222222223333333333R 1767 | L22222222223333333333R 1768 | 1769 | TTTTTTTTTTTTTTTTTTTTTT 1770 | L00000000001111111111R 1771 | L00000000001111111111R 1772 | L00000000001111111111R 1773 | L00000000001111111111R 1774 | L00000000001111111111R 1775 | L22222222223333333333R 1776 | L22222222223333333333R 1777 | L22222222223333333333R 1778 | L22222222223333333333R 1779 | L22222222223333333333R 1780 | BBBBBBBBBBBBBBBBBBBBBB 1781 | """ ) 1782 | 1783 | def test_Insert_WindowgramEdge_Partial(self): # Created in flex using "new unittest Insert_WindowgramEdge_Partial" 1784 | self.assertFlexSequence( [ 1785 | "reset ; break 1 4x2 ; scale 40x10", 1786 | "insert left 4 1 L", 1787 | "insert right 3 1 R", 1788 | "insert top 0 1 T", 1789 | "insert bottom 7 1 B", 1790 | "insert top 12 1 t", 1791 | "insert bottom 56 1 b", 1792 | ], """ 1793 | 0000000000111111111122222222223333333333 00000000000111111111122222222223333333333 1794 | 0000000000111111111122222222223333333333 00000000000111111111122222222223333333333 1795 | 0000000000111111111122222222223333333333 00000000000111111111122222222223333333333 1796 | 0000000000111111111122222222223333333333 00000000000111111111122222222223333333333 1797 | 0000000000111111111122222222223333333333 00000000000111111111122222222223333333333 1798 | 4444444444555555555566666666667777777777 L4444444444555555555566666666667777777777 1799 | 4444444444555555555566666666667777777777 L4444444444555555555566666666667777777777 1800 | 4444444444555555555566666666667777777777 L4444444444555555555566666666667777777777 1801 | 4444444444555555555566666666667777777777 L4444444444555555555566666666667777777777 1802 | 4444444444555555555566666666667777777777 L4444444444555555555566666666667777777777 1803 | 1804 | 00000000000111111111122222222223333333333R TTTTTTTTTTT111111111122222222223333333333R 1805 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1806 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1807 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1808 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1809 | L44444444445555555555666666666677777777777 00000000000111111111122222222223333333333R 1810 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1811 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1812 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1813 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1814 | L44444444445555555555666666666677777777777 1815 | 1816 | TTTTTTTTTTT111111111122222222223333333333R TTTTTTTTTTTtttttttttttttttttttt3333333333R 1817 | 00000000000111111111122222222223333333333R TTTTTTTTTTT111111111122222222223333333333R 1818 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1819 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1820 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1821 | 00000000000111111111122222222223333333333R 00000000000111111111122222222223333333333R 1822 | L44444444445555555555666666666677777777777 00000000000111111111122222222223333333333R 1823 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1824 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1825 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1826 | L44444444445555555555666666666677777777777 L44444444445555555555666666666677777777777 1827 | L444444444455555555556666666666BBBBBBBBBBB L44444444445555555555666666666677777777777 1828 | L444444444455555555556666666666BBBBBBBBBBB 1829 | 1830 | TTTTTTTTTTTtttttttttttttttttttt3333333333R 1831 | TTTTTTTTTTT111111111122222222223333333333R 1832 | 00000000000111111111122222222223333333333R 1833 | 00000000000111111111122222222223333333333R 1834 | 00000000000111111111122222222223333333333R 1835 | 00000000000111111111122222222223333333333R 1836 | 00000000000111111111122222222223333333333R 1837 | L44444444445555555555666666666677777777777 1838 | L44444444445555555555666666666677777777777 1839 | L44444444445555555555666666666677777777777 1840 | L44444444445555555555666666666677777777777 1841 | L44444444445555555555666666666677777777777 1842 | L444444444455555555556666666666BBBBBBBBBBB 1843 | L4444444444bbbbbbbbbbbbbbbbbbbbBBBBBBBBBBB 1844 | """ ) 1845 | 1846 | def test_Insert_ExamplesFromOutline(self): # Created in flex using "new unittest Insert_ExamplesFromOutline" 1847 | self.assertFlexSequence( [ 1848 | "reset ; break 1 3x3 1", 1849 | "reset ; break 1 3x3 1 ; insert v 12 2 X", 1850 | "reset ; break 1 3x3 1 ; insert r 3 1 X", 1851 | "reset ; break 1 3x3 1 ; insert r * 1 X", 1852 | "reset ; break 1 3x3 1 ; insert v 1245 1 X", 1853 | ], """ 1854 | 123 1XX23 123X 123X 1X23 1855 | 456 44556 4566 456X 4X56 1856 | 789 77889 7899 789X 7789 1857 | """ ) 1858 | 1859 | def test_Insert_Various_1(self): # Created in flex using "new unittest Insert_Various_1" 1860 | self.assertFlexSequence( [ 1861 | "break 1 3x3 1", 1862 | "insert 12 4", 1863 | "insert 23 2", 1864 | "insert 58 2", 1865 | "insert 69 1", 1866 | "insert r * 1", 1867 | "insert l * 1", 1868 | "insert t * 1", 1869 | "insert b * 1", 1870 | ], """ 1871 | 123 1000023 100002aa3 100002aa3 100002aa3 100002aa3d e100002aa3d fffffffffff fffffffffff 1872 | 456 4445556 444555566 444555566 444555566 444555566d e444555566d e100002aa3d e100002aa3d 1873 | 789 7778889 777888899 444bbbb66 444bbbb66 444bbbb66d e444bbbb66d e444555566d e444555566d 1874 | 777bbbb99 444bbbbcc 444bbbbccd e444bbbbccd e444bbbb66d e444bbbb66d 1875 | 777888899 777bbbb99 777bbbb99d e777bbbb99d e444bbbbccd e444bbbbccd 1876 | 777888899 777888899d e777888899d e777bbbb99d e777bbbb99d 1877 | e777888899d e777888899d 1878 | ggggggggggg 1879 | """ ) 1880 | 1881 | def test_Insert_Various_2(self): # Created in flex using "new unittest Insert_Various_2" 1882 | self.assertFlexSequence( [ 1883 | "reset ; break 1 5x4 ; scale 5x:2x", 1884 | "insert vertical 23:567abcfgh 45 A 100%", 1885 | "insert A5 2", 1886 | ], """ 1887 | 0000011111222223333344444 000001111122222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3333344444 1888 | 0000011111222223333344444 000001111122222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3333344444 1889 | 5555566666777778888899999 5555555555555555555566666666666666666666777777777777777777778888899999 1890 | 5555566666777778888899999 5555555555555555555566666666666666666666777777777777777777778888899999 1891 | aaaaabbbbbcccccdddddeeeee aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccdddddeeeee 1892 | aaaaabbbbbcccccdddddeeeee aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccdddddeeeee 1893 | fffffggggghhhhhiiiiijjjjj ffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiijjjjj 1894 | fffffggggghhhhhiiiiijjjjj ffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiijjjjj 1895 | 1896 | 000001111122222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3333344444 1897 | 000001111122222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3333344444 1898 | 000001111122222kkkkk66666666666666666666777777777777777777773333344444 1899 | 000001111122222kkkkk66666666666666666666777777777777777777778888899999 1900 | 5555555555555555555566666666666666666666777777777777777777778888899999 1901 | 5555555555555555555566666666666666666666777777777777777777778888899999 1902 | aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccdddddeeeee 1903 | aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccdddddeeeee 1904 | ffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiijjjjj 1905 | ffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiijjjjj 1906 | """ ) 1907 | 1908 | def test_Insert_Various_3(self): # Created in flex using "new unittest Insert_Various_3" 1909 | self.assertFlexSequence( [ 1910 | "reset ; break 1 4x3 d ; scale 5x:3x", 1911 | "insert vertical hilm 2", 1912 | "insert vertical efij 2", 1913 | "insert vertical jkno 2", 1914 | "insert horizontal deh0i 2", 1915 | "insert horizontal i1jmn 2", 1916 | "insert top fg 2", 1917 | "insert right ko 2", 1918 | "insert bottom mn 2", 1919 | "insert left lh 2", 1920 | ], """ 1921 | dddddeeeeefffffggggg ddddddeeeeeefffffggggg ddddddeeeeee11fffffggggg ddddddeeeeee11ffffffgggggg 1922 | dddddeeeeefffffggggg ddddddeeeeeefffffggggg ddddddeeeeee11fffffggggg ddddddeeeeee11ffffffgggggg 1923 | dddddeeeeefffffggggg ddddddeeeeeefffffggggg ddddddeeeeee11fffffggggg ddddddeeeeee11ffffffgggggg 1924 | hhhhhiiiiijjjjjkkkkk hhhhh00iiiiijjjjjkkkkk hhhhh00iiiii11jjjjjkkkkk hhhhh00iiiii11jjjjj22kkkkk 1925 | hhhhhiiiiijjjjjkkkkk hhhhh00iiiiijjjjjkkkkk hhhhh00iiiii11jjjjjkkkkk hhhhh00iiiii11jjjjj22kkkkk 1926 | hhhhhiiiiijjjjjkkkkk hhhhh00iiiiijjjjjkkkkk hhhhh00iiiii11jjjjjkkkkk hhhhh00iiiii11jjjjj22kkkkk 1927 | lllllmmmmmnnnnnooooo lllll00mmmmmnnnnnooooo lllll00mmmmmmnnnnnnooooo lllll00mmmmmmnnnnnn22ooooo 1928 | lllllmmmmmnnnnnooooo lllll00mmmmmnnnnnooooo lllll00mmmmmmnnnnnnooooo lllll00mmmmmmnnnnnn22ooooo 1929 | lllllmmmmmnnnnnooooo lllll00mmmmmnnnnnooooo lllll00mmmmmmnnnnnnooooo lllll00mmmmmmnnnnnn22ooooo 1930 | 1931 | ddddddeeeeee11ffffffgggggg ddddddeeeeee11ffffffgggggg ddddddeeeeee11555555555555 1932 | ddddddeeeeee11ffffffgggggg ddddddeeeeee11ffffffgggggg ddddddeeeeee11555555555555 1933 | ddddddeeeeee11ffffffgggggg ddddddeeeeee11ffffffgggggg ddddddeeeeee11ffffffgggggg 1934 | 33333333333311ffffffgggggg 33333333333311ffffffgggggg ddddddeeeeee11ffffffgggggg 1935 | 33333333333311jjjjj22kkkkk 33333333333311jjjjj22kkkkk ddddddeeeeee11ffffffgggggg 1936 | hhhhh00iiiii11jjjjj22kkkkk hhhhh00iiiii11jjjjj22kkkkk 33333333333311ffffffgggggg 1937 | hhhhh00iiiii11jjjjj22kkkkk hhhhh00iiiii11jjjjj22kkkkk 33333333333311jjjjj22kkkkk 1938 | hhhhh00iiiii11jjjjj22kkkkk hhhhh00iiiii11jjjjj22kkkkk hhhhh00iiiii11jjjjj22kkkkk 1939 | lllll00mmmmmmnnnnnn22ooooo hhhhh0044444444444422kkkkk hhhhh00iiiii11jjjjj22kkkkk 1940 | lllll00mmmmmmnnnnnn22ooooo lllll0044444444444422ooooo hhhhh00iiiii11jjjjj22kkkkk 1941 | lllll00mmmmmmnnnnnn22ooooo lllll00mmmmmmnnnnnn22ooooo hhhhh0044444444444422kkkkk 1942 | lllll00mmmmmmnnnnnn22ooooo lllll0044444444444422ooooo 1943 | lllll00mmmmmmnnnnnn22ooooo lllll00mmmmmmnnnnnn22ooooo 1944 | lllll00mmmmmmnnnnnn22ooooo 1945 | lllll00mmmmmmnnnnnn22ooooo 1946 | 1947 | ddddddeeeeee1155555555555555 ddddddeeeeee1155555555555555 ddddddddeeeeee1155555555555555 1948 | ddddddeeeeee1155555555555555 ddddddeeeeee1155555555555555 ddddddddeeeeee1155555555555555 1949 | ddddddeeeeee11ffffffgggggggg ddddddeeeeee11ffffffgggggggg ddddddddeeeeee11ffffffgggggggg 1950 | ddddddeeeeee11ffffffgggggggg ddddddeeeeee11ffffffgggggggg ddddddddeeeeee11ffffffgggggggg 1951 | ddddddeeeeee11ffffffgggggggg ddddddeeeeee11ffffffgggggggg ddddddddeeeeee11ffffffgggggggg 1952 | 33333333333311ffffffgggggggg 33333333333311ffffffgggggggg 3333333333333311ffffffgggggggg 1953 | 33333333333311jjjjj22kkkkk66 33333333333311jjjjj22kkkkk66 3333333333333311jjjjj22kkkkk66 1954 | hhhhh00iiiii11jjjjj22kkkkk66 hhhhh00iiiii11jjjjj22kkkkk66 88hhhhh00iiiii11jjjjj22kkkkk66 1955 | hhhhh00iiiii11jjjjj22kkkkk66 hhhhh00iiiii11jjjjj22kkkkk66 88hhhhh00iiiii11jjjjj22kkkkk66 1956 | hhhhh00iiiii11jjjjj22kkkkk66 hhhhh00iiiii11jjjjj22kkkkk66 88hhhhh00iiiii11jjjjj22kkkkk66 1957 | hhhhh0044444444444422kkkkk66 hhhhh0044444444444422kkkkk66 88hhhhh0044444444444422kkkkk66 1958 | lllll0044444444444422ooooo66 lllll0044444444444422ooooo66 88lllll0044444444444422ooooo66 1959 | lllll00mmmmmmnnnnnn22ooooo66 lllll00mmmmmmnnnnnn22ooooo66 88lllll00mmmmmmnnnnnn22ooooo66 1960 | lllll00mmmmmmnnnnnn22ooooo66 lllll00mmmmmmnnnnnn22ooooo66 88lllll00mmmmmmnnnnnn22ooooo66 1961 | lllll00mmmmmmnnnnnn22ooooo66 lllll00mmmmmmnnnnnn22ooooo66 88lllll00mmmmmmnnnnnn22ooooo66 1962 | lllll0077777777777722ooooo66 88lllll0077777777777722ooooo66 1963 | lllll0077777777777722ooooo66 88lllll0077777777777722ooooo66 1964 | """ ) 1965 | 1966 | def test_Insert_Various_4(self): # Created in flex using "new unittest Insert_Various_4" 1967 | self.assertFlexSequence( [ 1968 | "break 1 4x2 1", 1969 | "insert 78:1234 12", 1970 | ], """ 1971 | 1234 1111222233334444 1972 | 5678 5670000000000008 1973 | """ ) 1974 | 1975 | def test_Insert_Various_5(self): # Created in flex using "new unittest Insert_Various_5" 1976 | self.assertFlexSequence( [ 1977 | "reset ; break 1 9x2 ; join 0.a 123.b 4.X 567.y 8.z 9a.0 bcdef.1 gh.x ; insert X1 2", 1978 | "reset ; break 1 4x2 ; scale 3xx1x ; drag 56 left 1 ; drag 67 right 1 ; insert horizontal 16 2 x", 1979 | ], """ 1980 | abbbXyyyz 000111222333 1981 | abbb2yyyz 00055x222333 1982 | abbb2yyyz 44455x222333 1983 | 0011111xx 444556666677 1984 | """ ) 1985 | 1986 | def test_Insert_ThoroughEdgeV1V2(self): # Created in flex using "new unittest Insert_ThoroughEdgeV1V2" 1987 | self.assertFlexSequence( [ 1988 | "reset ; break 1 2x1 ; join 0.L 1.R ; insert vertical LR 2 z", 1989 | "reset ; break 1 2x3 ; join 024.L 3.R 1 5.2 ; insert vertical LR 2 z", 1990 | "reset ; break 1 2x3 ; join 02.L 3.R 1 4.2 5.3 ; insert vertical LR 2 z", 1991 | "reset ; break 1 2x3 ; join 0.1 24.L 3.R 5.2 1.3 ; insert vertical LR 2 x", 1992 | "reset ; break 1 2x3 ; join 2.L 3.R 0 1 4.3 5.4 ; insert vertical LR 2 z", 1993 | "reset ; break 1 2x3 ; join 2.L 35.R 0.1 1.2 4.3 ; insert vertical LR 2 z", 1994 | "reset ; break 1 2x3 ; join 2.L 13.R 0.1 4.2 5.3 ; insert vertical LR 2 z", 1995 | "reset ; break 1 2x3 ; join 2.L 135.R 0.1 4.2 ; insert vertical LR 2 z", 1996 | "reset ; break 1 2x3 ; join 02.L 35.R ; insert vertical LR 2 z", 1997 | "reset ; break 1 2x3 ; join 02.L 135.R ; insert vertical LR 2 z", 1998 | "reset ; break 1 2x3 ; join 02.L 13.R ; insert vertical LR 2 z", 1999 | "reset ; break 1 2x3 ; join 24.L 35.R ; insert vertical LR 2 z", 2000 | "reset ; break 1 2x3 ; join 24.L 135.R ; insert vertical LR 2 z", 2001 | "reset ; break 1 2x3 ; join 24.L 13.R ; insert vertical LR 2 z", 2002 | "reset ; break 1 2x3 ; join 024.L 135.R ; insert vertical LR 2 z", 2003 | ], """ 2004 | LzzR L111 L111 1133 0011 1122 111R 111R L111 LzzR LzzR 0011 000R 000R LzzR 2005 | LzzR LzzR LxxR LzzR LzzR LzzR LzzR LzzR LzzR LzzR LzzR LzzR LzzR LzzR 2006 | L222 2233 L222 3344 333R 2233 222R 444R 444R 4455 LzzR LzzR L555 LzzR 2007 | """ ) 2008 | 2009 | def test_Insert_ThoroughEdgeV3(self): # Created in flex using "new unittest Insert_ThoroughEdgeV3" 2010 | self.assertFlexSequence( [ 2011 | "reset ; break 1 2x5 1 ; join 357.L 6.R ; insert vertical LR 2 z", 2012 | "reset ; break 1 2x5 1 ; join 35.L 6.R ; insert vertical LR 2 z", 2013 | "reset ; break 1 2x5 1 ; join 57.L 6.R ; insert vertical LR 2 z", 2014 | "reset ; break 1 2x5 1 ; join 5.L 6.R ; insert vertical LR 2 z", 2015 | "reset ; break 1 2x5 1 ; join 5.L 68.R ; insert vertical LR 2 z", 2016 | "reset ; break 1 2x5 1 ; join 5.L 46.R ; insert vertical LR 2 x", 2017 | "reset ; break 1 2x5 1 ; join 5.L 468.R ; insert vertical LR 2 z", 2018 | "reset ; break 1 2x5 1 ; join 35.L 68.R ; insert vertical LR 2 z", 2019 | "reset ; break 1 2x5 1 ; join 35.L 468.R ; insert vertical LR 2 z", 2020 | "reset ; break 1 2x5 1 ; join 35.L 46.R ; insert vertical LR 2 z", 2021 | "reset ; break 1 2x5 1 ; join 57.L 68.R ; insert vertical LR 2 z", 2022 | "reset ; break 1 2x5 1 ; join 57.L 468.R ; insert vertical LR 2 z", 2023 | "reset ; break 1 2x5 1 ; join 57.L 46.R ; insert vertical LR 2 z", 2024 | "reset ; break 1 2x5 1 ; join 357.L 468.R ; insert vertical LR 2 z", 2025 | ], """ 2026 | 1122 1122 1122 1122 1122 1122 1122 1122 1122 1122 1122 1122 1122 1122 2027 | L444 L444 3344 3344 3344 333R 333R L444 LzzR LzzR 3344 333R 333R LzzR 2028 | LzzR LzzR LzzR LzzR LzzR LxxR LzzR LzzR LzzR LzzR LzzR LzzR LzzR LzzR 2029 | L888 7788 L888 7788 777R 7788 777R 777R 777R 7788 LzzR LzzR L888 LzzR 2030 | 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 99aa 2031 | """ ) 2032 | 2033 | def test_Insert_Scalegroups(self): # Created in flex using "new unittest Insert_Scalegroups" 2034 | self.assertFlexSequence( [ 2035 | "reset ; break 1 3x3 1 ; scale 5x 3x ; insert 23:456:789 6", 2036 | "reset ; break 1 3x3 1 ; scale 5x 3x ; insert 78:123:456 6", 2037 | "reset ; break 1 3x3 1 ; scale 5x 3x ; insert top 1:258:369 3", 2038 | "reset ; break 1 3x3 1 ; scale 5x 3x ; insert bottom 9:147:258 3", 2039 | ], """ 2040 | 111112222200000033333 111111122222223333333 000002222233333 111112222233333 2041 | 111112222200000033333 111111122222223333333 000002222233333 111112222233333 2042 | 111112222200000033333 111111122222223333333 000002222233333 111112222233333 2043 | 444444455555556666666 444444455555556666666 111112222233333 111112222266666 2044 | 444444455555556666666 444444455555556666666 111115555566666 444445555566666 2045 | 444444455555556666666 444444455555556666666 111115555566666 444445555566666 2046 | 777777788888889999999 777770000008888899999 444445555566666 444445555599999 2047 | 777777788888889999999 777770000008888899999 444445555566666 444445555599999 2048 | 777777788888889999999 777770000008888899999 444448888899999 777778888899999 2049 | 777778888899999 777778888800000 2050 | 777778888899999 777778888800000 2051 | 777778888899999 777778888800000 2052 | """ ) 2053 | 2054 | 2055 | 2056 | ##---------------------------------------------------------------------------------------------------------- 2057 | ## 2058 | ## Keep this note for adding new unit tests for flex 2059 | ## 2060 | ## flex> new unittest ScaleCommand # When created, the output switches to a convenient code dump 2061 | ## flex> scale 25x10 # Run commands and the unittest code will be built as you go 2062 | ## flex> scale 20x20 # When finished just paste the generated code into this class 2063 | ## 2064 | ##---------------------------------------------------------------------------------------------------------- 2065 | 2066 | 2067 | 2068 | ##---------------------------------------------------------------------------------------------------------------------- 2069 | ## 2070 | ## Unit Testing :: Flex Modifier Combinations 2071 | ## 2072 | ##---------------------------------------------------------------------------------------------------------------------- 2073 | 2074 | class Test_FlexModifierCombination_ScaleCoreDetails(SenseTestCase): 2075 | 2076 | ## These two tests were already done in a more direct form earlier in the core area 2077 | 2078 | def test_ScaleCoreDetails_VersionAssert(self): # Created in flex using "new unittest ScaleCoreDetails_VersionAssert" 2079 | # break 1 2x2 ; scale 3x3 ; scale 2x2 2080 | self.assertFlexSequence( [ 2081 | "break 1 2x2 ; scale 3x3 ; scale 2x2", 2082 | ], """ 2083 | 01 2084 | 23 2085 | """ ) 2086 | 2087 | def test_ScaleCoreDetails_ScaleRetries(self): # Created in flex using "new unittest ScaleCoreDetails_ScaleRetries" 2088 | # See this commit for the code used to discover this test 2089 | # break 1 11x1 ; scale 46 1 ; break 5 7x1 2090 | self.assertFlexSequence( [ 2091 | "break 1 11x1 ; scale 46 1 ; break 5 7x1", 2092 | ], """ 2093 | 00000001111111222222222333333344444445bcdefg666666677777778888888889999999aaaaaaa 2094 | """ ) 2095 | 2096 | class Test_FlexModifierCombination_AddBreakJoin(SenseTestCase): 2097 | 2098 | ## This asserts the underlying pane order of [0-9a-zA-Z] through default name assignment of the Add command 2099 | 2100 | def test_AddBreakJoin_DefaultNames(self): # Created in flex using "new unittest AddBreakJoin_DefaultNames" 2101 | self.assertFlexSequence( [ 2102 | "break 1 31x2 ; join 210 ba BA YZ", 2103 | "add left 1", 2104 | "add right 1", 2105 | "add top 1", 2106 | "add bottom 1", 2107 | "add top 1", 2108 | ], """ 2109 | 2223456789bbcdefghijklmnopqrstu 02223456789bbcdefghijklmnopqrstu 02223456789bbcdefghijklmnopqrstu1 2110 | vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY 0vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY 0vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY1 2111 | 2112 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ 2113 | 02223456789bbcdefghijklmnopqrstu1 02223456789bbcdefghijklmnopqrstu1 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 2114 | 0vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY1 0vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY1 02223456789bbcdefghijklmnopqrstu1 2115 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 0vwxyzBBCDEFGHIJKLMNOPQRSTUVWXYY1 2116 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 2117 | """ ) 2118 | 2119 | 2120 | 2121 | ##---------------------------------------------------------------------------------------------------------------------- 2122 | ## 2123 | ## Unit Testing :: Readme Demonstrations 2124 | ## 2125 | ##---------------------------------------------------------------------------------------------------------------------- 2126 | 2127 | class Test_ReadmeDemonstrations(SenseTestCase): 2128 | 2129 | def test_ReadmeDemonstration1(self): # Created in flex using "new unittest ReadmeDemonstration1" 2130 | self.assertFlexSequence( [ 2131 | "scale 25x10", 2132 | "add right 50%", 2133 | "break 0 3x5 A", 2134 | "join ABC.z DG.B EH.L FI.N JM.b KN.l LO.n", 2135 | ], """ 2136 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111AAAABBBBCCCC 2137 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111AAAABBBBCCCC 2138 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111DDDDEEEEFFFF 2139 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111DDDDEEEEFFFF 2140 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111GGGGHHHHIIII 2141 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111GGGGHHHHIIII 2142 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111JJJJKKKKLLLL 2143 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111JJJJKKKKLLLL 2144 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111MMMMNNNNOOOO 2145 | 1111111111111111111111111 1111111111111111111111111000000000000 1111111111111111111111111MMMMNNNNOOOO 2146 | 2147 | 1111111111111111111111111zzzzzzzzzzzz 2148 | 1111111111111111111111111zzzzzzzzzzzz 2149 | 1111111111111111111111111BBBBLLLLNNNN 2150 | 1111111111111111111111111BBBBLLLLNNNN 2151 | 1111111111111111111111111BBBBLLLLNNNN 2152 | 1111111111111111111111111BBBBLLLLNNNN 2153 | 1111111111111111111111111bbbbllllnnnn 2154 | 1111111111111111111111111bbbbllllnnnn 2155 | 1111111111111111111111111bbbbllllnnnn 2156 | 1111111111111111111111111bbbbllllnnnn 2157 | """ ) 2158 | 2159 | def test_ReadmeDemonstration2(self): # Created in flex using "new unittest ReadmeDemonstration2" 2160 | self.assertFlexSequence( [ 2161 | "scale 25x10 ; add right 50% ; break 0 3x5 A ; join ABC.z DG.B EH.L FI.N JM.b KN.l LO.n", 2162 | "split 1 bottom 3 s", 2163 | "rename Nn Dd", 2164 | "swap z s Ll Dd", 2165 | "drag left BDLbdl left 50%", 2166 | "insert left s:BDLbdl 6", 2167 | ], """ 2168 | 1111111111111111111111111zzzzzzzzzzzz 1111111111111111111111111zzzzzzzzzzzz 2169 | 1111111111111111111111111zzzzzzzzzzzz 1111111111111111111111111zzzzzzzzzzzz 2170 | 1111111111111111111111111BBBBLLLLNNNN 1111111111111111111111111BBBBLLLLNNNN 2171 | 1111111111111111111111111BBBBLLLLNNNN 1111111111111111111111111BBBBLLLLNNNN 2172 | 1111111111111111111111111BBBBLLLLNNNN 1111111111111111111111111BBBBLLLLNNNN 2173 | 1111111111111111111111111BBBBLLLLNNNN 1111111111111111111111111BBBBLLLLNNNN 2174 | 1111111111111111111111111bbbbllllnnnn 1111111111111111111111111bbbbllllnnnn 2175 | 1111111111111111111111111bbbbllllnnnn sssssssssssssssssssssssssbbbbllllnnnn 2176 | 1111111111111111111111111bbbbllllnnnn sssssssssssssssssssssssssbbbbllllnnnn 2177 | 1111111111111111111111111bbbbllllnnnn sssssssssssssssssssssssssbbbbllllnnnn 2178 | 2179 | 1111111111111111111111111zzzzzzzzzzzz 1111111111111111111111111ssssssssssss 2180 | 1111111111111111111111111zzzzzzzzzzzz 1111111111111111111111111ssssssssssss 2181 | 1111111111111111111111111BBBBLLLLDDDD 1111111111111111111111111BBBBDDDDLLLL 2182 | 1111111111111111111111111BBBBLLLLDDDD 1111111111111111111111111BBBBDDDDLLLL 2183 | 1111111111111111111111111BBBBLLLLDDDD 1111111111111111111111111BBBBDDDDLLLL 2184 | 1111111111111111111111111BBBBLLLLDDDD 1111111111111111111111111BBBBDDDDLLLL 2185 | 1111111111111111111111111bbbblllldddd 1111111111111111111111111bbbbddddllll 2186 | sssssssssssssssssssssssssbbbblllldddd zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 2187 | sssssssssssssssssssssssssbbbblllldddd zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 2188 | sssssssssssssssssssssssssbbbblllldddd zzzzzzzzzzzzzzzzzzzzzzzzzbbbbddddllll 2189 | 2190 | 1111111111111ssssssssssssssssssssssss 1111111111111000000ssssssssssssssssssssssss 2191 | 1111111111111ssssssssssssssssssssssss 1111111111111000000ssssssssssssssssssssssss 2192 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 2193 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 2194 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 2195 | 1111111111111BBBBBBBBDDDDDDDDLLLLLLLL 1111111111111BBBBBBBBBBDDDDDDDDDDLLLLLLLLLL 2196 | 1111111111111bbbbbbbbddddddddllllllll 1111111111111bbbbbbbbbbddddddddddllllllllll 2197 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 2198 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 2199 | zzzzzzzzzzzzzbbbbbbbbddddddddllllllll zzzzzzzzzzzzzbbbbbbbbbbddddddddddllllllllll 2200 | """ ) 2201 | 2202 | 2203 | 2204 | --------------------------------------------------------------------------------