├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── fetch.sh ├── git-radar ├── images ├── added.png ├── branch is ahead.png ├── combination.png ├── conflicts.png ├── detailed.png ├── local is ahead.png ├── master branch diverged.png ├── master diverged.png ├── master is ahead.png ├── remote is behind.png ├── remote local diverged.png ├── stash.png ├── unstaged.png └── untracked.png ├── prompt.bash ├── prompt.zsh ├── radar-base.sh ├── shunit ├── shunit2 ├── shunit2_test.sh ├── shunit2_test_asserts.sh ├── shunit2_test_failures.sh ├── shunit2_test_helpers ├── shunit2_test_macros.sh ├── shunit2_test_misc.sh └── shunit2_test_standalone.sh ├── test ├── test-branches.sh ├── test-colors.sh ├── test-commits.sh ├── test-directories.sh ├── test-files.sh ├── test-format-config.sh ├── test-performance.sh ├── test-radar-base.sh ├── test-stash.sh └── test-status.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *.swo 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Michael Allen 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SOURCES=git-radar radar-base.sh prompt.zsh prompt.bash fetch.sh 2 | PREFIX=$(HOME)/.local 3 | 4 | all: 5 | @echo 'Simple Install script for *git-radar* ' 6 | @echo 'For a normal installation for your user only use:' 7 | @echo ' make install' 8 | @echo '' 9 | @echo 'If you want to install *git-radar* system wide you should change' 10 | @echo 'the prefix' 11 | @echo '' 12 | @echo ' PREFIX=/usr/local/bin make install' 13 | @echo '' 14 | @echo 'For a development install (symlinking files) do:' 15 | @echo '' 16 | @echo ' make develop' 17 | 18 | .PHONY: install develop 19 | 20 | install: $(SOURCES) 21 | @echo 'Installing in ' $(PREFIX)/bin 22 | cp git-radar $(PREFIX)/bin 23 | cp radar-base.sh $(PREFIX)/bin 24 | cp prompt.zsh $(PREFIX)/bin 25 | cp prompt.bash $(PREFIX)/bin 26 | cp fetch.sh $(PREFIX)/bin 27 | 28 | 29 | develop: $(SOURCES) 30 | @echo 'Symlinking in ' $(PREFIX)/bin 31 | ln -s $(PWD)/git-radar $(PREFIX)/bin/git-radar 32 | ln -s $(PWD)/radar-base.sh $(PREFIX)/bin/radar-base.sh 33 | ln -s $(PWD)/prompt.zsh $(PREFIX)/bin/prompt.zsh 34 | ln -s $(PWD)/prompt.bash $(PREFIX)/bin/prompt.bash 35 | ln -s $(PWD)/fetch.sh $(PREFIX)/bin/fetch.sh 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Git Radar 2 | 3 | A heads up display for git. 4 | 5 | ![An example of git-radar] 6 | 7 | Git-radar is a tool you can add to your prompt to provide at-a-glance 8 | information on your git repo. It's a labour of love I've been dogfooding for the 9 | last few years. Maybe it can help you too. 10 | 11 | **Table of Contents** 12 | 13 | - [Installation](#installation) 14 | - [Usage](#usage) 15 | - [Features](#features) 16 | - [Files status](#files-status) 17 | - [Local commits status](#local-commits-status) 18 | - [Remote commits status](#remote-commits-status) 19 | - [Stash status](#stash-status) 20 | - [(Optional) Auto-fetch repos](#optional-auto-fetch-repos) 21 | - [Customise your prompt](#customise-your-prompt) 22 | - [Support](#support) 23 | - [Ensuring prompt execution](#ensuring-prompt-execution) 24 | - [Configuring colours](#configuring-colours) 25 | - [Exporting Environment Variables](#exporting-environment-variables) 26 | - [Setting an RC file](#setting-an-rc-file) 27 | - [Bash Colour Codes](#bash-colour-codes) 28 | - [Zsh Colour Codes](#zsh-colour-codes) 29 | - [Configuration values](#configuration-values) 30 | - [Colouring the Branch part](#colouring-the-branch-part) 31 | - [Colouring the local commits status](#colouring-the-local-commits-status) 32 | - [Colouring the remote commits status](#colouring-the-remote-commits-status) 33 | - [Colouring the file changes status](#colouring-the-file-changes-status) 34 | - [License](#license) 35 | - [Links](#links) 36 | 37 | ## Installation 38 | 39 | ### Install from brew: 40 | 41 | ``` 42 | > brew install michaeldfallen/formula/git-radar 43 | ``` 44 | 45 | ### Manually: 46 | 47 | ``` 48 | > cd ~ && git clone https://github.com/michaeldfallen/git-radar .git-radar 49 | > echo 'export PATH=$PATH:$HOME/.git-radar' >> ~/.bashrc 50 | ``` 51 | 52 | Then run `git-radar` to see the docs and prove it's installed. 53 | 54 | ## Usage 55 | 56 | To use git-radar you need to add it to your prompt. This is done in different 57 | ways depending on your shell. 58 | 59 | **Bash** 60 | 61 | Add to your `.bashrc` 62 | ```bash 63 | export PS1="$PS1\$(git-radar --bash --fetch)" 64 | ``` 65 | [(note: the `\` escaping the `$` is important)](#ensuring-prompt-execution) 66 | 67 | **Zsh** 68 | 69 | Add to your `.zshrc` 70 | ```zsh 71 | export PROMPT="$PROMPT\$(git-radar --zsh --fetch) " 72 | ``` 73 | [(note: the `\` escaping the `$` is important)](#ensuring-prompt-execution) 74 | 75 | **Fish** 76 | 77 | Add to your `config.fish` 78 | ```bash 79 | function fish_prompt 80 | set_color $fish_color_cwd 81 | echo -n (prompt_pwd) 82 | echo -n (git-radar --fish --fetch) 83 | set_color normal 84 | echo -n ' > ' 85 | end 86 | ``` 87 | 88 | ## Features 89 | 90 | ### Files status 91 | 92 | The prompt lists the file changes and whether they are staged, unstaged or 93 | untracked. 94 | 95 | Prompt | Meaning 96 | ---------------------------|-------- 97 | ![git:(master) 3A] | We have 3 untracked files 98 | ![git:(master) 2D2M] | We have 2 modifications and 2 deletions not yet staged to commit 99 | ![git:(master) 1M1R] | We have 1 modification and a file renamed staged and ready to commit 100 | ![git:(master) 1U] | We have a conflict caused by US that we need to address 101 | ![git:(master) 1M 1D2M 2A] | A combination of the above types 102 | 103 | Each symbol represents a different change to a file. These are based on what git 104 | considers has happened to the file. 105 | 106 | Symbol | Meaning 107 | --------|-------- 108 | A | A new Added file 109 | D | A file has been Deleted 110 | M | A file has been Modified 111 | R | A file has been renamed 112 | C | A file has been copied 113 | U | A conflict caused by Us 114 | T | A conflict caused by Them 115 | B | A conflict caused by Both us and them 116 | 117 | The color tells you what stage the change is at. 118 | 119 | Color | Meaning 120 | --------|-------- 121 | Green | Staged and ready to be committed (i.e. you have done a `git add`) 122 | Red | Unstaged, you'll need to `git add` them before you can commit 123 | Grey | Untracked, these are new files git is unaware of 124 | Yellow | Conflicted, these need resolved before they can be committed 125 | 126 | The use of feature is controlled by the `GIT_RADAR_FORMAT` environment variable. 127 | See [Customise your prompt](#customise-your-prompt) for how to personalise this. 128 | 129 | ### Local commits status 130 | 131 | The prompt will show you the difference in commits between your branch and the 132 | remote your branch is tracking. The examples below assume you are checked out on 133 | `master` and are tracking `origin/master`. 134 | 135 | Prompt | Meaning 136 | --------------------|-------- 137 | ![git:(master 2↑)] | We have 2 commits to push up 138 | ![git:(master 3↓)] | We have 3 commits to pull down 139 | ![git:(master 3⇵5)] | Our version and origins version of `master` have diverged 140 | 141 | The use of feature is controlled by the `GIT_RADAR_FORMAT` environment variable. 142 | See [Customise your prompt](#customise-your-prompt) for how to personalise this. 143 | 144 | ### Remote commits status 145 | 146 | The prompt will also show the difference between your branch on origin and what 147 | is on `origin/master`. This a is hard coded branch name which I intend to make 148 | configurable in the future. 149 | 150 | This is the difference between the commits you've pushed up and `origin/master`. 151 | 152 | Prompt | Meaning 153 | ---------------------------|--------------- 154 | ![git:(m ← 2 my-branch)] | We have 2 commits on `origin/my-branch` that aren't on `origin/master` 155 | ![git:(m 4 → my-branch)] | There are 4 commits on `origin/master` that aren't on `origin/my-branch` 156 | ![git:(m 1 ⇄ 2 my-branch)] | `origin/master` and `origin/my-branch` have diverged, we'll need to rebase or merge 157 | 158 | The use of feature is controlled by the `GIT_RADAR_FORMAT` environment variable. 159 | See [Customise your prompt](#customise-your-prompt) for how to personalise this. 160 | 161 | ### Stash status 162 | The prompt will show you whether and how many stashes you have stored. 163 | 164 | Prompt | Meaning 165 | ---------------------------|--------------- 166 | ![git:(master) 1≡] | We have one stash 167 | 168 | If you don't rely on this status, you can always hide this part of the prompt by 169 | [customising your prompt](#customise-your-prompt) 170 | 171 | ### (Optional) Auto-fetch repos 172 | 173 | Ensuring your refs are up to date I found can be a pain. To streamline this 174 | git-radar can be configured to auto-fetch your repo. When the `--fetch` flag is 175 | used git-radar will run `git fetch` asynchronously every 5 minutes. 176 | 177 | This will only occur when the prompt is rendered and it will only occur on the 178 | repo you are currently in. 179 | 180 | To use this feature, when setting your prompt, call git-radar with `--fetch`: 181 | 182 | **Bash** 183 | ```bash 184 | export PS1="$PS1\$(git-radar --bash --fetch)" 185 | ``` 186 | [(note: the `\` escaping the `$` is important)](#ensuring-prompt-execution) 187 | 188 | **Zsh** 189 | ```zsh 190 | export PROMPT="$PROMPT\$(git-radar --zsh --fetch) " 191 | ``` 192 | [(note: the `\` escaping the `$` is important)](#ensuring-prompt-execution) 193 | 194 | You may also choose to fetch at a customized interval of time. To do so, add 195 | this to your .bashrc, .zshrc: 196 | 197 | ```bash 198 | export GIT_RADAR_FETCH_TIME= 199 | ``` 200 | 201 | For example, to fetch every 30 seconds (instead of the default 5 minutes): 202 | 203 | ```bash 204 | export GIT_RADAR_FETCH_TIME=30 205 | ``` 206 | 207 | You can also do this in the gitradarrc file: 208 | 209 | ```bash 210 | GIT_RADAR_FETCH_TIME=30 211 | ``` 212 | 213 | ## Customise your prompt 214 | 215 | Git Radar is highly customisable using a prompt format string. The 4 features 216 | above: remote commits, local commits, branch and file changes; are controlled 217 | by the prompt format string. 218 | 219 | Feature | Control string 220 | ---------------|--------------- 221 | Remote commits | `%{remote}` 222 | Local commits | `%{local}` 223 | Branch | `%{branch}` 224 | File changes | `%{changes}` 225 | Stashes | `%{stash}` 226 | 227 | You can create any prompt shape you prefer by exporting `GIT_RADAR_FORMAT` with 228 | your preferred shape. The control strings above will be replaced with the output 229 | of the corresponding feature. 230 | 231 | **Examples** 232 | 233 | GIT_RADAR_FORMAT | Result 234 | --------------------------------------|--------------------- 235 | `%{branch}%{local}%{changes}` | `master1↑1M` 236 | `[%{branch}] - %{local} - %{changes}` | `[master] - 1↑ - 1M` 237 | 238 | ### Prefixing and Suffixing the features 239 | 240 | Often you will want certain parts of the prompt to only appear when there is 241 | content to render. For example, when in a repo you want `[branch]` but when out 242 | of a repo you don't want the `[]` appearing. 243 | 244 | To do this the control strings support prefixes and suffixes. Prefixes and 245 | Suffixes are separated from the feature name by `:` and will only render if the 246 | feature would render: 247 | 248 | Format: `prompt > %{prefix - :changes: - suffix}` 249 | 250 | In a repo: `prompt > prefix - 1M - suffix` 251 | 252 | Outside a repo: `prompt > ` 253 | 254 | The default prompt format uses this to add spaces only if the feature would 255 | render. In that way the prompt always looks well spaced out no matter how many 256 | features are rendering. 257 | 258 | 259 | ## Support 260 | 261 | ### Ensuring prompt execution 262 | 263 | When setting your prompt variable, `PROMPT` in Zsh and `PS1` in Bash, it's 264 | important that the function executes each time the prompt renders. That way the 265 | prompt will respond to changes in your git repo. To ensure this you will need 266 | to escape the execution of the function. There are two ways to do this: 267 | 268 | **1. Use `$'` to render raw characters** 269 | ```bash 270 | export PROMPT=$'$(git-radar --zsh)' 271 | export PS1=$'$(git-radar --bash)' 272 | ``` 273 | 274 | **2. Use `\` to escape execution of the subshell** 275 | ```bash 276 | export PROMPT="\$(git-radar --zsh)" 277 | export PS1="\$(git-radar --bash)" 278 | ``` 279 | 280 | ### Configuring colours 281 | 282 | You can configure the colour scheme in two ways: export 283 | [Environment Variables](#exporting-environment-variables) 284 | or use an [rc file](#setting-an-rc-file). 285 | 286 | #### Exporting Environment Variables 287 | 288 | To configure the prompt this way just add to your `~/.bashrc` or `~/.zshrc` an 289 | export directive with the value you want to change. 290 | 291 | **Example: Change the branch colour in Zsh** 292 | 293 | In `~/.zshrc`: 294 | ```zsh 295 | export GIT_RADAR_COLOR_BRANCH='$fg[yellow]' 296 | ``` 297 | 298 | **Example: Change the branch colour in Bash** 299 | 300 | In `~/.bashrc`: 301 | ```zsh 302 | export GIT_RADAR_COLOR_BRANCH='\\033[0;33m' 303 | ``` 304 | 305 | #### Setting an RC file 306 | 307 | Git radar supports multiple rc files. One of these will be sourced when the 308 | prompt renders. 309 | 310 | **Example: Change the branch colour in Zsh** 311 | 312 | In `~/.gitradarrc`: 313 | ```zsh 314 | GIT_RADAR_COLOR_BRANCH='$fg[yellow]' 315 | ``` 316 | 317 | **Basic RC file** 318 | 319 | Create a file at `~/.gitradarrc` which sets the Environment variables listed in 320 | [Configuration values](#configuration-values) using colour codes listed in 321 | either [Zsh Colour Codes](#zsh-colour-codes) or 322 | [Bash Colour Codes](#Bash-Colour-Codes) depending on your shell. 323 | 324 | **Shell specific RC file** 325 | 326 | If you use both Bash and Zsh you can set RC files that are specific for those 327 | shells. 328 | 329 | For Bash: Create a file at `~/.gitradarrc.bash` 330 | 331 | For Zsh: Create a file at `~/.gitradarrc.zsh` 332 | 333 | 334 | #### Bash Colour Codes 335 | 336 | Bash colour codes make use of the colours your terminal app claims to be `red` 337 | or `green`. Using one of these codes will only produce the colour your terminal 338 | claims, so you should customise your colour scheme on your terminal as well as 339 | customising git-radar. 340 | 341 | Note the "Bright" colours can be shown as bold instead, it depends on your 342 | terminal. By default, for example, the Mac OSX Terminal.app uses the "Bright" 343 | colours to provide 8 new lighter colours but some terminals only support 8 and 344 | will show the text as bold instead. 345 | 346 | Colour | Code for Text | Code for Background 347 | --------------|----------------|-------------------- 348 | Black | `\\033[0;30m` | `\\033[0;40m` 349 | Red | `\\033[0;31m` | `\\033[0;41m` 350 | Green | `\\033[0;32m` | `\\033[0;42m` 351 | Yellow | `\\033[0;33m` | `\\033[0;43m` 352 | Blue | `\\033[0;34m` | `\\033[0;44m` 353 | Magenta | `\\033[0;35m` | `\\033[0;45m` 354 | Cyan | `\\033[0;36m` | `\\033[0;46m` 355 | White | `\\033[0;37m` | `\\033[0;47m` 356 | Bright Black | `\\033[1;30m` | `\\033[1;40m` 357 | Bright Red | `\\033[1;31m` | `\\033[1;41m` 358 | Bright Green | `\\033[1;32m` | `\\033[1;42m` 359 | Bright Yellow | `\\033[1;33m` | `\\033[1;43m` 360 | Bright Blue | `\\033[1;34m` | `\\033[1;44m` 361 | Bright Magenta| `\\033[1;35m` | `\\033[1;45m` 362 | Bright Cyan | `\\033[1;36m` | `\\033[1;46m` 363 | Bright White | `\\033[1;37m` | `\\033[1;47m` 364 | Reset | `\\033[0m` | `\\033[0m` 365 | 366 | Note the Reset will set back to what your terminal claims as standard text and 367 | background. 368 | 369 | #### Zsh Colour Codes 370 | 371 | Zsh also provides a way to access the colours that your terminal claims as `red` 372 | or `green`, etc. 373 | 374 | Note the "Bright" colours can be shown as bold instead, it depends on your 375 | terminal. By default, for example, the Mac OSX Terminal.app uses the "Bright" 376 | colours to provide 8 new lighter colours but some terminals only support 8 and 377 | will show the text as bold instead. 378 | 379 | Colour | Code for Text | Code for Background 380 | --------------|--------------------|-------------------- 381 | Black | `$fg[black]` | `$bg[black]` 382 | Red | `$fg[red]` | `$bg[red]` 383 | Green | `$fg[green]` | `$bg[green]` 384 | Yellow | `$fg[yellow]` | `$bg[yellow]` 385 | Blue | `$fg[blue]` | `$bg[blue]` 386 | Magenta | `$fg[magenta]` | `$bg[magenta]` 387 | Cyan | `$fg[cyan]` | `$bg[cyan]` 388 | White | `$fg[white]` | `$bg[white]` 389 | Bright Black | `$fg_bold[black]` | `$bg_bold[black]` 390 | Bright Red | `$fg_bold[red]` | `$bg_bold[red]` 391 | Bright Green | `$fg_bold[green]` | `$bg_bold[green]` 392 | Bright Yellow | `$fg_bold[yellow]` | `$bg_bold[yellow]` 393 | Bright Blue | `$fg_bold[blue]` | `$bg_bold[blue]` 394 | Bright Magenta| `$fg_bold[magenta]`| `$bg_bold[magenta]` 395 | Bright Cyan | `$fg_bold[cyan]` | `$bg_bold[cyan]` 396 | Bright White | `$fg_bold[white]` | `$bg_bold[white]` 397 | Reset | `$reset_color` | `$reset_color` 398 | 399 | #### Configuration values 400 | 401 | All these values should be set using a the correct colour code for your 402 | terminal. You should also choose the colour code based on what shell you are 403 | using. There is a way to support [colouring multiple shells using rc files](#setting-an-rc-file). 404 | 405 | ##### Colouring the Branch part 406 | 407 | **GIT_RADAR_COLOR_BRANCH='[colour code]'** 408 | ``` 409 | git:(my-branch) 410 | ^^^^^^^^^ 411 | ``` 412 | The colour to use for the Branch or git reference. 413 | 414 | It is unset by 415 | `GIT_RADAR_COLOR_BRANCH_RESET` which you can set if you want a different 416 | background colour to return to. 417 | 418 | ##### Colouring the local commits status 419 | 420 | **GIT_RADAR_COLOR_LOCAL_AHEAD='[colour code]'** 421 | ``` 422 | git:(my-branch 1↑) 423 | ^ 424 | ``` 425 | The colour to use for the arrow that indicates how many commits you have to push 426 | up. 427 | 428 | It is unset by `GIT_RADAR_COLOR_LOCAL_RESET` which you can set if you want 429 | a different background colour to return to. 430 | 431 | **GIT_RADAR_COLOR_LOCAL_BEHIND='[colour code]'** 432 | ``` 433 | git:(my-branch 1↓) 434 | ^ 435 | ``` 436 | The colour to use for the arrow that indicates how many commits you have to pull 437 | down. 438 | 439 | It is unset by `GIT_RADAR_COLOR_LOCAL_RESET` which you can set if you want 440 | a different background colour to return to. 441 | 442 | **GIT_RADAR_COLOR_LOCAL_DIVERGED='[colour code]'** 443 | ``` 444 | git:(my-branch 1⇵1) 445 | ^ 446 | ``` 447 | The colour to use for the arrow that indicates how many commits your branch has diverged by. 448 | 449 | It is unset by `GIT_RADAR_COLOR_LOCAL_RESET` which you can set if you want 450 | a different background colour to return to. 451 | 452 | ##### Colouring the remote commits status 453 | 454 | **GIT_RADAR_COLOR_REMOTE_AHEAD='[colour code]'** 455 | ``` 456 | git:(m ← 1 my-branch) 457 | ^ 458 | ``` 459 | The colour to use for the arrow that indicates how many commits your branch has to merge on to master. 460 | 461 | It is unset by `GIT_RADAR_COLOR_REMOTE_RESET` which you can set if you want 462 | a different background colour to return to. 463 | 464 | **GIT_RADAR_COLOR_REMOTE_BEHIND='[colour code]'** 465 | ``` 466 | git:(m 1 → my-branch) 467 | ^ 468 | ``` 469 | The colour to use for the arrow that indicates how many commits your branch is 470 | behind master. 471 | 472 | It is unset by `GIT_RADAR_COLOR_REMOTE_RESET` which you can set if you want 473 | a different background colour to return to. 474 | 475 | **GIT_RADAR_COLOR_REMOTE_DIVERGED='[colour code]'** 476 | ``` 477 | git:(m 1 ⇄ 1 my-branch) 478 | ^ 479 | ``` 480 | The colour to use for the arrow that indicates how many commits your branch has 481 | diverged from master. 482 | 483 | It is unset by `GIT_RADAR_COLOR_REMOTE_RESET` which you can set if you want 484 | a different background colour to return to. 485 | 486 | **GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM='[colour code]'** 487 | ``` 488 | git:(upstream ⚡ my-branch) 489 | ^ 490 | ``` 491 | The colour to use for the lightning bolt which indicates that your branch is not 492 | tracking an upstream branch. 493 | 494 | It is unset by `GIT_RADAR_COLOR_REMOTE_RESET` which you can set if you want 495 | a different background colour to return to. 496 | 497 | ##### Colouring the file changes status 498 | 499 | **GIT_RADAR_COLOR_CHANGES_STAGED='[colour code]'** 500 | ``` 501 | git:(my-branch) 1M 502 | ^ 503 | ``` 504 | The colour to use for the letters that indicate changes that have been staged to 505 | commit. 506 | 507 | It is unset by `GIT_RADAR_COLOR_CHANGES_RESET` which you can set if you want 508 | a different background colour to return to. 509 | 510 | **GIT_RADAR_COLOR_CHANGES_UNSTAGED='[colour code]'** 511 | ``` 512 | git:(my-branch) 1M 513 | ^ 514 | ``` 515 | The colour to use for the letters that indicate changes that have not yet been 516 | staged to commit. 517 | 518 | It is unset by `GIT_RADAR_COLOR_CHANGES_RESET` which you can set if you want 519 | a different background colour to return to. 520 | 521 | **GIT_RADAR_COLOR_CHANGES_CONFLICTED='[colour code]'** 522 | ``` 523 | git:(my-branch) 1B 524 | ^ 525 | ``` 526 | The colour to use for the letters that indicate changes that have conflicts that 527 | need resolved. 528 | 529 | It is unset by `GIT_RADAR_COLOR_CHANGES_RESET` which you can set if you want 530 | a different background colour to return to. 531 | 532 | **GIT_RADAR_COLOR_CHANGES_UNTRACKED='[colour code]'** 533 | ``` 534 | git:(my-branch) 1A 535 | ^ 536 | ``` 537 | The colour to use for the letters that indicate files that are currently not 538 | tracked by git. 539 | 540 | It is unset by `GIT_RADAR_COLOR_CHANGES_RESET` which you can set if you want 541 | a different background colour to return to. 542 | 543 | ##### Colouring the stash status 544 | 545 | **GIT_RADAR_COLOR_STASH='[colour code]'** 546 | ``` 547 | git:(my-branch) 1≡ 548 | ^ 549 | ``` 550 | The colour to use for the lines that indicates how many stashes you have stored. 551 | 552 | It is unset by `GIT_RADAR_COLOR_STASH_RESET` which you can set if you want 553 | a different background colour to return to. 554 | 555 | ## License 556 | 557 | Git Radar is licensed under the MIT license. 558 | 559 | See [LICENSE] for the full license text. 560 | 561 | ## Links 562 | 563 | * [mini-git-radar](https://github.com/bogem/mini-git-radar) - lightweight version of git-radar. Only for macOS and bash/fish. 564 | 565 | [LICENSE]: https://github.com/michaeldfallen/git-radar/blob/master/LICENSE 566 | [git:(master) 1≡]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/stash.png 567 | [git:(master) 3A]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/untracked.png 568 | [git:(master) 2D2M]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/unstaged.png 569 | [git:(master) 1M1R]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/added.png 570 | [git:(master) 1U]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/conflicts.png 571 | [git:(master) 1M 1D2M 2A]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/combination.png 572 | [git:(master 2↑)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/local%20is%20ahead.png 573 | [git:(master 3↓)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/remote%20is%20behind.png 574 | [git:(master 3⇵5)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/remote%20local%20diverged.png 575 | [git:(m ← 2 my-branch)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/branch%20is%20ahead.png 576 | [git:(m 4 → my-branch)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/master%20is%20ahead.png 577 | [git:(m 1 ⇄ 2 my-branch)]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/master%20branch%20diverged.png 578 | [An example of git-radar]: https://raw.githubusercontent.com/michaeldfallen/git-radar/master/images/detailed.png 579 | -------------------------------------------------------------------------------- /fetch.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | if [[ "$OSTYPE" == *darwin* ]]; then 4 | READLINK_CMD='greadlink' 5 | else 6 | READLINK_CMD='readlink' 7 | fi 8 | 9 | dot="$(cd "$(dirname "$([ -L "$0" ] && $READLINK_CMD -f "$0" || echo "$0")")"; pwd)" 10 | 11 | source $dot/radar-base.sh 12 | 13 | fetch; 14 | -------------------------------------------------------------------------------- /git-radar: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | # 3 | # git-radar 4 | # 5 | # A heads up display for git 6 | 7 | if [[ "$OSTYPE" == *darwin* ]]; then 8 | READLINK_CMD='greadlink' 9 | else 10 | READLINK_CMD='readlink' 11 | fi 12 | 13 | dot="$(cd "$(dirname "$([ -L "$0" ] && $READLINK_CMD -f "$0" || echo "$0")")"; pwd)" 14 | args=$@ 15 | 16 | if [[ -z $@ ]]; then 17 | _git="\033[1;30mgit:(\033[0m" 18 | _master="\033[0;37mmaster\033[0m" 19 | _my_branch="\033[0;37mmy-branch\033[0m" 20 | _endgit="\033[1;30m)\033[0m" 21 | _untracked="\033[1;37mA\033[0m" 22 | _added_staged="\033[1;32mA\033[0m" 23 | _modified_unstaged="\033[1;31mM\033[0m" 24 | _local_up="\033[1;32m↑\033[0m" 25 | _2_from_master="\xF0\x9D\x98\xAE 2 \033[1;31m→\033[0m " 26 | _diverged_from_master="\xF0\x9D\x98\xAE 2 \033[1;33m⇄\033[0m 3 " 27 | _not_upstream="upstream \033[1;31m⚡\033[0m " 28 | _detached="\033[0;37mdetached@94eac67\033[0m" 29 | _conflicted_us="\033[1;33mU\033[0m" 30 | _conflicted_them="\033[1;33mT\033[0m" 31 | _ahead_master="\xF0\x9D\x98\xAE \033[1;32m←\033[0m" 32 | _local_diverged="\033[1;33m⇵\033[0m" 33 | _stash="\033[1;33m≡\033[0m" 34 | echo "git-radar - a heads up display for git" 35 | echo "" 36 | echo "examples:" 37 | printf " $_git$_master$_endgit" 38 | echo " # You are on the master branch and everything is clean" 39 | printf " $_git$_not_upstream$_my_branch$_endgit" 40 | echo " # Fresh branch that we haven't pushed upstream" 41 | printf " $_git$_my_branch$_endgit 2$_untracked" 42 | echo " # Two files created that aren't tracked by git" 43 | printf " $_git$_my_branch$_endgit 1$_added_staged 3$_modified_unstaged" 44 | echo " # 1 new file staged to commit and 3 modifications that we still need to \`git add\`" 45 | printf " $_git$_2_from_master$_my_branch 3$_local_up$_endgit" 46 | echo " # 3 commits made locally ready to push up while master is ahead of us by 2" 47 | printf " $_git$_diverged_from_master$_my_branch$_endgit" 48 | echo " # our commits pushed up, master and my-branch have diverged" 49 | printf " $_git$_detached$_endgit 2${_conflicted_them}3${_conflicted_us}" 50 | echo " # mid rebase, we are detached and have 3 conflicts caused by US and 2 caused by THEM" 51 | printf " $_git$_diverged_from_master$_my_branch 3${_local_diverged}5$_endgit" 52 | echo " # rebase complete, our rewritten commits now need pushed up" 53 | printf " $_git$_ahead_master 3 $_my_branch$_endgit" 54 | echo " # origin/my-branch is up to date with master and has our 3 commits waiting merge" 55 | printf " $_git$_master$_endgit 3$_stash" 56 | echo " # You have 3 stashes stored" 57 | 58 | echo "" 59 | echo "usage:" 60 | echo " git-radar [--zsh|--bash|--fish] [--fetch]" 61 | echo "" 62 | echo " --fetch # Fetches your repo asynchronously in the background every 5 mins" 63 | echo " --zsh # Output prompt using Zsh style color characters" 64 | echo " --bash # Output prompt using Bash style color characters" 65 | echo " --fish # Output prompt using fish style color characters" 66 | echo "" 67 | echo "Bash example:" 68 | echo " export PS1=\"\\W\\\$(git-radar --bash --fetch) \"" 69 | echo "" 70 | echo " This will show your current directory and the full git-radar." 71 | echo " As an added benefit, if you are in a repo, it will asynchronously" 72 | echo " run \`git fetch\` every 5 mins, so that you are never out of date." 73 | echo "" 74 | echo "Zsh example:" 75 | echo " export PROMPT=\"%1/%\\\$(git-radar --zsh --fetch) \"" 76 | echo "" 77 | echo " Same as the Bash but for Zsh." 78 | echo "" 79 | echo "fish example:" 80 | echo " function fish_prompt" 81 | echo " set_color \$fish_color_cwd" 82 | echo " echo -n (prompt_pwd)" 83 | echo " git-radar --fish -fetch" 84 | echo " set_color normal" 85 | echo " echo -n ' > '" 86 | echo " end" 87 | echo "" 88 | echo " Same as the Bash but for fish." 89 | exit 90 | fi 91 | while [[ $# > 0 ]];do 92 | command="$1" 93 | shift 94 | 95 | if [[ "$command" == "--fetch" ]]; then 96 | nohup $dot/fetch.sh >/dev/null 2>&1 & 97 | fi 98 | 99 | if [[ "$command" == "--zsh" ]]; then 100 | $dot/prompt.zsh $args 101 | fi 102 | 103 | if [[ "$command" == "--bash" || "$command" == "--fish" ]]; then 104 | $dot/prompt.bash $args 105 | fi 106 | done 107 | -------------------------------------------------------------------------------- /images/added.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/added.png -------------------------------------------------------------------------------- /images/branch is ahead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/branch is ahead.png -------------------------------------------------------------------------------- /images/combination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/combination.png -------------------------------------------------------------------------------- /images/conflicts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/conflicts.png -------------------------------------------------------------------------------- /images/detailed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/detailed.png -------------------------------------------------------------------------------- /images/local is ahead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/local is ahead.png -------------------------------------------------------------------------------- /images/master branch diverged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/master branch diverged.png -------------------------------------------------------------------------------- /images/master diverged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/master diverged.png -------------------------------------------------------------------------------- /images/master is ahead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/master is ahead.png -------------------------------------------------------------------------------- /images/remote is behind.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/remote is behind.png -------------------------------------------------------------------------------- /images/remote local diverged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/remote local diverged.png -------------------------------------------------------------------------------- /images/stash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/stash.png -------------------------------------------------------------------------------- /images/unstaged.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/unstaged.png -------------------------------------------------------------------------------- /images/untracked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michaeldfallen/git-radar/2ac25e3d1047cdf19f15bc894ff39449b83d65d4/images/untracked.png -------------------------------------------------------------------------------- /prompt.bash: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | dot="$(cd "$(dirname "$0")"; pwd)" 4 | args=$@ 5 | source "$dot/radar-base.sh" 6 | 7 | if is_repo; then 8 | prepare_bash_colors 9 | render_prompt 10 | fi 11 | -------------------------------------------------------------------------------- /prompt.zsh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env zsh 2 | 3 | dot="$(cd "$(dirname "$0")"; pwd)" 4 | args=$@ 5 | source "$dot/radar-base.sh" 6 | 7 | if is_repo; then 8 | autoload colors && colors 9 | 10 | prepare_zsh_colors 11 | render_prompt 12 | fi 13 | -------------------------------------------------------------------------------- /radar-base.sh: -------------------------------------------------------------------------------- 1 | NO_REMOTE_STATUS='--no-remote-status' 2 | 3 | dot_git="" 4 | stat_type="" 5 | cwd="" 6 | remote="" 7 | rcfile_path="$HOME" 8 | 9 | timethis() { 10 | cmd="$@" 11 | start=$(gdate +%s.%N) 12 | eval $cmd 13 | dur=$(echo "$(gdate +%s.%N) - $start" | bc) 14 | echo "$1 - $dur" >> $HOME/duration.dat 15 | } 16 | 17 | get_fetch_time() { 18 | if [ -f "$rcfile_path/.gitradarrc.bash" ]; then 19 | source "$rcfile_path/.gitradarrc.bash" 20 | elif [ -f "$rcfile_path/.gitradarrc.zsh" ]; then 21 | source "$rcfile_path/.gitradarrc.zsh" 22 | elif [ -f "$rcfile_path/.gitradarrc" ]; then 23 | source "$rcfile_path/.gitradarrc" 24 | fi 25 | 26 | FETCH_TIME="${GIT_RADAR_FETCH_TIME:-"$((5 * 60))"}" 27 | echo $FETCH_TIME 28 | 29 | } 30 | 31 | prepare_bash_colors() { 32 | if [ -f "$rcfile_path/.gitradarrc.bash" ]; then 33 | source "$rcfile_path/.gitradarrc.bash" 34 | elif [ -f "$rcfile_path/.gitradarrc" ]; then 35 | source "$rcfile_path/.gitradarrc" 36 | fi 37 | 38 | PRINT_F_OPTION="" 39 | 40 | COLOR_REMOTE_AHEAD="\x01${GIT_RADAR_COLOR_REMOTE_AHEAD:-"\\033[1;32m"}\x02" 41 | COLOR_REMOTE_BEHIND="\x01${GIT_RADAR_COLOR_REMOTE_BEHIND:-"\\033[1;31m"}\x02" 42 | COLOR_REMOTE_DIVERGED="\x01${GIT_RADAR_COLOR_REMOTE_DIVERGED:-"\\033[1;33m"}\x02" 43 | COLOR_REMOTE_NOT_UPSTREAM="\x01${GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM:-"\\033[1;31m"}\x02" 44 | 45 | COLOR_LOCAL_AHEAD="\x01${GIT_RADAR_COLOR_LOCAL_AHEAD:-"\\033[1;32m"}\x02" 46 | COLOR_LOCAL_BEHIND="\x01${GIT_RADAR_COLOR_LOCAL_BEHIND:-"\\033[1;31m"}\x02" 47 | COLOR_LOCAL_DIVERGED="\x01${GIT_RADAR_COLOR_LOCAL_DIVERGED:-"\\033[1;33m"}\x02" 48 | 49 | COLOR_CHANGES_STAGED="\x01${GIT_RADAR_COLOR_CHANGES_STAGED:-"\\033[1;32m"}\x02" 50 | COLOR_CHANGES_UNSTAGED="\x01${GIT_RADAR_COLOR_CHANGES_UNSTAGED:-"\\033[1;31m"}\x02" 51 | COLOR_CHANGES_CONFLICTED="\x01${GIT_RADAR_COLOR_CHANGES_CONFLICTED:-"\\033[1;33m"}\x02" 52 | COLOR_CHANGES_UNTRACKED="\x01${GIT_RADAR_COLOR_CHANGES_UNTRACKED:-"\\033[1;37m"}\x02" 53 | 54 | COLOR_STASH="\x01${GIT_RADAR_COLOR_STASH:-"\\033[1;33m"}\x02" 55 | 56 | COLOR_BRANCH="\x01${GIT_RADAR_COLOR_BRANCH:-"\\033[0m"}\x02" 57 | MASTER_SYMBOL="${GIT_RADAR_MASTER_SYMBOL:-"\\x01\\033[0m\\x02\\xF0\\x9D\\x98\\xAE\\x01\\033[0m\\x02"}" 58 | 59 | PROMPT_FORMAT="${GIT_RADAR_FORMAT:-" \\x01\\033[1;30m\\x02git:(\\x01\\033[0m\\x02%{remote: }%{branch}%{ :local}\\x01\\033[1;30m\\x02)\\x01\\033[0m\\x02%{ :stash}%{ :changes}"}" 60 | 61 | RESET_COLOR_LOCAL="\x01${GIT_RADAR_COLOR_LOCAL_RESET:-"\\033[0m"}\x02" 62 | RESET_COLOR_REMOTE="\x01${GIT_RADAR_COLOR_REMOTE_RESET:-"\\033[0m"}\x02" 63 | RESET_COLOR_CHANGES="\x01${GIT_RADAR_COLOR_CHANGES_RESET:-"\\033[0m"}\x02" 64 | RESET_COLOR_BRANCH="\x01${GIT_RADAR_COLOR_BRANCH_RESET:-"\\033[0m"}\x02" 65 | RESET_COLOR_STASH="\x01${GIT_RADAR_COLOR_STASH:-"\\033[0m"}\x02" 66 | 67 | } 68 | 69 | prepare_zsh_colors() { 70 | if [ -f "$rcfile_path/.gitradarrc.zsh" ]; then 71 | source "$rcfile_path/.gitradarrc.zsh" 72 | elif [ -f "$rcfile_path/.gitradarrc" ]; then 73 | source "$rcfile_path/.gitradarrc" 74 | fi 75 | 76 | PRINT_F_OPTION="%s" 77 | 78 | COLOR_REMOTE_AHEAD="%{${GIT_RADAR_COLOR_REMOTE_AHEAD:-$fg_bold[green]}%}" 79 | COLOR_REMOTE_BEHIND="%{${GIT_RADAR_COLOR_REMOTE_BEHIND:-$fg_bold[red]}%}" 80 | COLOR_REMOTE_DIVERGED="%{${GIT_RADAR_COLOR_REMOTE_DIVERGED:-$fg_bold[yellow]}%}" 81 | COLOR_REMOTE_NOT_UPSTREAM="%{${GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM:-$fg_bold[red]}%}" 82 | 83 | COLOR_LOCAL_AHEAD="%{${GIT_RADAR_COLOR_LOCAL_AHEAD:-$fg_bold[green]}%}" 84 | COLOR_LOCAL_BEHIND="%{${GIT_RADAR_COLOR_LOCAL_BEHIND:-$fg_bold[red]}%}" 85 | COLOR_LOCAL_DIVERGED="%{${GIT_RADAR_COLOR_LOCAL_DIVERGED:-$fg_bold[yellow]}%}" 86 | 87 | COLOR_CHANGES_STAGED="%{${GIT_RADAR_COLOR_CHANGES_STAGED:-$fg_bold[green]}%}" 88 | COLOR_CHANGES_UNSTAGED="%{${GIT_RADAR_COLOR_CHANGES_UNSTAGED:-$fg_bold[red]}%}" 89 | COLOR_CHANGES_CONFLICTED="%{${GIT_RADAR_COLOR_CHANGES_CONFLICTED:-$fg_bold[yellow]}%}" 90 | COLOR_CHANGES_UNTRACKED="%{${GIT_RADAR_COLOR_CHANGES_UNTRACKED:-$fg_bold[white]}%}" 91 | 92 | COLOR_STASH="%{${GIT_RADAR_COLOR_STASH:-$fg_bold[yellow]}%}" 93 | 94 | local italic_m="$(printf '\xF0\x9D\x98\xAE')" 95 | 96 | COLOR_BRANCH="%{${GIT_RADAR_COLOR_BRANCH:-$reset_color}%}" 97 | MASTER_SYMBOL="${GIT_RADAR_MASTER_SYMBOL:-"%{$reset_color%}$italic_m%{$reset_color%}"}" 98 | 99 | PROMPT_FORMAT="${GIT_RADAR_FORMAT:-" %{$fg_bold[grey]%}git:(%{$reset_color%}%{remote: }%{branch}%{ :local}%{$fg_bold[grey]%})%{$reset_color%}%{ :stash}%{ :changes}"}" 100 | 101 | RESET_COLOR_LOCAL="%{${GIT_RADAR_COLOR_LOCAL_RESET:-$reset_color}%}" 102 | RESET_COLOR_REMOTE="%{${GIT_RADAR_COLOR_REMOTE_RESET:-$reset_color}%}" 103 | RESET_COLOR_CHANGES="%{${GIT_RADAR_COLOR_CHANGES_RESET:-$reset_color}%}" 104 | RESET_COLOR_BRANCH="%{${GIT_RADAR_COLOR_BRANCH_RESET:-$reset_color}%}" 105 | RESET_COLOR_STASH="%{${GIT_RADAR_COLOR_STASH:-$reset_color}%}" 106 | } 107 | 108 | in_current_dir() { 109 | local wd="$(pwd)" 110 | if [[ "$wd" == $cwd ]]; then 111 | cwd="$wd" 112 | return 0 113 | else 114 | cwd="$wd" 115 | return 1 116 | fi 117 | } 118 | 119 | echodebug() { 120 | echo "$@" 1>&2 121 | } 122 | 123 | debug_print() { 124 | local debug=$1 125 | local message=$2 126 | if [[ $debug == "debug" ]]; then 127 | echo $message 128 | fi 129 | } 130 | 131 | dot_git() { 132 | if in_current_dir && [[ -n "$dot_git" ]]; then 133 | # cache dot_git to save calls to rev-parse 134 | printf '%s' $dot_git 135 | elif [ -d .git ]; then 136 | dot_git=".git" 137 | printf '%s' $dot_git 138 | else 139 | dot_git="$(git rev-parse --git-dir 2>/dev/null)" 140 | printf '%s' $dot_git 141 | fi 142 | } 143 | 144 | stat_type() { 145 | if [[ "$OSTYPE" == "darwin"* ]]; then 146 | stat_type="gstat" 147 | else 148 | stat_type="stat" 149 | fi 150 | printf '%s' $stat_type 151 | } 152 | 153 | is_repo() { 154 | if [[ -n "$(dot_git)" ]]; then 155 | return 0 156 | else 157 | return 1 158 | fi 159 | } 160 | 161 | git_root() { 162 | if [ -d .git ]; then 163 | printf '%s' "$(pwd)" 164 | else 165 | printf '%s' "$(git rev-parse --show-toplevel 2>/dev/null)" 166 | fi 167 | } 168 | 169 | record_timestamp() { 170 | if is_repo; then 171 | touch "$(dot_git)/lastupdatetime" 172 | fi 173 | } 174 | 175 | timestamp() { 176 | if is_repo; then 177 | printf '%s' "$($(stat_type) -c%Y "$(dot_git)/lastupdatetime" 2>/dev/null || printf '%s' "0")" 178 | fi 179 | } 180 | 181 | time_now() { 182 | printf '%s' "$(date +%s)" 183 | } 184 | 185 | time_to_update() { 186 | last_time_updated="${1:-$FETCH_TIME}" 187 | if is_repo; then 188 | local timesincelastupdate="$(($(time_now) - $(timestamp)))" 189 | if (( $timesincelastupdate > $last_time_updated )); then 190 | # time to update return 0 (which is true) 191 | return 0 192 | else 193 | # not time to update return 1 (which is false) 194 | return 1 195 | fi 196 | else 197 | return 1 198 | fi 199 | } 200 | 201 | fetch() { 202 | # Gives $FETCH_TIME a value 203 | get_fetch_time 204 | 205 | if time_to_update $FETCH_TIME; then 206 | record_timestamp 207 | git fetch --quiet > /dev/null 2>&1 208 | fi 209 | } 210 | 211 | commit_short_sha() { 212 | if is_repo; then 213 | printf '%s' "$(git rev-parse --short HEAD 2>/dev/null)" 214 | fi 215 | } 216 | 217 | branch_name() { 218 | name="$(git symbolic-ref --short HEAD 2>/dev/null)" 219 | retcode="$?" 220 | if [[ "$retcode" == "0" ]]; then 221 | printf %s "$name" 222 | else 223 | return 1 224 | fi 225 | } 226 | 227 | branch_ref() { 228 | if is_repo; then 229 | printf '%s' "$(branch_name || commit_short_sha)" 230 | fi 231 | } 232 | 233 | remote_branch_name() { 234 | local localRef="$(branch_name)" 235 | local remote="$(git config --get "branch.$localRef.remote")" 236 | if [[ -n $remote ]]; then 237 | local remoteBranch="$(git config --get "branch.${localRef}.merge" | sed -e 's/^refs\/heads\///')" 238 | if [[ -n $remoteBranch ]]; then 239 | printf '%s/%s' $remote $remoteBranch 240 | return 0 241 | else 242 | return 1 243 | fi 244 | else 245 | return 1 246 | fi 247 | } 248 | 249 | commits_behind_of_remote() { 250 | remote_branch=${1:-"$(remote_branch_name)"} 251 | if [[ -n "$remote_branch" ]]; then 252 | git rev-list --left-only --count ${remote_branch}...HEAD 2>/dev/null 253 | else 254 | printf '%s' "0" 255 | fi 256 | } 257 | 258 | commits_ahead_of_remote() { 259 | remote_branch=${1:-"$(remote_branch_name)"} 260 | if [[ -n "$remote_branch" ]]; then 261 | git rev-list --right-only --count ${remote_branch}...HEAD 2>/dev/null 262 | else 263 | printf '%s' "0" 264 | fi 265 | } 266 | 267 | remote_behind_of_master() { 268 | remote_branch=${1:-"$(remote_branch_name)"} 269 | tracked_remote="origin/master" 270 | if [[ -n "$remote_branch" && "$remote_branch" != "$tracked_remote" ]]; then 271 | git rev-list --left-only --count ${tracked_remote}...${remote_branch} 2>/dev/null || printf '%s' "0" 272 | else 273 | printf '%s' "0" 274 | fi 275 | } 276 | 277 | remote_ahead_of_master() { 278 | remote_branch=${1:-"$(remote_branch_name)"} 279 | tracked_remote="origin/master" 280 | if [[ -n "$remote_branch" && "$remote_branch" != "$tracked_remote" ]]; then 281 | git rev-list --right-only --count ${tracked_remote}...${remote_branch} 2>/dev/null || printf '%s' "0" 282 | else 283 | printf '%s' "0" 284 | fi 285 | } 286 | 287 | # Diacritic marks for overlaying an arrow over A D C etc 288 | #us="\xE2\x83\x97{$reset_color%}" 289 | #them="\xE2\x83\x96%{$reset_color%}" 290 | #both="\xE2\x83\xA1%{$reset_color%}" 291 | 292 | is_dirty() { 293 | if ! git rev-parse &> /dev/null; then 294 | #not in repo, thus not dirty 295 | return 1 296 | else 297 | #in repo, might be dirty 298 | if [[ -n "$(git ls-files --exclude-standard --others 2>/dev/null)" ]]; then 299 | #untracked files thus dirty 300 | return 0 301 | else 302 | #no untracked files 303 | if git show HEAD -- &> /dev/null; then 304 | #has a commit hash, thus not on an initial commit 305 | if ! git diff --quiet --ignore-submodules HEAD -- &> /dev/null; then 306 | #has differences thus dirty 307 | return 0 308 | else 309 | return 1 310 | fi 311 | else 312 | #no commit hash, thus can't use HEAD. 313 | #As it's inital commit we can just list the files. 314 | if [[ -n "$(ls -a -1 "$(git_root)" | grep -Ev '(\.|\.\.|\.git)')" ]]; then 315 | #files listed and no commit hash, thus changes 316 | return 0 317 | else 318 | return 1 319 | fi 320 | fi 321 | fi 322 | fi 323 | } 324 | 325 | porcelain_status() { 326 | printf '%s' "$(git status --porcelain 2>/dev/null)" 327 | } 328 | 329 | staged_status() { 330 | local gitStatus=${1:-"$(porcelain_status)"} 331 | local prefix=${2:-""} 332 | local suffix=${3:-""} 333 | 334 | local staged_string="" 335 | local filesModified="$(printf '%s' "$gitStatus" | grep -oE "M[ACDRM ] " | wc -l | grep -oEi '[1-9][0-9]*')" 336 | local filesAdded="$(printf '%s' "$gitStatus" | grep -oE "A[MCDR ] " | wc -l | grep -oEi '[1-9][0-9]*')" 337 | local filesDeleted="$(printf '%s' "$gitStatus" | grep -oE "D[AMCR ] " | wc -l | grep -oEi '[1-9][0-9]*')" 338 | local filesRenamed="$(printf '%s' "$gitStatus" | grep -oE "R[AMCD ] " | wc -l | grep -oEi '[1-9][0-9]*')" 339 | local filesCopied="$(printf '%s' "$gitStatus" | grep -oE "C[AMDR ] " | wc -l | grep -oEi '[1-9][0-9]*')" 340 | 341 | if [ -n "$filesAdded" ]; then 342 | staged_string="$staged_string$filesAdded${prefix}A${suffix}" 343 | fi 344 | if [ -n "$filesDeleted" ]; then 345 | staged_string="$staged_string$filesDeleted${prefix}D${suffix}" 346 | fi 347 | if [ -n "$filesModified" ]; then 348 | staged_string="$staged_string$filesModified${prefix}M${suffix}" 349 | fi 350 | if [ -n "$filesRenamed" ]; then 351 | staged_string="$staged_string$filesRenamed${prefix}R${suffix}" 352 | fi 353 | if [ -n "$filesCopied" ]; then 354 | staged_string="$staged_string$filesCopied${prefix}C${suffix}" 355 | fi 356 | printf '%s' "$staged_string" 357 | } 358 | 359 | conflicted_status() { 360 | local gitStatus=${1:-"$(porcelain_status)"} 361 | local prefix=${2:-""} 362 | local suffix=${3:-""} 363 | local conflicted_string="" 364 | 365 | local filesUs="$(printf '%s' "$gitStatus" | grep -oE "[AD]U " | wc -l | grep -oEi '[1-9][0-9]*')" 366 | local filesThem="$(printf '%s' "$gitStatus" | grep -oE "U[AD] " | wc -l | grep -oEi '[1-9][0-9]*')" 367 | local filesBoth="$(printf '%s' "$gitStatus" | grep -oE "(UU|AA|DD) " | wc -l | grep -oEi '[1-9][0-9]*')" 368 | 369 | if [ -n "$filesUs" ]; then 370 | conflicted_string="$conflicted_string$filesUs${prefix}U${suffix}" 371 | fi 372 | if [ -n "$filesThem" ]; then 373 | conflicted_string="$conflicted_string$filesThem${prefix}T${suffix}" 374 | fi 375 | if [ -n "$filesBoth" ]; then 376 | conflicted_string="$conflicted_string$filesBoth${prefix}B${suffix}" 377 | fi 378 | printf '%s' "$conflicted_string" 379 | } 380 | 381 | unstaged_status() { 382 | local gitStatus=${1:-"$(porcelain_status)"} 383 | local prefix=${2:-""} 384 | local suffix=${3:-""} 385 | local unstaged_string="" 386 | 387 | local filesModified="$(printf '%s' "$gitStatus" | grep -oE "[ACDRM ]M " | wc -l | grep -oEi '[1-9][0-9]*')" 388 | local filesDeleted="$(printf '%s' "$gitStatus" | grep -oE "[AMCR ]D " | wc -l | grep -oEi '[1-9][0-9]*')" 389 | 390 | if [ -n "$filesDeleted" ]; then 391 | unstaged_string="$unstaged_string$filesDeleted${prefix}D${suffix}" 392 | fi 393 | if [ -n "$filesModified" ]; then 394 | unstaged_string="$unstaged_string$filesModified${prefix}M${suffix}" 395 | fi 396 | printf '%s' "$unstaged_string" 397 | } 398 | 399 | untracked_status() { 400 | local gitStatus=${1:-"$(porcelain_status)"} 401 | local prefix=${2:-""} 402 | local suffix=${3:-""} 403 | local untracked_string="" 404 | 405 | local filesUntracked="$(printf '%s' "$gitStatus" | grep "?? " | wc -l | grep -oEi '[1-9][0-9]*')" 406 | 407 | if [ -n "$filesUntracked" ]; then 408 | untracked_string="$untracked_string$filesUntracked${prefix}A${suffix}" 409 | fi 410 | printf '%s' "$untracked_string" 411 | } 412 | 413 | color_changes_status() { 414 | local separator="${1:- }" 415 | 416 | local porcelain="$(porcelain_status)" 417 | local changes="" 418 | 419 | if [[ -n "$porcelain" ]]; then 420 | local staged_changes="$(staged_status "$porcelain" "$COLOR_CHANGES_STAGED" "$RESET_COLOR_CHANGES")" 421 | local unstaged_changes="$(unstaged_status "$porcelain" "$COLOR_CHANGES_UNSTAGED" "$RESET_COLOR_CHANGES")" 422 | local untracked_changes="$(untracked_status "$porcelain" "$COLOR_CHANGES_UNTRACKED" "$RESET_COLOR_CHANGES")" 423 | local conflicted_changes="$(conflicted_status "$porcelain" "$COLOR_CHANGES_CONFLICTED" "$RESET_COLOR_CHANGES")" 424 | if [[ -n "$staged_changes" ]]; then 425 | staged_changes="$separator$staged_changes" 426 | fi 427 | 428 | if [[ -n "$unstaged_changes" ]]; then 429 | unstaged_changes="$separator$unstaged_changes" 430 | fi 431 | 432 | if [[ -n "$conflicted_changes" ]]; then 433 | conflicted_changes="$separator$conflicted_changes" 434 | fi 435 | 436 | if [[ -n "$untracked_changes" ]]; then 437 | untracked_changes="$separator$untracked_changes" 438 | fi 439 | 440 | changes="$staged_changes$conflicted_changes$unstaged_changes$untracked_changes" 441 | fi 442 | printf $PRINT_F_OPTION "${changes:1}" 443 | } 444 | 445 | bash_color_changes_status() { 446 | color_changes_status 447 | } 448 | 449 | zsh_color_changes_status() { 450 | color_changes_status 451 | } 452 | 453 | color_local_commits() { 454 | local green_ahead_arrow="${COLOR_LOCAL_AHEAD}↑$RESET_COLOR_LOCAL" 455 | local red_behind_arrow="${COLOR_LOCAL_BEHIND}↓$RESET_COLOR_LOCAL" 456 | local yellow_diverged_arrow="${COLOR_LOCAL_DIVERGED}⇵$RESET_COLOR_LOCAL" 457 | 458 | local local_commits="" 459 | if remote_branch="$(remote_branch_name)"; then 460 | local_ahead="$(commits_ahead_of_remote "$remote_branch")" 461 | local_behind="$(commits_behind_of_remote "$remote_branch")" 462 | 463 | if [[ "$local_behind" -gt "0" && "$local_ahead" -gt "0" ]]; then 464 | local_commits="$local_behind$yellow_diverged_arrow$local_ahead" 465 | elif [[ "$local_behind" -gt "0" ]]; then 466 | local_commits="$local_behind$red_behind_arrow" 467 | elif [[ "$local_ahead" -gt "0" ]]; then 468 | local_commits="$local_ahead$green_ahead_arrow" 469 | fi 470 | fi 471 | printf $PRINT_F_OPTION "$local_commits" 472 | } 473 | 474 | bash_color_local_commits() { 475 | color_local_commits 476 | } 477 | 478 | zsh_color_local_commits() { 479 | color_local_commits 480 | } 481 | 482 | color_remote_commits() { 483 | local green_ahead_arrow="${COLOR_REMOTE_AHEAD}←$RESET_COLOR_REMOTE" 484 | local red_behind_arrow="${COLOR_REMOTE_BEHIND}→$RESET_COLOR_REMOTE" 485 | local yellow_diverged_arrow="${COLOR_REMOTE_DIVERGED}⇄$RESET_COLOR_REMOTE" 486 | local not_upstream="${COLOR_REMOTE_NOT_UPSTREAM}⚡$RESET_COLOR_REMOTE" 487 | 488 | if remote_branch="$(remote_branch_name)"; then 489 | remote_ahead="$(remote_ahead_of_master "$remote_branch")" 490 | remote_behind="$(remote_behind_of_master "$remote_branch")" 491 | 492 | if [[ "$remote_behind" -gt "0" && "$remote_ahead" -gt "0" ]]; then 493 | remote="$MASTER_SYMBOL $remote_behind $yellow_diverged_arrow $remote_ahead" 494 | elif [[ "$remote_ahead" -gt "0" ]]; then 495 | remote="$MASTER_SYMBOL $green_ahead_arrow $remote_ahead" 496 | elif [[ "$remote_behind" -gt "0" ]]; then 497 | remote="$MASTER_SYMBOL $remote_behind $red_behind_arrow" 498 | fi 499 | else 500 | remote="upstream $not_upstream" 501 | fi 502 | 503 | printf $PRINT_F_OPTION "$remote" 504 | } 505 | 506 | bash_color_remote_commits() { 507 | color_remote_commits 508 | } 509 | 510 | zsh_color_remote_commits() { 511 | color_remote_commits 512 | } 513 | 514 | readable_branch_name() { 515 | if is_repo; then 516 | printf $PRINT_F_OPTION "$COLOR_BRANCH$(branch_name || printf '%s' "detached@$(commit_short_sha)")$RESET_COLOR_BRANCH" 517 | fi 518 | } 519 | 520 | zsh_readable_branch_name() { 521 | readable_branch_name 522 | } 523 | 524 | bash_readable_branch_name() { 525 | readable_branch_name 526 | } 527 | 528 | show_remote_status() { 529 | if [[ $@ == *$NO_REMOTE_STATUS* ]]; then 530 | return 1 # don't show the git remote status 531 | fi 532 | return 0 533 | } 534 | 535 | stashed_status() { 536 | printf '%s' "$(git stash list | wc -l 2>/dev/null | grep -oEi '[0-9][0-9]*')" 537 | } 538 | 539 | is_cwd_a_dot_git_directory() { 540 | [[ "$(basename "$PWD")" == ".git" ]]; return $? 541 | } 542 | 543 | stash_status() { 544 | if ! is_cwd_a_dot_git_directory; then 545 | local number_stashes="$(stashed_status)" 546 | if [ $number_stashes -gt 0 ]; then 547 | printf $PRINT_F_OPTION "${number_stashes}${COLOR_STASH}≡${RESET_COLOR_STASH}" 548 | fi 549 | fi 550 | } 551 | 552 | render_prompt() { 553 | output="$PROMPT_FORMAT" 554 | branch_sed="" 555 | remote_sed="" 556 | local_sed="" 557 | changes_sed="" 558 | stash_sed="" 559 | 560 | 561 | if_pre="%\{([^%{}]{1,}:){0,1}" 562 | if_post="(:[^%{}]{1,}){0,1}\}" 563 | sed_pre="%{\(\([^%^{^}]*\)\:\)\{0,1\}" 564 | sed_post="\(\:\([^%^{^}]*\)\)\{0,1\}}" 565 | 566 | if [[ $output =~ ${if_pre}remote${if_post} ]]; then 567 | remote_result="$(color_remote_commits)" 568 | if [[ -n "$remote_result" ]]; then 569 | remote_sed="s/${sed_pre}remote${sed_post}/\2${remote_result}\4/" 570 | else 571 | remote_sed="s/${sed_pre}remote${sed_post}//" 572 | fi 573 | fi 574 | if [[ $PROMPT_FORMAT =~ ${if_pre}branch${if_post} ]]; then 575 | branch_result="$(readable_branch_name | sed -e 's/\//\\\//g')" 576 | if [[ -n "$branch_result" ]]; then 577 | branch_sed="s/${sed_pre}branch${sed_post}/\2${branch_result}\4/" 578 | else 579 | branch_sed="s/${sed_pre}branch${sed_post}//" 580 | fi 581 | fi 582 | if [[ $PROMPT_FORMAT =~ ${if_pre}local${if_post} ]]; then 583 | local_result="$(color_local_commits)" 584 | if [[ -n "$local_result" ]]; then 585 | local_sed="s/${sed_pre}local${sed_post}/\2$local_result\4/" 586 | else 587 | local_sed="s/${sed_pre}local${sed_post}//" 588 | fi 589 | fi 590 | if [[ $PROMPT_FORMAT =~ ${if_pre}changes${if_post} ]]; then 591 | changes_result="$(color_changes_status)" 592 | if [[ -n "$changes_result" ]]; then 593 | changes_sed="s/${sed_pre}changes${sed_post}/\2${changes_result}\4/" 594 | else 595 | changes_sed="s/${sed_pre}changes${sed_post}//" 596 | fi 597 | fi 598 | if [[ $PROMPT_FORMAT =~ ${if_pre}stash${if_post} ]]; then 599 | stash_result="$(stash_status)" 600 | if [[ -n "$stash_result" ]]; then 601 | stash_sed="s/${sed_pre}stash${sed_post}/\2${stash_result}\4/" 602 | else 603 | stash_sed="s/${sed_pre}stash${sed_post}//" 604 | fi 605 | fi 606 | 607 | printf '%b' "$output" | sed \ 608 | -e "$remote_sed" \ 609 | -e "$branch_sed" \ 610 | -e "$changes_sed" \ 611 | -e "$local_sed" \ 612 | -e "$stash_sed" 613 | } 614 | -------------------------------------------------------------------------------- /shunit/shunit2: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # 8 | # shUnit2 -- Unit testing framework for Unix shell scripts. 9 | # http://code.google.com/p/shunit2/ 10 | # 11 | # Author: kate.ward@forestent.com (Kate Ward) 12 | # 13 | # shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is 14 | # based on the popular JUnit unit testing framework for Java. 15 | 16 | # return if shunit already loaded 17 | [ -n "${SHUNIT_VERSION:-}" ] && exit 0 18 | 19 | SHUNIT_VERSION='2.1.6' 20 | 21 | SHUNIT_TRUE=0 22 | SHUNIT_FALSE=1 23 | SHUNIT_ERROR=2 24 | 25 | # enable strict mode by default 26 | SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} 27 | 28 | _shunit_warn() { echo "shunit2:WARN $@" >&2; } 29 | _shunit_error() { echo "shunit2:ERROR $@" >&2; } 30 | _shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } 31 | 32 | # specific shell checks 33 | if [ -n "${ZSH_VERSION:-}" ]; then 34 | setopt |grep "^shwordsplit$" >/dev/null 35 | if [ $? -ne ${SHUNIT_TRUE} ]; then 36 | _shunit_fatal 'zsh shwordsplit option is required for proper operation' 37 | fi 38 | if [ -z "${SHUNIT_PARENT:-}" ]; then 39 | _shunit_fatal "zsh does not pass \$0 through properly. please declare \ 40 | \"SHUNIT_PARENT=\$0\" before calling shUnit2" 41 | fi 42 | fi 43 | 44 | # 45 | # constants 46 | # 47 | 48 | __SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' 49 | __SHUNIT_MODE_SOURCED='sourced' 50 | __SHUNIT_MODE_STANDALONE='standalone' 51 | __SHUNIT_PARENT=${SHUNIT_PARENT:-$0} 52 | 53 | # set the constants readonly 54 | shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` 55 | echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ 56 | shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` 57 | for shunit_constant_ in ${shunit_constants_}; do 58 | shunit_ro_opts_='' 59 | case ${ZSH_VERSION:-} in 60 | '') ;; # this isn't zsh 61 | [123].*) ;; # early versions (1.x, 2.x, 3.x) 62 | *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally 63 | esac 64 | readonly ${shunit_ro_opts_} ${shunit_constant_} 65 | done 66 | unset shunit_constant_ shunit_constants_ shunit_ro_opts_ 67 | 68 | # variables 69 | __shunit_lineno='' # line number of executed test 70 | __shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode 71 | __shunit_reportGenerated=${SHUNIT_FALSE} # is report generated 72 | __shunit_script='' # filename of unittest script (standalone mode) 73 | __shunit_skip=${SHUNIT_FALSE} # is skipping enabled 74 | __shunit_suite='' # suite of tests to execute 75 | 76 | # counts of tests 77 | __shunit_testSuccess=${SHUNIT_TRUE} 78 | __shunit_testsTotal=0 79 | __shunit_testsPassed=0 80 | __shunit_testsFailed=0 81 | 82 | # counts of asserts 83 | __shunit_assertsTotal=0 84 | __shunit_assertsPassed=0 85 | __shunit_assertsFailed=0 86 | __shunit_assertsSkipped=0 87 | 88 | # macros 89 | _SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' 90 | 91 | #----------------------------------------------------------------------------- 92 | # assert functions 93 | # 94 | 95 | # Assert that two values are equal to one another. 96 | # 97 | # Args: 98 | # message: string: failure message [optional] 99 | # expected: string: expected value 100 | # actual: string: actual value 101 | # Returns: 102 | # integer: success (TRUE/FALSE/ERROR constant) 103 | assertEquals() 104 | { 105 | ${_SHUNIT_LINENO_} 106 | if [ $# -lt 2 -o $# -gt 3 ]; then 107 | _shunit_error "assertEquals() requires two or three arguments; $# given" 108 | _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" 109 | return ${SHUNIT_ERROR} 110 | fi 111 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 112 | 113 | shunit_message_=${__shunit_lineno} 114 | if [ $# -eq 3 ]; then 115 | shunit_message_="${shunit_message_}$1" 116 | shift 117 | fi 118 | shunit_expected_=$1 119 | shunit_actual_=$2 120 | 121 | shunit_return=${SHUNIT_TRUE} 122 | if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then 123 | _shunit_assertPass 124 | else 125 | failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" 126 | shunit_return=${SHUNIT_FALSE} 127 | fi 128 | 129 | unset shunit_message_ shunit_expected_ shunit_actual_ 130 | return ${shunit_return} 131 | } 132 | _ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' 133 | 134 | # Assert that two values are not equal to one another. 135 | # 136 | # Args: 137 | # message: string: failure message [optional] 138 | # expected: string: expected value 139 | # actual: string: actual value 140 | # Returns: 141 | # integer: success (TRUE/FALSE/ERROR constant) 142 | assertNotEquals() 143 | { 144 | ${_SHUNIT_LINENO_} 145 | if [ $# -lt 2 -o $# -gt 3 ]; then 146 | _shunit_error "assertNotEquals() requires two or three arguments; $# given" 147 | return ${SHUNIT_ERROR} 148 | fi 149 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 150 | 151 | shunit_message_=${__shunit_lineno} 152 | if [ $# -eq 3 ]; then 153 | shunit_message_="${shunit_message_}$1" 154 | shift 155 | fi 156 | shunit_expected_=$1 157 | shunit_actual_=$2 158 | 159 | shunit_return=${SHUNIT_TRUE} 160 | if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then 161 | _shunit_assertPass 162 | else 163 | failSame "${shunit_message_}" "$@" 164 | shunit_return=${SHUNIT_FALSE} 165 | fi 166 | 167 | unset shunit_message_ shunit_expected_ shunit_actual_ 168 | return ${shunit_return} 169 | } 170 | _ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' 171 | 172 | # Assert that a value is null (i.e. an empty string) 173 | # 174 | # Args: 175 | # message: string: failure message [optional] 176 | # actual: string: actual value 177 | # Returns: 178 | # integer: success (TRUE/FALSE/ERROR constant) 179 | assertNull() 180 | { 181 | ${_SHUNIT_LINENO_} 182 | if [ $# -lt 1 -o $# -gt 2 ]; then 183 | _shunit_error "assertNull() requires one or two arguments; $# given" 184 | return ${SHUNIT_ERROR} 185 | fi 186 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 187 | 188 | shunit_message_=${__shunit_lineno} 189 | if [ $# -eq 2 ]; then 190 | shunit_message_="${shunit_message_}$1" 191 | shift 192 | fi 193 | assertTrue "${shunit_message_}" "[ -z '$1' ]" 194 | shunit_return=$? 195 | 196 | unset shunit_message_ 197 | return ${shunit_return} 198 | } 199 | _ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' 200 | 201 | # Assert that a value is not null (i.e. a non-empty string) 202 | # 203 | # Args: 204 | # message: string: failure message [optional] 205 | # actual: string: actual value 206 | # Returns: 207 | # integer: success (TRUE/FALSE/ERROR constant) 208 | assertNotNull() 209 | { 210 | ${_SHUNIT_LINENO_} 211 | if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null 212 | _shunit_error "assertNotNull() requires one or two arguments; $# given" 213 | return ${SHUNIT_ERROR} 214 | fi 215 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 216 | 217 | shunit_message_=${__shunit_lineno} 218 | if [ $# -eq 2 ]; then 219 | shunit_message_="${shunit_message_}$1" 220 | shift 221 | fi 222 | shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` 223 | test -n "${shunit_actual_}" 224 | assertTrue "${shunit_message_}" $? 225 | shunit_return=$? 226 | 227 | unset shunit_actual_ shunit_message_ 228 | return ${shunit_return} 229 | } 230 | _ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' 231 | 232 | # Assert that two values are the same (i.e. equal to one another). 233 | # 234 | # Args: 235 | # message: string: failure message [optional] 236 | # expected: string: expected value 237 | # actual: string: actual value 238 | # Returns: 239 | # integer: success (TRUE/FALSE/ERROR constant) 240 | assertSame() 241 | { 242 | ${_SHUNIT_LINENO_} 243 | if [ $# -lt 2 -o $# -gt 3 ]; then 244 | _shunit_error "assertSame() requires two or three arguments; $# given" 245 | return ${SHUNIT_ERROR} 246 | fi 247 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 248 | 249 | shunit_message_=${__shunit_lineno} 250 | if [ $# -eq 3 ]; then 251 | shunit_message_="${shunit_message_}$1" 252 | shift 253 | fi 254 | assertEquals "${shunit_message_}" "$1" "$2" 255 | shunit_return=$? 256 | 257 | unset shunit_message_ 258 | return ${shunit_return} 259 | } 260 | _ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' 261 | 262 | # Assert that two values are not the same (i.e. not equal to one another). 263 | # 264 | # Args: 265 | # message: string: failure message [optional] 266 | # expected: string: expected value 267 | # actual: string: actual value 268 | # Returns: 269 | # integer: success (TRUE/FALSE/ERROR constant) 270 | assertNotSame() 271 | { 272 | ${_SHUNIT_LINENO_} 273 | if [ $# -lt 2 -o $# -gt 3 ]; then 274 | _shunit_error "assertNotSame() requires two or three arguments; $# given" 275 | return ${SHUNIT_ERROR} 276 | fi 277 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 278 | 279 | shunit_message_=${__shunit_lineno} 280 | if [ $# -eq 3 ]; then 281 | shunit_message_="${shunit_message_:-}$1" 282 | shift 283 | fi 284 | assertNotEquals "${shunit_message_}" "$1" "$2" 285 | shunit_return=$? 286 | 287 | unset shunit_message_ 288 | return ${shunit_return} 289 | } 290 | _ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' 291 | 292 | # Assert that a value or shell test condition is true. 293 | # 294 | # In shell, a value of 0 is true and a non-zero value is false. Any integer 295 | # value passed can thereby be tested. 296 | # 297 | # Shell supports much more complicated tests though, and a means to support 298 | # them was needed. As such, this function tests that conditions are true or 299 | # false through evaluation rather than just looking for a true or false. 300 | # 301 | # The following test will succeed: 302 | # assertTrue 0 303 | # assertTrue "[ 34 -gt 23 ]" 304 | # The folloing test will fail with a message: 305 | # assertTrue 123 306 | # assertTrue "test failed" "[ -r '/non/existant/file' ]" 307 | # 308 | # Args: 309 | # message: string: failure message [optional] 310 | # condition: string: integer value or shell conditional statement 311 | # Returns: 312 | # integer: success (TRUE/FALSE/ERROR constant) 313 | assertTrue() 314 | { 315 | ${_SHUNIT_LINENO_} 316 | if [ $# -gt 2 ]; then 317 | _shunit_error "assertTrue() takes one two arguments; $# given" 318 | return ${SHUNIT_ERROR} 319 | fi 320 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 321 | 322 | shunit_message_=${__shunit_lineno} 323 | if [ $# -eq 2 ]; then 324 | shunit_message_="${shunit_message_}$1" 325 | shift 326 | fi 327 | shunit_condition_=$1 328 | 329 | # see if condition is an integer, i.e. a return value 330 | shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 331 | shunit_return=${SHUNIT_TRUE} 332 | if [ -z "${shunit_condition_}" ]; then 333 | # null condition 334 | shunit_return=${SHUNIT_FALSE} 335 | elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 336 | then 337 | # possible return value. treating 0 as true, and non-zero as false. 338 | [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} 339 | else 340 | # (hopefully) a condition 341 | ( eval ${shunit_condition_} ) >/dev/null 2>&1 342 | [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} 343 | fi 344 | 345 | # record the test 346 | if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 347 | _shunit_assertPass 348 | else 349 | _shunit_assertFail "${shunit_message_}" 350 | fi 351 | 352 | unset shunit_message_ shunit_condition_ shunit_match_ 353 | return ${shunit_return} 354 | } 355 | _ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' 356 | 357 | # Assert that a value or shell test condition is false. 358 | # 359 | # In shell, a value of 0 is true and a non-zero value is false. Any integer 360 | # value passed can thereby be tested. 361 | # 362 | # Shell supports much more complicated tests though, and a means to support 363 | # them was needed. As such, this function tests that conditions are true or 364 | # false through evaluation rather than just looking for a true or false. 365 | # 366 | # The following test will succeed: 367 | # assertFalse 1 368 | # assertFalse "[ 'apples' = 'oranges' ]" 369 | # The folloing test will fail with a message: 370 | # assertFalse 0 371 | # assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" 372 | # 373 | # Args: 374 | # message: string: failure message [optional] 375 | # condition: string: integer value or shell conditional statement 376 | # Returns: 377 | # integer: success (TRUE/FALSE/ERROR constant) 378 | assertFalse() 379 | { 380 | ${_SHUNIT_LINENO_} 381 | if [ $# -lt 1 -o $# -gt 2 ]; then 382 | _shunit_error "assertFalse() quires one or two arguments; $# given" 383 | return ${SHUNIT_ERROR} 384 | fi 385 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 386 | 387 | shunit_message_=${__shunit_lineno} 388 | if [ $# -eq 2 ]; then 389 | shunit_message_="${shunit_message_}$1" 390 | shift 391 | fi 392 | shunit_condition_=$1 393 | 394 | # see if condition is an integer, i.e. a return value 395 | shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` 396 | shunit_return=${SHUNIT_TRUE} 397 | if [ -z "${shunit_condition_}" ]; then 398 | # null condition 399 | shunit_return=${SHUNIT_FALSE} 400 | elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] 401 | then 402 | # possible return value. treating 0 as true, and non-zero as false. 403 | [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} 404 | else 405 | # (hopefully) a condition 406 | ( eval ${shunit_condition_} ) >/dev/null 2>&1 407 | [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} 408 | fi 409 | 410 | # record the test 411 | if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then 412 | _shunit_assertPass 413 | else 414 | _shunit_assertFail "${shunit_message_}" 415 | fi 416 | 417 | unset shunit_message_ shunit_condition_ shunit_match_ 418 | return ${shunit_return} 419 | } 420 | _ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' 421 | 422 | #----------------------------------------------------------------------------- 423 | # failure functions 424 | # 425 | 426 | # Records a test failure. 427 | # 428 | # Args: 429 | # message: string: failure message [optional] 430 | # Returns: 431 | # integer: success (TRUE/FALSE/ERROR constant) 432 | fail() 433 | { 434 | ${_SHUNIT_LINENO_} 435 | if [ $# -gt 1 ]; then 436 | _shunit_error "fail() requires zero or one arguments; $# given" 437 | return ${SHUNIT_ERROR} 438 | fi 439 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 440 | 441 | shunit_message_=${__shunit_lineno} 442 | if [ $# -eq 1 ]; then 443 | shunit_message_="${shunit_message_}$1" 444 | shift 445 | fi 446 | 447 | _shunit_assertFail "${shunit_message_}" 448 | 449 | unset shunit_message_ 450 | return ${SHUNIT_FALSE} 451 | } 452 | _FAIL_='eval fail --lineno "${LINENO:-}"' 453 | 454 | # Records a test failure, stating two values were not equal. 455 | # 456 | # Args: 457 | # message: string: failure message [optional] 458 | # expected: string: expected value 459 | # actual: string: actual value 460 | # Returns: 461 | # integer: success (TRUE/FALSE/ERROR constant) 462 | failNotEquals() 463 | { 464 | ${_SHUNIT_LINENO_} 465 | if [ $# -lt 2 -o $# -gt 3 ]; then 466 | _shunit_error "failNotEquals() requires one or two arguments; $# given" 467 | return ${SHUNIT_ERROR} 468 | fi 469 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 470 | 471 | shunit_message_=${__shunit_lineno} 472 | if [ $# -eq 3 ]; then 473 | shunit_message_="${shunit_message_}$1" 474 | shift 475 | fi 476 | shunit_expected_=$1 477 | shunit_actual_=$2 478 | 479 | _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" 480 | 481 | unset shunit_message_ shunit_expected_ shunit_actual_ 482 | return ${SHUNIT_FALSE} 483 | } 484 | _FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' 485 | 486 | # Records a test failure, stating two values should have been the same. 487 | # 488 | # Args: 489 | # message: string: failure message [optional] 490 | # expected: string: expected value 491 | # actual: string: actual value 492 | # Returns: 493 | # integer: success (TRUE/FALSE/ERROR constant) 494 | failSame() 495 | { 496 | ${_SHUNIT_LINENO_} 497 | if [ $# -lt 2 -o $# -gt 3 ]; then 498 | _shunit_error "failSame() requires two or three arguments; $# given" 499 | return ${SHUNIT_ERROR} 500 | fi 501 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 502 | 503 | shunit_message_=${__shunit_lineno} 504 | if [ $# -eq 3 ]; then 505 | shunit_message_="${shunit_message_}$1" 506 | shift 507 | fi 508 | 509 | _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" 510 | 511 | unset shunit_message_ 512 | return ${SHUNIT_FALSE} 513 | } 514 | _FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' 515 | 516 | # Records a test failure, stating two values were not equal. 517 | # 518 | # This is functionally equivalent to calling failNotEquals(). 519 | # 520 | # Args: 521 | # message: string: failure message [optional] 522 | # expected: string: expected value 523 | # actual: string: actual value 524 | # Returns: 525 | # integer: success (TRUE/FALSE/ERROR constant) 526 | failNotSame() 527 | { 528 | ${_SHUNIT_LINENO_} 529 | if [ $# -lt 2 -o $# -gt 3 ]; then 530 | _shunit_error "failNotEquals() requires one or two arguments; $# given" 531 | return ${SHUNIT_ERROR} 532 | fi 533 | _shunit_shouldSkip && return ${SHUNIT_TRUE} 534 | 535 | shunit_message_=${__shunit_lineno} 536 | if [ $# -eq 3 ]; then 537 | shunit_message_="${shunit_message_}$1" 538 | shift 539 | fi 540 | failNotEquals "${shunit_message_}" "$1" "$2" 541 | shunit_return=$? 542 | 543 | unset shunit_message_ 544 | return ${shunit_return} 545 | } 546 | _FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' 547 | 548 | #----------------------------------------------------------------------------- 549 | # skipping functions 550 | # 551 | 552 | # Force remaining assert and fail functions to be "skipped". 553 | # 554 | # This function forces the remaining assert and fail functions to be "skipped", 555 | # i.e. they will have no effect. Each function skipped will be recorded so that 556 | # the total of asserts and fails will not be altered. 557 | # 558 | # Args: 559 | # None 560 | startSkipping() 561 | { 562 | __shunit_skip=${SHUNIT_TRUE} 563 | } 564 | 565 | # Resume the normal recording behavior of assert and fail calls. 566 | # 567 | # Args: 568 | # None 569 | endSkipping() 570 | { 571 | __shunit_skip=${SHUNIT_FALSE} 572 | } 573 | 574 | # Returns the state of assert and fail call skipping. 575 | # 576 | # Args: 577 | # None 578 | # Returns: 579 | # boolean: (TRUE/FALSE constant) 580 | isSkipping() 581 | { 582 | return ${__shunit_skip} 583 | } 584 | 585 | #----------------------------------------------------------------------------- 586 | # suite functions 587 | # 588 | 589 | # Stub. This function should contains all unit test calls to be made. 590 | # 591 | # DEPRECATED (as of 2.1.0) 592 | # 593 | # This function can be optionally overridden by the user in their test suite. 594 | # 595 | # If this function exists, it will be called when shunit2 is sourced. If it 596 | # does not exist, shunit2 will search the parent script for all functions 597 | # beginning with the word 'test', and they will be added dynamically to the 598 | # test suite. 599 | # 600 | # This function should be overridden by the user in their unit test suite. 601 | # Note: see _shunit_mktempFunc() for actual implementation 602 | # 603 | # Args: 604 | # None 605 | #suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION 606 | 607 | # Adds a function name to the list of tests schedule for execution. 608 | # 609 | # This function should only be called from within the suite() function. 610 | # 611 | # Args: 612 | # function: string: name of a function to add to current unit test suite 613 | suite_addTest() 614 | { 615 | shunit_func_=${1:-} 616 | 617 | __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" 618 | __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` 619 | 620 | unset shunit_func_ 621 | } 622 | 623 | # Stub. This function will be called once before any tests are run. 624 | # 625 | # Common one-time environment preparation tasks shared by all tests can be 626 | # defined here. 627 | # 628 | # This function should be overridden by the user in their unit test suite. 629 | # Note: see _shunit_mktempFunc() for actual implementation 630 | # 631 | # Args: 632 | # None 633 | #oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION 634 | 635 | # Stub. This function will be called once after all tests are finished. 636 | # 637 | # Common one-time environment cleanup tasks shared by all tests can be defined 638 | # here. 639 | # 640 | # This function should be overridden by the user in their unit test suite. 641 | # Note: see _shunit_mktempFunc() for actual implementation 642 | # 643 | # Args: 644 | # None 645 | #oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 646 | 647 | # Stub. This function will be called before each test is run. 648 | # 649 | # Common environment preparation tasks shared by all tests can be defined here. 650 | # 651 | # This function should be overridden by the user in their unit test suite. 652 | # Note: see _shunit_mktempFunc() for actual implementation 653 | # 654 | # Args: 655 | # None 656 | #setUp() { :; } 657 | 658 | # Note: see _shunit_mktempFunc() for actual implementation 659 | # Stub. This function will be called after each test is run. 660 | # 661 | # Common environment cleanup tasks shared by all tests can be defined here. 662 | # 663 | # This function should be overridden by the user in their unit test suite. 664 | # Note: see _shunit_mktempFunc() for actual implementation 665 | # 666 | # Args: 667 | # None 668 | #tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION 669 | 670 | #------------------------------------------------------------------------------ 671 | # internal shUnit2 functions 672 | # 673 | 674 | # Create a temporary directory to store various run-time files in. 675 | # 676 | # This function is a cross-platform temporary directory creation tool. Not all 677 | # OSes have the mktemp function, so one is included here. 678 | # 679 | # Args: 680 | # None 681 | # Outputs: 682 | # string: the temporary directory that was created 683 | _shunit_mktempDir() 684 | { 685 | # try the standard mktemp function 686 | ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return 687 | 688 | # the standard mktemp didn't work. doing our own. 689 | if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then 690 | _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" 719 | #! /bin/sh 720 | exit ${SHUNIT_TRUE} 721 | EOF 722 | chmod +x "${_shunit_file_}" 723 | done 724 | 725 | unset _shunit_file_ 726 | } 727 | 728 | # Final cleanup function to leave things as we found them. 729 | # 730 | # Besides removing the temporary directory, this function is in charge of the 731 | # final exit code of the unit test. The exit code is based on how the script 732 | # was ended (e.g. normal exit, or via Ctrl-C). 733 | # 734 | # Args: 735 | # name: string: name of the trap called (specified when trap defined) 736 | _shunit_cleanup() 737 | { 738 | _shunit_name_=$1 739 | 740 | case ${_shunit_name_} in 741 | EXIT) _shunit_signal_=0 ;; 742 | INT) _shunit_signal_=2 ;; 743 | TERM) _shunit_signal_=15 ;; 744 | *) 745 | _shunit_warn "unrecognized trap value (${_shunit_name_})" 746 | _shunit_signal_=0 747 | ;; 748 | esac 749 | 750 | # do our work 751 | rm -fr "${__shunit_tmpDir}" 752 | 753 | # exit for all non-EXIT signals 754 | if [ ${_shunit_name_} != 'EXIT' ]; then 755 | _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" 756 | # disable EXIT trap 757 | trap 0 758 | # add 128 to signal and exit 759 | exit `expr ${_shunit_signal_} + 128` 760 | elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then 761 | _shunit_assertFail 'Unknown failure encountered running a test' 762 | _shunit_generateReport 763 | exit ${SHUNIT_ERROR} 764 | fi 765 | 766 | unset _shunit_name_ _shunit_signal_ 767 | } 768 | 769 | # The actual running of the tests happens here. 770 | # 771 | # Args: 772 | # None 773 | _shunit_execSuite() 774 | { 775 | for _shunit_test_ in ${__shunit_suite}; do 776 | __shunit_testSuccess=${SHUNIT_TRUE} 777 | 778 | # disable skipping 779 | endSkipping 780 | 781 | # execute the per-test setup function 782 | setUp 783 | 784 | # execute the test 785 | echo "${_shunit_test_}" 786 | eval ${_shunit_test_} 787 | 788 | # execute the per-test tear-down function 789 | tearDown 790 | 791 | # update stats 792 | if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then 793 | __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` 794 | else 795 | __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` 796 | fi 797 | done 798 | 799 | unset _shunit_test_ 800 | } 801 | 802 | # Generates the user friendly report with appropriate OK/FAILED message. 803 | # 804 | # Args: 805 | # None 806 | # Output: 807 | # string: the report of successful and failed tests, as well as totals. 808 | _shunit_generateReport() 809 | { 810 | _shunit_ok_=${SHUNIT_TRUE} 811 | 812 | # if no exit code was provided one, determine an appropriate one 813 | [ ${__shunit_testsFailed} -gt 0 \ 814 | -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ 815 | && _shunit_ok_=${SHUNIT_FALSE} 816 | 817 | echo 818 | if [ ${__shunit_testsTotal} -eq 1 ]; then 819 | echo "Ran ${__shunit_testsTotal} test." 820 | else 821 | echo "Ran ${__shunit_testsTotal} tests." 822 | fi 823 | 824 | _shunit_failures_='' 825 | _shunit_skipped_='' 826 | [ ${__shunit_assertsFailed} -gt 0 ] \ 827 | && _shunit_failures_="failures=${__shunit_assertsFailed}" 828 | [ ${__shunit_assertsSkipped} -gt 0 ] \ 829 | && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" 830 | 831 | if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then 832 | _shunit_msg_='OK' 833 | [ -n "${_shunit_skipped_}" ] \ 834 | && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" 835 | else 836 | _shunit_msg_="FAILED (${_shunit_failures_}" 837 | [ -n "${_shunit_skipped_}" ] \ 838 | && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" 839 | _shunit_msg_="${_shunit_msg_})" 840 | fi 841 | 842 | echo 843 | echo ${_shunit_msg_} 844 | __shunit_reportGenerated=${SHUNIT_TRUE} 845 | 846 | unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ 847 | } 848 | 849 | # Test for whether a function should be skipped. 850 | # 851 | # Args: 852 | # None 853 | # Returns: 854 | # boolean: whether the test should be skipped (TRUE/FALSE constant) 855 | _shunit_shouldSkip() 856 | { 857 | [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} 858 | _shunit_assertSkip 859 | } 860 | 861 | # Records a successful test. 862 | # 863 | # Args: 864 | # None 865 | _shunit_assertPass() 866 | { 867 | __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` 868 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 869 | } 870 | 871 | # Records a test failure. 872 | # 873 | # Args: 874 | # message: string: failure message to provide user 875 | _shunit_assertFail() 876 | { 877 | _shunit_msg_=$1 878 | 879 | __shunit_testSuccess=${SHUNIT_FALSE} 880 | __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` 881 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 882 | echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" 883 | 884 | unset _shunit_msg_ 885 | } 886 | 887 | # Records a skipped test. 888 | # 889 | # Args: 890 | # None 891 | _shunit_assertSkip() 892 | { 893 | __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` 894 | __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` 895 | } 896 | 897 | # Prepare a script filename for sourcing. 898 | # 899 | # Args: 900 | # script: string: path to a script to source 901 | # Returns: 902 | # string: filename prefixed with ./ (if necessary) 903 | _shunit_prepForSourcing() 904 | { 905 | _shunit_script_=$1 906 | case "${_shunit_script_}" in 907 | /*|./*) echo "${_shunit_script_}" ;; 908 | *) echo "./${_shunit_script_}" ;; 909 | esac 910 | unset _shunit_script_ 911 | } 912 | 913 | # Escape a character in a string. 914 | # 915 | # Args: 916 | # c: string: unescaped character 917 | # s: string: to escape character in 918 | # Returns: 919 | # string: with escaped character(s) 920 | _shunit_escapeCharInStr() 921 | { 922 | [ -n "$2" ] || return # no point in doing work on an empty string 923 | 924 | # Note: using shorter variable names to prevent conflicts with 925 | # _shunit_escapeCharactersInString(). 926 | _shunit_c_=$1 927 | _shunit_s_=$2 928 | 929 | 930 | # escape the character 931 | echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' 932 | 933 | unset _shunit_c_ _shunit_s_ 934 | } 935 | 936 | # Escape a character in a string. 937 | # 938 | # Args: 939 | # str: string: to escape characters in 940 | # Returns: 941 | # string: with escaped character(s) 942 | _shunit_escapeCharactersInString() 943 | { 944 | [ -n "$1" ] || return # no point in doing work on an empty string 945 | 946 | _shunit_str_=$1 947 | 948 | # Note: using longer variable names to prevent conflicts with 949 | # _shunit_escapeCharInStr(). 950 | for _shunit_char_ in '"' '$' "'" '`'; do 951 | _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` 952 | done 953 | 954 | echo "${_shunit_str_}" 955 | unset _shunit_char_ _shunit_str_ 956 | } 957 | 958 | # Extract list of functions to run tests against. 959 | # 960 | # Args: 961 | # script: string: name of script to extract functions from 962 | # Returns: 963 | # string: of function names 964 | _shunit_extractTestFunctions() 965 | { 966 | _shunit_script_=$1 967 | 968 | # extract the lines with test function names, strip of anything besides the 969 | # function name, and output everything on a single line. 970 | _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' 971 | egrep "${_shunit_regex_}" "${_shunit_script_}" \ 972 | |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ 973 | |xargs 974 | 975 | unset _shunit_regex_ _shunit_script_ 976 | } 977 | 978 | #------------------------------------------------------------------------------ 979 | # main 980 | # 981 | 982 | # determine the operating mode 983 | if [ $# -eq 0 ]; then 984 | __shunit_script=${__SHUNIT_PARENT} 985 | __shunit_mode=${__SHUNIT_MODE_SOURCED} 986 | else 987 | __shunit_script=$1 988 | [ -r "${__shunit_script}" ] || \ 989 | _shunit_fatal "unable to read from ${__shunit_script}" 990 | __shunit_mode=${__SHUNIT_MODE_STANDALONE} 991 | fi 992 | 993 | # create a temporary storage location 994 | __shunit_tmpDir=`_shunit_mktempDir` 995 | 996 | # provide a public temporary directory for unit test scripts 997 | # TODO(kward): document this 998 | SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" 999 | mkdir "${SHUNIT_TMPDIR}" 1000 | 1001 | # setup traps to clean up after ourselves 1002 | trap '_shunit_cleanup EXIT' 0 1003 | trap '_shunit_cleanup INT' 2 1004 | trap '_shunit_cleanup TERM' 15 1005 | 1006 | # create phantom functions to work around issues with Cygwin 1007 | _shunit_mktempFunc 1008 | PATH="${__shunit_tmpDir}:${PATH}" 1009 | 1010 | # make sure phantom functions are executable. this will bite if /tmp (or the 1011 | # current $TMPDIR) points to a path on a partition that was mounted with the 1012 | # 'noexec' option. the noexec command was created with _shunit_mktempFunc(). 1013 | noexec 2>/dev/null || _shunit_fatal \ 1014 | 'please declare TMPDIR with path on partition with exec permission' 1015 | 1016 | # we must manually source the tests in standalone mode 1017 | if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then 1018 | . "`_shunit_prepForSourcing \"${__shunit_script}\"`" 1019 | fi 1020 | 1021 | # execute the oneTimeSetUp function (if it exists) 1022 | oneTimeSetUp 1023 | 1024 | # execute the suite function defined in the parent test script 1025 | # deprecated as of 2.1.0 1026 | suite 1027 | 1028 | # if no suite function was defined, dynamically build a list of functions 1029 | if [ -z "${__shunit_suite}" ]; then 1030 | shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` 1031 | for shunit_func_ in ${shunit_funcs_}; do 1032 | suite_addTest ${shunit_func_} 1033 | done 1034 | fi 1035 | unset shunit_func_ shunit_funcs_ 1036 | 1037 | # execute the tests 1038 | _shunit_execSuite 1039 | 1040 | # execute the oneTimeTearDown function (if it exists) 1041 | oneTimeTearDown 1042 | 1043 | # generate the report 1044 | _shunit_generateReport 1045 | 1046 | # that's it folks 1047 | [ ${__shunit_testsFailed} -eq 0 ] 1048 | exit $? 1049 | -------------------------------------------------------------------------------- /shunit/shunit2_test.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2_test.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # Author: kate.ward@forestent.com (Kate Ward) 8 | # 9 | # shUnit2 unit test suite runner. 10 | # 11 | # This script runs all the unit tests that can be found, and generates a nice 12 | # report of the tests. 13 | 14 | MY_NAME=`basename $0` 15 | MY_PATH=`dirname $0` 16 | 17 | PREFIX='shunit2_test_' 18 | SHELLS='/bin/sh /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh' 19 | TESTS='' 20 | for test in ${PREFIX}[a-z]*.sh; do 21 | TESTS="${TESTS} ${test}" 22 | done 23 | 24 | # load common unit test functions 25 | . ../lib/versions 26 | . ./shunit2_test_helpers 27 | 28 | usage() 29 | { 30 | echo "usage: ${MY_NAME} [-e key=val ...] [-s shell(s)] [-t test(s)]" 31 | } 32 | 33 | env='' 34 | 35 | # process command line flags 36 | while getopts 'e:hs:t:' opt; do 37 | case ${opt} in 38 | e) # set an environment variable 39 | key=`expr "${OPTARG}" : '\([^=]*\)='` 40 | val=`expr "${OPTARG}" : '[^=]*=\(.*\)'` 41 | if [ -z "${key}" -o -z "${val}" ]; then 42 | usage 43 | exit 1 44 | fi 45 | eval "${key}='${val}'" 46 | export ${key} 47 | env="${env:+${env} }${key}" 48 | ;; 49 | h) usage; exit 0 ;; # output help 50 | s) shells=${OPTARG} ;; # list of shells to run 51 | t) tests=${OPTARG} ;; # list of tests to run 52 | *) usage; exit 1 ;; 53 | esac 54 | done 55 | shift `expr ${OPTIND} - 1` 56 | 57 | # fill shells and/or tests 58 | shells=${shells:-${SHELLS}} 59 | tests=${tests:-${TESTS}} 60 | 61 | # error checking 62 | if [ -z "${tests}" ]; then 63 | th_error 'no tests found to run; exiting' 64 | exit 1 65 | fi 66 | 67 | cat <&1; ) 123 | done 124 | done 125 | -------------------------------------------------------------------------------- /shunit/shunit2_test_asserts.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2_test_asserts.sh 312 2011-03-14 22:41:29Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # 8 | # Author: kate.ward@forestent.com (Kate Ward) 9 | # 10 | # shUnit2 unit test for assert functions 11 | 12 | # load test helpers 13 | . ./shunit2_test_helpers 14 | 15 | #------------------------------------------------------------------------------ 16 | # suite tests 17 | # 18 | 19 | commonEqualsSame() 20 | { 21 | fn=$1 22 | 23 | ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 24 | th_assertTrueWithNoOutput 'equal' $? "${stdoutF}" "${stderrF}" 25 | 26 | ( ${fn} "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 27 | th_assertTrueWithNoOutput 'equal; with msg' $? "${stdoutF}" "${stderrF}" 28 | 29 | ( ${fn} 'abc def' 'abc def' >"${stdoutF}" 2>"${stderrF}" ) 30 | th_assertTrueWithNoOutput 'equal with spaces' $? "${stdoutF}" "${stderrF}" 31 | 32 | ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 33 | th_assertFalseWithOutput 'not equal' $? "${stdoutF}" "${stderrF}" 34 | 35 | ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) 36 | th_assertTrueWithNoOutput 'null values' $? "${stdoutF}" "${stderrF}" 37 | 38 | ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) 39 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 40 | 41 | ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) 42 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 43 | } 44 | 45 | commonNotEqualsSame() 46 | { 47 | fn=$1 48 | 49 | ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 50 | th_assertTrueWithNoOutput 'not same' $? "${stdoutF}" "${stderrF}" 51 | 52 | ( ${fn} "${MSG}" 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 53 | th_assertTrueWithNoOutput 'not same, with msg' $? "${stdoutF}" "${stderrF}" 54 | 55 | ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 56 | th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" 57 | 58 | ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) 59 | th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" 60 | 61 | ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) 62 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 63 | 64 | ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) 65 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 66 | } 67 | 68 | testAssertEquals() 69 | { 70 | commonEqualsSame 'assertEquals' 71 | } 72 | 73 | testAssertNotEquals() 74 | { 75 | commonNotEqualsSame 'assertNotEquals' 76 | } 77 | 78 | testAssertSame() 79 | { 80 | commonEqualsSame 'assertSame' 81 | } 82 | 83 | testAssertNotSame() 84 | { 85 | commonNotEqualsSame 'assertNotSame' 86 | } 87 | 88 | testAssertNull() 89 | { 90 | ( assertNull '' >"${stdoutF}" 2>"${stderrF}" ) 91 | th_assertTrueWithNoOutput 'null' $? "${stdoutF}" "${stderrF}" 92 | 93 | ( assertNull "${MSG}" '' >"${stdoutF}" 2>"${stderrF}" ) 94 | th_assertTrueWithNoOutput 'null, with msg' $? "${stdoutF}" "${stderrF}" 95 | 96 | ( assertNull 'x' >"${stdoutF}" 2>"${stderrF}" ) 97 | th_assertFalseWithOutput 'not null' $? "${stdoutF}" "${stderrF}" 98 | 99 | ( assertNull >"${stdoutF}" 2>"${stderrF}" ) 100 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 101 | 102 | ( assertNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) 103 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 104 | } 105 | 106 | testAssertNotNull() 107 | { 108 | ( assertNotNull 'x' >"${stdoutF}" 2>"${stderrF}" ) 109 | th_assertTrueWithNoOutput 'not null' $? "${stdoutF}" "${stderrF}" 110 | 111 | ( assertNotNull "${MSG}" 'x' >"${stdoutF}" 2>"${stderrF}" ) 112 | th_assertTrueWithNoOutput 'not null, with msg' $? "${stdoutF}" "${stderrF}" 113 | 114 | ( assertNotNull 'x"b' >"${stdoutF}" 2>"${stderrF}" ) 115 | th_assertTrueWithNoOutput 'not null, with double-quote' $? \ 116 | "${stdoutF}" "${stderrF}" 117 | 118 | ( assertNotNull "x'b" >"${stdoutF}" 2>"${stderrF}" ) 119 | th_assertTrueWithNoOutput 'not null, with single-quote' $? \ 120 | "${stdoutF}" "${stderrF}" 121 | 122 | ( assertNotNull 'x$b' >"${stdoutF}" 2>"${stderrF}" ) 123 | th_assertTrueWithNoOutput 'not null, with dollar' $? \ 124 | "${stdoutF}" "${stderrF}" 125 | 126 | ( assertNotNull 'x`b' >"${stdoutF}" 2>"${stderrF}" ) 127 | th_assertTrueWithNoOutput 'not null, with backtick' $? \ 128 | "${stdoutF}" "${stderrF}" 129 | 130 | ( assertNotNull '' >"${stdoutF}" 2>"${stderrF}" ) 131 | th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" 132 | 133 | # there is no test for too few arguments as $1 might actually be null 134 | 135 | ( assertNotNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) 136 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 137 | } 138 | 139 | testAssertTrue() 140 | { 141 | ( assertTrue 0 >"${stdoutF}" 2>"${stderrF}" ) 142 | th_assertTrueWithNoOutput 'true' $? "${stdoutF}" "${stderrF}" 143 | 144 | ( assertTrue "${MSG}" 0 >"${stdoutF}" 2>"${stderrF}" ) 145 | th_assertTrueWithNoOutput 'true, with msg' $? "${stdoutF}" "${stderrF}" 146 | 147 | ( assertTrue '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) 148 | th_assertTrueWithNoOutput 'true condition' $? "${stdoutF}" "${stderrF}" 149 | 150 | ( assertTrue 1 >"${stdoutF}" 2>"${stderrF}" ) 151 | th_assertFalseWithOutput 'false' $? "${stdoutF}" "${stderrF}" 152 | 153 | ( assertTrue '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) 154 | th_assertFalseWithOutput 'false condition' $? "${stdoutF}" "${stderrF}" 155 | 156 | ( assertTrue '' >"${stdoutF}" 2>"${stderrF}" ) 157 | th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" 158 | 159 | ( assertTrue >"${stdoutF}" 2>"${stderrF}" ) 160 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 161 | 162 | ( assertTrue arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) 163 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 164 | } 165 | 166 | testAssertFalse() 167 | { 168 | ( assertFalse 1 >"${stdoutF}" 2>"${stderrF}" ) 169 | th_assertTrueWithNoOutput 'false' $? "${stdoutF}" "${stderrF}" 170 | 171 | ( assertFalse "${MSG}" 1 >"${stdoutF}" 2>"${stderrF}" ) 172 | th_assertTrueWithNoOutput 'false, with msg' $? "${stdoutF}" "${stderrF}" 173 | 174 | ( assertFalse '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) 175 | th_assertTrueWithNoOutput 'false condition' $? "${stdoutF}" "${stderrF}" 176 | 177 | ( assertFalse 0 >"${stdoutF}" 2>"${stderrF}" ) 178 | th_assertFalseWithOutput 'true' $? "${stdoutF}" "${stderrF}" 179 | 180 | ( assertFalse '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) 181 | th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" 182 | 183 | ( assertFalse '' >"${stdoutF}" 2>"${stderrF}" ) 184 | th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" 185 | 186 | ( assertFalse >"${stdoutF}" 2>"${stderrF}" ) 187 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 188 | 189 | ( assertFalse arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) 190 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 191 | } 192 | 193 | #------------------------------------------------------------------------------ 194 | # suite functions 195 | # 196 | 197 | oneTimeSetUp() 198 | { 199 | tmpDir="${__shunit_tmpDir}/output" 200 | mkdir "${tmpDir}" 201 | stdoutF="${tmpDir}/stdout" 202 | stderrF="${tmpDir}/stderr" 203 | 204 | MSG='This is a test message' 205 | } 206 | 207 | # load and run shUnit2 208 | [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 209 | . ${TH_SHUNIT} 210 | -------------------------------------------------------------------------------- /shunit/shunit2_test_failures.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2_test_failures.sh 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # 8 | # Author: kate.ward@forestent.com (Kate Ward) 9 | # 10 | # shUnit2 unit test for failure functions 11 | 12 | # load common unit-test functions 13 | . ./shunit2_test_helpers 14 | 15 | #----------------------------------------------------------------------------- 16 | # suite tests 17 | # 18 | 19 | testFail() 20 | { 21 | ( fail >"${stdoutF}" 2>"${stderrF}" ) 22 | th_assertFalseWithOutput 'fail' $? "${stdoutF}" "${stderrF}" 23 | 24 | ( fail "${MSG}" >"${stdoutF}" 2>"${stderrF}" ) 25 | th_assertFalseWithOutput 'fail with msg' $? "${stdoutF}" "${stderrF}" 26 | 27 | ( fail arg1 >"${stdoutF}" 2>"${stderrF}" ) 28 | th_assertFalseWithOutput 'too many arguments' $? "${stdoutF}" "${stderrF}" 29 | } 30 | 31 | testFailNotEquals() 32 | { 33 | ( failNotEquals 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 34 | th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" 35 | 36 | ( failNotEquals "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 37 | th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" 38 | 39 | ( failNotEquals 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 40 | th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" 41 | 42 | ( failNotEquals '' '' >"${stdoutF}" 2>"${stderrF}" ) 43 | th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" 44 | 45 | ( failNotEquals >"${stdoutF}" 2>"${stderrF}" ) 46 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 47 | 48 | ( failNotEquals arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) 49 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 50 | } 51 | 52 | testFailSame() 53 | { 54 | ( failSame 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 55 | th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" 56 | 57 | ( failSame "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 58 | th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" 59 | 60 | ( failSame 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 61 | th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" 62 | 63 | ( failSame '' '' >"${stdoutF}" 2>"${stderrF}" ) 64 | th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" 65 | 66 | ( failSame >"${stdoutF}" 2>"${stderrF}" ) 67 | th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" 68 | 69 | ( failSame arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) 70 | th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" 71 | } 72 | 73 | #----------------------------------------------------------------------------- 74 | # suite functions 75 | # 76 | 77 | oneTimeSetUp() 78 | { 79 | tmpDir="${__shunit_tmpDir}/output" 80 | mkdir "${tmpDir}" 81 | stdoutF="${tmpDir}/stdout" 82 | stderrF="${tmpDir}/stderr" 83 | 84 | MSG='This is a test message' 85 | } 86 | 87 | # load and run shUnit2 88 | [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 89 | . ${TH_SHUNIT} 90 | -------------------------------------------------------------------------------- /shunit/shunit2_test_helpers: -------------------------------------------------------------------------------- 1 | # $Id: shunit2_test_helpers 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ 2 | # vim:et:ft=sh:sts=2:sw=2 3 | # 4 | # Copyright 2008 Kate Ward. All Rights Reserved. 5 | # Released under the LGPL (GNU Lesser General Public License) 6 | # 7 | # Author: kate.ward@forestent.com (Kate Ward) 8 | # 9 | # shUnit2 unit test common functions 10 | 11 | # treat unset variables as an error when performing parameter expansion 12 | set -u 13 | 14 | # set shwordsplit for zsh 15 | [ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit 16 | 17 | # 18 | # constants 19 | # 20 | 21 | # path to shUnit2 library. can be overridden by setting SHUNIT_INC 22 | TH_SHUNIT=${SHUNIT_INC:-./shunit2} 23 | 24 | # configure debugging. set the DEBUG environment variable to any 25 | # non-empty value to enable debug output, or TRACE to enable trace 26 | # output. 27 | TRACE=${TRACE:+'th_trace '} 28 | [ -n "${TRACE}" ] && DEBUG=1 29 | [ -z "${TRACE}" ] && TRACE=':' 30 | 31 | DEBUG=${DEBUG:+'th_debug '} 32 | [ -z "${DEBUG}" ] && DEBUG=':' 33 | 34 | # 35 | # variables 36 | # 37 | 38 | th_RANDOM=0 39 | 40 | # 41 | # functions 42 | # 43 | 44 | # message functions 45 | th_trace() { echo "${MY_NAME}:TRACE $@" >&2; } 46 | th_debug() { echo "${MY_NAME}:DEBUG $@" >&2; } 47 | th_info() { echo "${MY_NAME}:INFO $@" >&2; } 48 | th_warn() { echo "${MY_NAME}:WARN $@" >&2; } 49 | th_error() { echo "${MY_NAME}:ERROR $@" >&2; } 50 | th_fatal() { echo "${MY_NAME}:FATAL $@" >&2; } 51 | 52 | # output subtest name 53 | th_subtest() { echo " $@" >&2; } 54 | 55 | # generate a random number 56 | th_generateRandom() 57 | { 58 | tfgr_random=${th_RANDOM} 59 | 60 | while [ "${tfgr_random}" = "${th_RANDOM}" ]; do 61 | if [ -n "${RANDOM:-}" ]; then 62 | # $RANDOM works 63 | tfgr_random=${RANDOM}${RANDOM}${RANDOM}$$ 64 | elif [ -r '/dev/urandom' ]; then 65 | tfgr_random=`od -vAn -N4 -tu4 "${stdoutF}" 2>"${stderrF}" ) 24 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 25 | rtrn=$? 26 | assertTrue '_ASSERT_EQUALS_ failure' ${rtrn} 27 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 28 | 29 | ( ${_ASSERT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 30 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 31 | rtrn=$? 32 | assertTrue '_ASSERT_EQUALS_ w/ msg failure' ${rtrn} 33 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 34 | } 35 | 36 | testAssertNotEquals() 37 | { 38 | # start skipping if LINENO not available 39 | [ -z "${LINENO:-}" ] && startSkipping 40 | 41 | ( ${_ASSERT_NOT_EQUALS_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 42 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 43 | rtrn=$? 44 | assertTrue '_ASSERT_NOT_EQUALS_ failure' ${rtrn} 45 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 46 | 47 | ( ${_ASSERT_NOT_EQUALS_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 48 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 49 | rtrn=$? 50 | assertTrue '_ASSERT_NOT_EQUALS_ w/ msg failure' ${rtrn} 51 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 52 | } 53 | 54 | testSame() 55 | { 56 | # start skipping if LINENO not available 57 | [ -z "${LINENO:-}" ] && startSkipping 58 | 59 | ( ${_ASSERT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 60 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 61 | rtrn=$? 62 | assertTrue '_ASSERT_SAME_ failure' ${rtrn} 63 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 64 | 65 | ( ${_ASSERT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 66 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 67 | rtrn=$? 68 | assertTrue '_ASSERT_SAME_ w/ msg failure' ${rtrn} 69 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 70 | } 71 | 72 | testNotSame() 73 | { 74 | # start skipping if LINENO not available 75 | [ -z "${LINENO:-}" ] && startSkipping 76 | 77 | ( ${_ASSERT_NOT_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 78 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 79 | rtrn=$? 80 | assertTrue '_ASSERT_NOT_SAME_ failure' ${rtrn} 81 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 82 | 83 | ( ${_ASSERT_NOT_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 84 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 85 | rtrn=$? 86 | assertTrue '_ASSERT_NOT_SAME_ w/ msg failure' ${rtrn} 87 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 88 | } 89 | 90 | testNull() 91 | { 92 | # start skipping if LINENO not available 93 | [ -z "${LINENO:-}" ] && startSkipping 94 | 95 | ( ${_ASSERT_NULL_} 'x' >"${stdoutF}" 2>"${stderrF}" ) 96 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 97 | rtrn=$? 98 | assertTrue '_ASSERT_NULL_ failure' ${rtrn} 99 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 100 | 101 | ( ${_ASSERT_NULL_} '"some msg"' 'x' >"${stdoutF}" 2>"${stderrF}" ) 102 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 103 | rtrn=$? 104 | assertTrue '_ASSERT_NULL_ w/ msg failure' ${rtrn} 105 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 106 | } 107 | 108 | testNotNull() 109 | { 110 | # start skipping if LINENO not available 111 | [ -z "${LINENO:-}" ] && startSkipping 112 | 113 | ( ${_ASSERT_NOT_NULL_} '' >"${stdoutF}" 2>"${stderrF}" ) 114 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 115 | rtrn=$? 116 | assertTrue '_ASSERT_NOT_NULL_ failure' ${rtrn} 117 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 118 | 119 | ( ${_ASSERT_NOT_NULL_} '"some msg"' '""' >"${stdoutF}" 2>"${stderrF}" ) 120 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 121 | rtrn=$? 122 | assertTrue '_ASSERT_NOT_NULL_ w/ msg failure' ${rtrn} 123 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stdoutF}" "${stderrF}" >&2 124 | } 125 | 126 | testAssertTrue() 127 | { 128 | # start skipping if LINENO not available 129 | [ -z "${LINENO:-}" ] && startSkipping 130 | 131 | ( ${_ASSERT_TRUE_} ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) 132 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 133 | rtrn=$? 134 | assertTrue '_ASSERT_TRUE_ failure' ${rtrn} 135 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 136 | 137 | 138 | ( ${_ASSERT_TRUE_} '"some msg"' ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) 139 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 140 | rtrn=$? 141 | assertTrue '_ASSERT_TRUE_ w/ msg failure' ${rtrn} 142 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 143 | } 144 | 145 | testAssertFalse() 146 | { 147 | # start skipping if LINENO not available 148 | [ -z "${LINENO:-}" ] && startSkipping 149 | 150 | ( ${_ASSERT_FALSE_} ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) 151 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 152 | rtrn=$? 153 | assertTrue '_ASSERT_FALSE_ failure' ${rtrn} 154 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 155 | 156 | ( ${_ASSERT_FALSE_} '"some msg"' ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) 157 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 158 | rtrn=$? 159 | assertTrue '_ASSERT_FALSE_ w/ msg failure' ${rtrn} 160 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 161 | } 162 | 163 | testFail() 164 | { 165 | # start skipping if LINENO not available 166 | [ -z "${LINENO:-}" ] && startSkipping 167 | 168 | ( ${_FAIL_} >"${stdoutF}" 2>"${stderrF}" ) 169 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 170 | rtrn=$? 171 | assertTrue '_FAIL_ failure' ${rtrn} 172 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 173 | 174 | ( ${_FAIL_} '"some msg"' >"${stdoutF}" 2>"${stderrF}" ) 175 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 176 | rtrn=$? 177 | assertTrue '_FAIL_ w/ msg failure' ${rtrn} 178 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 179 | } 180 | 181 | testFailNotEquals() 182 | { 183 | # start skipping if LINENO not available 184 | [ -z "${LINENO:-}" ] && startSkipping 185 | 186 | ( ${_FAIL_NOT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 187 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 188 | rtrn=$? 189 | assertTrue '_FAIL_NOT_EQUALS_ failure' ${rtrn} 190 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 191 | 192 | ( ${_FAIL_NOT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 193 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 194 | rtrn=$? 195 | assertTrue '_FAIL_NOT_EQUALS_ w/ msg failure' ${rtrn} 196 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 197 | } 198 | 199 | testFailSame() 200 | { 201 | # start skipping if LINENO not available 202 | [ -z "${LINENO:-}" ] && startSkipping 203 | 204 | ( ${_FAIL_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 205 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 206 | rtrn=$? 207 | assertTrue '_FAIL_SAME_ failure' ${rtrn} 208 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 209 | 210 | ( ${_FAIL_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) 211 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 212 | rtrn=$? 213 | assertTrue '_FAIL_SAME_ w/ msg failure' ${rtrn} 214 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 215 | } 216 | 217 | testFailNotSame() 218 | { 219 | # start skipping if LINENO not available 220 | [ -z "${LINENO:-}" ] && startSkipping 221 | 222 | ( ${_FAIL_NOT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 223 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 224 | rtrn=$? 225 | assertTrue '_FAIL_NOT_SAME_ failure' ${rtrn} 226 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 227 | 228 | ( ${_FAIL_NOT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) 229 | grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null 230 | rtrn=$? 231 | assertTrue '_FAIL_NOT_SAME_ w/ msg failure' ${rtrn} 232 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 233 | } 234 | 235 | #------------------------------------------------------------------------------ 236 | # suite functions 237 | # 238 | 239 | oneTimeSetUp() 240 | { 241 | tmpDir="${__shunit_tmpDir}/output" 242 | mkdir "${tmpDir}" 243 | stdoutF="${tmpDir}/stdout" 244 | stderrF="${tmpDir}/stderr" 245 | } 246 | 247 | # load and run shUnit2 248 | [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 249 | . ${TH_SHUNIT} 250 | -------------------------------------------------------------------------------- /shunit/shunit2_test_misc.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2_test_misc.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2008 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # 8 | # Author: kate.ward@forestent.com (Kate Ward) 9 | # 10 | # shUnit2 unit tests of miscellaneous things 11 | 12 | # load test helpers 13 | . ./shunit2_test_helpers 14 | 15 | #------------------------------------------------------------------------------ 16 | # suite tests 17 | # 18 | 19 | # Note: the test script is prefixed with '#' chars so that shUnit2 does not 20 | # incorrectly interpret the embedded functions as real functions. 21 | testUnboundVariable() 22 | { 23 | sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) 37 | assertFalse 'expected a non-zero exit value' $? 38 | grep '^ASSERT:Unknown failure' "${stdoutF}" >/dev/null 39 | assertTrue 'assert message was not generated' $? 40 | grep '^Ran [0-9]* test' "${stdoutF}" >/dev/null 41 | assertTrue 'test count message was not generated' $? 42 | grep '^FAILED' "${stdoutF}" >/dev/null 43 | assertTrue 'failure message was not generated' $? 44 | } 45 | 46 | testIssue7() 47 | { 48 | ( assertEquals 'Some message.' 1 2 >"${stdoutF}" 2>"${stderrF}" ) 49 | diff "${stdoutF}" - >/dev/null < but was:<2> 51 | EOF 52 | rtrn=$? 53 | assertEquals ${SHUNIT_TRUE} ${rtrn} 54 | [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 55 | } 56 | 57 | testPrepForSourcing() 58 | { 59 | assertEquals '/abc' `_shunit_prepForSourcing '/abc'` 60 | assertEquals './abc' `_shunit_prepForSourcing './abc'` 61 | assertEquals './abc' `_shunit_prepForSourcing 'abc'` 62 | } 63 | 64 | testEscapeCharInStr() 65 | { 66 | actual=`_shunit_escapeCharInStr '\' ''` 67 | assertEquals '' "${actual}" 68 | assertEquals 'abc\\' `_shunit_escapeCharInStr '\' 'abc\'` 69 | assertEquals 'abc\\def' `_shunit_escapeCharInStr '\' 'abc\def'` 70 | assertEquals '\\def' `_shunit_escapeCharInStr '\' '\def'` 71 | 72 | actual=`_shunit_escapeCharInStr '"' ''` 73 | assertEquals '' "${actual}" 74 | assertEquals 'abc\"' `_shunit_escapeCharInStr '"' 'abc"'` 75 | assertEquals 'abc\"def' `_shunit_escapeCharInStr '"' 'abc"def'` 76 | assertEquals '\"def' `_shunit_escapeCharInStr '"' '"def'` 77 | 78 | actual=`_shunit_escapeCharInStr '$' ''` 79 | assertEquals '' "${actual}" 80 | assertEquals 'abc\$' `_shunit_escapeCharInStr '$' 'abc$'` 81 | assertEquals 'abc\$def' `_shunit_escapeCharInStr '$' 'abc$def'` 82 | assertEquals '\$def' `_shunit_escapeCharInStr '$' '$def'` 83 | 84 | # actual=`_shunit_escapeCharInStr "'" ''` 85 | # assertEquals '' "${actual}" 86 | # assertEquals "abc\\'" `_shunit_escapeCharInStr "'" "abc'"` 87 | # assertEquals "abc\\'def" `_shunit_escapeCharInStr "'" "abc'def"` 88 | # assertEquals "\\'def" `_shunit_escapeCharInStr "'" "'def"` 89 | 90 | # # must put the backtick in a variable so the shell doesn't misinterpret it 91 | # # while inside a backticked sequence (e.g. `echo '`'` would fail). 92 | # backtick='`' 93 | # actual=`_shunit_escapeCharInStr ${backtick} ''` 94 | # assertEquals '' "${actual}" 95 | # assertEquals '\`abc' \ 96 | # `_shunit_escapeCharInStr "${backtick}" ${backtick}'abc'` 97 | # assertEquals 'abc\`' \ 98 | # `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}` 99 | # assertEquals 'abc\`def' \ 100 | # `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}'def'` 101 | } 102 | 103 | testEscapeCharInStr_specialChars() 104 | { 105 | # make sure our forward slash doesn't upset sed 106 | assertEquals '/' `_shunit_escapeCharInStr '\' '/'` 107 | 108 | # some shells escape these differently 109 | #assertEquals '\\a' `_shunit_escapeCharInStr '\' '\a'` 110 | #assertEquals '\\b' `_shunit_escapeCharInStr '\' '\b'` 111 | } 112 | 113 | # Test the various ways of declaring functions. 114 | # 115 | # Prefixing (then stripping) with comment symbol so these functions aren't 116 | # treated as real functions by shUnit2. 117 | testExtractTestFunctions() 118 | { 119 | f="${tmpD}/extract_test_functions" 120 | sed 's/^#//' <"${f}" 121 | #testABC() { echo 'ABC'; } 122 | #test_def() { 123 | # echo 'def' 124 | #} 125 | #testG3 () 126 | #{ 127 | # echo 'G3' 128 | #} 129 | #function test4() { echo '4'; } 130 | # test5() { echo '5'; } 131 | #some_test_function() { echo 'some func'; } 132 | #func_with_test_vars() { 133 | # testVariable=1234 134 | #} 135 | EOF 136 | 137 | actual=`_shunit_extractTestFunctions "${f}"` 138 | assertEquals 'testABC test_def testG3 test4 test5' "${actual}" 139 | } 140 | 141 | #------------------------------------------------------------------------------ 142 | # suite functions 143 | # 144 | 145 | setUp() 146 | { 147 | for f in ${expectedF} ${stdoutF} ${stderrF}; do 148 | cp /dev/null ${f} 149 | done 150 | rm -fr "${tmpD}" 151 | mkdir "${tmpD}" 152 | } 153 | 154 | oneTimeSetUp() 155 | { 156 | tmpD="${SHUNIT_TMPDIR}/tmp" 157 | expectedF="${SHUNIT_TMPDIR}/expected" 158 | stdoutF="${SHUNIT_TMPDIR}/stdout" 159 | stderrF="${SHUNIT_TMPDIR}/stderr" 160 | unittestF="${SHUNIT_TMPDIR}/unittest" 161 | } 162 | 163 | # load and run shUnit2 164 | [ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 165 | . ${TH_SHUNIT} 166 | -------------------------------------------------------------------------------- /shunit/shunit2_test_standalone.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # $Id: shunit2_test_standalone.sh 303 2010-05-03 13:11:27Z kate.ward@forestent.com $ 3 | # vim:et:ft=sh:sts=2:sw=2 4 | # 5 | # Copyright 2010 Kate Ward. All Rights Reserved. 6 | # Released under the LGPL (GNU Lesser General Public License) 7 | # Author: kate.ward@forestent.com (Kate Ward) 8 | # 9 | # shUnit2 unit test for standalone operation. 10 | # 11 | # This unit test is purely to test that calling shunit2 directly, while passing 12 | # the name of a unit test script, works. When run, this script determines if it 13 | # is running as a standalone program, and calls main() if it is. 14 | 15 | ARGV0=`basename "$0"` 16 | 17 | # load test helpers 18 | . ./shunit2_test_helpers 19 | 20 | #------------------------------------------------------------------------------ 21 | # suite tests 22 | # 23 | 24 | testStandalone() 25 | { 26 | assertTrue ${SHUNIT_TRUE} 27 | } 28 | 29 | #------------------------------------------------------------------------------ 30 | # main 31 | # 32 | 33 | main() 34 | { 35 | ${TH_SHUNIT} "${ARGV0}" 36 | } 37 | 38 | # are we running as a standalone? 39 | if [ "${ARGV0}" = 'shunit2_test_standalone.sh' ]; then 40 | if [ $# -gt 0 ]; then main "$@"; else main; fi 41 | fi 42 | -------------------------------------------------------------------------------- /test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ./test-radar-base.sh 4 | ./test-directories.sh 5 | ./test-commits.sh 6 | ./test-branches.sh 7 | ./test-files.sh 8 | ./test-status.sh 9 | ./test-stash.sh 10 | ./test-colors.sh 11 | ./test-format-config.sh 12 | -------------------------------------------------------------------------------- /test-branches.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | tmpfile="" 6 | 7 | cd_to_tmp() { 8 | tmpfile="/tmp/git-prompt-tests-$(time_now)" 9 | mkdir -p "$tmpfile" 10 | cd "$tmpfile" 11 | } 12 | 13 | rm_tmp() { 14 | cd $scriptDir 15 | rm -rf /tmp/git-prompt-tests* 16 | } 17 | 18 | test_branch_name_in_repo() { 19 | cd_to_tmp 20 | git init --quiet 21 | git checkout -b foo --quiet 22 | assertEquals "foo" "$(branch_name)" 23 | 24 | git checkout -b bar --quiet 25 | assertEquals "bar" "$(branch_name)" 26 | 27 | git checkout -b baz --quiet 28 | assertEquals "baz" "$(branch_name)" 29 | 30 | rm_tmp 31 | } 32 | 33 | test_branch_name_not_in_repo() { 34 | cd_to_tmp 35 | assertEquals "" "$(branch_name)" 36 | rm_tmp 37 | } 38 | 39 | test_detached_from_branch() { 40 | cd_to_tmp 41 | git init --quiet 42 | assertEquals "master" "$(branch_name)" 43 | 44 | touch README 45 | git add . 46 | git commit -m "initial commit" --quiet 47 | 48 | touch foo 49 | git add . 50 | git commit -m "foo" --quiet 51 | 52 | git checkout --quiet HEAD^ >/dev/null 53 | sha="$(commit_short_sha)" 54 | 55 | assertNotEquals "master" "$(branch_name)" 56 | assertEquals "$sha" "$(branch_ref)" 57 | assertEquals "detached@$sha" "$(zsh_readable_branch_name)" 58 | assertEquals "detached@$sha" "$(bash_readable_branch_name)" 59 | assertEquals "detached@$sha" "$(readable_branch_name)" 60 | 61 | rm_tmp 62 | } 63 | 64 | test_branch_name_returns_error() { 65 | cd_to_tmp 66 | git init --quiet 67 | 68 | touch README 69 | git add . 70 | git commit -m "initial commit" --quiet 71 | 72 | touch foo 73 | git add . 74 | git commit -m "foo" --quiet 75 | 76 | git checkout --quiet HEAD^ >/dev/null 77 | 78 | retcode="$(branch_name; echo $?)" 79 | assertEquals "1" "$retcode" 80 | rm_tmp 81 | } 82 | 83 | test_remote_branch_name_quiet_when_not_in_repo() { 84 | cd_to_tmp 85 | 86 | debug_output="$( 87 | { 88 | output="$( 89 | remote_branch_name; 90 | )" 91 | } 2>&1 92 | echo "$output" 93 | )" 94 | 95 | usages="$(echo "$debug_output" | grep -E "(usage|fatal):" | wc -l)" 96 | 97 | echo "$debug_output" 98 | 99 | assertEquals " 0" "$usages" 100 | 101 | rm_tmp 102 | } 103 | 104 | . ./shunit/shunit2 105 | -------------------------------------------------------------------------------- /test-colors.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | cd_to_tmp() { 6 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 7 | mkdir -p "$tmpfile" 8 | cd "$tmpfile" 9 | } 10 | 11 | rm_tmp() { 12 | cd $scriptDir 13 | rm -rf /tmp/git-prompt-tests* 14 | } 15 | 16 | mock_zsh_colors() { 17 | fg_bold[green]=1 18 | fg_bold[red]=2 19 | fg_bold[yellow]=3 20 | fg_bold[white]=4 21 | 22 | reset_color=0 23 | } 24 | 25 | test_no_rcfile_bash() { 26 | reset_env_vars 27 | prepare_bash_colors 28 | 29 | assertEquals "$COLOR_REMOTE_AHEAD" "\x01\033[1;32m\x02" 30 | assertEquals "$COLOR_REMOTE_BEHIND" "\x01\033[1;31m\x02" 31 | assertEquals "$COLOR_REMOTE_DIVERGED" "\x01\033[1;33m\x02" 32 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "\x01\033[1;31m\x02" 33 | 34 | assertEquals "$COLOR_LOCAL_AHEAD" "\x01\033[1;32m\x02" 35 | assertEquals "$COLOR_LOCAL_BEHIND" "\x01\033[1;31m\x02" 36 | assertEquals "$COLOR_LOCAL_DIVERGED" "\x01\033[1;33m\x02" 37 | 38 | assertEquals "$COLOR_CHANGES_STAGED" "\x01\033[1;32m\x02" 39 | assertEquals "$COLOR_CHANGES_UNSTAGED" "\x01\033[1;31m\x02" 40 | assertEquals "$COLOR_CHANGES_CONFLICTED" "\x01\033[1;33m\x02" 41 | assertEquals "$COLOR_CHANGES_UNTRACKED" "\x01\033[1;37m\x02" 42 | 43 | assertEquals "$RESET_COLOR_LOCAL" "\x01\033[0m\x02" 44 | assertEquals "$RESET_COLOR_REMOTE" "\x01\033[0m\x02" 45 | assertEquals "$RESET_COLOR_CHANGES" "\x01\033[0m\x02" 46 | } 47 | 48 | test_no_rcfile_zsh() { 49 | reset_env_vars 50 | mock_zsh_colors 51 | prepare_zsh_colors 52 | 53 | assertEquals "$COLOR_REMOTE_AHEAD" "%{$fg_bold[green]%}" 54 | assertEquals "$COLOR_REMOTE_BEHIND" "%{$fg_bold[red]%}" 55 | assertEquals "$COLOR_REMOTE_DIVERGED" "%{$fg_bold[yellow]%}" 56 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "%{$fg_bold[red]%}" 57 | 58 | assertEquals "$COLOR_LOCAL_AHEAD" "%{$fg_bold[green]%}" 59 | assertEquals "$COLOR_LOCAL_BEHIND" "%{$fg_bold[red]%}" 60 | assertEquals "$COLOR_LOCAL_DIVERGED" "%{$fg_bold[yellow]%}" 61 | 62 | assertEquals "$COLOR_CHANGES_STAGED" "%{$fg_bold[green]%}" 63 | assertEquals "$COLOR_CHANGES_UNSTAGED" "%{$fg_bold[red]%}" 64 | assertEquals "$COLOR_CHANGES_CONFLICTED" "%{$fg_bold[yellow]%}" 65 | assertEquals "$COLOR_CHANGES_UNTRACKED" "%{$fg_bold[white]%}" 66 | 67 | assertEquals "$RESET_COLOR_LOCAL" "%{$reset_color%}" 68 | assertEquals "$RESET_COLOR_REMOTE" "%{$reset_color%}" 69 | assertEquals "$RESET_COLOR_CHANGES" "%{$reset_color%}" 70 | } 71 | 72 | set_env_vars() { 73 | export GIT_RADAR_COLOR_REMOTE_AHEAD="remote-ahead" 74 | export GIT_RADAR_COLOR_REMOTE_BEHIND="remote-behind" 75 | export GIT_RADAR_COLOR_REMOTE_DIVERGED="remote-diverged" 76 | export GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM="not-upstream" 77 | 78 | export GIT_RADAR_COLOR_LOCAL_AHEAD="local-ahead" 79 | export GIT_RADAR_COLOR_LOCAL_BEHIND="local-behind" 80 | export GIT_RADAR_COLOR_LOCAL_DIVERGED="local-diverged" 81 | 82 | export GIT_RADAR_COLOR_CHANGES_STAGED="changes-staged" 83 | export GIT_RADAR_COLOR_CHANGES_UNSTAGED="changes-unstaged" 84 | export GIT_RADAR_COLOR_CHANGES_CONFLICTED="changes-conflicted" 85 | export GIT_RADAR_COLOR_CHANGES_UNTRACKED="changes-untracked" 86 | 87 | export GIT_RADAR_COLOR_BRANCH="branch-color" 88 | export GIT_RADAR_MASTER_SYMBOL="m" 89 | 90 | export GIT_RADAR_COLOR_LOCAL_RESET="local-reset" 91 | export GIT_RADAR_COLOR_REMOTE_RESET="remote-reset" 92 | export GIT_RADAR_COLOR_CHANGES_RESET="change-reset" 93 | export GIT_RADAR_COLOR_BRANCH_RESET="branch-reset" 94 | } 95 | 96 | reset_env_vars() { 97 | export GIT_RADAR_COLOR_REMOTE_AHEAD="" 98 | export GIT_RADAR_COLOR_REMOTE_BEHIND="" 99 | export GIT_RADAR_COLOR_REMOTE_DIVERGED="" 100 | export GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM="" 101 | 102 | export GIT_RADAR_COLOR_LOCAL_AHEAD="" 103 | export GIT_RADAR_COLOR_LOCAL_BEHIND="" 104 | export GIT_RADAR_COLOR_LOCAL_DIVERGED="" 105 | 106 | export GIT_RADAR_COLOR_CHANGES_STAGED="" 107 | export GIT_RADAR_COLOR_CHANGES_UNSTAGED="" 108 | export GIT_RADAR_COLOR_CHANGES_CONFLICTED="" 109 | export GIT_RADAR_COLOR_CHANGES_UNTRACKED="" 110 | 111 | export GIT_RADAR_COLOR_BRANCH="" 112 | export GIT_RADAR_MASTER_SYMBOL="" 113 | 114 | export GIT_RADAR_COLOR_LOCAL_RESET="" 115 | export GIT_RADAR_COLOR_REMOTE_RESET="" 116 | export GIT_RADAR_COLOR_CHANGES_RESET="" 117 | export GIT_RADAR_COLOR_BRANCH_RESET="" 118 | } 119 | 120 | create_rc_file() { 121 | echo 'GIT_RADAR_COLOR_REMOTE_AHEAD="remote-ahead"' >> .gitradarrc$1 122 | echo 'GIT_RADAR_COLOR_REMOTE_BEHIND="remote-behind"' >> .gitradarrc$1 123 | echo 'GIT_RADAR_COLOR_REMOTE_DIVERGED="remote-diverged"' >> .gitradarrc$1 124 | echo 'GIT_RADAR_COLOR_REMOTE_NOT_UPSTREAM="not-upstream"' >> .gitradarrc$1 125 | 126 | echo 'GIT_RADAR_COLOR_LOCAL_AHEAD="local-ahead"' >> .gitradarrc$1 127 | echo 'GIT_RADAR_COLOR_LOCAL_BEHIND="local-behind"' >> .gitradarrc$1 128 | echo 'GIT_RADAR_COLOR_LOCAL_DIVERGED="local-diverged"' >> .gitradarrc$1 129 | 130 | echo 'GIT_RADAR_COLOR_CHANGES_STAGED="changes-staged"' >> .gitradarrc$1 131 | echo 'GIT_RADAR_COLOR_CHANGES_UNSTAGED="changes-unstaged"' >> .gitradarrc$1 132 | echo 'GIT_RADAR_COLOR_CHANGES_CONFLICTED="changes-conflicted"' >> .gitradarrc$1 133 | echo 'GIT_RADAR_COLOR_CHANGES_UNTRACKED="changes-untracked"' >> .gitradarrc$1 134 | 135 | echo 'export GIT_RADAR_COLOR_BRANCH="branch-color"' >> .gitradarrc$1 136 | echo 'export GIT_RADAR_MASTER_SYMBOL="m"' >> .gitradarrc$1 137 | 138 | echo 'GIT_RADAR_COLOR_LOCAL_RESET="local-reset"' >> .gitradarrc$1 139 | echo 'GIT_RADAR_COLOR_REMOTE_RESET="remote-reset"' >> .gitradarrc$1 140 | echo 'GIT_RADAR_COLOR_CHANGES_RESET="change-reset"' >> .gitradarrc$1 141 | echo 'GIT_RADAR_COLOR_BRANCH_RESET="branch-reset"' >> .gitradarrc$1 142 | } 143 | 144 | test_with_rcfile_bash() { 145 | reset_env_vars 146 | cd_to_tmp 147 | 148 | rcfile_path="$(pwd)" 149 | 150 | create_rc_file ".bash" 151 | prepare_bash_colors 152 | 153 | assertEquals "$COLOR_REMOTE_AHEAD" "\x01remote-ahead\x02" 154 | assertEquals "$COLOR_REMOTE_BEHIND" "\x01remote-behind\x02" 155 | assertEquals "$COLOR_REMOTE_DIVERGED" "\x01remote-diverged\x02" 156 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "\x01not-upstream\x02" 157 | 158 | assertEquals "$COLOR_LOCAL_AHEAD" "\x01local-ahead\x02" 159 | assertEquals "$COLOR_LOCAL_BEHIND" "\x01local-behind\x02" 160 | assertEquals "$COLOR_LOCAL_DIVERGED" "\x01local-diverged\x02" 161 | 162 | assertEquals "$COLOR_CHANGES_STAGED" "\x01changes-staged\x02" 163 | assertEquals "$COLOR_CHANGES_UNSTAGED" "\x01changes-unstaged\x02" 164 | assertEquals "$COLOR_CHANGES_CONFLICTED" "\x01changes-conflicted\x02" 165 | assertEquals "$COLOR_CHANGES_UNTRACKED" "\x01changes-untracked\x02" 166 | 167 | assertEquals "$COLOR_BRANCH" "\x01branch-color\x02" 168 | assertEquals "$MASTER_SYMBOL" "m" 169 | 170 | assertEquals "$RESET_COLOR_LOCAL" "\x01local-reset\x02" 171 | assertEquals "$RESET_COLOR_REMOTE" "\x01remote-reset\x02" 172 | assertEquals "$RESET_COLOR_CHANGES" "\x01change-reset\x02" 173 | assertEquals "$RESET_COLOR_BRANCH" "\x01branch-reset\x02" 174 | 175 | rm_tmp 176 | } 177 | 178 | test_with_rcfile_zsh() { 179 | reset_env_vars 180 | cd_to_tmp 181 | 182 | rcfile_path="$(pwd)" 183 | 184 | create_rc_file ".zsh" 185 | mock_zsh_colors 186 | prepare_zsh_colors 187 | 188 | assertEquals "$COLOR_REMOTE_AHEAD" "%{remote-ahead%}" 189 | assertEquals "$COLOR_REMOTE_BEHIND" "%{remote-behind%}" 190 | assertEquals "$COLOR_REMOTE_DIVERGED" "%{remote-diverged%}" 191 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "%{not-upstream%}" 192 | 193 | assertEquals "$COLOR_LOCAL_AHEAD" "%{local-ahead%}" 194 | assertEquals "$COLOR_LOCAL_BEHIND" "%{local-behind%}" 195 | assertEquals "$COLOR_LOCAL_DIVERGED" "%{local-diverged%}" 196 | 197 | assertEquals "$COLOR_CHANGES_STAGED" "%{changes-staged%}" 198 | assertEquals "$COLOR_CHANGES_UNSTAGED" "%{changes-unstaged%}" 199 | assertEquals "$COLOR_CHANGES_CONFLICTED" "%{changes-conflicted%}" 200 | assertEquals "$COLOR_CHANGES_UNTRACKED" "%{changes-untracked%}" 201 | 202 | assertEquals "$COLOR_BRANCH" "%{branch-color%}" 203 | assertEquals "$MASTER_SYMBOL" "m" 204 | 205 | assertEquals "$RESET_COLOR_LOCAL" "%{local-reset%}" 206 | assertEquals "$RESET_COLOR_REMOTE" "%{remote-reset%}" 207 | assertEquals "$RESET_COLOR_CHANGES" "%{change-reset%}" 208 | assertEquals "$RESET_COLOR_BRANCH" "%{branch-reset%}" 209 | 210 | rm_tmp 211 | } 212 | 213 | test_with_env_vars_bash() { 214 | reset_env_vars 215 | set_env_vars 216 | prepare_bash_colors 217 | 218 | assertEquals "$COLOR_REMOTE_AHEAD" "\x01remote-ahead\x02" 219 | assertEquals "$COLOR_REMOTE_BEHIND" "\x01remote-behind\x02" 220 | assertEquals "$COLOR_REMOTE_DIVERGED" "\x01remote-diverged\x02" 221 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "\x01not-upstream\x02" 222 | 223 | assertEquals "$COLOR_LOCAL_AHEAD" "\x01local-ahead\x02" 224 | assertEquals "$COLOR_LOCAL_BEHIND" "\x01local-behind\x02" 225 | assertEquals "$COLOR_LOCAL_DIVERGED" "\x01local-diverged\x02" 226 | 227 | assertEquals "$COLOR_CHANGES_STAGED" "\x01changes-staged\x02" 228 | assertEquals "$COLOR_CHANGES_UNSTAGED" "\x01changes-unstaged\x02" 229 | assertEquals "$COLOR_CHANGES_CONFLICTED" "\x01changes-conflicted\x02" 230 | assertEquals "$COLOR_CHANGES_UNTRACKED" "\x01changes-untracked\x02" 231 | 232 | assertEquals "$COLOR_BRANCH" "\x01branch-color\x02" 233 | assertEquals "$MASTER_SYMBOL" "m" 234 | 235 | assertEquals "$RESET_COLOR_LOCAL" "\x01local-reset\x02" 236 | assertEquals "$RESET_COLOR_REMOTE" "\x01remote-reset\x02" 237 | assertEquals "$RESET_COLOR_CHANGES" "\x01change-reset\x02" 238 | assertEquals "$RESET_COLOR_BRANCH" "\x01branch-reset\x02" 239 | } 240 | 241 | test_with_env_vars_zsh() { 242 | reset_env_vars 243 | set_env_vars 244 | mock_zsh_colors 245 | prepare_zsh_colors 246 | 247 | assertEquals "$COLOR_REMOTE_AHEAD" "%{remote-ahead%}" 248 | assertEquals "$COLOR_REMOTE_BEHIND" "%{remote-behind%}" 249 | assertEquals "$COLOR_REMOTE_DIVERGED" "%{remote-diverged%}" 250 | assertEquals "$COLOR_REMOTE_NOT_UPSTREAM" "%{not-upstream%}" 251 | 252 | assertEquals "$COLOR_LOCAL_AHEAD" "%{local-ahead%}" 253 | assertEquals "$COLOR_LOCAL_BEHIND" "%{local-behind%}" 254 | assertEquals "$COLOR_LOCAL_DIVERGED" "%{local-diverged%}" 255 | 256 | assertEquals "$COLOR_CHANGES_STAGED" "%{changes-staged%}" 257 | assertEquals "$COLOR_CHANGES_UNSTAGED" "%{changes-unstaged%}" 258 | assertEquals "$COLOR_CHANGES_CONFLICTED" "%{changes-conflicted%}" 259 | assertEquals "$COLOR_CHANGES_UNTRACKED" "%{changes-untracked%}" 260 | 261 | assertEquals "$COLOR_BRANCH" "%{branch-color%}" 262 | assertEquals "$MASTER_SYMBOL" "m" 263 | 264 | assertEquals "$RESET_COLOR_LOCAL" "%{local-reset%}" 265 | assertEquals "$RESET_COLOR_REMOTE" "%{remote-reset%}" 266 | assertEquals "$RESET_COLOR_CHANGES" "%{change-reset%}" 267 | assertEquals "$RESET_COLOR_BRANCH" "%{branch-reset%}" 268 | } 269 | 270 | test_bash_colors_local() { 271 | reset_env_vars 272 | set_env_vars 273 | prepare_bash_colors 274 | 275 | cd_to_tmp "remote" 276 | git init --bare --quiet 277 | remoteLocation="$(pwd)" 278 | 279 | cd_to_tmp "repo" 280 | git init --quiet 281 | git remote add origin $remoteLocation 282 | git fetch origin --quiet 283 | git checkout -b master --quiet 284 | touch README 285 | git add README 286 | git commit -m "initial commit" --quiet 287 | git push --quiet -u origin master >/dev/null 288 | repoLocation="$(pwd)" 289 | 290 | echo "foo" > foo 291 | git add . 292 | git commit -m "test commit" --quiet 293 | 294 | printf -v expected "1\x01local-ahead\x02↑\x01local-reset\x02" 295 | assertEquals "$expected" "$(bash_color_local_commits)" 296 | assertEquals "$expected" "$(color_local_commits)" 297 | 298 | git push --quiet >/dev/null 299 | git reset --hard head^ --quiet >/dev/null 300 | 301 | printf -v expected "1\x01local-behind\x02↓\x01local-reset\x02" 302 | assertEquals "$expected" "$(bash_color_local_commits)" 303 | assertEquals "$expected" "$(color_local_commits)" 304 | 305 | echo "foo" > foo 306 | git add . 307 | git commit -m "new commit" --quiet 308 | 309 | printf -v expected "1\x01local-diverged\x02⇵\x01local-reset\x021" 310 | assertEquals "$expected" "$(bash_color_local_commits)" 311 | assertEquals "$expected" "$(color_local_commits)" 312 | 313 | rm_tmp 314 | } 315 | 316 | test_zsh_colors_local() { 317 | reset_env_vars 318 | set_env_vars 319 | prepare_zsh_colors 320 | 321 | cd_to_tmp "remote" 322 | git init --bare --quiet 323 | remoteLocation="$(pwd)" 324 | 325 | cd_to_tmp "repo" 326 | git init --quiet 327 | git remote add origin $remoteLocation 328 | git fetch origin --quiet 329 | git checkout -b master --quiet 330 | touch README 331 | git add README 332 | git commit -m "initial commit" --quiet 333 | git push --quiet -u origin master >/dev/null 334 | repoLocation="$(pwd)" 335 | 336 | echo "foo" > foo 337 | git add . 338 | git commit -m "test commit" --quiet 339 | 340 | assertEquals "1%{local-ahead%}↑%{local-reset%}" "$(zsh_color_local_commits)" 341 | 342 | git push --quiet >/dev/null 343 | git reset --hard head^ --quiet >/dev/null 344 | 345 | assertEquals "1%{local-behind%}↓%{local-reset%}" "$(zsh_color_local_commits)" 346 | 347 | echo "foo" > foo 348 | git add . 349 | git commit -m "new commit" --quiet 350 | 351 | assertEquals "1%{local-diverged%}⇵%{local-reset%}1" "$(zsh_color_local_commits)" 352 | 353 | rm_tmp 354 | } 355 | 356 | test_bash_colors_remote() { 357 | reset_env_vars 358 | set_env_vars 359 | prepare_bash_colors 360 | 361 | cd_to_tmp "remote" 362 | git init --bare --quiet 363 | remoteLocation="$(pwd)" 364 | 365 | cd_to_tmp "repo" 366 | git init --quiet 367 | git remote add origin $remoteLocation 368 | git fetch origin --quiet 369 | git checkout -b master --quiet 370 | touch README 371 | git add README 372 | git commit -m "initial commit" --quiet 373 | echo "foo" > foo 374 | git add . 375 | git commit -m "test commit" --quiet 376 | git push --quiet -u origin master >/dev/null 377 | repoLocation="$(pwd)" 378 | 379 | git reset --hard head^ --quiet >/dev/null 380 | git checkout -b mybranch --quiet 381 | git push --quiet -u origin mybranch >/dev/null 382 | 383 | printf -v expected "m 1 \x01remote-behind\x02→\x01remote-reset\x02" 384 | assertEquals "$expected" "$(bash_color_remote_commits)" 385 | assertEquals "$expected" "$(color_remote_commits)" 386 | 387 | echo "bar" > bar 388 | git add . 389 | git commit -m "new commit" --quiet 390 | git push --quiet >/dev/null 391 | 392 | printf -v expected "m 1 \x01remote-diverged\x02⇄\x01remote-reset\x02 1" 393 | assertEquals "$expected" "$(bash_color_remote_commits)" 394 | assertEquals "$expected" "$(color_remote_commits)" 395 | 396 | git pull origin master --quiet >/dev/null 397 | git push --quiet >/dev/null 398 | 399 | printf -v expected "m \x01remote-ahead\x02←\x01remote-reset\x02 2" 400 | assertEquals "$expected" "$(bash_color_remote_commits)" 401 | assertEquals "$expected" "$(color_remote_commits)" 402 | 403 | rm_tmp 404 | } 405 | 406 | test_zsh_colors_remote() { 407 | reset_env_vars 408 | set_env_vars 409 | prepare_zsh_colors 410 | 411 | cd_to_tmp "remote" 412 | git init --bare --quiet 413 | remoteLocation="$(pwd)" 414 | 415 | cd_to_tmp "repo" 416 | git init --quiet 417 | git remote add origin $remoteLocation 418 | git fetch origin --quiet 419 | git checkout -b master --quiet 420 | touch README 421 | git add README 422 | git commit -m "initial commit" --quiet 423 | echo "foo" > foo 424 | git add . 425 | git commit -m "test commit" --quiet 426 | git push --quiet -u origin master >/dev/null 427 | repoLocation="$(pwd)" 428 | 429 | git reset --hard head^ --quiet >/dev/null 430 | git checkout -b mybranch --quiet 431 | git push --quiet -u origin mybranch >/dev/null 432 | 433 | assertEquals "m 1 %{remote-behind%}→%{remote-reset%}" "$(zsh_color_remote_commits)" 434 | 435 | echo "bar" > bar 436 | git add . 437 | git commit -m "new commit" --quiet 438 | git push --quiet >/dev/null 439 | 440 | assertEquals "m 1 %{remote-diverged%}⇄%{remote-reset%} 1" "$(zsh_color_remote_commits)" 441 | 442 | git pull origin master --quiet >/dev/null 443 | git push --quiet >/dev/null 444 | 445 | assertEquals "m %{remote-ahead%}←%{remote-reset%} 2" "$(zsh_color_remote_commits)" 446 | 447 | rm_tmp 448 | } 449 | 450 | test_bash_colors_changes() { 451 | reset_env_vars 452 | set_env_vars 453 | prepare_bash_colors 454 | 455 | cd_to_tmp 456 | git init --quiet 457 | 458 | touch foo 459 | touch bar 460 | git add bar 461 | echo "bar" > bar 462 | untracked="1\x01changes-untracked\x02A\x01change-reset\x02" 463 | unstaged="1\x01changes-unstaged\x02M\x01change-reset\x02" 464 | staged="1\x01changes-staged\x02A\x01change-reset\x02" 465 | 466 | printf -v expected "$staged $unstaged $untracked" 467 | assertEquals "$expected" "$(bash_color_changes_status)" 468 | assertEquals "$expected" "$(color_changes_status)" 469 | rm_tmp 470 | } 471 | 472 | test_zsh_colors_changes() { 473 | reset_env_vars 474 | set_env_vars 475 | prepare_zsh_colors 476 | 477 | cd_to_tmp 478 | git init --quiet 479 | 480 | touch foo 481 | touch bar 482 | git add bar 483 | echo "bar" > bar 484 | untracked="1%{changes-untracked%}A%{change-reset%}" 485 | unstaged="1%{changes-unstaged%}M%{change-reset%}" 486 | staged="1%{changes-staged%}A%{change-reset%}" 487 | 488 | assertEquals "$staged $unstaged $untracked" "$(zsh_color_changes_status)" 489 | rm_tmp 490 | } 491 | 492 | . ./shunit/shunit2 493 | -------------------------------------------------------------------------------- /test-commits.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | tmpfile="" 6 | 7 | cd_to_tmp() { 8 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 9 | mkdir -p "$tmpfile" 10 | cd "$tmpfile" 11 | } 12 | 13 | rm_tmp() { 14 | cd $scriptDir 15 | rm -rf /tmp/git-prompt-tests* 16 | } 17 | 18 | test_commits_with_no_commits() { 19 | cd_to_tmp 20 | git init --quiet 21 | 22 | assertEquals "0" "$(commits_ahead_of_remote)" 23 | assertEquals "0" "$(commits_behind_of_remote)" 24 | 25 | rm_tmp 26 | } 27 | 28 | test_commits_behind_no_remote() { 29 | cd_to_tmp 30 | git init --quiet 31 | 32 | echo "foo" > foo 33 | git add . 34 | git commit -m "test commit" --quiet 35 | assertEquals "0" "$(commits_behind_of_remote)" 36 | 37 | rm_tmp 38 | } 39 | 40 | test_commits_ahead_no_remote() { 41 | cd_to_tmp 42 | git init --quiet 43 | 44 | echo "foo" > foo 45 | git add . 46 | git commit -m "test commit" --quiet 47 | assertEquals "0" "$(commits_ahead_of_remote)" 48 | 49 | echo "bar" > bar 50 | git add . 51 | git commit -m "test commit" --quiet 52 | assertEquals "0" "$(commits_ahead_of_remote)" 53 | 54 | rm_tmp 55 | } 56 | 57 | test_commits_ahead_with_remote() { 58 | cd_to_tmp "remote" 59 | git init --quiet 60 | touch README 61 | git add . 62 | git commit -m "initial commit" --quiet 63 | remoteLocation="$(pwd)" 64 | 65 | cd_to_tmp "new" 66 | git init --quiet 67 | git remote add origin $remoteLocation 68 | git fetch origin --quiet 69 | git checkout master --quiet 70 | repoLocation="$(pwd)" 71 | 72 | cd "$remoteLocation" 73 | echo "foo" > foo 74 | git add . 75 | git commit -m "test commit" --quiet 76 | cd "$repoLocation" 77 | git fetch origin --quiet 78 | assertEquals "1" "$(commits_ahead_of_remote)" 79 | 80 | cd "$remoteLocation" 81 | echo "bar" > bar 82 | git add . 83 | git commit -m "test commit" --quiet 84 | cd "$repoLocation" 85 | git fetch origin --quiet 86 | assertEquals "2" "$(commits_ahead_of_remote)" 87 | 88 | rm_tmp 89 | } 90 | 91 | test_commits_ahead_with_remote() { 92 | cd_to_tmp "remote" 93 | git init --quiet 94 | touch README 95 | git add . 96 | git commit -m "initial commit" --quiet 97 | remoteLocation="$(pwd)" 98 | 99 | cd_to_tmp "new" 100 | git init --quiet 101 | git remote add origin $remoteLocation 102 | git fetch origin --quiet 103 | git checkout master --quiet 104 | 105 | echo "foo" > foo 106 | git add . 107 | git commit -m "test commit" --quiet 108 | assertEquals "1" "$(commits_ahead_of_remote)" 109 | 110 | echo "bar" > bar 111 | git add . 112 | git commit -m "test commit" --quiet 113 | assertEquals "2" "$(commits_ahead_of_remote)" 114 | 115 | rm_tmp 116 | } 117 | 118 | test_remote_ahead_master() { 119 | cd_to_tmp "remote" 120 | git init --quiet 121 | touch README 122 | git add . 123 | git commit -m "initial commit" --quiet 124 | remoteLocation="$(pwd)" 125 | 126 | cd_to_tmp "new" 127 | git init --quiet 128 | git remote add origin $remoteLocation 129 | git fetch origin --quiet 130 | git checkout master --quiet 131 | 132 | git checkout -b foo --quiet 133 | git push --quiet -u origin foo >/dev/null 134 | 135 | echo "foo" > foo 136 | git add . 137 | git commit -m "test commit" --quiet 138 | assertEquals "0" "$(remote_ahead_of_master)" 139 | git push --quiet 140 | assertEquals "1" "$(remote_ahead_of_master)" 141 | 142 | echo "bar" > bar 143 | git add . 144 | git commit -m "test commit" --quiet 145 | assertEquals "1" "$(remote_ahead_of_master)" 146 | git push --quiet 147 | assertEquals "2" "$(remote_ahead_of_master)" 148 | 149 | rm_tmp 150 | } 151 | 152 | test_remote_behind_master() { 153 | cd_to_tmp "remote" 154 | git init --bare --quiet 155 | remoteLocation="$(pwd)" 156 | 157 | cd_to_tmp "new" 158 | git init --quiet 159 | git remote add origin $remoteLocation 160 | git fetch origin --quiet 161 | git checkout -b master --quiet 162 | touch README 163 | git add README 164 | git commit -m "initial commit" --quiet 165 | 166 | git push --quiet -u origin master >/dev/null 167 | git reset --quiet --hard HEAD 168 | 169 | git checkout -b foo --quiet 170 | git push --quiet -u origin foo >/dev/null 171 | 172 | assertEquals "0" "$(remote_behind_of_master)" 173 | git checkout master --quiet 174 | echo "foo" > foo 175 | git add . 176 | git commit -m "test commit" --quiet 177 | git push --quiet >/dev/null 178 | git checkout foo --quiet 179 | assertEquals "1" "$(remote_behind_of_master)" 180 | 181 | git checkout master --quiet 182 | echo "bar" > bar 183 | git add . 184 | git commit -m "test commit" --quiet 185 | git push --quiet >/dev/null 186 | git checkout foo --quiet 187 | assertEquals "2" "$(remote_behind_of_master)" 188 | 189 | rm_tmp 190 | } 191 | 192 | test_remote_branch_starts_with_local_branch_name() { 193 | cd_to_tmp "remote" 194 | git init --bare --quiet 195 | remoteLocation="$(pwd)" 196 | 197 | cd_to_tmp "local" 198 | git init --quiet 199 | git remote add origin $remoteLocation 200 | git fetch origin --quiet 201 | 202 | git checkout -b master --quiet 203 | touch README 204 | git add README 205 | git commit -m "initial commit" --quiet 206 | 207 | git push --quiet -u origin master >/dev/null 208 | git reset --quiet --hard HEAD 209 | 210 | git checkout -b foobar --quiet 211 | touch foobarfile 212 | git add foobarfile 213 | git commit -m "added foobar" --quiet 214 | git push --quiet -u origin foobar >/dev/null 215 | 216 | git checkout -b foo --quiet 217 | 218 | assertEquals "0" "$(remote_ahead_of_master)" 219 | assertEquals "0" "$(remote_behind_of_master)" 220 | assertEquals "0" "$(commits_behind_of_remote)" 221 | assertEquals "0" "$(commits_ahead_of_remote)" 222 | 223 | rm_tmp 224 | } 225 | 226 | test_remote_branch_ends_with_local_branch_name() { 227 | cd_to_tmp "remote" 228 | git init --bare --quiet 229 | remoteLocation="$(pwd)" 230 | 231 | cd_to_tmp "local" 232 | git init --quiet 233 | git remote add origin $remoteLocation 234 | git fetch origin --quiet 235 | 236 | git checkout -b master --quiet 237 | touch README 238 | git add README 239 | git commit -m "initial commit" --quiet 240 | 241 | git push --quiet -u origin master >/dev/null 242 | git reset --quiet --hard HEAD 243 | 244 | git checkout -b foobar --quiet 245 | touch foobarfile 246 | git add foobarfile 247 | git commit -m "added foobar" --quiet 248 | git push --quiet -u origin foobar >/dev/null 249 | 250 | git checkout -b bar --quiet 251 | 252 | assertEquals "0" "$(remote_ahead_of_master)" 253 | assertEquals "0" "$(remote_behind_of_master)" 254 | assertEquals "0" "$(commits_behind_of_remote)" 255 | assertEquals "0" "$(commits_ahead_of_remote)" 256 | 257 | rm_tmp 258 | } 259 | 260 | test_dont_call_remote_branch_name() { 261 | cd_to_tmp "remote" 262 | git init --bare --quiet 263 | remoteLocation="$(pwd)" 264 | 265 | cd_to_tmp "new" 266 | git init --quiet 267 | git remote add origin $remoteLocation 268 | git fetch origin --quiet 269 | git checkout -b master --quiet 270 | touch README 271 | git add README 272 | git commit -m "initial commit" --quiet 273 | 274 | git push --quiet -u origin master >/dev/null 275 | git reset --quiet --hard HEAD 276 | 277 | git checkout -b foo --quiet 278 | git push --quiet -u origin foo >/dev/null 279 | 280 | remote_branch="$(remote_branch_name)" 281 | 282 | debug_output="$( 283 | { 284 | set -x 285 | output="$( 286 | remote_behind_of_master "$remote_branch"; 287 | remote_ahead_of_master "$remote_branch"; 288 | commits_ahead_of_remote "$remote_branch"; 289 | commits_behind_of_remote "$remote_branch"; 290 | )" 291 | set +x 292 | } 2>&1 293 | echo "$output" 294 | )" 295 | 296 | #Grep through the output and look for remote_branch_name being called 297 | usages="$(echo "$debug_output" | grep 'remote_branch_name' | wc -l )" 298 | 299 | #wc -l has a weird output 300 | assertEquals " 0" "$usages" 301 | 302 | rm_tmp 303 | } 304 | 305 | test_dont_remote_if_remote_is_master() { 306 | cd_to_tmp 307 | git init --quiet 308 | 309 | remote_branch="origin/master" 310 | 311 | debug_output="$( 312 | { 313 | set -x 314 | output="$( 315 | remote_behind_of_master "$remote_branch"; 316 | remote_ahead_of_master "$remote_branch"; 317 | )" 318 | set +x 319 | } 2>&1 320 | echo "$output" 321 | )" 322 | 323 | usages="$(echo "$debug_output" | grep 'git rev-list' | wc -l )" 324 | 325 | assertEquals " 0" "$usages" 326 | 327 | rm_tmp 328 | } 329 | 330 | test_quiet_if_no_remote_master() { 331 | cd_to_tmp "remote" 332 | git init --quiet 333 | touch README 334 | git add . 335 | git checkout -b foo --quiet 336 | git commit -m "initial commit" --quiet 337 | remoteLocation="$(pwd)" 338 | 339 | cd_to_tmp "new" 340 | git init --quiet 341 | git remote add origin $remoteLocation 342 | git fetch origin --quiet 343 | git checkout foo --quiet 344 | repoLocation="$(pwd)" 345 | 346 | remote_branch="$(remote_branch_name)" 347 | 348 | debug_output="$( 349 | { 350 | output="$( 351 | remote_behind_of_master "$remote_branch"; 352 | )" 353 | } 2>&1 354 | echo "$output" 355 | )" 356 | 357 | assertEquals "0" "$debug_output" 358 | debug_output="$( 359 | { 360 | output="$( 361 | remote_ahead_of_master "$remote_branch"; 362 | )" 363 | } 2>&1 364 | echo "$output" 365 | )" 366 | 367 | assertEquals "0" "$debug_output" 368 | 369 | rm_tmp 370 | } 371 | 372 | test_local_commits() { 373 | local up="↑" 374 | local both="⇵" 375 | local down="↓" 376 | 377 | cd_to_tmp "remote" 378 | 379 | assertEquals "" "$(zsh_color_local_commits)" 380 | assertEquals "" "$(bash_color_local_commits)" 381 | assertEquals "" "$(color_local_commits)" 382 | 383 | git init --quiet 384 | touch README 385 | git add . 386 | git commit -m "initial commit" --quiet 387 | remote="$(pwd)" 388 | 389 | cd_to_tmp "new" 390 | git init --quiet 391 | git remote add origin $remote 392 | git fetch origin --quiet 393 | git checkout master --quiet 394 | repo="$(pwd)" 395 | 396 | assertEquals "" "$(zsh_color_local_commits)" 397 | assertEquals "" "$(bash_color_local_commits)" 398 | assertEquals "" "$(color_local_commits)" 399 | 400 | cd "$repo" 401 | echo "bar" > bar 402 | git add . 403 | git commit -m "test commit" --quiet 404 | 405 | assertEquals "1$up" "$(zsh_color_local_commits)" 406 | assertEquals "1$up" "$(bash_color_local_commits)" 407 | assertEquals "1$up" "$(color_local_commits)" 408 | 409 | cd "$remote" 410 | echo "foo" > foo 411 | git add . 412 | git commit -m "test commit" --quiet 413 | 414 | cd "$repo" 415 | git fetch origin --quiet 416 | 417 | assertEquals "1${both}1" "$(zsh_color_local_commits)" 418 | assertEquals "1${both}1" "$(bash_color_local_commits)" 419 | assertEquals "1${both}1" "$(color_local_commits)" 420 | 421 | git reset --hard HEAD^ --quiet 422 | 423 | assertEquals "1$down" "$(zsh_color_local_commits)" 424 | assertEquals "1$down" "$(bash_color_local_commits)" 425 | assertEquals "1$down" "$(color_local_commits)" 426 | } 427 | 428 | . ./shunit/shunit2 429 | -------------------------------------------------------------------------------- /test-directories.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | tmpfile="" 6 | 7 | cd_to_tmp() { 8 | tmpfile="/tmp/git-prompt-tests-$(time_now)" 9 | mkdir -p "$tmpfile" 10 | cd "$tmpfile" 11 | } 12 | 13 | rm_tmp() { 14 | cd $scriptDir 15 | rm -rf /tmp/git-prompt-tests* 16 | } 17 | 18 | test_git_root_in_repo() { 19 | cd $scriptDir 20 | local root="$(git_root)" 21 | assertEquals "$scriptDir" "$root" 22 | } 23 | 24 | test_git_root_not_in_repo() { 25 | cd_to_tmp 26 | local root="$(git_root)" 27 | assertEquals "" "$root" 28 | rm_tmp 29 | } 30 | 31 | test_dot_git_location_not_in_repo() { 32 | cd_to_tmp 33 | local filePath="$(dot_git)" 34 | assertEquals "" "$filePath" 35 | rm_tmp 36 | } 37 | 38 | test_dot_git_location_in_repo() { 39 | cd $scriptDir 40 | local filePath="$(dot_git)" 41 | local expected=".git" 42 | assertEquals "$expected" "$filePath" 43 | } 44 | 45 | test_is_repo_not_in_repo() { 46 | cd_to_tmp 47 | assertFalse is_repo 48 | rm_tmp 49 | } 50 | 51 | test_is_repo_in_repo() { 52 | cd $scriptDir 53 | assertTrue is_repo 54 | } 55 | 56 | test_record_timestamp_in_repo() { 57 | cd $scriptDir 58 | record_timestamp 59 | local timestamp="$(timestamp)" 60 | local timenow="$(time_now)" 61 | assertSame "$timenow" "$timestamp" 62 | } 63 | 64 | test_time_to_update_when_timestamp_is_old() { 65 | cd $scriptDir 66 | FETCH_TIME="$((5 * 60))" # Fetch every 5 mins 67 | touch -A "-010000" "$(dot_git)/lastupdatetime" 68 | assertTrue time_to_update 69 | } 70 | 71 | test_not_time_to_update_when_just_recorded() { 72 | cd $scriptDir 73 | FETCH_TIME="$((5 * 60))" # Fetch every 5 mins 74 | record_timestamp 75 | assertFalse time_to_update 76 | } 77 | 78 | test_time_to_update_when_no_timestamp() { 79 | cd_to_tmp 80 | git init --quiet 81 | 82 | FETCH_TIME="$((5 * 60))" # Fetch every 5 mins 83 | time_to_update 84 | assertTrue time_to_update 85 | 86 | rm_tmp 87 | } 88 | 89 | . ./shunit/shunit2 90 | -------------------------------------------------------------------------------- /test-files.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | tmpfile="" 6 | 7 | cd_to_tmp() { 8 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 9 | mkdir -p "$tmpfile" 10 | cd "$tmpfile" 11 | } 12 | 13 | rm_tmp() { 14 | cd $scriptDir 15 | rm -rf /tmp/git-prompt-tests* 16 | } 17 | 18 | test_untracked_files() { 19 | cd_to_tmp 20 | git init --quiet 21 | 22 | assertEquals "" "$(untracked_status)" 23 | 24 | touch foo 25 | assertEquals "1A" "$(untracked_status)" 26 | 27 | git add . 28 | assertEquals "" "$(untracked_status)" 29 | 30 | rm_tmp 31 | } 32 | 33 | test_unstaged_modified_files() { 34 | cd_to_tmp 35 | git init --quiet 36 | 37 | assertEquals "" "$(unstaged_status)" 38 | 39 | touch foo 40 | touch bar 41 | git add . 42 | git commit -m "foo and bar" >/dev/null 43 | 44 | echo "foo" >> foo 45 | assertEquals "1M" "$(unstaged_status)" 46 | 47 | echo "bar" >> bar 48 | assertEquals "2M" "$(unstaged_status)" 49 | 50 | rm_tmp 51 | } 52 | 53 | test_unstaged_deleted_files() { 54 | cd_to_tmp 55 | git init --quiet 56 | 57 | assertEquals "" "$(unstaged_status)" 58 | 59 | touch foo 60 | touch bar 61 | git add . 62 | git commit -m "foo and bar" >/dev/null 63 | 64 | rm foo 65 | assertEquals "1D" "$(unstaged_status)" 66 | 67 | rm bar 68 | assertEquals "2D" "$(unstaged_status)" 69 | 70 | rm_tmp 71 | } 72 | 73 | test_staged_added_files() { 74 | cd_to_tmp 75 | git init --quiet 76 | 77 | assertEquals "" "$(staged_status)" 78 | 79 | touch foo 80 | git add . 81 | assertEquals "1A" "$(staged_status)" 82 | 83 | touch bar 84 | git add . 85 | assertEquals "2A" "$(staged_status)" 86 | 87 | rm_tmp 88 | } 89 | 90 | test_staged_modified_files() { 91 | cd_to_tmp 92 | git init --quiet 93 | 94 | assertEquals "" "$(staged_status)" 95 | 96 | touch foo 97 | touch bar 98 | git add . 99 | git commit -m "foo and bar" >/dev/null 100 | 101 | echo "foo" >> foo 102 | git add . 103 | assertEquals "1M" "$(staged_status)" 104 | 105 | echo "bar" >> bar 106 | git add . 107 | assertEquals "2M" "$(staged_status)" 108 | 109 | rm_tmp 110 | } 111 | 112 | test_staged_deleted_files() { 113 | cd_to_tmp 114 | git init --quiet 115 | 116 | assertEquals "" "$(staged_status)" 117 | 118 | touch foo 119 | touch bar 120 | git add . 121 | git commit -m "foo and bar" >/dev/null 122 | 123 | rm foo 124 | git add . 125 | assertEquals "1D" "$(staged_status)" 126 | 127 | rm bar 128 | git add . 129 | assertEquals "2D" "$(staged_status)" 130 | 131 | rm_tmp 132 | } 133 | 134 | test_staged_renamed_files() { 135 | cd_to_tmp 136 | git init --quiet 137 | 138 | assertEquals "" "$(staged_status)" 139 | 140 | touch foo 141 | touch bar 142 | git add . 143 | git commit -m "foo and bar" >/dev/null 144 | 145 | mv foo foo2 146 | git add . 147 | assertEquals "1R" "$(staged_status)" 148 | 149 | mv bar bar2 150 | git add . 151 | assertEquals "2R" "$(staged_status)" 152 | 153 | rm_tmp 154 | } 155 | 156 | test_conflicted_both_changes() { 157 | cd_to_tmp 158 | git init --quiet 159 | 160 | git checkout -b foo --quiet 161 | echo "foo" >> foo 162 | git add . 163 | git commit -m "foo" --quiet 164 | 165 | git checkout -b foo2 --quiet 166 | echo "bar" >> foo 167 | git add . 168 | git commit -m "bar" --quiet 169 | 170 | git checkout foo --quiet 171 | echo "foo2" >> foo 172 | git add . 173 | git commit -m "foo2" --quiet 174 | 175 | assertEquals "" "$(conflicted_status)" 176 | 177 | git merge foo2 >/dev/null 178 | 179 | assertEquals "1B" "$(conflicted_status)" 180 | 181 | rm_tmp 182 | } 183 | 184 | test_conflicted_them_changes() { 185 | cd_to_tmp 186 | git init --quiet 187 | 188 | git checkout -b foo --quiet 189 | echo "foo" >> foo 190 | git add . 191 | git commit -m "foo" --quiet 192 | 193 | git checkout -b foo2 --quiet 194 | rm foo 195 | git add . 196 | git commit -m "delete foo" --quiet 197 | 198 | git checkout foo --quiet 199 | echo "foo2" >> foo 200 | git add . 201 | git commit -m "foo2" --quiet 202 | 203 | assertEquals "" "$(conflicted_status)" 204 | 205 | git merge foo2 >/dev/null 206 | 207 | assertEquals "1T" "$(conflicted_status)" 208 | 209 | rm_tmp 210 | } 211 | 212 | test_conflicted_us_changes() { 213 | cd_to_tmp 214 | git init --quiet 215 | 216 | git checkout -b foo --quiet 217 | echo "foo" >> foo 218 | git add . 219 | git commit -m "foo" --quiet 220 | 221 | git checkout -b foo2 --quiet 222 | echo "bar" >> foo 223 | git add . 224 | git commit -m "bar" --quiet 225 | 226 | git checkout foo --quiet 227 | rm foo 228 | git add . 229 | git commit -m "delete foo" --quiet 230 | 231 | assertEquals "" "$(conflicted_status)" 232 | 233 | git merge foo2 >/dev/null 234 | 235 | assertEquals "1U" "$(conflicted_status)" 236 | 237 | rm_tmp 238 | } 239 | 240 | test_is_dirty() { 241 | cd_to_tmp 242 | 243 | assertFalse "not in repo" is_dirty 244 | 245 | git init --quiet 246 | assertFalse "in repo and clean" is_dirty 247 | 248 | touch foo 249 | assertTrue "untracked files" is_dirty 250 | 251 | mkdir sneakSubDir 252 | cd sneakSubDir 253 | assertTrue "untracked files while in an empty sub dir" is_dirty 254 | 255 | cd ../ 256 | 257 | git add . 258 | assertTrue "staged addition files" is_dirty 259 | 260 | git commit -m "inital commit" --quiet 261 | 262 | assertFalse "commited and clean" is_dirty 263 | 264 | echo "foo" >> foo 265 | assertTrue "modified file unstaged" is_dirty 266 | 267 | git add . 268 | assertTrue "modified file staged" is_dirty 269 | 270 | rm_tmp 271 | } 272 | 273 | . ./shunit/shunit2 274 | -------------------------------------------------------------------------------- /test-format-config.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | cd_to_tmp() { 6 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 7 | mkdir -p "$tmpfile" 8 | cd "$tmpfile" 9 | } 10 | 11 | rm_tmp() { 12 | cd $scriptDir 13 | rm -rf /tmp/git-prompt-tests* 14 | } 15 | 16 | unset_colours() { 17 | export COLOR_REMOTE_AHEAD="" 18 | export COLOR_REMOTE_BEHIND="" 19 | export COLOR_REMOTE_DIVERGED="" 20 | export COLOR_REMOTE_NOT_UPSTREAM="" 21 | 22 | export COLOR_LOCAL_AHEAD="" 23 | export COLOR_LOCAL_BEHIND="" 24 | export COLOR_LOCAL_DIVERGED="" 25 | 26 | export COLOR_CHANGES_STAGED="" 27 | export COLOR_CHANGES_UNSTAGED="" 28 | export COLOR_CHANGES_CONFLICTED="" 29 | export COLOR_CHANGES_UNTRACKED="" 30 | 31 | export COLOR_BRANCH="" 32 | export MASTER_SYMBOL="m" 33 | 34 | export RESET_COLOR_LOCAL="" 35 | export RESET_COLOR_REMOTE="" 36 | export RESET_COLOR_CHANGES="" 37 | export RESET_COLOR_BRANCH="" 38 | } 39 | 40 | prepare_test_repo() { 41 | cd_to_tmp "remote" 42 | 43 | git init --quiet 44 | touch README 45 | git add . 46 | git commit -m "initial commit" --quiet 47 | origin="$(pwd)" 48 | 49 | cd_to_tmp "new" 50 | git init --quiet 51 | git remote add origin $origin 52 | git fetch origin --quiet 53 | git checkout master --quiet 54 | git checkout -b foo --quiet 55 | git push --quiet -u origin foo >/dev/null 56 | repo="$(pwd)" 57 | 58 | cd "$origin" 59 | echo "foo" > foo 60 | git add . 61 | git commit -m "remote commit" --quiet 62 | cd "$repo" 63 | echo "foo" > foo 64 | git add . 65 | git commit -m "local commit" --quiet 66 | echo "foo" > bar 67 | git fetch origin --quiet 68 | } 69 | 70 | test_all_options_set_config() { 71 | cd_to_tmp "empty" 72 | export GIT_RADAR_FORMAT="%{branch}%{local}%{changes}" 73 | # Don't test remote as in no repo you will get upstream error message 74 | prepare_zsh_colors 75 | unset_colours 76 | 77 | prompt="$(render_prompt)" 78 | assertEquals "$prompt" "" 79 | 80 | export GIT_RADAR_FORMAT="%{remote}" 81 | # Don't test remote as in no repo you will get upstream error message 82 | prepare_zsh_colors 83 | unset_colours 84 | 85 | prompt="$(render_prompt)" 86 | assertEquals "$prompt" "upstream ⚡" 87 | prepare_test_repo 88 | 89 | export GIT_RADAR_FORMAT="%{remote}%{branch}%{local}%{changes}" 90 | prepare_zsh_colors 91 | unset_colours 92 | 93 | prompt="$(render_prompt)" 94 | assertEquals "$prompt" "m 1 →foo1↑1A" 95 | 96 | export GIT_RADAR_FORMAT="%{remote}%{branch}%{changes}" 97 | prepare_zsh_colors 98 | unset_colours 99 | 100 | prompt="$(render_prompt)" 101 | assertEquals "$prompt" "m 1 →foo1A" 102 | 103 | export GIT_RADAR_FORMAT="%{branch}%{local}%{changes}" 104 | prepare_zsh_colors 105 | unset_colours 106 | 107 | prompt="$(render_prompt)" 108 | assertEquals "$prompt" "foo1↑1A" 109 | 110 | export GIT_RADAR_FORMAT="%{branch}%{changes}" 111 | prepare_zsh_colors 112 | unset_colours 113 | 114 | prompt="$(render_prompt)" 115 | assertEquals "$prompt" "foo1A" 116 | 117 | export GIT_RADAR_FORMAT="%{branch}" 118 | prepare_zsh_colors 119 | unset_colours 120 | 121 | prompt="$(render_prompt)" 122 | assertEquals "$prompt" "foo" 123 | 124 | rm_tmp 125 | } 126 | 127 | #test_reorder_parts() { 128 | # prepare_test_repo 129 | # 130 | # export GIT_RADAR_FORMAT="%{branch}%{local}%{changes}%{remote}" 131 | # prepare_zsh_colors 132 | # unset_colours 133 | # 134 | # prompt="$(render_prompt)" 135 | # assertEquals "foo1↑1Am 1 →" "$prompt" 136 | # 137 | # export GIT_RADAR_FORMAT="%{local}%{changes}%{remote}%{branch}" 138 | # prepare_zsh_colors 139 | # unset_colours 140 | # 141 | # prompt="$(render_prompt)" 142 | # assertEquals "1↑1Am 1 →foo" "$prompt" 143 | # 144 | # export GIT_RADAR_FORMAT="%{changes}%{remote}%{branch}%{local}" 145 | # prepare_zsh_colors 146 | # unset_colours 147 | # 148 | # prompt="$(render_prompt)" 149 | # assertEquals "1Am 1 →foo1↑" "$prompt" 150 | # 151 | # rm_tmp 152 | #} 153 | # 154 | #test_prefix_and_suffix_changes() { 155 | # prepare_test_repo 156 | # 157 | # export GIT_RADAR_FORMAT="%{changes}" 158 | # prepare_zsh_colors 159 | # unset_colours 160 | # 161 | # prompt="$(render_prompt)" 162 | # assertEquals "1A" "$prompt" 163 | # 164 | # export GIT_RADAR_FORMAT="%{[:changes:]}" 165 | # prepare_zsh_colors 166 | # unset_colours 167 | # 168 | # prompt="$(render_prompt)" 169 | # assertEquals "[1A]" "$prompt" 170 | # 171 | # rm_tmp 172 | #} 173 | # 174 | #test_prefix_and_suffix_local() { 175 | # prepare_test_repo 176 | # 177 | # export GIT_RADAR_FORMAT="%{local}" 178 | # prepare_zsh_colors 179 | # unset_colours 180 | # 181 | # prompt="$(render_prompt)" 182 | # assertEquals "1↑" "$prompt" 183 | # 184 | # export GIT_RADAR_FORMAT="%{[:local:]}" 185 | # prepare_zsh_colors 186 | # unset_colours 187 | # 188 | # prompt="$(render_prompt)" 189 | # assertEquals "[1↑]" "$prompt" 190 | # 191 | # rm_tmp 192 | #} 193 | # 194 | #test_prefix_and_suffix_branch() { 195 | # prepare_test_repo 196 | # 197 | # export GIT_RADAR_FORMAT="%{branch}" 198 | # prepare_zsh_colors 199 | # unset_colours 200 | # 201 | # prompt="$(render_prompt)" 202 | # assertEquals "foo" "$prompt" 203 | # 204 | # export GIT_RADAR_FORMAT="%{[:branch:]}" 205 | # prepare_zsh_colors 206 | # unset_colours 207 | # 208 | # prompt="$(render_prompt)" 209 | # assertEquals "[foo]" "$prompt" 210 | # 211 | # rm_tmp 212 | #} 213 | # 214 | #test_prefix_and_suffix_remote() { 215 | # prepare_test_repo 216 | # 217 | # export GIT_RADAR_FORMAT="%{remote}" 218 | # prepare_zsh_colors 219 | # unset_colours 220 | # 221 | # prompt="$(render_prompt)" 222 | # assertEquals "m 1 →" "$prompt" 223 | # 224 | # export GIT_RADAR_FORMAT="%{[:remote:]}" 225 | # prepare_zsh_colors 226 | # unset_colours 227 | # 228 | # prompt="$(render_prompt)" 229 | # assertEquals "[m 1 →]" "$prompt" 230 | # 231 | # rm_tmp 232 | #} 233 | 234 | . ./shunit/shunit2 235 | -------------------------------------------------------------------------------- /test-performance.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | cd_to_tmp() { 6 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 7 | mkdir -p "$tmpfile" 8 | cd "$tmpfile" 9 | } 10 | 11 | rm_tmp() { 12 | cd $scriptDir 13 | rm -rf /tmp/git-prompt-tests* 14 | } 15 | 16 | report() { 17 | arr=( "$@" ) 18 | printf '%s\n' "${arr[@]}" | sort -n | awk ' 19 | function colored(s) { 20 | OFMT="%2.3fs"; 21 | OFS=""; 22 | ORS=""; 23 | if( s > 0.2 ) { 24 | print "\033[1;31m", s, "\033[0m" 25 | } else if( s > 0.1 ) { 26 | print "\033[1;33m", s, "\033[0m" 27 | } else { 28 | print "\033[1;32m", s, "\033[0m" 29 | } 30 | OFS="\t"; 31 | ORS="\n"; 32 | } 33 | BEGIN { 34 | c = 0; 35 | sum = 0; 36 | } 37 | $1 ~ /^[0-9]*(\.[0-9]*)?$/ { 38 | a[c++] = $1; 39 | sum += $1; 40 | } 41 | END { 42 | min = a[0] + 0; 43 | max = a[c-1] + 0; 44 | ave = sum / c; 45 | if( (c % 2) == 1 ) { 46 | median = a[ int(c/2) ]; 47 | } else { 48 | median = ( a[c/2] + a[c/2-1] ) / 2; 49 | } 50 | OFS="\t"; 51 | OFMT="%2.3fs"; 52 | print c, colored(ave), colored(median), colored(min), colored(max); 53 | } 54 | ' 55 | } 56 | 57 | table_headers() { 58 | printf " Count\tMean\tMedian\tMin\tMax\n" 59 | } 60 | 61 | profile () { 62 | cmd="$2" 63 | for (( i = 0; i < 100; i++ )); do 64 | start=$(gdate +%s.%N) 65 | eval $cmd > /dev/null 66 | duration=$(echo "$(gdate +%s.%N) - $start" | bc) 67 | timings[$i]=$duration 68 | done 69 | printf '%-25s' "$1" 70 | report "${timings[@]}" 71 | } 72 | 73 | test_empty_repo() { 74 | cd_to_tmp 75 | git init --quiet 76 | 77 | table_headers 78 | profile "prompt.zsh" "/.$scriptDir/prompt.zsh" 79 | profile "prompt.bash" "/.$scriptDir/prompt.bash" 80 | 81 | rm_tmp 82 | } 83 | 84 | test_lots_of_file_changes() { 85 | cd_to_tmp 86 | git init --quiet 87 | 88 | table_headers 89 | 90 | profile "no changes zsh" "/.$scriptDir/prompt.zsh" 91 | profile "no changes bash" "/.$scriptDir/prompt.bash" 92 | 93 | for (( i = 0; i < 100; i++ )); do 94 | touch foo$i 95 | done 96 | 97 | profile "100 untracked zsh" "/.$scriptDir/prompt.zsh" 98 | profile "100 untracked bash" "/.$scriptDir/prompt.bash" 99 | 100 | for (( i = 0; i < 100; i++ )); do 101 | touch bar$i 102 | git add bar$i 103 | done 104 | 105 | profile "100 added zsh" "/.$scriptDir/prompt.zsh" 106 | profile "100 added bash" "/.$scriptDir/prompt.bash" 107 | 108 | for (( i = 0; i < 100; i++ )); do 109 | echo "bar$i" > bar$i 110 | done 111 | 112 | profile "100 modify zsh" "/.$scriptDir/prompt.zsh" 113 | profile "100 modify bash" "/.$scriptDir/prompt.bash" 114 | 115 | rm_tmp 116 | } 117 | 118 | test_commits_local_and_remote_ahead() { 119 | cd_to_tmp "remote" 120 | git init --quiet 121 | touch README 122 | git add . 123 | git commit -m "initial commit" --quiet 124 | remoteLocation="$(pwd)" 125 | 126 | cd_to_tmp "new" 127 | git init --quiet 128 | git remote add origin $remoteLocation 129 | git fetch origin --quiet 130 | git checkout master --quiet 131 | 132 | git checkout -b foo --quiet 133 | git push --quiet -u origin foo >/dev/null 134 | 135 | table_headers 136 | 137 | profile "0 commits zsh" "/.$scriptDir/prompt.zsh" 138 | profile "0 commits bash" "/.$scriptDir/prompt.bash" 139 | 140 | for (( i = 0; i < 100; i++ )); do 141 | echo "foo$i" >> foo 142 | git add . 143 | git commit -m "foo $i" --quiet 144 | done 145 | 146 | profile "100 local zsh" "/.$scriptDir/prompt.zsh" 147 | profile "100 local bash" "/.$scriptDir/prompt.bash" 148 | 149 | git push --quiet 150 | 151 | profile "100 remote zsh" "/.$scriptDir/prompt.zsh" 152 | profile "100 remote bash" "/.$scriptDir/prompt.bash" 153 | 154 | rm_tmp 155 | } 156 | 157 | test_commits_local_and_remote_behind() { 158 | cd_to_tmp "remote" 159 | git init --bare --quiet 160 | remoteLocation="$(pwd)" 161 | 162 | cd_to_tmp "new" 163 | git init --quiet 164 | git remote add origin $remoteLocation 165 | git fetch origin --quiet 166 | git checkout -b master --quiet 167 | touch README 168 | git add README 169 | git commit -m "initial commit" --quiet 170 | 171 | git push --quiet -u origin master >/dev/null 172 | git reset --quiet --hard HEAD 173 | 174 | git checkout -b foo --quiet 175 | git push --quiet -u origin foo >/dev/null 176 | 177 | git checkout master --quiet 178 | 179 | table_headers 180 | 181 | profile "0 commits zsh" "/.$scriptDir/prompt.zsh" 182 | profile "0 commits bash" "/.$scriptDir/prompt.bash" 183 | 184 | for (( i = 0; i < 100; i++ )); do 185 | echo "foo$i" >> foo 186 | git add . 187 | git commit -m "foo $i" --quiet 188 | done 189 | 190 | git push --quiet 191 | git checkout foo --quiet 192 | 193 | profile "100 behind remote zsh" "/.$scriptDir/prompt.zsh" 194 | profile "100 behind remote bash" "/.$scriptDir/prompt.bash" 195 | 196 | git checkout master --quiet 197 | git checkout -b bar --quiet 198 | git push --quiet -u origin bar >/dev/null 199 | git reset --hard origin/foo --quiet 200 | 201 | profile "100 behind mine zsh" "/.$scriptDir/prompt.zsh" 202 | profile "100 behind mine bash" "/.$scriptDir/prompt.bash" 203 | 204 | } 205 | 206 | test_large_repo() { 207 | cd_to_tmp 208 | git clone https://github.com/Homebrew/homebrew --quiet 209 | cd homebrew 210 | 211 | table_headers 212 | profile "prompt.zsh" "/.$scriptDir/prompt.zsh" 213 | profile "prompt.bash" "/.$scriptDir/prompt.bash" 214 | 215 | rm_tmp 216 | } 217 | 218 | test_lots_of_submodules() { 219 | cd_to_tmp 220 | git clone https://github.com/michaeldfallen/dotfiles --quiet 221 | cd dotfiles 222 | git submodule update --init --quiet 223 | 224 | table_headers 225 | profile "prompt.zsh" "/.$scriptDir/prompt.zsh" 226 | profile "prompt.bash" "/.$scriptDir/prompt.bash" 227 | 228 | rm_tmp 229 | } 230 | 231 | . ./shunit/shunit2 232 | -------------------------------------------------------------------------------- /test-radar-base.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | test_show_remote_status() { 6 | show_remote_status 7 | assertTrue $? 8 | 9 | show_remote_status --bash 10 | assertTrue $? 11 | 12 | show_remote_status --bash --fetch 13 | assertTrue $? 14 | 15 | show_remote_status --bash --no-remote-status --fetch 16 | assertFalse $? 17 | 18 | show_remote_status --bash --fetch --no-remote-status 19 | assertFalse $? 20 | 21 | show_remote_status --no-remote-status --bash --fetch 22 | assertFalse $? 23 | 24 | show_remote_status --bash --fetch --minimal --no-remote-status 25 | assertFalse $? 26 | } 27 | 28 | . ./shunit/shunit2 -------------------------------------------------------------------------------- /test-stash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 3 | 4 | source "$scriptDir/radar-base.sh" 5 | 6 | tmpfile="" 7 | 8 | cd_to_tmp() { 9 | tmpfile="/tmp/git-prompt-tests-$(time_now)$1" 10 | mkdir -p "$tmpfile" 11 | cd "$tmpfile" 12 | } 13 | 14 | rm_tmp() { 15 | cd $scriptDir 16 | rm -rf /tmp/git-prompt-tests* 17 | } 18 | 19 | test_unstashed_status() { 20 | cd_to_tmp 21 | git init --quiet 22 | 23 | assertEquals "0" "$(stashed_status)" 24 | 25 | rm_tmp 26 | } 27 | 28 | test_stashed_status() { 29 | cd_to_tmp 30 | git init --quiet 31 | 32 | touch foo 33 | git add --all 34 | git commit -m "Initial commit" >/dev/null 35 | echo "test">foo 36 | git stash > /dev/null 37 | assertEquals "1" "$(stashed_status)" 38 | 39 | echo "test2">foo 40 | git stash > /dev/null 41 | assertEquals "2" "$(stashed_status)" 42 | 43 | git stash drop > /dev/null 44 | assertEquals "1" "$(stashed_status)" 45 | 46 | 47 | rm_tmp 48 | } 49 | 50 | . ./shunit/shunit2 51 | -------------------------------------------------------------------------------- /test-status.sh: -------------------------------------------------------------------------------- 1 | scriptDir="$(cd "$(dirname "$0")"; pwd)" 2 | 3 | source "$scriptDir/radar-base.sh" 4 | 5 | test_prefix_and_suffix() { 6 | status=""" 7 | M unstaged-modified 8 | D unstaged-deleted 9 | M staged-modified 10 | A staged-added 11 | D staged-deleted 12 | C staged-copied 13 | R staged-renamed 14 | MM staged-and-unstaged-modified 15 | UD deleted-them-conflicted 16 | AU added-us-conflicted 17 | UU modified-both-conflicted 18 | ?? untacked 19 | """ 20 | 21 | prefix="_" 22 | suffix="-" 23 | 24 | assertEquals "line:${LINENO}" "1_D-2_M-"\ 25 | "$(unstaged_status "$status" "$prefix" "$suffix")" 26 | 27 | assertEquals "line:${LINENO}" "1_A-1_D-2_M-1_R-1_C-"\ 28 | "$(staged_status "$status" "$prefix" "$suffix")" 29 | 30 | assertEquals "line:${LINENO}" "1_U-1_T-1_B-"\ 31 | "$(conflicted_status "$status" "$prefix" "$suffix")" 32 | 33 | assertEquals "line:${LINENO}" "1_A-"\ 34 | "$(untracked_status "$status" "$prefix" "$suffix")" 35 | } 36 | 37 | test_basic_unstaged_options() { 38 | status=""" 39 | M modified-and-unstaged 40 | D deleted-and-unstaged 41 | A impossible-added-and-unstaged-(as-added-and-unstaged-is-untracked) 42 | C impossible-copied-and-unstaged-(as-copied-and-unstaged-is-untracked) 43 | R impossible-renamed-and-unstaged-(as-renamed-and-unstaged-is-untracked) 44 | U impossible-updated-but-unmerged 45 | ! impossible-ignored-without-!-in-position-1 46 | ? impossible-untracked-without-?-in-position-1 47 | empty-spaces-mean-nothing 48 | """ 49 | assertEquals "line:${LINENO} staged status failed match" "" "$(staged_status "$status")" 50 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 51 | assertEquals "line:${LINENO} unstaged status failed match"\ 52 | "1D1M" "$(unstaged_status "$status")" 53 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 54 | } 55 | 56 | test_basic_staged_options() { 57 | status=""" 58 | A added-and-staged 59 | """ 60 | assertEquals "line:${LINENO} staged status failed match"\ 61 | "1A" "$(staged_status "$status")" 62 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 63 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 64 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 65 | 66 | status=""" 67 | M modified-and-staged 68 | """ 69 | assertEquals "line:${LINENO} staged status failed match"\ 70 | "1M" "$(staged_status "$status")" 71 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 72 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 73 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 74 | 75 | status=""" 76 | D deleted-and-staged 77 | """ 78 | assertEquals "line:${LINENO} staged status failed match"\ 79 | "1D" "$(staged_status "$status")" 80 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 81 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 82 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 83 | 84 | status=""" 85 | C copied-and-staged 86 | """ 87 | assertEquals "line:${LINENO} staged status failed match"\ 88 | "1C" "$(staged_status "$status")" 89 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 90 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 91 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 92 | 93 | status=""" 94 | R renamed-and-staged 95 | """ 96 | assertEquals "line:${LINENO} staged status failed match"\ 97 | "1R" "$(staged_status "$status")" 98 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 99 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 100 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 101 | 102 | status=""" 103 | U impossible-unmerged-without-a-character-in-position-2 104 | ? impossible-untracked-without-?-in-position-2 105 | ! impossible-ignored-without-!-in-position-2 106 | empty-spaces-do-nothing 107 | """ 108 | assertEquals "line:${LINENO} staged status failed match" "" "$(staged_status "$status")" 109 | assertEquals "line:${LINENO} untracked status failed match" "" "$(untracked_status "$status")" 110 | assertEquals "line:${LINENO} unstaged status failed match" "" "$(unstaged_status "$status")" 111 | assertEquals "line:${LINENO} conflicted status failed match" "" "$(conflicted_status "$status")" 112 | } 113 | 114 | test_conflicts() { 115 | status=""" 116 | UD unmerged-deleted-by-them 117 | UA unmerged-added-by-them 118 | """ 119 | assertEquals "line:${LINENO}" "" "$(staged_status "$status")" 120 | assertEquals "line:${LINENO}" "" "$(untracked_status "$status")" 121 | assertEquals "line:${LINENO}" "" "$(unstaged_status "$status")" 122 | assertEquals "line:${LINENO}" "2T" "$(conflicted_status "$status")" 123 | 124 | status=""" 125 | AU unmerged-added-by-us 126 | DU unmerged-deleted-by-us 127 | """ 128 | assertEquals "line:${LINENO}" "" "$(staged_status "$status")" 129 | assertEquals "line:${LINENO}" "" "$(untracked_status "$status")" 130 | assertEquals "line:${LINENO}" "" "$(unstaged_status "$status")" 131 | assertEquals "line:${LINENO}" "2U" "$(conflicted_status "$status")" 132 | 133 | status=""" 134 | AA unmerged-both-added 135 | DD unmerged-both-deleted 136 | UU unmerged-both-modified 137 | """ 138 | assertEquals "line:${LINENO}" "" "$(staged_status "$status")" 139 | assertEquals "line:${LINENO}" "" "$(untracked_status "$status")" 140 | assertEquals "line:${LINENO}" "" "$(unstaged_status "$status")" 141 | assertEquals "line:${LINENO}" "3B" "$(conflicted_status "$status")" 142 | } 143 | 144 | . ./shunit/shunit2 145 | --------------------------------------------------------------------------------