diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 1a22f88..0000000 --- a/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -/node_modules/ -/build/ -*.log -*~ diff --git a/INFO b/INFO new file mode 100644 index 0000000..4ce1b30 --- /dev/null +++ b/INFO @@ -0,0 +1,3 @@ +Fish-like fast/unobtrusive autosuggestions for zsh. +https://github.com/tarruda/zsh-autosuggestions +v0.1.0 diff --git a/LICENSE b/LICENSE index ae7014d..ee52ee2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ Copyright (c) 2013 Thiago de Arruda +Copyright (c) 2016 Eric Freese Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..85d8264 --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +DIST_DIR := ./dist +SRC_DIR := ./src +SCRIPT_DIR := ./script + +SRC_TARGETS := \ + $(SRC_DIR)/config.zsh \ + $(SRC_DIR)/deprecated.zsh \ + $(SRC_DIR)/bind.zsh \ + $(SRC_DIR)/highlight.zsh \ + $(SRC_DIR)/widgets.zsh \ + $(SRC_DIR)/suggestion.zsh \ + $(SRC_DIR)/start.zsh + +$(DIST_DIR)/autosuggestions.zsh: $(SRC_TARGETS) LICENSE + mkdir -p $(DIST_DIR) + cat INFO | sed -e 's/^/# /g' > $@ + echo "#" >> $@ + cat LICENSE | sed -e 's/^/# /g' >> $@ + cat >> $@ $(SRC_TARGETS) + +.PHONY: clean +clean: + rm -rf $(DIST_DIR) + +.PHONY: test +test: $(DIST_DIR)/autosuggestions.zsh $(SCRIPT_DIR)/test.sh + $(SCRIPT_DIR)/test.sh diff --git a/README.md b/README.md index 4afb200..97489e9 100644 --- a/README.md +++ b/README.md @@ -7,136 +7,130 @@ It suggests commands as you type, based on command history. ## Installation -If you already use [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting) plugin, then make sure to be loaded **before** zsh-autosuggestions. - -Note: _.zshrc_ is a file that contains user-specific ZSH configuration. -ZSH assumes this file in your home directory (i.e. `~/.zshrc`), but the location can be changed using `ZDOTDIR` variable. - -### Using zgen - -[Zgen](https://github.com/tarjoilija/zgen) is a simple and fast plugin manager for ZSH. -If you don’t use zgen, then use instructions for the manual installation. - -1. Load `tarruda/zsh-autosuggestions` and `zsh-users/zsh-syntax-highlighting` using zgen in your .zshrc file, for example: - - ```sh - if ! zgen saved; then - echo "Creating a zgen save" - - zgen load zsh-users/zsh-syntax-highlighting - - # autosuggestions should be loaded last - zgen load tarruda/zsh-autosuggestions - - zgen save - fi - ``` - -2. Enable zsh-autosuggestions; copy the following snippet and put it after the zgen config section in your .zshrc file: - - ```sh - # Enable autosuggestions automatically. - zle-line-init() { - zle autosuggest-start - } - zle -N zle-line-init - ``` - -3. Run `zgen reset` and reopen your terminal. - - -### Manually - -1. Clone this repository to `~/.zsh/zsh-autosuggestions` (or anywhere else): +1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`. ```sh git clone git://github.com/tarruda/zsh-autosuggestions ~/.zsh/zsh-autosuggestions ``` -2. Clone zsh-syntax-highlighting repository to `~/.zsh/zsh-syntax-highlighting` (or anywhere else): +2. Add the following to your `.zshrc`: ```sh - git clone git://github.com/zsh-users/zsh-syntax-highlighting ~/.zsh/zsh-syntax-highlighting + source ~/.zsh/zsh-autosuggestions/dist/autosuggestions.zsh + autosuggest_start ``` -3. Load and enable autosuggestions; copy the following snippet and put it to your .zshrc file: - - ```sh - # Load zsh-syntax-highlighting. - source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh - - # Load zsh-autosuggestions. - source ~/.zsh/zsh-autosuggestions/autosuggestions.zsh - - # Enable autosuggestions automatically. - zle-line-init() { - zle autosuggest-start - } - zle -N zle-line-init - ``` - -4. Reopen your terminal. + **Note:** If you're using other zle plugins like `zsh-syntax-highlighting` or `zsh-history-substring-search`, check out the [section on compatibility](#compatibility-with-other-zle-plugins) below. -## Uninstallation +## Usage -Just remove the config lines from .zshrc that you’ve added during “installation.” -If you don’t use zgen, then also delete `~/.zsh/zsh-autosuggestions` and `~/.zsh/zsh-syntax-highlighting`. +As you type commands, you will see a completion offered after the cursor in a muted gray color. This color can be changed by setting the `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` variable. See [configuration](#configuration). +If you press the key (`forward-char` widget) or End (`end-of-line` widget) with the cursor at the end of the buffer, it will accept the suggestion, replacing the contents of the command line buffer with the suggestion. -## How to use - -As you type commands, you will see a completion offered after the cursor, in a muted gray color (which can be changed, see [Configuration](#configuration)). -To accept the autosuggestion (replacing the command line contents), hit End, Alt+F, Ctrl+F, or any other key that moves the cursor to the right. -If the autosuggestion is not what you want, just ignore it: it won’t execute unless you accept it. - -Any widget that moves the cursor to the right (forward-word, forward-char, end-of-line…) will accept parts of the suggested text. -For example, vi-mode users can do this: - -```sh -# Accept suggestions without leaving insert mode -bindkey '^f' vi-forward-word -# or -bindkey '^f' vi-forward-blank-word -``` - -You can also use right arrow key to accept the suggested text as in Fish shell; see [Configuration](#configuration) section to enable it. - -### Exposed widgets - -This plugin defines some ZLE widgets (think about them as functions) which you can bind to some key using [bindkey](http://zshwiki.org/home/zle/bindkeys). -For example, to toggle autosuggestions using Ctrl+T add this to your .zshrc: - -```sh -bindkey '^T' autosuggest-toggle -``` - -List of widgets: - - - `autosuggest-toggle` – disable/enable autosuggestions. - - `autosuggest-execute-suggestion` – accept the suggestion and execute it. +If you invoke the `forward-word` widget, it will partially accept the suggestion up to the point that the cursor moves to. ## Configuration -You may override default global config variables after plugin load, i.e. put it to your .zshrc after the code that loads plugins. - -- `AUTOSUGGESTION_HIGHLIGHT_COLOR` – suggestion highlight color, default is `'fg=8'`. -- `AUTOSUGGESTION_HIGHLIGHT_CURSOR` – highlight word after cursor, or not. Must be integer value `1` or `0`, default is `1`. -- `AUTOSUGGESTION_ACCEPT_RIGHT_ARROW` – complete entire suggestion with right arrow. Must be integer value `1` or `0`, default is `0` (right arrow completes one letter at a time). +You may want to override the default global config variables after sourcing the plugin. Default values of these variables can be found [here](/tarruda/zsh-autosuggestions/blob/master/src/config.zsh). -## Known Issues +### Suggestion Highlight Style -> When I hit Tab and autosuggestions is enabled, it deletes the previous line, and scrolls up the terminal. +Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion is shown with. The default is `fg=8`. -This usually happens when autosuggestions is used along with something like [“completion waiting dots.”](http://michael.thegrebs.com/2012/09/04/zsh-completion-waiting-dots/) -Check which widget is bind to the Tab key; run `bindkey "^I"`. -If it prints something other than `"^I" expand-or-complete`, then this may be the problem. -If you use [Oh My Zsh](https://github.com/robbyrussell/oh-my-zsh), then make sure that the variable `COMPLETION_WAITING_DOTS` is not set (it enables [this](https://github.com/robbyrussell/oh-my-zsh/blob/e55c715508a2f652fed741f2047c66dda2c6e5b0/lib/completion.zsh#L56-L64) problematic code). +### Widget Mapping -If you use module [editor](https://github.com/sorin-ionescu/prezto/tree/master/modules/editor) from [Prezto](https://github.com/sorin-ionescu/prezto), then you must comment out [these lines](https://github.com/sorin-ionescu/prezto/blob/a84ac5b0023d71c98bb28a68c550dc13f6c51945/modules/editor/init.zsh#L303-L304). +This plugin works by triggering custom behavior when certain [zle widgets](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets) are invoked. You can add and remove widgets from these arrays to change the behavior of this plugin: + +- `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`: Widgets in this array will clear the suggestion when invoked. +- `ZSH_AUTOSUGGEST_MODIFY_WIDGETS`: Widgets in this array will modify the buffer and fetch a new suggestion when invoked. +- `ZSH_AUTOSUGGEST_ACCEPT_WIDGETS`: Widgets in this array will accept the suggestion when invoked. +- `ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS`: Widgets in this array will partially accept the suggestion when invoked. + +**Note:** These arrays must be set before calling `autosuggest_start`. + +**Note:** A widget shouldn't belong to more than one of the above arrays. + + +### Key Bindings + +This plugin provides two widgets that you can use with `bindkey`: + +1. `autosuggest-accept`: Accepts the current suggestion. +2. `autosuggest-clear`: Clears the current suggestion. + +For example, this would bind ctrl + space to accept the current suggestion. + +```sh +bindkey '^ ' autosuggest-accept +``` + + +## Compatibility With Other ZLE Plugins + + +### [`zsh-syntax-highlighting`](https://github.com/zsh-users/zsh-syntax-highlighting) + +Source `zsh-autosuggestions.zsh` *before* `zsh-syntax-highlighting`. + +Call `autosuggest_start` *after* sourcing `zsh-syntax-highlighting`. + +For example: + +```sh +source ~/.zsh/zsh-autosuggestions/dist/autosuggestions.zsh +source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh + +autosuggest_start +``` + + +### [`zsh-history-substring-search`](https://github.com/zsh-users/zsh-history-substring-search) + +When the buffer is empty and one of the `history-substring-search-up/down` widgets is invoked, it will call the `up/down-line-or-history` widget. If the `up/down-line-or-history` widgets are in `ZSH_AUTOSUGGEST_CLEAR_WIDGETS` (the list of widgets that clear the suggestion), this can create an infinite recursion, crashing the shell session. + +For best results, you'll want to remove `up-line-or-history` and `down-line-or-history` from `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`: + +``` +# Remove *-line-or-history widgets from list of widgets that clear the autosuggestion to avoid conflict with history-substring-search-* widgets +ZSH_AUTOSUGGEST_CLEAR_WIDGETS=("${(@)ZSH_AUTOSUGGEST_CLEAR_WIDGETS:#(up|down)-line-or-history}") +``` + +Additionally, the `history-substring-search-up` and `history-substring-search-down` widgets are not bound by default. You'll probably want to add them to `ZSH_AUTOSUGGEST_CLEAR_WIDGETS` so that the suggestion will be cleared when you start searching through history: + +```sh +# Add history-substring-search-* widgets to list of widgets that clear the autosuggestion +ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(history-substring-search-up history-substring-search-down) +``` + +Make sure you add/remove these widgets *before* calling `autosuggest_start`. + +For example: + +```sh +source ~/.zsh/zsh-autosuggestions/dist/autosuggestions.zsh +source ~/Code/zsh-history-substring-search/zsh-history-substring-search.zsh + +ZSH_AUTOSUGGEST_CLEAR_WIDGETS=("${(@)ZSH_AUTOSUGGEST_CLEAR_WIDGETS:#(up|down)-line-or-history}") +ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(history-substring-search-up history-substring-search-down) + +autosuggest_start +``` + + +## Uninstallation + +1. Remove the code referencing this plugin from `~/.zshrc`. + +2. Remove the git repository from your hard drive + + ```sh + rm -rf ~/.zsh/zsh-autosuggestions # Or wherever you installed + ``` ## License diff --git a/autosuggestions.plugin.zsh b/autosuggestions.plugin.zsh deleted file mode 120000 index 65220e1..0000000 --- a/autosuggestions.plugin.zsh +++ /dev/null @@ -1 +0,0 @@ -autosuggestions.zsh \ No newline at end of file diff --git a/autosuggestions.zsh b/autosuggestions.zsh deleted file mode 100644 index 7a9112f..0000000 --- a/autosuggestions.zsh +++ /dev/null @@ -1,294 +0,0 @@ -# Fish-like autosuggestions for zsh. Some of the code was based on the code -# for 'predict-on' -# -# ```zsh -# zle-line-init() { -# autosuggest-enable -# } -# zle -N zle-line-init -# ``` -zmodload zsh/net/socket - -source "${0:a:h}/completion-client.zsh" - -# configuration variables -AUTOSUGGESTION_HIGHLIGHT_COLOR='fg=8' -AUTOSUGGESTION_HIGHLIGHT_CURSOR=1 - -function { - if [[ -n $ZLE_DISABLE_AUTOSUGGEST ]]; then - ZSH_HIGHLIGHT_HIGHLIGHTERS=() - return - fi - autoload -U is-at-least - - # if is-at-least 5.0.3; then - # autosuggest-ensure-server - # fi -} - -ZLE_AUTOSUGGEST_SUSPEND_WIDGETS=( - vi-cmd-mode vi-backward-char backward-char backward-word beginning-of-line - history-search-forward history-search-backward up-line-or-history - history-beginning-search-forward history-beginning-search-backward - down-line-or-history history-substring-search-up history-substring-search-down - backward-kill-word -) - -ZLE_AUTOSUGGEST_COMPLETION_WIDGETS=( - complete-word expand-or-complete expand-or-complete-prefix list-choices - menu-complete reverse-menu-complete menu-expand-or-complete menu-select - accept-and-menu-complete -) - -ZLE_AUTOSUGGEST_ACCEPT_WIDGETS=( - vi-forward-char forward-char vi-forward-word forward-word vi-add-eol - vi-add-next vi-forward-blank-word vi-end-of-line end-of-line -) - -ZLE_AUTOSUGGEST_ALL_WIDGETS=( - self-insert magic-space backward-delete-char accept-line - $ZLE_AUTOSUGGEST_ACCEPT_WIDGETS - $ZLE_AUTOSUGGEST_SUSPEND_WIDGETS - $ZLE_AUTOSUGGEST_COMPLETION_WIDGETS -) - -autosuggest-pause() { - [[ -z $ZLE_AUTOSUGGESTING ]] && return - unset ZLE_AUTOSUGGESTING - - # Restore standard widgets except for self-insert, which triggers resume - autosuggest-restore-widgets - zle -A autosuggest-paused-self-insert self-insert - - # When autosuggestions are disabled, kill the unmaterialized part - RBUFFER='' - autosuggest-highlight-suggested-text - - if [[ -n $ZLE_AUTOSUGGEST_CONNECTION ]]; then - zle -F $ZLE_AUTOSUGGEST_CONNECTION - fi -} - -autosuggest-resume() { - [[ -n $ZLE_AUTOSUGGESTING ]] && return - ZLE_AUTOSUGGESTING=1 - autosuggest-hook-widgets - if [[ -n $ZLE_AUTOSUGGEST_CONNECTION ]]; then - # install listen for suggestions asynchronously - zle -Fw $ZLE_AUTOSUGGEST_CONNECTION autosuggest-pop-suggestion - fi -} - -autosuggest-start() { - if [[ -z $ZLE_DISABLE_AUTOSUGGEST && -n $functions[_zsh_highlight] ]]; then - if [[ ${ZSH_HIGHLIGHT_HIGHLIGHTERS[(i)autosuggest]} -gt ${#ZSH_HIGHLIGHT_HIGHLIGHTERS} ]]; then - ZSH_HIGHLIGHT_HIGHLIGHTERS+=(autosuggest) - fi - fi - autosuggest-resume -} - -# Toggles autosuggestions on/off -autosuggest-toggle() { - if [[ -n $ZLE_AUTOSUGGESTING ]]; then - autosuggest-pause - zle -A .self-insert self-insert - else - autosuggest-resume - fi -} - -autosuggest-highlight-suggested-text() { - if (( $+functions[_zsh_highlight_buffer_modified] > 0 )); then - _zsh_highlight - else - region_highlight=() - _zsh_highlight_autosuggest_highlighter - fi -} - -_zsh_highlight_autosuggest_highlighter_predicate() { - [[ -n $ZLE_AUTOSUGGESTING ]] && (( $#RBUFFER > 0 )) -} - -_zsh_highlight_autosuggest_highlighter() { - region_highlight+=("$(( $CURSOR + $AUTOSUGGESTION_HIGHLIGHT_CURSOR )) $(( $CURSOR + $#RBUFFER )) $AUTOSUGGESTION_HIGHLIGHT_COLOR") -} - -autosuggest-insert-or-space() { - setopt localoptions noshwordsplit noksharrays - if [[ $LBUFFER == *$'\012'* ]] || (( PENDING )); then - # Editing multiline buffer or pasting a chunk of text, pause - autosuggest-suspend - return - fi - - if [[ ${RBUFFER[1]} == ${KEYS[-1]} ]]; then - # Same as what's typed, just move on - ((++CURSOR)) - autosuggest-invalidate-highlight-cache - else - LBUFFER="$LBUFFER$KEYS" - if [[ $LASTWIDGET == (self-insert|magic-space|backward-delete-char) || $LASTWIDGET == (complete-word|accept-*|zle-line-init) ]]; then - if ! zle .history-beginning-search-backward; then - RBUFFER='' - if [[ ${KEYS[-1]} != ' ' ]]; then - autosuggest-send-request ${LBUFFER} - fi - fi - fi - fi - autosuggest-highlight-suggested-text -} - -autosuggest-backward-delete-char() { - if (( $#LBUFFER > 1 )); then - setopt localoptions noshwordsplit noksharrays - - if [[ $LBUFFER = *$'\012'* || $LASTWIDGET != (self-insert|magic-space|backward-delete-char) ]]; then - LBUFFER="$LBUFFER[1,-2]" - else - ((--CURSOR)) - autosuggest-invalidate-highlight-cache - zle .history-beginning-search-forward || RBUFFER='' - fi - autosuggest-highlight-suggested-text - else - zle .kill-whole-line - fi -} - -# When autosuggesting, ignore RBUFFER which corresponds to the 'unmaterialized' -# section when the user accepts the line -autosuggest-accept-line() { - RBUFFER='' - if ! (( $+functions[_zsh_highlight_buffer_modified] )); then - # Only clear the colors if the user doesn't have zsh-highlight installed - region_highlight=() - fi - zle .accept-line -} - -autosuggest-paused-self-insert() { - if [[ $RBUFFER == '' ]]; then - # Resume autosuggestions when inserting at the end of the line - autosuggest-resume - zle self-insert - else - zle .self-insert - fi -} - -autosuggest-pop-suggestion() { - local words last_word suggestion - if ! IFS= read -r -u $ZLE_AUTOSUGGEST_CONNECTION suggestion; then - # server closed the connection, stop listenting - zle -F $ZLE_AUTOSUGGEST_CONNECTION - unset ZLE_AUTOSUGGEST_CONNECTION - return - fi - if [[ -n $suggestion ]]; then - local prefix=${suggestion%$'\2'*} - suggestion=${suggestion#*$'\2'} - # only use the suggestion if the prefix is still compatible with - # the suggestion(prefix should be contained in LBUFFER) - if [[ ${LBUFFER#$prefix*} != ${LBUFFER} ]]; then - words=(${(z)LBUFFER}) - last_word=${words[-1]} - suggestion=${suggestion:$#last_word} - RBUFFER="$suggestion" - autosuggest-highlight-suggested-text - else - RBUFFER='' - fi - else - RBUFFER='' - fi - zle -Rc -} - -autosuggest-suspend() { - autosuggest-pause - zle .${WIDGET} "$@" -} - -autosuggest-tab() { - RBUFFER='' - zle .${WIDGET} "$@" - autosuggest-invalidate-highlight-cache - autosuggest-highlight-suggested-text -} - -autosuggest-accept-suggestion() { - if [[ AUTOSUGGESTION_ACCEPT_RIGHT_ARROW -eq 1 && ("$WIDGET" == 'forward-char' || "$WIDGET" == 'vi-forward-char') ]]; then - zle .end-of-line "$@" - else - zle .${WIDGET} "$@" - fi - if [[ -n $ZLE_AUTOSUGGESTING ]]; then - autosuggest-invalidate-highlight-cache - autosuggest-highlight-suggested-text - fi -} - -autosuggest-execute-suggestion() { - if [[ -n $ZLE_AUTOSUGGESTING ]]; then - zle .end-of-line - autosuggest-invalidate-highlight-cache - autosuggest-highlight-suggested-text - fi - zle .accept-line -} - -autosuggest-invalidate-highlight-cache() { - # invalidate the buffer for zsh-syntax-highlighting - _zsh_highlight_autosuggest_highlighter_cache=() -} - -autosuggest-restore-widgets() { - for widget in $ZLE_AUTOSUGGEST_ALL_WIDGETS; do - [[ -z $widgets[$widget] ]] && continue - zle -A .${widget} ${widget} - done -} - -autosuggest-hook-widgets() { - local widget - # Replace prediction widgets by versions that will also highlight RBUFFER - zle -A autosuggest-insert-or-space self-insert - zle -A autosuggest-insert-or-space magic-space - zle -A autosuggest-backward-delete-char backward-delete-char - zle -A autosuggest-accept-line accept-line - # Hook into some default widgets that should suspend autosuggestion - # automatically - for widget in $ZLE_AUTOSUGGEST_ACCEPT_WIDGETS; do - [[ -z $widgets[$widget] ]] && continue - eval "zle -A autosuggest-accept-suggestion $widget" - done - for widget in $ZLE_AUTOSUGGEST_SUSPEND_WIDGETS; do - [[ -z $widgets[$widget] ]] && continue - eval "zle -A autosuggest-suspend $widget" - done - for widget in $ZLE_AUTOSUGGEST_COMPLETION_WIDGETS; do - [[ -z $widgets[$widget] ]] && continue - eval "zle -A autosuggest-tab $widget" - done -} - -zle -N autosuggest-toggle -zle -N autosuggest-start -zle -N autosuggest-accept-suggested-small-word -zle -N autosuggest-accept-suggested-word -zle -N autosuggest-execute-suggestion - -zle -N autosuggest-paused-self-insert -zle -N autosuggest-insert-or-space -zle -N autosuggest-backward-delete-char -zle -N autosuggest-accept-line - -zle -N autosuggest-tab -zle -N autosuggest-suspend -zle -N autosuggest-accept-suggestion - -autosuggest-restore-widgets diff --git a/completion-client.zsh b/completion-client.zsh deleted file mode 100755 index c8cd957..0000000 --- a/completion-client.zsh +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env zsh -zmodload zsh/net/socket - -AUTOSUGGEST_SERVER_SCRIPT="${0:a:h}/completion-server.zsh" - -autosuggest-ensure-server() { - setopt local_options no_hup - local server_dir="/tmp/zsh-autosuggest-$USER" - local pid_file="$server_dir/pid" - local socket_path="$server_dir/socket" - - if [[ ! -d $server_dir || ! -r $pid_file ]] || ! kill -0 $(<$pid_file) &> /dev/null; then - if which setsid &> /dev/null; then - setsid zsh $AUTOSUGGEST_SERVER_SCRIPT $server_dir $pid_file $socket_path &! - else - zsh $AUTOSUGGEST_SERVER_SCRIPT $server_dir $pid_file $socket_path &! - fi - fi - - autosuggest-server-connect -} - -autosuggest-server-connect() { - unset ZLE_AUTOSUGGEST_CONNECTION - - integer remaining_tries=10 - while (( --remaining_tries )) && ! zsocket $socket_path &>/dev/null; do - sleep 0.3 - done - - [[ -z $REPLY ]] && return 1 - - ZLE_AUTOSUGGEST_CONNECTION=$REPLY -} - -autosuggest-send-request() { - [[ -z $ZLE_AUTOSUGGEST_CONNECTION ]] && return 1 - setopt local_options noglob - print -u $ZLE_AUTOSUGGEST_CONNECTION - $1 &> /dev/null || return 1 -} diff --git a/completion-server-init.zsh b/completion-server-init.zsh deleted file mode 100644 index 5e98dcf..0000000 --- a/completion-server-init.zsh +++ /dev/null @@ -1,121 +0,0 @@ -# Based on: -# https://github.com/Valodim/zsh-capture-completion/blob/master/.zshrc - -ZLE_DISABLE_AUTOSUGGEST=1 -# no prompt! -PROMPT= - -# load completion system -autoload compinit -compinit - -# never run a command -bindkey '\C-m' .kill-buffer -bindkey '\C-j' .kill-buffer -bindkey '\C-i' complete-word - -# send an emtpy line before completions are output -empty-line() { - print - # handler needs to reinsert itself after being called - compprefuncs+=empty-line -} -compprefuncs+=empty-line - -# send a line with null-byte after completions are output -null-line() { - print $'\0' - # handler needs to reinsert itself after being called - comppostfuncs+=null-line -} -comppostfuncs+=null-line - -zstyle ':completion:*' completer _complete -# never group stuff! -zstyle ':completion:*' list-grouped false -# don't insert tab when attempting completion on empty line -zstyle ':completion:*' insert-tab false -# no list separator, this saves some stripping later on -zstyle ':completion:*' list-separator '' -# dont use matchers -zstyle -d ':completion:*' matcher-list -# dont format -zstyle -d ':completion:*' format -# no color formatting -zstyle -d ':completion:*' list-colors - -# we use zparseopts -zmodload zsh/zutil - -# override compadd (this our hook) -compadd() { - - # check if any of -O, -A or -D are given - if [[ ${@[1,(i)(-|--)]} == *-(O|A|D)\ * ]]; then - # if that is the case, just delegate and leave - builtin compadd "$@" - return $? - fi - - # be careful with namespacing here, we don't want to mess with stuff that - # should be passed to compadd! - typeset -a __hits __dscr __tmp - - # do we have a description parameter? - # note we don't use zparseopts here because of combined option parameters - # with arguments like -default- confuse it. - if (( $@[(I)-d] )); then # kind of a hack, $+@[(r)-d] doesn't work because of line noise overload - # next param after -d - __tmp=${@[$[${@[(i)-d]}+1]]} - # description can be given as an array parameter name, or inline () array - if [[ $__tmp == \(* ]]; then - eval "__dscr=$__tmp" - else - __dscr=( "${(@P)__tmp}" ) - fi - fi - - # capture completions by injecting -A parameter into the compadd call. - # this takes care of matching for us. - builtin compadd -A __hits -D __dscr "$@" - - # JESUS CHRIST IT TOOK ME FOREVER TO FIGURE OUT THIS OPTION WAS SET AND WAS MESSING WITH MY SHIT HERE - setopt localoptions norcexpandparam extendedglob - - # extract prefixes and suffixes from compadd call. we can't do zsh's cool - # -r remove-func magic, but it's better than nothing. - typeset -A apre hpre hsuf asuf - zparseopts -E P:=apre p:=hpre S:=asuf s:=hsuf - - # append / to directories? we are only emulating -f in a half-assed way - # here, but it's better than nothing. - integer dirsuf=0 - # don't be fooled by -default- >.> - if [[ -z $hsuf && "${${@//-default-/}% -# *}" == *-[[:alnum:]]#f* ]]; then - dirsuf=1 - fi - - # just drop - [[ -n $__hits ]] || return - - # this is the point where we have all matches in $__hits and all - # descriptions in $__dscr! - - # display all matches - local dsuf dscr - for i in {1..$#__hits}; do - - # add a dir suffix? - (( dirsuf )) && [[ -d $__hits[$i] ]] && dsuf=/ || dsuf= - # description to be displayed afterwards - # (( $#__dscr >= $i )) && dscr=" -- ${${__dscr[$i]}##$__hits[$i] #}" || dscr= - - print - $'\1'$IPREFIX$apre$hpre$__hits[$i]$dsuf$hsuf$asuf$dscr - - done - - unset __hits __dscr __tmp -} - -# signal the daemon we are ready for input -print $'\0' diff --git a/completion-server.zsh b/completion-server.zsh deleted file mode 100755 index e8e2946..0000000 --- a/completion-server.zsh +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env zsh -# Based on: -# https://github.com/Valodim/zsh-capture-completion/blob/master/capture.zsh - -# read everything until a line containing the byte 0 is found -read-to-null() { - while zpty -r z chunk; do - [[ $chunk == *$'\0'* ]] && break - [[ $chunk != $'\1'* ]] && continue # ignore what doesnt start with '1' - print -n - ${chunk:1} - done -} - -accept-connection() { - zsocket -a $server - fds[$REPLY]=1 - print "connection accepted, fd: $REPLY" >&2 -} - -handle-request() { - local connection=$1 current line - integer read_something=0 - print "request received from fd $connection" - while read -u $connection prefix &> /dev/null; do - read_something=1 - # send the prefix to be completed followed by a TAB to force - # completion - zpty -w -n z $prefix$'\t' - zpty -r z chunk &> /dev/null # read empty line before completions - current='' - # read completions one by one, storing the longest match - read-to-null | while IFS= read -r line; do - (( $#line > $#current )) && current=$line - done - # send the longest completion back to the client, strip the last - # non-printable character - if (( $#current )); then - print -u $connection - $prefix$'\2'${current:0:-1} - else - print -u $connection '' - fi - # clear input buffer - zpty -w z $'\n' - break # handle more requests/return to zselect - done - if ! (( read_something )); then - print "connection with fd $connection closed" >&2 - unset fds[$connection] - exec {connection}>&- # free the file descriptor - fi -} - - -if [[ -n $ZLE_AUTOSUGGEST_SERVER_LOG ]]; then - exec >> "$HOME/.autosuggest-server.log" -else - exec > /dev/null -fi - -if [[ -n $ZLE_AUTOSUGGEST_SERVER_LOG_ERRORS ]]; then - exec 2>> "$HOME/.autosuggest-server-errors.log" -else - exec 2> /dev/null -fi - -exec < /dev/null - -zmodload zsh/zpty -zmodload zsh/zselect -zmodload zsh/net/socket -setopt noglob -print "autosuggestion server started, pid: $$" >&2 - -# Start an interactive zsh connected to a zpty -zpty z ZLE_DISABLE_AUTOSUGGEST=1 zsh -i -print 'interactive shell started' -# Source the init script -zpty -w z "source '${0:a:h}/completion-server-init.zsh'" - -# wait for ok from shell -read-to-null &> /dev/null -print 'interactive shell ready' - -# listen on a socket for completion requests -server_dir=$1 -pid_file=$2 -socket_path=$3 - - -cleanup() { - print 'removing socket and pid file...' - rm -f $socket_path $pid_file - print "autosuggestion server stopped, pid: $$" - exit -} - -trap cleanup TERM INT HUP EXIT - -mkdir -m 700 $server_dir - -while ! zsocket -l $socket_path; do - if [[ ! -r $pid_file ]] || ! kill -0 $(<$pid_file); then - rm -f $socket_path - else - exit 1 - fi - print "will retry listening on '$socket_path'" -done - -server=$REPLY - -print "server listening on '$socket_path'" - -print $$ > $pid_file - -typeset -A fds ready -fds[$server]=1 - -while zselect -A ready ${(k)fds}; do - queue=(${(k)ready}) - for fd in $queue; do - if (( fd == server )); then - accept-connection - else - handle-request $fd - fi - done -done diff --git a/dist/autosuggestions.zsh b/dist/autosuggestions.zsh new file mode 100644 index 0000000..13e099f --- /dev/null +++ b/dist/autosuggestions.zsh @@ -0,0 +1,345 @@ +# Fish-like fast/unobtrusive autosuggestions for zsh. +# https://github.com/tarruda/zsh-autosuggestions +# v0.1.0 +# +# Copyright (c) 2013 Thiago de Arruda +# Copyright (c) 2016 Eric Freese +# +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this software and associated documentation +# files (the "Software"), to deal in the Software without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following +# conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +#--------------------------------# +# Global Configuration Variables # +#--------------------------------# + +# Color to use when highlighting suggestion +# Uses format of `region_highlight` +# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets +ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' + +# Prefix to use when saving original versions of bound widgets +ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig- + +# Widgets that clear the suggestion +ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( + history-search-forward + history-search-backward + history-beginning-search-forward + history-beginning-search-backward + up-line-or-history + down-line-or-history + accept-line +) + +# Widgets that modify the suggestion +ZSH_AUTOSUGGEST_MODIFY_WIDGETS=( + list-choices + complete-word + menu-complete + menu-expand-or-complete + reverse-menu-complete + expand-or-complete + expand-or-complete-prefix + self-insert + magic-space + bracketed-paste + expand-cmd-path + accept-and-menu-complete + backward-delete-char + vi-backward-delete-char + delete-char + vi-delete-char + delete-char-or-list +) + +# Widgets that accept the entire suggestion +ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( + forward-char + end-of-line + vi-forward-char + vi-end-of-line +) + +# Widgets that accept the suggestion as far as the cursor moves +ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( + forward-word + vi-forward-word + vi-forward-word-end + vi-forward-blank-word + vi-forward-blank-word-end +) + +#-------------------------------------# +# Handle Deprecated Variables/Widgets # +#-------------------------------------# + +unset _ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN + +_zsh_autosuggest_check_deprecated_config() { + if [ -n "$AUTOSUGGESTION_HIGHLIGHT_COLOR" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_COLOR is deprecated. Use ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE instead." + [ -z "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" ] && ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=$AUTOSUGGESTION_HIGHLIGHT_STYLE + unset AUTOSUGGESTION_HIGHLIGHT_STYLE + fi + + if [ -n "$AUTOSUGGESTION_HIGHLIGHT_CURSOR" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_CURSOR is deprecated." + unset AUTOSUGGESTION_HIGHLIGHT_CURSOR + fi + + if [ -n "$AUTOSUGGESTION_ACCEPT_RIGHT_ARROW" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_ACCEPT_RIGHT_ARROW is deprecated. The right arrow now accepts the suggestion by default." + unset AUTOSUGGESTION_ACCEPT_RIGHT_ARROW + fi +} + +_zsh_autosuggest_deprecated_warning() { + >&2 echo "zsh-autosuggestions: $@" +} + +_zsh_autosuggest_deprecated_start_widget() { + if [ -z "$_ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN" ]; then + _zsh_autosuggest_deprecated_warning "The autosuggest-start widget is deprecated. Use the autosuggest_start function instead. For more info, see README at https://github.com/tarruda/zsh-autosuggestions." + _ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN=true + fi + + autosuggest_start +} + +zle -N autosuggest-start _zsh_autosuggest_deprecated_start_widget + +#----------------# +# Widget Helpers # +#----------------# + +# Bind a single widget to an autosuggest widget, saving a reference to the original widget +_zsh_autosuggest_bind_widget() { + local widget=$1 + local autosuggest_function=$2 + local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX + local action + + case $widgets[$widget] in + # Already bound + user:_zsh_autosuggest_(bound|orig)_*);; + + # User-defined widget + user:*) + zle -N $prefix$widget ${widgets[$widget]#*:} + ;; + + # Built-in widget + builtin) + eval "_zsh_autosuggest_orig_$widget() { zle .$widget }" + zle -N $prefix$widget _zsh_autosuggest_orig_$widget + ;; + + # Completion widget + completion:*) + eval "zle -C $prefix$widget ${${widgets[$widget]#*:}/:/ }" + ;; + esac + + # Set up widget to call $autosuggest_function if it exists + # Otherwise just call the original widget + if [ -n "$autosuggest_function" ]; then; + action=$autosuggest_function; + else; + action="zle $prefix$widget \$@" + fi + + # Create new function for the widget that highlights and calls the action + eval "_zsh_autosuggest_bound_$widget() { + _zsh_autosuggest_highlight_reset + $action + _zsh_autosuggest_highlight_apply + }" + + # Create the bound widget + zle -N $widget _zsh_autosuggest_bound_$widget +} + +# Map all configured widgets to the right autosuggest widgets +_zsh_autosuggest_bind_widgets() { + local widget; + + # Find every widget we might want to bind and bind it appropriately + for widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|autosuggest-*|$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX*|run-help|which-command|beep|set-local-history|yank)}; do + if [ ${ZSH_AUTOSUGGEST_MODIFY_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_modify + elif [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_clear + elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_accept + elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_partial_accept + else + _zsh_autosuggest_bind_widget $widget + fi + done +} + +# Given the name of a widget, invoke the original we saved, if it exists +_zsh_autosuggest_invoke_original_widget() { + local original_widget_name="$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX$1" + + if [ $widgets[$original_widget_name] ]; then + zle $original_widget_name + fi +} + +#--------------# +# Highlighting # +#--------------# + +# If there was a highlight, remove it +_zsh_autosuggest_highlight_reset() { + if [ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]; then + region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}") + unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT + fi +} + +# If there's a suggestion, highlight it +_zsh_autosuggest_highlight_apply() { + if [ $#POSTDISPLAY -gt 0 ]; then + _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" + region_highlight+=($_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT) + else + unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT + fi +} + +#------------------------------------# +# Autosuggest Widget Implementations # +#------------------------------------# + +# Clear the suggestion +_zsh_autosuggest_clear() { + # Remove the suggestion + unset POSTDISPLAY + + _zsh_autosuggest_invoke_original_widget $WIDGET +} + +# Modify the buffer and get a new suggestion +_zsh_autosuggest_modify() { + # Original widget modifies the buffer + _zsh_autosuggest_invoke_original_widget $WIDGET + + # Get a new suggestion if the buffer is not empty after modification + local suggestion + if [ $#BUFFER -gt 0 ]; then + suggestion=$(_zsh_autosuggest_suggestion $BUFFER) + fi + + # Add the suggestion to the POSTDISPLAY + if [ -n "$suggestion" ]; then + POSTDISPLAY=${suggestion#$BUFFER} + else + unset POSTDISPLAY + fi +} + +# Accept the entire suggestion +_zsh_autosuggest_accept() { + # Only accept if the cursor is at the end of the buffer + if [ $CURSOR -eq $#BUFFER ]; then + # Add the suggestion to the buffer + BUFFER="$BUFFER$POSTDISPLAY" + + # Remove the suggestion + unset POSTDISPLAY + + # Move the cursor to the end of the buffer + CURSOR=${#BUFFER} + fi + + _zsh_autosuggest_invoke_original_widget $WIDGET +} + +# Partially accept the suggestion +_zsh_autosuggest_partial_accept() { + # Save the contents of the buffer so we can restore later if needed + local original_buffer=$BUFFER + + # Temporarily accept the suggestion. + BUFFER="$BUFFER$POSTDISPLAY" + + # Original widget moves the cursor + _zsh_autosuggest_invoke_original_widget $WIDGET + + # If we've moved past the end of the original buffer + if [ $CURSOR -gt $#original_buffer ]; then + # Set POSTDISPLAY to text right of the cursor + POSTDISPLAY=$RBUFFER + + # Clip the buffer at the cursor + BUFFER=$LBUFFER + else + # Restore the original buffer + BUFFER=$original_buffer + fi +} + +_zsh_autosuggest_widget_accept() { + _zsh_autosuggest_highlight_reset + _zsh_autosuggest_accept + _zsh_autosuggest_highlight_apply +} + +_zsh_autosuggest_widget_clear() { + _zsh_autosuggest_highlight_reset + _zsh_autosuggest_clear + _zsh_autosuggest_highlight_apply +} + +zle -N autosuggest-accept _zsh_autosuggest_widget_accept +zle -N autosuggest-clear _zsh_autosuggest_clear + +#------------# +# Suggestion # +#------------# + +# Get a suggestion from history that matches a given prefix +_zsh_autosuggest_suggestion() { + setopt localoptions extendedglob + + # Escape the prefix (requires EXTENDED_GLOB) + local prefix=${1//(#m)[\][()|\\*?#<>~^]/\\$MATCH} + + # Get all history items (reversed) that match pattern $prefix* + local history_matches + history_matches=(${history[(R)$prefix*]}) + + # Echo the first item that matches + echo ${history_matches[1]} +} + +#-------# +# Start # +#-------# + +# Start the autosuggestion widgets +autosuggest_start() { + _zsh_autosuggest_check_deprecated_config + _zsh_autosuggest_bind_widgets +} diff --git a/install b/install deleted file mode 100755 index 9169519..0000000 --- a/install +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/bash - -# Install script for zsh-autocomplete - -config="$HOME/.zshrc" -for config in "$HOME/.zshrc" "$ZDOTDIR/.zshrc" "$1"; do - echo $config - #first checks if ~/.zshrc file exists and is readable - if [ -r "$config" ]; then - break - elif [ "$config" = "$1" ]; then - echo "\nError: Please specify as first argument the file in which to load zsh-autosuggestions (usually ~/.zshrc)!\n" - exit 1 - fi -done - -SOURCE="${BASH_SOURCE[0]}" -while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink - DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - SOURCE="$(readlink "$SOURCE")" - [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located -done -DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" - -# appends the string to $config (usually ~/.zshrc) file -cat >> "$config" <<-EOF - - # Setup zsh-autosuggestions - source $DIR/autosuggestions.zsh - - # Enable autosuggestions automatically - zle-line-init() { - zle autosuggest-start - } - - zle -N zle-line-init - - # use ctrl+t to toggle autosuggestions(hopefully this wont be needed as - # zsh-autosuggestions is designed to be unobtrusive) - bindkey '^T' autosuggest-toggle -EOF - -echo "\nSetup completed successfully!\n" -exit 0 diff --git a/script/test.sh b/script/test.sh new file mode 100755 index 0000000..b1c1b77 --- /dev/null +++ b/script/test.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env zsh + +SCRIPT_DIR=$(dirname "$0") +TEST_DIR=$SCRIPT_DIR/../test +DIST_DIR=$SCRIPT_DIR/../dist + +source $DIST_DIR/autosuggestions.zsh + +testDefaultHighlightStyle() { + assertEquals \ + "fg=8" \ + "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" +} + +testHighlightApplyWithSuggestion() { + orig_style=ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE + ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=4" + + BUFFER="ec" + POSTDISPLAY="ho hello" + region_highlight=("0 2 fg=1") + + _zsh_autosuggest_highlight_apply + + assertEquals \ + "adds to region_highlight with correct style" \ + "0 2 fg=1 2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \ + "$region_highlight" + + assertEquals \ + "saves the higlight to be removed later" \ + "2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \ + "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" + + ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=orig_style +} + +testHighlightApplyWithoutSuggestion() { + BUFFER="echo hello" + POSTDISPLAY="" + region_highlight=("0 4 fg=1") + + _zsh_autosuggest_highlight_apply + + assertEquals \ + "leaves region_highlight alone" \ + "0 4 fg=1" \ + "$region_highlight" + + assertNull \ + "clears the last highlight" \ + "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" +} + +testHighlightReset() { + BUFFER="ec" + POSTDISPLAY="ho hello" + region_highlight=("0 1 fg=1" "2 10 fg=8" "1 2 fg=1") + _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="2 10 fg=8" + + _zsh_autosuggest_highlight_reset + + assertEquals \ + "removes last highlight region" \ + "0 1 fg=1 1 2 fg=1" \ + "$region_highlight" + + assertNull \ + "clears the last highlight" \ + "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" +} + +# For zsh compatibility +setopt shwordsplit +SHUNIT_PARENT=$0 + +source $TEST_DIR/shunit2-2.1.6/src/shunit2 diff --git a/src/bind.zsh b/src/bind.zsh new file mode 100644 index 0000000..d77715d --- /dev/null +++ b/src/bind.zsh @@ -0,0 +1,80 @@ + +#----------------# +# Widget Helpers # +#----------------# + +# Bind a single widget to an autosuggest widget, saving a reference to the original widget +_zsh_autosuggest_bind_widget() { + local widget=$1 + local autosuggest_function=$2 + local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX + local action + + case $widgets[$widget] in + # Already bound + user:_zsh_autosuggest_(bound|orig)_*);; + + # User-defined widget + user:*) + zle -N $prefix$widget ${widgets[$widget]#*:} + ;; + + # Built-in widget + builtin) + eval "_zsh_autosuggest_orig_$widget() { zle .$widget }" + zle -N $prefix$widget _zsh_autosuggest_orig_$widget + ;; + + # Completion widget + completion:*) + eval "zle -C $prefix$widget ${${widgets[$widget]#*:}/:/ }" + ;; + esac + + # Set up widget to call $autosuggest_function if it exists + # Otherwise just call the original widget + if [ -n "$autosuggest_function" ]; then; + action=$autosuggest_function; + else; + action="zle $prefix$widget \$@" + fi + + # Create new function for the widget that highlights and calls the action + eval "_zsh_autosuggest_bound_$widget() { + _zsh_autosuggest_highlight_reset + $action + _zsh_autosuggest_highlight_apply + }" + + # Create the bound widget + zle -N $widget _zsh_autosuggest_bound_$widget +} + +# Map all configured widgets to the right autosuggest widgets +_zsh_autosuggest_bind_widgets() { + local widget; + + # Find every widget we might want to bind and bind it appropriately + for widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|autosuggest-*|$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX*|run-help|which-command|beep|set-local-history|yank)}; do + if [ ${ZSH_AUTOSUGGEST_MODIFY_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_modify + elif [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_clear + elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_accept + elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then + _zsh_autosuggest_bind_widget $widget _zsh_autosuggest_partial_accept + else + _zsh_autosuggest_bind_widget $widget + fi + done +} + +# Given the name of a widget, invoke the original we saved, if it exists +_zsh_autosuggest_invoke_original_widget() { + local original_widget_name="$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX$1" + + if [ $widgets[$original_widget_name] ]; then + zle $original_widget_name + fi +} diff --git a/src/config.zsh b/src/config.zsh new file mode 100644 index 0000000..d0bad9e --- /dev/null +++ b/src/config.zsh @@ -0,0 +1,61 @@ + +#--------------------------------# +# Global Configuration Variables # +#--------------------------------# + +# Color to use when highlighting suggestion +# Uses format of `region_highlight` +# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets +ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8' + +# Prefix to use when saving original versions of bound widgets +ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig- + +# Widgets that clear the suggestion +ZSH_AUTOSUGGEST_CLEAR_WIDGETS=( + history-search-forward + history-search-backward + history-beginning-search-forward + history-beginning-search-backward + up-line-or-history + down-line-or-history + accept-line +) + +# Widgets that modify the suggestion +ZSH_AUTOSUGGEST_MODIFY_WIDGETS=( + list-choices + complete-word + menu-complete + menu-expand-or-complete + reverse-menu-complete + expand-or-complete + expand-or-complete-prefix + self-insert + magic-space + bracketed-paste + expand-cmd-path + accept-and-menu-complete + backward-delete-char + vi-backward-delete-char + delete-char + vi-delete-char + delete-char-or-list +) + +# Widgets that accept the entire suggestion +ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=( + forward-char + end-of-line + vi-forward-char + vi-end-of-line +) + +# Widgets that accept the suggestion as far as the cursor moves +ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=( + forward-word + vi-forward-word + vi-forward-word-end + vi-forward-blank-word + vi-forward-blank-word-end +) diff --git a/src/deprecated.zsh b/src/deprecated.zsh new file mode 100644 index 0000000..a369135 --- /dev/null +++ b/src/deprecated.zsh @@ -0,0 +1,39 @@ + +#-------------------------------------# +# Handle Deprecated Variables/Widgets # +#-------------------------------------# + +unset _ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN + +_zsh_autosuggest_check_deprecated_config() { + if [ -n "$AUTOSUGGESTION_HIGHLIGHT_COLOR" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_COLOR is deprecated. Use ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE instead." + [ -z "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" ] && ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=$AUTOSUGGESTION_HIGHLIGHT_STYLE + unset AUTOSUGGESTION_HIGHLIGHT_STYLE + fi + + if [ -n "$AUTOSUGGESTION_HIGHLIGHT_CURSOR" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_CURSOR is deprecated." + unset AUTOSUGGESTION_HIGHLIGHT_CURSOR + fi + + if [ -n "$AUTOSUGGESTION_ACCEPT_RIGHT_ARROW" ]; then + _zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_ACCEPT_RIGHT_ARROW is deprecated. The right arrow now accepts the suggestion by default." + unset AUTOSUGGESTION_ACCEPT_RIGHT_ARROW + fi +} + +_zsh_autosuggest_deprecated_warning() { + >&2 echo "zsh-autosuggestions: $@" +} + +_zsh_autosuggest_deprecated_start_widget() { + if [ -z "$_ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN" ]; then + _zsh_autosuggest_deprecated_warning "The autosuggest-start widget is deprecated. Use the autosuggest_start function instead. For more info, see README at https://github.com/tarruda/zsh-autosuggestions." + _ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN=true + fi + + autosuggest_start +} + +zle -N autosuggest-start _zsh_autosuggest_deprecated_start_widget diff --git a/src/highlight.zsh b/src/highlight.zsh new file mode 100644 index 0000000..ecce3d1 --- /dev/null +++ b/src/highlight.zsh @@ -0,0 +1,22 @@ + +#--------------# +# Highlighting # +#--------------# + +# If there was a highlight, remove it +_zsh_autosuggest_highlight_reset() { + if [ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]; then + region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}") + unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT + fi +} + +# If there's a suggestion, highlight it +_zsh_autosuggest_highlight_apply() { + if [ $#POSTDISPLAY -gt 0 ]; then + _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" + region_highlight+=($_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT) + else + unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT + fi +} diff --git a/src/start.zsh b/src/start.zsh new file mode 100644 index 0000000..f793e75 --- /dev/null +++ b/src/start.zsh @@ -0,0 +1,10 @@ + +#-------# +# Start # +#-------# + +# Start the autosuggestion widgets +autosuggest_start() { + _zsh_autosuggest_check_deprecated_config + _zsh_autosuggest_bind_widgets +} diff --git a/src/suggestion.zsh b/src/suggestion.zsh new file mode 100644 index 0000000..54ca892 --- /dev/null +++ b/src/suggestion.zsh @@ -0,0 +1,19 @@ + +#------------# +# Suggestion # +#------------# + +# Get a suggestion from history that matches a given prefix +_zsh_autosuggest_suggestion() { + setopt localoptions extendedglob + + # Escape the prefix (requires EXTENDED_GLOB) + local prefix=${1//(#m)[\][()|\\*?#<>~^]/\\$MATCH} + + # Get all history items (reversed) that match pattern $prefix* + local history_matches + history_matches=(${history[(R)$prefix*]}) + + # Echo the first item that matches + echo ${history_matches[1]} +} diff --git a/src/widgets.zsh b/src/widgets.zsh new file mode 100644 index 0000000..009e7e2 --- /dev/null +++ b/src/widgets.zsh @@ -0,0 +1,87 @@ + +#------------------------------------# +# Autosuggest Widget Implementations # +#------------------------------------# + +# Clear the suggestion +_zsh_autosuggest_clear() { + # Remove the suggestion + unset POSTDISPLAY + + _zsh_autosuggest_invoke_original_widget $WIDGET +} + +# Modify the buffer and get a new suggestion +_zsh_autosuggest_modify() { + # Original widget modifies the buffer + _zsh_autosuggest_invoke_original_widget $WIDGET + + # Get a new suggestion if the buffer is not empty after modification + local suggestion + if [ $#BUFFER -gt 0 ]; then + suggestion=$(_zsh_autosuggest_suggestion $BUFFER) + fi + + # Add the suggestion to the POSTDISPLAY + if [ -n "$suggestion" ]; then + POSTDISPLAY=${suggestion#$BUFFER} + else + unset POSTDISPLAY + fi +} + +# Accept the entire suggestion +_zsh_autosuggest_accept() { + # Only accept if the cursor is at the end of the buffer + if [ $CURSOR -eq $#BUFFER ]; then + # Add the suggestion to the buffer + BUFFER="$BUFFER$POSTDISPLAY" + + # Remove the suggestion + unset POSTDISPLAY + + # Move the cursor to the end of the buffer + CURSOR=${#BUFFER} + fi + + _zsh_autosuggest_invoke_original_widget $WIDGET +} + +# Partially accept the suggestion +_zsh_autosuggest_partial_accept() { + # Save the contents of the buffer so we can restore later if needed + local original_buffer=$BUFFER + + # Temporarily accept the suggestion. + BUFFER="$BUFFER$POSTDISPLAY" + + # Original widget moves the cursor + _zsh_autosuggest_invoke_original_widget $WIDGET + + # If we've moved past the end of the original buffer + if [ $CURSOR -gt $#original_buffer ]; then + # Set POSTDISPLAY to text right of the cursor + POSTDISPLAY=$RBUFFER + + # Clip the buffer at the cursor + BUFFER=$LBUFFER + else + # Restore the original buffer + BUFFER=$original_buffer + fi +} + +_zsh_autosuggest_widget_accept() { + _zsh_autosuggest_highlight_reset + _zsh_autosuggest_accept + _zsh_autosuggest_highlight_apply +} + +_zsh_autosuggest_widget_clear() { + _zsh_autosuggest_highlight_reset + _zsh_autosuggest_clear + _zsh_autosuggest_highlight_apply +} + +zle -N autosuggest-accept _zsh_autosuggest_widget_accept +zle -N autosuggest-clear _zsh_autosuggest_clear diff --git a/test/shunit2-2.1.6/bin/gen_test_results.sh b/test/shunit2-2.1.6/bin/gen_test_results.sh new file mode 100755 index 0000000..dc825ac --- /dev/null +++ b/test/shunit2-2.1.6/bin/gen_test_results.sh @@ -0,0 +1,62 @@ +#! /bin/sh +# $Id: gen_test_results.sh 54 2008-10-21 23:29:23Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# This script runs the provided unit tests and sends the output to the +# appropriate file. +# + +# treat unset variables as an error +set -u + +die() +{ + [ $# -gt 0 ] && echo "error: $@" >&2 + exit 1 +} + +BASE_DIR="`dirname $0`/.." +LIB_DIR="${BASE_DIR}/lib" + +# load libraries +. ${LIB_DIR}/shflags || die 'unable to load shflags library' +. ${LIB_DIR}/shlib || die 'unable to load shlib library' +. ${LIB_DIR}/versions || die 'unable to load versions library' + +BASE_DIR=`shlib_relToAbsPath "${BASE_DIR}"` +SRC_DIR="${BASE_DIR}/src" + +os_name=`versions_osName |sed 's/ /_/g'` +os_version=`versions_osVersion` + +DEFINE_boolean force false 'force overwrite' f +DEFINE_string output_dir "`pwd`" 'output dir' d +DEFINE_string output_file "${os_name}-${os_version}.txt" 'output file' o +DEFINE_string suite 'shunit2_test.sh' 'unit test suite' s +FLAGS "${@:-}" || exit $?; shift ${FLAGS_ARGC} + +# determine output filename +output="${FLAGS_output_dir:+${FLAGS_output_dir}/}${FLAGS_output_file}" +output=`shlib_relToAbsPath "${output}"` + +# checks +if [ -f "${output}" ]; then + if [ ${FLAGS_force} -eq ${FLAGS_TRUE} ]; then + rm -f "${output}" + else + echo "not overwriting '${output}'" >&2 + exit ${FLAGS_ERROR} + fi +fi +touch "${output}" 2>/dev/null || die "unable to write to '${output}'" + +# run tests +( cd "${SRC_DIR}"; ./${FLAGS_suite} |tee "${output}" ) + +echo >&2 +echo "output written to '${output}'" >&2 diff --git a/test/shunit2-2.1.6/bin/which b/test/shunit2-2.1.6/bin/which new file mode 100755 index 0000000..4eefe74 --- /dev/null +++ b/test/shunit2-2.1.6/bin/which @@ -0,0 +1,36 @@ +#! /bin/sh +# $Id: which 12 2007-02-18 03:31:14Z sfsetse $ +# +# This is a simple implementation of the 'which' command for those OSes that +# don't have one. +# + +true; TRUE=$? +false; FALSE=$? + +showAll=${FALSE} + +# process command line flags +while getopts 'a' opt; do + case ${opt} in + a) showAll=${TRUE} + esac +done +shift `expr ${OPTIND} - 1` + +# exit if no arguments were given +[ $# -eq 0 ] && exit 1 + +command=$1 + +# search for command +out=`echo "${PATH}" |sed "s/:/\n/g" |\ +while read path; do + fullPath="${path}/${command}" + if [ -x "${fullPath}" ]; then + echo "${fullPath}" + [ ${showAll} -eq ${FALSE} ] && break + fi +done` +[ -z "${out}" ] && exit 1 +echo "${out}" diff --git a/test/shunit2-2.1.6/doc/CHANGES-2.1.txt b/test/shunit2-2.1.6/doc/CHANGES-2.1.txt new file mode 100644 index 0000000..14764b1 --- /dev/null +++ b/test/shunit2-2.1.6/doc/CHANGES-2.1.txt @@ -0,0 +1,214 @@ +Changes in shUnit2 2.1.X +======================== + +Changes with 2.1.6 +------------------ + +Removed all references to the DocBook documentation. + +Simplified the 'src' structure. + +Fixed error message in fail() that stated wrong number of required arguments. + +Updated lib/versions. + +Fixed bug in _shunit_mktempDir() where a failure occurred when the 'od' command was not present in /usr/bin. + +Renamed shunit_tmpDir variable to SHUNIT_TMPDIR to closer match the standard +TMPDIR variable. + +Added support for calling shunit2 as an executable, in addition to the existing +method of sourcing it in as a library. This allows users to keep tests working +despite the location of the shunit2 executable being different for each OS +distribution. + +Issue #14: Improved handling of some strange chars (e.g. single and double +quotes) in messages. + +Issue# 27: Fixed error message for assertSame(). + +Issue# 25: Added check and error message to user when phantom functions are +written to a partition mounted with noexec. + +Issue# 11: Added support for defining functions like 'function someFunction()'. + + +Changes with 2.1.5 +------------------ + +Issue# 1: Fixed bug pointed out by R Bernstein in the trap code where certain +types of exit conditions did not generate the ending report. + +Issue# 2: Added assertNotEquals() assert. + +Issue# 3: Moved check for unset variables out of shUnit2 into the unit tests. +Testing poorly written software blows up if this check is in, but it is only +interesting for shUnit2 itself. Added shunit_test_output.sh unit test for this. +Some shells still do not catch such errors properly (e.g. Bourne shell and BASH +2.x). + +Added new custom assert in test_helpers to check for output to STDOUT, and none +to STDERR. + +Replaced fatal message in the temp directory creation with a _shunit_fatal() +function call. + +Fixed test_output unit test so it works now that the 'set -u' stuff was removed +for Issue# 3. + +Flushed out the coding standards in the README.txt a bit more, and brought the +shunit2 code up to par with the documented standards. + +Issue# 4: Completely changed the reporting output to be a closer match for +JUnit and PyUnit. As a result, tests are counted separately from assertions. + +Provide public shunit_tmpDir variable that can be used by unit test scripts that +need automated and guaranteed cleanup. + +Issue# 7: Fixed duplicated printing of messages passed to asserts. + +Per code review, fixed wording of failSame() and failNotSame() messages. + +Replaced version_info.sh with versions library and made appropriate changes in +other scripts to use it. + +Added gen_test_results.sh to make releases easier. + +Fixed bugs in shlib_relToAbsPath() in shlib. + +Converted DocBook documentation to reStructuredText for easier maintenance. The +DocBook documentation is now considered obsolete, and will be removed in a +future release. + +Issue# 5: Fixed the documentation around the usage of failures. + +Issue# 9: Added unit tests and updated documentation to demonstrate the +requirement of quoting values twice when macros are used. This is due to how +shell parses arguments. + +When an invalid number of arguments is passed to a function, the invalid number +is returned to the user so they are more aware of what the cause might be. + + +Changes with 2.1.4 +------------------ + +Removed the _shunit_functionExists() function as it was dead code. + +Fixed zsh version number check in version_info. + +Fixed bug in last resort temporary directory creation. + +Fixed off-by-one in exit value for scripts caught by the trap handler. + +Added argument count error checking to all functions. + +Added mkdir_test.sh example. + +Moved src/test into src/shell to better match structure used with shFlags. + +Fixed problem where null values were not handled properly under ksh. + +Added support for outputting line numbers as part of assert messages. + +Started documenting the coding standards, and changed some variable names as a +result. + +Improved zsh version and option checks. + +Renamed the __SHUNIT_VERSION variable to SHUNIT_VERSION. + + +Changes with 2.1.3 +------------------ + +Added some explicit variable defaults, even though the variables are set, as +they sometimes behave strange when the script is canceled. + +Additional workarounds for zsh compatibility. + +shUnit2 now exits with a non-zero exit code if any of the tests failed. This was +done for automated testing frameworks. Tests that were skipped are not +considered failures, and do not affect the exit code. + +Changed detection of STDERR output in unit tests. + + +Changes with 2.1.2 +------------------ + +Unset additional variables that were missed. + +Added checks and workarounds to improve zsh compatibility. + +Added some argument count checks ``assertEquals()``, ``assertNull()``, and +``assertSame()`` + + +Changes with 2.1.1 +------------------ + +Fixed bug where ``fail()`` was not honoring skipping. + +Fixed problem with ``docs-docbook-prep`` target that prevented it from working. +(Thanks to Bryan Larsen for pointing this out.) + +Changed the test in ``assertFalse()`` so that any non-zero value registers as +false. (Credits to Bryan Larsen) + +Major fiddling to bring more in line with `JUnit `. Asserts +give better output when no message is given, and failures now just fail. + +It was pointed out that the simple 'failed' message for a failed assert was not +only insufficient, it was nonstandard (when compared to JUnit) and didn't +provide the user with an expected vs actual result. The code was revised +somewhat to bring closer into alignment with JUnit (v4.3.1 specifically) so +that it feels more "normal". (Credits to Richard Jensen) + +As part of the JUnit realignment, it was noticed that fail*() functions in +JUnit don't actually do any comparisons themselves. They only generate a +failure message. Updated the code to match. + +Added self-testing unit tests. Kinda horkey, but they did find bugs during the +JUnit realignment. + +Fixed the code for returning from asserts as the return was being called before +the unsetting of variables occurred. (Credits to Mathias Goldau) + +The assert(True|False)() functions now accept an integer value for a +conditional test. A value of '0' is considered 'true', while any non-zero value +is considered 'false'. + +All public functions now fill use default values to work properly with the '-x' +shell debugging flag. + +Fixed the method of percent calculation for the report to get achieve better +accuracy. + + +Changes with 2.1.0 (since 2.0.1) +-------------------------------- + +This release is a branch of the 2.0.1 release. + +Moving to `reStructured Text `_ for +the documentation. + +Fixed problem with ``fail()``. The failure message was not properly printed. + +Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be +downloaded before parsing can continue. + +Renamed the internal ``__SHUNIT_TRUE`` and ``__SHUNIT_FALSE`` variables to +``SHUNIT_TRUE`` and ``SHUNIT_FALSE`` so that unit tests can "use" them. + +Added support for test "skipping". If skipping is turned on with the +``startSkip()`` function, ``assert`` and ``fail`` functions will return +immediately, and the skip will be recorded. + +The report output format was changed to include the percentage for each test +result, rather than just those successful. + + +.. $Revision: 326 $ +.. vim:fileencoding=latin1:ft=text:spell:tw=80 diff --git a/test/shunit2-2.1.6/doc/LGPL-2.1 b/test/shunit2-2.1.6/doc/LGPL-2.1 new file mode 100644 index 0000000..b1e3f5a --- /dev/null +++ b/test/shunit2-2.1.6/doc/LGPL-2.1 @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/test/shunit2-2.1.6/doc/README.html b/test/shunit2-2.1.6/doc/README.html new file mode 100644 index 0000000..b7b4672 --- /dev/null +++ b/test/shunit2-2.1.6/doc/README.html @@ -0,0 +1,540 @@ + + + + + + +shUnit2 2.1.x README + + + +
+

shUnit2 2.1.x README

+ +
+

code.google.com

+

This project is stored on code.google.com as http://code.google.com/p/shunit2/. +All releases as of 2.1.4 and full source are available there. Documentation is +included as part of the source and each release. Source code is stored in +Subversion and can be accessed using the following information.

+

Browse the code in a web browser:

+ +

Check out the code locally

+
+$ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only
+
+
+
+

SourceForge

+

DEPRECATED

+

This project is stored on SourceForge as http://sf.net/projects/shunit2. The +source code is stored in Subversion and can be accessed using the following +information.

+

Check out the code locally

+
+$ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2
+
+

Browse the code in a web browser:

+ +
+
+

Making a release

+

For these steps, it is assumed we are working with release 2.0.0.

+

Steps:

+
    +
  • write release notes
  • +
  • update version
  • +
  • finish changelog
  • +
  • check all the code in
  • +
  • tag the release
  • +
  • export the release
  • +
  • create tarball
  • +
  • md5sum the tarball and sign with gpg
  • +
  • update website
  • +
  • post to SourceForge and Freshmeat
  • +
+
+

Write Release Notes

+

This should be pretty self explanatory. Use one of the release notes from a +previous release as an example.

+

The versions of the various platforms and shells are included when the +master unit test script is run, or when bin/gen_test_results.sh is +used. To determine the versions of the installed shells by hand, use the +lib/versions script.

+

Alternatively, do the following:

+ +++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ShellOSNotes
bash $ bash --version
dashLinux$ dpkg -l |grep dash
ksh $ ksh --version +-or- +$ echo 'echo $KSH_VERSION' |ksh
Cygwinsee pdksh
Solaris$ strings /usr/bin/ksh |grep 'Version'
pdksh $ strings /bin/pdksh |grep 'PD KSH'
Cygwinlook in the downloaded Cygwin directory
shSolarisnot possible
zsh $ zsh --version
+
+
+

Update Version

+

Edit src/shell/shunit2 and change the version number in the comment, as well +as in the SHUNIT_VERSION variable.

+
+
+

Finish Documentation

+

Make sure that any remaining changes get put into the CHANGES-X.X.txt file.

+

Finish writing the RELEASE_NOTES-X.X.X.txt. If necessary, run it +through the fmt command to make it pretty (hopefully it is already).

+
+$ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new
+$ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt
+
+

We want to have an up-to-date version of the documentation in the release, so +we'd better build it.

+
+$ pwd
+.../shunit2/source/2.1
+$ cd doc
+$ RST2HTML_OPTS='--stylesheet-path=rst2html.css'
+$ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html
+$ rst2html ${RST2HTML_OPTS} README.txt >README.html
+
+
+
+

Check In All the Code

+

This step is pretty self-explanatory

+
+$ pwd
+.../shunit2/source/2.0
+$ svn ci -m "finalizing release"
+
+
+
+

Tag the Release

+
+$ pwd
+.../shunit2/source
+$ ls
+2.0  2.1
+$ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0
+
+
+
+

Export the Release

+
+$ pwd
+.../shunit2/builds
+$ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0
+
+
+
+

Create Tarball

+
+$ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0
+
+
+
+

Sign the Tarball with gpg

+
+$ cd ../releases
+$ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz
+
+
+
+

Update Website

+

Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once +that is done, make sure to tag the website so we can go back in time if needed.

+
+$ pwd
+.../shunit2
+$ ls
+source  website
+$ svn cp -m "Release 2.0.0" \
+website https://shunit2.googlecode.com/svn/tags/website/20060916
+
+

Now, update the website. It too is held in Subversion, so ssh into the web +server and use svn up to grab the latest version.

+
+
+

Post to code.google.com and Freshmeat

+ +
+
+ +
+ + diff --git a/test/shunit2-2.1.6/doc/README.txt b/test/shunit2-2.1.6/doc/README.txt new file mode 100644 index 0000000..2d8d534 --- /dev/null +++ b/test/shunit2-2.1.6/doc/README.txt @@ -0,0 +1,214 @@ +==================== +shUnit2 2.1.x README +==================== + +code.google.com +=============== + +This project is stored on code.google.com as http://code.google.com/p/shunit2/. +All releases as of 2.1.4 and full source are available there. Documentation is +included as part of the source and each release. Source code is stored in +Subversion and can be accessed using the following information. + +Browse the code in a web browser: + +- http://code.google.com/p/shunit2/source/browse +- svn > trunk > source > 2.1 + +Check out the code locally :: + + $ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only + + +SourceForge +=========== + +DEPRECATED + +This project is stored on SourceForge as http://sf.net/projects/shunit2. The +source code is stored in Subversion and can be accessed using the following +information. + +Check out the code locally :: + + $ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2 + +Browse the code in a web browser: + +- http://shunit2.svn.sourceforge.net/viewvc/shunit2/trunk/source/2.1/ +- http://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1/ + + +Making a release +================ + +For these steps, it is assumed we are working with release 2.0.0. + +Steps: + +- write release notes +- update version +- finish changelog +- check all the code in +- tag the release +- export the release +- create tarball +- md5sum the tarball and sign with gpg +- update website +- post to SourceForge and Freshmeat + +Write Release Notes +------------------- + +This should be pretty self explanatory. Use one of the release notes from a +previous release as an example. + +The versions of the various platforms and shells are included when the +master unit test script is run, or when ``bin/gen_test_results.sh`` is +used. To determine the versions of the installed shells by hand, use the +``lib/versions`` script. + +Alternatively, do the following: + ++-------+---------+-----------------------------------------------------------+ +| Shell | OS | Notes | ++=======+=========+===========================================================+ +| bash | | ``$ bash --version`` | ++-------+---------+-----------------------------------------------------------+ +| dash | Linux | ``$ dpkg -l |grep dash`` | ++-------+---------+-----------------------------------------------------------+ +| ksh | | ``$ ksh --version`` | +| | | -or- | +| | | ``$ echo 'echo $KSH_VERSION' |ksh`` | +| +---------+-----------------------------------------------------------+ +| | Cygwin | see pdksh | +| +---------+-----------------------------------------------------------+ +| | Solaris | ``$ strings /usr/bin/ksh |grep 'Version'`` | ++-------+---------+-----------------------------------------------------------+ +| pdksh | | ``$ strings /bin/pdksh |grep 'PD KSH'`` | +| +---------+-----------------------------------------------------------+ +| | Cygwin | look in the downloaded Cygwin directory | ++-------+---------+-----------------------------------------------------------+ +| sh | Solaris | not possible | ++-------+---------+-----------------------------------------------------------+ +| zsh | | ``$ zsh --version`` | ++-------+---------+-----------------------------------------------------------+ + +Update Version +-------------- + +Edit ``src/shell/shunit2`` and change the version number in the comment, as well +as in the ``SHUNIT_VERSION`` variable. + +Finish Documentation +-------------------- + +Make sure that any remaining changes get put into the ``CHANGES-X.X.txt`` file. + +Finish writing the ``RELEASE_NOTES-X.X.X.txt``. If necessary, run it +through the **fmt** command to make it pretty (hopefully it is already). :: + + $ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new + $ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt + +We want to have an up-to-date version of the documentation in the release, so +we'd better build it. :: + + $ pwd + .../shunit2/source/2.1 + $ cd doc + $ RST2HTML_OPTS='--stylesheet-path=rst2html.css' + $ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html + $ rst2html ${RST2HTML_OPTS} README.txt >README.html + +Check In All the Code +--------------------- + +This step is pretty self-explanatory :: + + $ pwd + .../shunit2/source/2.0 + $ svn ci -m "finalizing release" + +Tag the Release +--------------- +:: + + $ pwd + .../shunit2/source + $ ls + 2.0 2.1 + $ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0 + +Export the Release +------------------ +:: + + $ pwd + .../shunit2/builds + $ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0 + +Create Tarball +-------------- +:: + + $ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0 + +Sign the Tarball with gpg +------------------------- +:: + + $ cd ../releases + $ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz + +Update Website +-------------- + +Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once +that is done, make sure to tag the website so we can go back in time if needed. +:: + + $ pwd + .../shunit2 + $ ls + source website + $ svn cp -m "Release 2.0.0" \ + website https://shunit2.googlecode.com/svn/tags/website/20060916 + +Now, update the website. It too is held in Subversion, so **ssh** into the web +server and use ``svn up`` to grab the latest version. + +Post to code.google.com and Freshmeat +------------------------------------- + +- http://code.google.com/p/shunit2/ +- http://freshmeat.net/ + + +Related Documentation +===================== + +Docbook: + http://www.docbook.org/ + +Docbook XML + docbook-xml-4.4.zip: + http://www.docbook.org/xml/4.4/docbook-xml-4.4.zip + http://www.oasis-open.org/docbook/xml/4.4/docbook-xml-4.4.zip + docbook-xml-4.5.zip: + http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip +Docbook XSL + docbook-xsl-1.71.0.tar.bz2: + http://prdownloads.sourceforge.net/docbook/docbook-xsl-1.71.0.tar.bz2?download + docbook-xsl-1.71.1.tar.bz2: + http://downloads.sourceforge.net/docbook/docbook-xsl-1.71.1.tar.bz2?use_mirror=puzzle +JUnit: + http://www.junit.org/ +reStructuredText: + http://docutils.sourceforge.net/docs/user/rst/quickstart.html + +.. generate HTML using rst2html from Docutils of +.. http://docutils.sourceforge.net/ +.. +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 +.. $Revision: 310 $ diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt new file mode 100644 index 0000000..9aba387 --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.0.txt @@ -0,0 +1,104 @@ +Release Notes for shUnit2 2.1.0 +=============================== + +This release was branched from shUnit2 2.0.1. It mostly adds new functionality, +but there are couple of bugs fixed from the previous release. + +See the ``CHANGES-2.1.rst`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Cygwin + +- bash 3.2.9(10) +- pdksh 5.2.14 + +Linux + +- bash 3.1.17(1), 3.2.10(1) +- dash 0.5.3 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.2 (does not work) + +Mac OS X 10.4.8 (Darwin 8.8) + +- bash 2.05b.0(1) +- ksh 1993-12-28 + +Solaris 8 U3 (x86) + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i + +Solaris 10 U2 (sparc) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + +Solaris 10 U2 (x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + + +New Features +------------ + +Test skipping + + Support added for test "skipping". A skip mode can be enabled so that + subsequent ``assert`` and ``fail`` functions that are called will be recorded + as "skipped" rather than as "passed" or "failed". This functionality can be + used such that when a set of tests makes sense on one platform but not on + another, they can be effectively disabled without altering the total number + of tests. + + One example might be when something is supported under ``bash``, but not + under a standard Bourne shell. + + New functions: ``startSkipping()``, ``endSkipping``, ``isSkipping`` + + +Changes and Enhancements +------------------------ + +Moving to the use of `reStructured Text +`_ for documentation. It is easy to +read and edit in textual form, but converts nicely to HTML. + +The report format has changed. Rather than including a simple "success" +percentage at the end, a percentage is given for each type of test. + + +Bug Fixes +--------- + +The ``fail()`` function did not output the optional failure message. + +Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be +downloaded before documentation parsing will continue. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +None. + + +.. $Revision: 273 $ +.. vim:fileencoding=latin1:spell:syntax=rst:textwidth=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt new file mode 100644 index 0000000..4c61005 --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.1.txt @@ -0,0 +1,88 @@ +Release Notes for shUnit2 2.1.1 +=============================== + +This is mainly a bug fix release, but it also incorporates a realignment with +the JUnit 4 code. Asserts now provide better failure messages, and the failure +functions no longer perform tests. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Cygwin + +- bash 3.2.15(13) +- pdksh 5.2.14 + +Linux + +- bash 3.1.17(1), 3.2.10(1) +- dash 0.5.3 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.2 (does not work) + +Mac OS X 10.4.9 (Darwin 8.9.1) + +- bash 2.05b.0(1) +- ksh 1993-12-28 + +Solaris 8 U3 (x86) + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i + +Solaris 10 U2 (sparc, x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i + + +New Features +------------ + +None. + + +Changes and Enhancements +------------------------ + +The internal test in ``assertFalse()`` now accepts any non-zero value as false. + +The ``assertTrue()`` and ``assertFalse()`` functions now accept an integer value +for a conditional test. A value of '0' is considered 'true', while any non-zero +value is considered 'false'. + +Self-testing unit tests were added. + + +Bug Fixes +--------- + +The ``fail()`` assert now honors skipping. + +The ``docs-docbook-prep`` target now works properly. + +All asserts now properly unset their variables. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt new file mode 100644 index 0000000..5492984 --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.2.txt @@ -0,0 +1,83 @@ +Release Notes for shUnit2 2.1.2 +=============================== + +This release adds initial support for the zsh shell. Due to some differences +with this shell as compared with others, some special checks have been added, +and there are some extra requirements necessary when this shell is to be used. + +To use zsh with shUnit2, the following two requirements must be met: +* The ``shwordsplit`` option must be set. +* The ``function_argzero`` option must be unset. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +This list of platforms comes from the latest version of log4sh as shUnit2 is +used in the testing of log4sh on each of these platforms. + +Linux + +- bash 3.1.17(1), 3.2.25(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.2.5, 4.3.4 + +Mac OS X 10.4.11 (Darwin 8.11.1) + +- bash 2.05b.0(1) +- ksh 1993-12-28 +- zsh 4.2.3 + +Solaris 10 U3 (x86) + +- /bin/sh +- bash 3.00.16(1) +- ksh M-11/16/88i +- zsh 4.2.1 + + +New Features +------------ + +Support for the zsh shell. + + +Changes and Enhancements +------------------------ + +Added some argument count checks. + + +Bug Fixes +--------- + +None. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + +ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, +and as such checks do not work properly. + +zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` +option to be unset for proper operation. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt new file mode 100644 index 0000000..7d1c9f6 --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.3.txt @@ -0,0 +1,84 @@ +Release Notes for shUnit2 2.1.3 +=============================== + +This release is minor feature release. It improves support for zsh (although it +still isn't what it could be) and adds automated testing framework support by +returning a non-zero exit when tests fail. + +To use zsh with shUnit2, the following two requirements must be met: +* The ``shwordsplit`` option must be set. +* The ``function_argzero`` option must be unset. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.33(18) +- pdksh 5.2.14 + +Linux + +- bash 3.2.33(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.4 + +Mac OS X 10.5.2 (Darwin 9.2.2) + +- bash 3.2.17(1) +- ksh 1993-12-28 +- zsh 4.3.4 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +None. + + +Changes and Enhancements +------------------------ + +Support for automated testing frameworks. + + +Bug Fixes +--------- + +Fixed some issues with zsh support. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Functions do not properly test for an invalid number of arguments. + +ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly, +and as such checks do not work properly. + +zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero`` +option to be unset for proper operation. + + +.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt new file mode 100644 index 0000000..007b5c3 --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.4.txt @@ -0,0 +1,100 @@ +Release Notes for shUnit2 2.1.4 +=============================== + +This release contains lots of bug fixes and changes. Mostly, it fixes zsh +support in zsh 3.0, and the handling of null values in ksh. + +To use zsh with shUnit2, the following requirement must be met: + +- The ``shwordsplit`` option must be set. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.39(19) +- pdksh 5.2.14 +- zsh 4.3.4 + +Linux (Ubuntu Dapper 6.06) + +- bash 3.1.17(1) +- pdksh 5.2.14 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh 1993-12-28 +- pdksh 5.2.14 +- zsh 4.3.4 + +Mac OS X 10.5.4 (Darwin 9.4.0) + +- bash 3.2.17(1) +- ksh 1993-12-28 +- zsh 4.3.4 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +Support added to output assert source line number as part of assert messages. + + +Changes and Enhancements +------------------------ + +Support for automated testing frameworks. + +Added argument count error checking to all functions. + + +Bug Fixes +--------- + +Fixed some issues with ksh and zsh support. + +Fixed off-by-one of exit value in trap handler. + +Fixed handling of null values under ksh. + +Fixed bug in last resort temporary directory creation. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +zsh requires the ``shwordsplit`` option to be set. + +Line numbers in assert messages do not work properly with Bash 2.x. + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt new file mode 100644 index 0000000..d9f26ce --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.5.txt @@ -0,0 +1,128 @@ +Release Notes for shUnit2 2.1.5 +=============================== + +This release contains several bug fixes and changes. Additionally, it includes +a rewrite of the test output to better match JUnit and PyUnit. + +This version also includes a slightly expanded set of coding standards by which +shUnit2 is coded. It should help anyone reading the code to better understand +it. + + + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + + +Tested Platforms +---------------- + +Cygwin + +- bash 3.2.39(20) +- ksh (sym-link to pdksh) +- pdksh 5.2.14 +- zsh 4.3.4 + +Linux (Ubuntu Dapper 6.06) + +- bash 3.1.17(1) +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.4 + +Mac OS X 10.5.4 (Darwin 9.4.0) + +- bash 3.2.17(1) +- ksh M-1993-12-28 +- zsh 4.3.4 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +Solaris 11 x86 (Nevada 77) + +- /bin/sh +- bash 3.2.25(1) +- ksh M-11/16/88i +- zsh 4.3.4 + + +New Features +------------ + +Support added for output assert source line number as part of assert messages. + +Issue #2: Added assertNotEquals() assert. + +Provided a public ``shunit_tmpDir`` variable that can be used by unit test +scripts that need automated and guaranteed cleanup. + + +Changes and Enhancements +------------------------ + +Issue #3: Removed the check for unset variables as shUnit2 should not expect +scripts being tested to be clean. + +Issue #4: Rewrote the test summary. It is now greatly simplified and much more +script friendly. + +Issue #5: Fixed the documentation around the usage of failures. + +Issue #9: Added unit tests and improved documentation around the use of macros. + +Code updated to meet documented coding standards. + +Improved code reuse of ``_shunit_exit()`` and ``_shunit_fatal()`` functions. + +All output except shUnit2 error messages now goes to STDOUT. + +Converted DocBook documentation to reStructuredText for easier maintenance. + + +Bug Fixes +--------- + +Issue #1: Fixed bug in rap code where certain types of exit conditions did not +generate the ending report. + +Issue #7: Fixed duplicated printing of messages passed to asserts. + +Fixed bugs in ``shlib_relToAbsPath()`` in ``shlib``. + + +Deprecated Features +------------------- + +None. + + +Known Bugs and Issues +--------------------- + +Zsh requires the ``shwordsplit`` option to be set. See the documentation for +examples of how to do this. + +Line numbers in assert messages do not work properly with BASH 2.x. + +The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the +SIGTERM signal. As such, shell interpreter failures due to such things as +unbound variables cannot be caught. (See ``shunit_test_misc.sh``) + + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt new file mode 100644 index 0000000..50087fe --- /dev/null +++ b/test/shunit2-2.1.6/doc/RELEASE_NOTES-2.1.6.txt @@ -0,0 +1,112 @@ +Release Notes for shUnit2 2.1.6 +=============================== + +This release contains bug fixes and changes. It is also the first release to +support running shunit2 as a standalone program. + +Please read the Shell Errata section of the documentation for guidance on how +to meet these requirements. + +See the ``CHANGES-2.1.txt`` file for a full list of changes. + +New Features +------------ + +Support for running shUnit2 as a standalone program. This makes it possible for +users to execute their unit tests in a manner that is not dependent on the +location an OS distribution maintainer chose to place shUnit2 in the file +system. + +Added support for functions defined like 'function someFunction()'. + +Changes and Enhancements +------------------------ + +Renamed the public ``shunit_tmpDir`` variable to ``SHUNIT_TMPDIR`` to be more +consistent with the ``TMPDIR`` variable. + +Bug Fixes +--------- + +Fixed issue where shunit2 would fail on some distributions when creating a +temporary directory because the **od** command was not present. + +Deprecated Features +------------------- + +None. + +Known Bugs and Issues +--------------------- + +Zsh requires the ``shwordsplit`` option to be set. See the documentation for +examples of how to do this. + +Line numbers in assert messages do not work properly with BASH 2.x. + +The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the +SIGTERM signal. As such, shell interpreter failures due to such things as +unbound variables cannot be caught. (See ``shunit_test_misc.sh``) + +Tested Platforms +---------------- + +Cygwin 1.7.9 (Windows XP SP2) + +- bash 4.1.10(4) +- dash 0.5.6.1 +- ksh (sym-link to pdksh) +- pdksh 5.2.14 +- zsh 4.3.11 + +Linux (Ubuntu Dapper 6.06.2 LTS) + +- bash 3.1.17(1) +- dash 0.5.3 +- ksh (sym-link to pdksh) +- pdksh 5.2.14-99/07/13.2 +- zsh 4.2.5 + +Linux (Ubuntu Hardy 8.04.4 LTS) + +- bash 3.2.39(1) +- dash 0.5.4 +- ksh M-1993-12-28 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.4 + +Linux (Ubuntu Lucid 10.04.2 LTS) + +- bash 4.1.5(1) +- dash 0.5.5.1 +- ksh JM-93t+-2009-05-01 +- pdksh 5.2.14-99/07/13.2 +- zsh 4.3.10 + +Mac OS X 10.6.7 + +- bash 3.2.48(1) +- ksh M-1993-12-28 +- zsh 4.3.9 + +Solaris 8 U7 x86 + +- /bin/sh +- bash 2.03.0(1) +- ksh M-11/16/88i +- zsh 3.0.6 + +Solaris 9 U6 x86 + +- /bin/sh +- bash 2.05.0(1) +- ksh M-11/16/88i +- zsh 3.0.8 + +OpenSolaris 2009.06(snv_111b) x86 + +- /bin/sh +- bash 3.2.25(1) +- ksh 2008-11-04 + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 diff --git a/test/shunit2-2.1.6/doc/TODO.txt b/test/shunit2-2.1.6/doc/TODO.txt new file mode 100644 index 0000000..f917cee --- /dev/null +++ b/test/shunit2-2.1.6/doc/TODO.txt @@ -0,0 +1,13 @@ +Make it possible to execute a single test by passing the name of the test on +the command line + +Add support for '--randomize-order' so that the test order is randomized to +check for dependencies (which shouldn't be there) between tests. + +--debug option to display point in source code (line number and such) where the +problem showed up. + +assertTrue() just gives 'ASSERT:', nothing else :-(. others too? +upd: assertNull() will give message passed, but nothing else useful :-( + +$Revision: 228 $ diff --git a/test/shunit2-2.1.6/doc/coding_standards.txt b/test/shunit2-2.1.6/doc/coding_standards.txt new file mode 100644 index 0000000..651f40d --- /dev/null +++ b/test/shunit2-2.1.6/doc/coding_standards.txt @@ -0,0 +1,74 @@ +Coding Standards +================ + +Variable and Function Names +--------------------------- + +All shUnit2 specific constants, variables, and functions will be prefixed +appropriately with 'shunit'. This is to distinguish usage in the shUnit2 code +from users own scripts so that the shell name space remains predictable to +users. The exceptions here are the standard ``assertEquals``, etc. functions. + +All non-builtin constants and variables will be surrouned with squiggle +brackets, e.g. '${shunit_someVariable}' to improve code readability. + +Due to some shells not supporting local variables in functions, care in the +naming and use of variables, both public and private, is very important. +Accidental overriding of the variables can occur easily if care is not taken as +all variables are technically global variables in some shells. + ++----------------------------------+---------------------------+ +| *type* | *sample* | ++==================================+===========================+ +| global public constant | ``SHUNIT_TRUE`` | ++----------------------------------+---------------------------+ +| global private constant | ``__SHUNIT_SHELL_FLAGS`` | ++----------------------------------+---------------------------+ +| global public variable | not used | ++----------------------------------+---------------------------+ +| global private variable | ``__shunit_someVariable`` | ++----------------------------------+---------------------------+ +| global macro | ``_SHUNIT_SOME_MACRO_`` | ++----------------------------------+---------------------------+ +| public function | ``assertEquals`` | ++----------------------------------+---------------------------+ +| public function, local variable | ``shunit_someVariable_`` | ++----------------------------------+---------------------------+ +| private function | ``_shunit_someFunction`` | ++----------------------------------+---------------------------+ +| private function, local variable | ``_shunit_someVariable_`` | ++----------------------------------+---------------------------+ + +Where it makes sense, variables can have the first letter of the second and +later words capitalized. For example, the local variable name for the total +number of test cases seen might be ``shunit_totalTestsSeen_``. + +Local Variable Cleanup +---------------------- + +As many shells do not support local variables, no support for cleanup of +variables is present either. As such, all variables local to a function must be +cleared up with the ``unset`` command at the end of each function. + +Indentation +----------- + +Code block indentation is two (2) spaces, and tabs may not be used. :: + + if [ -z 'some string' ]; then + someFunction + fi + +Lines of code should be no longer than 80 characters unless absolutely +necessary. When lines are wrapped using the backslash character '\', subsequent +lines should be indented with four (4) spaces so as to differentiate from the +standard spacing of two characters. Tabs may *not* be used. :: + + for x in some set of very long set of arguments that make for a very long \ + that extends much too long for one line + do + echo ${x} + done + +.. vim:fileencoding=latin1:ft=rst:spell:tw=80 +.. $Revision: 301 $ diff --git a/test/shunit2-2.1.6/doc/contributors.txt b/test/shunit2-2.1.6/doc/contributors.txt new file mode 100644 index 0000000..97c7d09 --- /dev/null +++ b/test/shunit2-2.1.6/doc/contributors.txt @@ -0,0 +1,14 @@ +The original author of shunit2 is Kate Ward. The following people have +contributed in some way or another to shunit2. + +Bryan Larsen +Kevin Van Horn +Maciej Bliziński +Mario Sparada +Mathias Goldau +Richard Jensen +Rob Holland +Rocky Bernstein +wood4321 (of code.google.com) + +$Revision: 313 $ diff --git a/test/shunit2-2.1.6/doc/design_doc.txt b/test/shunit2-2.1.6/doc/design_doc.txt new file mode 100644 index 0000000..7ac8002 --- /dev/null +++ b/test/shunit2-2.1.6/doc/design_doc.txt @@ -0,0 +1,34 @@ +Design Doc for shUnit + +shUnit is based upon JUnit. The initial ideas for the script came from the book +"Pragmatic Unit Testing - In Java with JUnit" by Andrew Hunt and David Thomas. + +The script was written to perform unit testing for log4sh. log4sh had grown +enough that it was becoming difficult to easily test and and verify that the +tests passed for the many different operating systems on which it was being +used. + +The functions in shUnit are meant to match those in JUnit as much as possible +where shell allows. In the initial version, there will be no concept of +exceptions (as normal POSIX shell has no concept of them) but attempts to trap +problems will be done. + +Programatic Standards: + +* SHUNIT_TRUE - public global constant +* __SHUNIT_SHELL_FLAGS - private global constant +* __shunit_oldShellFlags - private global variable + +* assertEquals - public unit test function +* shunit_publicFunc - public shUnit function; can be called from parent unit + test script +* _shunit_privateFunc - private shUnit function; should not be called from + parent script. meant for internal use by shUnit + +* _su_myVar - variable inside a public function. prefixing with '_su_' to + reduce the chances that a variable outside of shUnit will be overridden. +* _su__myVar - variable inside a private function. prefixing with '_su__' to + reduce the chances that a variable in a shUnit public function, or a variable + outside of shUnit will be overridden. + +$Revision: 4 $ diff --git a/test/shunit2-2.1.6/doc/rst2html.css b/test/shunit2-2.1.6/doc/rst2html.css new file mode 100644 index 0000000..01983a5 --- /dev/null +++ b/test/shunit2-2.1.6/doc/rst2html.css @@ -0,0 +1,292 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:Date: $Date: 2007-04-11 11:48:16 +0100 (Wed, 11 Apr 2007) $ +:Revision: $Revision: 2791 $ +:Copyright: This stylesheet has been placed in the public domain. +:Modified by: Kate Ward + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 5em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + margin: 2em ; + border: medium outset ; + padding: 1em } + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + border: medium outset ; + padding: 1em } + +div.system-message p.system-message-title { + color: red ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left { + clear: left } + +img.align-right { + clear: right } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin-left: 2em ; + margin-right: 2em ; + background-color: #eeeeee } + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +/* +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } +*/ + +table.footnote { + border-left: solid 1px black; + margin-left: 1px ; + font-size: 80% } + } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +/* +tt.docutils { + background-color: #eeeeee } +*/ + +ul.auto-toc { + list-style-type: none } + +/* customizations by kward */ + +h1 { font-size: 133%; border-top:1px solid #CCCCFF; } +h1.title { font-size: 150%; border-top:0px; padding-top: 1em; } +/* div.document { font-size: 90% } */ diff --git a/test/shunit2-2.1.6/doc/shunit2.html b/test/shunit2-2.1.6/doc/shunit2.html new file mode 100644 index 0000000..c5aa336 --- /dev/null +++ b/test/shunit2-2.1.6/doc/shunit2.html @@ -0,0 +1,880 @@ + + + + + + +shUnit2 2.1.x Documentation + + + +
+

shUnit2 2.1.x Documentation

+ +
+

Abstract

+

shUnit2 is a xUnit unit test framework for Bourne based shell scripts, and it +is designed to work in a similar manner to JUnit, PyUnit, etc.. If you have +ever had the desire to write a unit test for a shell script, shUnit2 can do the +job.

+ +
+
+

Introduction

+

shUnit2 was originally developed to provide a consistent testing solution for +log4sh, a shell based logging framework similar to log4j. During the +development of that product, a repeated problem of having things work just fine +under one shell (/bin/bash on Linux to be specific), and then not working +under another shell (/bin/sh on Solaris) kept coming up. Although several +simple tests were run, they were not adequate and did not catch some corner +cases. The decision was finally made to write a proper unit test framework after +multiple brown-bag releases were made. Research was done to look for an +existing product that met the testing requirements, but no adequate product was +found.

+

Tested Operating Systems (varies over time)

+
    +
  • Cygwin
  • +
  • FreeBSD (user supported)
  • +
  • Linux (Gentoo, Ubuntu)
  • +
  • Mac OS X
  • +
  • Solaris 8, 9, 10 (inc. OpenSolaris)
  • +
+

Tested Shells

+
    +
  • Bourne Shell (sh)
  • +
  • BASH - GNU Bourne Again SHell (bash)
  • +
  • DASH (dash)
  • +
  • Korn Shell (ksh)
  • +
  • pdksh - Public Domain Korn Shell (pdksh)
  • +
  • zsh - Zsh (zsh) (since 2.1.2) please see the Zsh shell errata for more +information
  • +
+

See the appropriate Release Notes for this release +(doc/RELEASE_NOTES-X.X.X.txt) for the list of actual versions tested.

+
+

Credits / Contributors

+

A list of contributors to shUnit2 can be found in the source archive in +doc/contributors.txt. Many thanks go out to all those who have contributed +to make this a better tool.

+

shUnit2 is the original product of many hours of work by Kate Ward, the primary +author of the code. For other products by her, look up log4sh or shFlags, or +visit her website at http://forestent.com/.

+
+
+

Feedback

+

Feedback is most certainly welcome for this document. Send your additions, +comments and criticisms to the shunit2-users@google.com mailing list.

+
+
+
+

Quickstart

+

This section will give a very quick start to running unit tests with shUnit2. +More information is located in later sections.

+

Here is a quick sample script to show how easy it is to write a unit test in +shell. Note: the script as it stands expects that you are running it from the +``examples`` directory.

+
+#! /bin/sh
+# file: examples/equality_test.sh
+
+testEquality()
+{
+  assertEquals 1 1
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

Running the unit test should give results similar to the following.

+
+testEquality
+
+Ran 1 test.
+
+OK
+
+

W00t! You've just run your first successful unit test. So, what just happened? +Quite a bit really, and it all happened simply by sourcing the shunit2 +library. The basic functionality for the script above goes like this:

+
    +
  • When shUnit2 is sourced, it will walk through any functions defined whose +namestart with the string test and add those to an internal list of tests +to execute. Once a list of test functions to be run has been determined, +shunit2 will go to work.
  • +
  • Before any tests are executed, shUnit2 again looks for a function, this time +one named oneTimeSetUp(). If it exists, it will be run. This function is +normally used to setup the environment for all tests to be run. Things like +creating directories for output or setting environment variables are good to +place here. Just so you know, you can also declare a corresponding function +named oneTimeTearDown() function that does the same thing, but once all +the tests have been completed. It is good for removing temporary directories, +etc.
  • +
  • shUnit2 is now ready to run tests. Before doing so though, it again looks for +another function that might be declared, one named setUp(). If the +function exists, it will be run before each test. It is good for resetting the +environment so that each test starts with a clean slate. At this stage, the +first test is finally run. The success of the test is recorded for a report +that will be generated later. After the test is run, shUnit2 looks for a final +function that might be declared, one named tearDown(). If it exists, it +will be run after each test. It is a good place for cleaning up after each +test, maybe doing things like removing files that were created, or removing +directories. This set of steps, setUp() > test() > tearDown(), is +repeated for all of the available tests.
  • +
  • Once all the work is done, shUnit2 will generate the nice report you saw +above. A summary of all the successes and failures will be given so that you +know how well your code is doing.
  • +
+

We should now try adding a test that fails. Change your unit test to look like +this.

+
+#! /bin/sh
+# file: examples/party_test.sh
+
+testEquality()
+{
+  assertEquals 1 1
+}
+
+testPartyLikeItIs1999()
+{
+  year=`date '+%Y'`
+  assertEquals "It's not 1999 :-(" \
+      '1999' "${year}"
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

So, what did you get? I guess it told you that this isn't 1999. Bummer, eh? +Hopefully, you noticed a couple of things that were different about the second +test. First, we added an optional message that the user will see if the assert +fails. Second, we did comparisons of strings instead of integers as in the first +test. It doesn't matter whether you are testing for equality of strings or +integers. Both work equally well with shUnit2.

+

Hopefully, this is enough to get you started with unit testing. If you want a +ton more examples, take a look at the tests provided with log4sh or shFlags. +Both provide excellent examples of more advanced usage. shUnit2 was after all +written to help with the unit testing problems that log4sh had.

+
+
+

Function Reference

+
+

General Info

+

Any string values passed should be properly quoted -- they should must be +surrounded by single-quote (') or double-quote (") characters -- so that the +shell will properly parse them.

+
+
+

Asserts

+
+
assertEquals [message] expected actual
+
Asserts that expected and actual are equal to one another. The expected +and actual values can be either strings or integer values as both will be +treated as strings. The message is optional, and must be quoted.
+
assertNotEquals [message] expected actual
+
Asserts that unexpected and actual are not equal to one another. The +unexpected and actual values can be either strings or integer values as +both will be treaded as strings. The message is optional, and must be +quoted.
+
assertSame [message] expected actual
+
This function is functionally equivalent to assertEquals.
+
assertNotSame [message] unexpected actual
+
This function is functionally equivalent to assertNotEquals.
+
assertNull [message] value
+
Asserts that value is null, or in shell terms, a zero-length string. The +value must be a string as an integer value does not translate into a +zero-length string. The message is optional, and must be quoted.
+
assertNotNull [message] value
+
Asserts that value is not null, or in shell terms, a non-empty string. The +value may be a string or an integer as the later will be parsed as a +non-empty string value. The message is optional, and must be quoted.
+
assertTrue [message] condition
+

Asserts that a given shell test condition is true. The condition can be as +simple as a shell true value (the value 0 -- equivalent to +${SHUNIT_TRUE}), or a more sophisticated shell conditional expression. The +message is optional, and must be quoted.

+

A sophisticated shell conditional expression is equivalent to what the if +or while shell built-ins would use (more specifically, what the test +command would use). Testing for example whether some value is greater than +another value can be done this way.

+
+assertTrue "[ 34 -gt 23 ]"
+
+

Testing for the ability to read a file can also be done. This particular test +will fail.

+
+assertTrue 'test failed' "[ -r /some/non-existant/file' ]"
+
+

As the expressions are standard shell test expressions, it is possible to +string multiple expressions together with -a and -o in the standard +fashion. This test will succeed as the entire expression evaluates to true.

+
+assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]'
+
+

One word of warning: be very careful with your quoting as shell is not the +most forgiving of bad quoting, and things will fail in strange ways.

+
+
assertFalse [message] condition
+

Asserts that a given shell test condition is false. The condition can be +as simple as a shell false value (the value 1 -- equivalent to +${SHUNIT_FALSE}), or a more sophisticated shell conditional expression. +The message is optional, and must be quoted.

+

For examples of more sophisticated expressions, see ``assertTrue``.

+
+
+
+
+

Failures

+

Just to clarify, failures do not test the various arguments against one +another. Failures simply fail, optionally with a message, and that is all they +do. If you need to test arguments against one another, use asserts.

+

If all failures do is fail, why might one use them? There are times when you may +have some very complicated logic that you need to test, and the simple asserts +provided are simply not adequate. You can do your own validation of the code, +use an assertTrue ${SHUNIT_TRUE} if your own tests succeeded, and use a +failure to record a failure.

+
+
fail [message]
+
Fails the test immediately. The message is optional, and must be quoted.
+
failNotEquals [message] unexpected actual
+

Fails the test immediately, reporting that the unexpected and actual +values are not equal to one another. The message is optional, and must be +quoted.

+

Note: no actual comparison of unexpected and actual is done.

+
+
failSame [message] expected actual
+

Fails the test immediately, reporting that the expected and actual values +are the same. The message is optional, and must be quoted.

+

Note: no actual comparison of expected and actual is done.

+
+
failNotSame [message] expected actual
+

Fails the test immediately, reporting that the expected and actual values +are not the same. The message is optional, and must be quoted.

+

Note: no actual comparison of expected and actual is done.

+
+
+
+
+

Setup/Teardown

+
+
oneTimeSetUp
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called once before any tests are run. It +is useful to prepare a common environment for all tests.

+
+
oneTimeTearDown
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called once after all tests are completed. +It is useful to clean up the environment after all tests.

+
+
setUp
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called before each test is run. It is +useful to reset the environment before each test.

+
+
tearDown
+

This function can be be optionally overridden by the user in their test suite.

+

If this function exists, it will be called after each test completes. It is +useful to clean up the environment after each test.

+
+
+
+
+

Skipping

+
+
startSkipping
+
This function forces the remaining assert and fail functions to be +"skipped", i.e. they will have no effect. Each function skipped will be +recorded so that the total of asserts and fails will not be altered.
+
endSkipping
+
This function returns calls to the assert and fail functions to their +default behavior, i.e. they will be called.
+
isSkipping
+
This function returns the current state of skipping. It can be compared +against ${SHUNIT_TRUE} or ${SHUNIT_FALSE} if desired.
+
+
+
+

Suites

+

The default behavior of shUnit2 is that all tests will be found dynamically. If +you have a specific set of tests you want to run, or you don't want to use the +standard naming scheme of prefixing your tests with test, these functions +are for you. Most users will never use them though.

+
+
suite
+

This function can be optionally overridden by the user in their test suite.

+

If this function exists, it will be called when shunit2 is sourced. If it +does not exist, shUnit2 will search the parent script for all functions +beginning with the word test, and they will be added dynamically to the +test suite.

+
+
suite_addTest name
+
This function adds a function named name to the list of tests scheduled for +execution as part of this test suite. This function should only be called from +within the suite() function.
+
+
+
+
+

Advanced Usage

+

This section covers several advanced usage topics.

+
+

Some constants you can use

+

There are several constants provided by shUnit2 as variables that might be of +use to you.

+

Predefined

+ ++++ + + + + + + + + + + + + + + + + + +
SHUNIT_VERSIONThe version of shUnit2 you are running.
SHUNIT_TRUEStandard shell true value (the integer value 0).
SHUNIT_FALSEStandard shell false value (the integer value 1).
SHUNIT_ERRORThe integer value 2.
SHUNIT_TMPDIRPath to temporary directory that will be automatically +cleaned up upon exit of shUnit2.
+

User defined

+ ++++ + + + + + +
SHUNIT_PARENTThe filename of the shell script containing the tests. This +is needed specifically for Zsh support.
+
+
+

Error handling

+

The constants values SHUNIT_TRUE, SHUNIT_FALSE, and SHUNIT_ERROR are +returned from nearly every function to indicate the success or failure of the +function. Additionally the variable flags_error is filled with a detailed +error message if any function returns with a SHUNIT_ERROR value.

+
+
+

Including Line Numbers in Asserts (Macros)

+

If you include lots of assert statements in an individual test function, it can +become difficult to determine exactly which assert was thrown unless your +messages are unique. To help somewhat, line numbers can be included in the +assert messages. To enable this, a special shell "macro" must be used rather +than the standard assert calls. Shell doesn't actually have macros; the name is +used here as the operation is similar to a standard macro.

+

For example, to include line numbers for a assertEquals() function call, +replace the assertEquals() with ${_ASSERT_EQUALS_}.

+

Example -- Asserts with and without line numbers

+
+#! /bin/sh
+# file: examples/lineno_test.sh
+
+testLineNo()
+{
+  # this assert will have line numbers included (e.g. "ASSERT:[123] ...")
+  echo "ae: ${_ASSERT_EQUALS_}"
+  ${_ASSERT_EQUALS_} 'not equal' 1 2
+
+  # this assert will not have line numbers included (e.g. "ASSERT: ...")
+  assertEquals 'not equal' 1 2
+}
+
+# load shunit2
+. ../src/shell/shunit2
+
+

Notes:

+
    +
  1. Due to how shell parses command-line arguments, all strings used with macros +should be quoted twice. Namely, single-quotes must be converted to +single-double-quotes, and vice-versa. If the string being passed is +absolutely for sure not empty, the extra quoting is not necessary.

    +

    Normal assertEquals call.

    +
    +assertEquals 'some message' 'x' ''
    +
    +

    Macro _ASSERT_EQUALS_ call. Note the extra quoting around the message +and the null value.

    +
    +_ASSERT_EQUALS_ '"some message"' 'x' '""'
    +
    +
  2. +
  3. Line numbers are not supported in all shells. If a shell does not support +them, no errors will be thrown. Supported shells include: bash (>=3.0), +ksh, pdksh, and zsh.

    +
  4. +
+
+
+

Test Skipping

+

There are times where the test code you have written is just not applicable to +the system you are running on. This section describes how to skip these tests +but maintain the total test count.

+

Probably the easiest example would be shell code that is meant to run under the +bash shell, but the unit test is running under the Bourne shell. There are +things that just won't work. The following test code demonstrates two sample +functions, one that will be run under any shell, and the another that will run +only under the bash shell.

+

Example -- math include

+
+# available as examples/math.inc
+
+add_generic()
+{
+  num_a=$1
+  num_b=$2
+
+  expr $1 + $2
+}
+
+add_bash()
+{
+  num_a=$1
+  num_b=$2
+
+  echo $(($1 + $2))
+}
+
+

And here is a corresponding unit test that correctly skips the add_bash() +function when the unit test is not running under the bash shell.

+

Example -- math unit test

+
+#! /bin/sh
+# available as examples/math_test.sh
+
+testAdding()
+{
+  result=`add_generic 1 2`
+  assertEquals \
+      "the result of '${result}' was wrong" \
+      3 "${result}"
+
+  # disable non-generic tests
+  [ -z "${BASH_VERSION:-}" ] && startSkipping
+
+  result=`add_bash 1 2`
+  assertEquals \
+      "the result of '${result}' was wrong" \
+      3 "${result}"
+}
+
+oneTimeSetUp()
+{
+  # load include to test
+  . ./math.inc
+}
+
+# load and run shUnit2
+. ../src/shell/shunit2
+
+

Running the above test under the bash shell will result in the following +output.

+
+$ /bin/bash math_test.sh
+testAdding
+
+Ran 1 test.
+
+OK
+
+

But, running the test under any other Unix shell will result in the following +output.

+
+$ /bin/ksh math_test.sh
+testAdding
+
+Ran 1 test.
+
+OK (skipped=1)
+
+

As you can see, the total number of tests has not changed, but the report +indicates that some tests were skipped.

+

Skipping can be controlled with the following functions: startSkipping(), +stopSkipping(), and isSkipping(). Once skipping is enabled, it will +remain enabled until the end of the current test function call, after which +skipping is disabled.

+
+
+
+

Appendix

+
+

Getting help

+

For help, please send requests to either the shunit2-users@googlegroups.com +mailing list (archives available on the web at +http://groups.google.com/group/shunit2-users) or directly to +Kate Ward <kate dot ward at forestent dot com>.

+
+
+

Zsh

+

For compatibility with Zsh, there is one requirement that must be met -- the +shwordsplit option must be set. There are three ways to accomplish this.

+
    +
  1. In the unit-test script, add the following shell code snippet before sourcing +the shunit2 library.

    +
    +setopt shwordsplit
    +
    +
  2. +
  3. When invoking zsh from either the command-line or as a script with +#!, add the -y parameter.

    +
    +#! /bin/zsh -y
    +
    +
  4. +
  5. When invoking zsh from the command-line, add -o shwordsplit -- as +parameters before the script name.

    +
    +$ zsh -o shwordsplit -- some_script
    +
    +
  6. +
+ + + + + +
+
+
+ + diff --git a/test/shunit2-2.1.6/doc/shunit2.txt b/test/shunit2-2.1.6/doc/shunit2.txt new file mode 100644 index 0000000..fec1b53 --- /dev/null +++ b/test/shunit2-2.1.6/doc/shunit2.txt @@ -0,0 +1,562 @@ +=========================== +shUnit2 2.1.x Documentation +=========================== + +Abstract +======== + +shUnit2_ is a xUnit_ unit test framework for Bourne based shell scripts, and it +is designed to work in a similar manner to JUnit_, PyUnit_, etc.. If you have +ever had the desire to write a unit test for a shell script, shUnit2 can do the +job. + +.. contents:: Table of Contents + :depth: 2 + +Introduction +============ + +shUnit2 was originally developed to provide a consistent testing solution for +log4sh_, a shell based logging framework similar to log4j_. During the +development of that product, a repeated problem of having things work just fine +under one shell (``/bin/bash`` on Linux to be specific), and then not working +under another shell (``/bin/sh`` on Solaris) kept coming up. Although several +simple tests were run, they were not adequate and did not catch some corner +cases. The decision was finally made to write a proper unit test framework after +multiple brown-bag releases were made. *Research was done to look for an +existing product that met the testing requirements, but no adequate product was +found.* + +Tested Operating Systems (varies over time) + +- Cygwin +- FreeBSD (user supported) +- Linux (Gentoo, Ubuntu) +- Mac OS X +- Solaris 8, 9, 10 (inc. OpenSolaris) + +Tested Shells + +- Bourne Shell (**sh**) +- BASH - GNU Bourne Again SHell (**bash**) +- DASH (**dash**) +- Korn Shell (**ksh**) +- pdksh - Public Domain Korn Shell (**pdksh**) +- zsh - Zsh (**zsh**) (since 2.1.2) *please see the Zsh shell errata for more + information* + +See the appropriate Release Notes for this release +(``doc/RELEASE_NOTES-X.X.X.txt``) for the list of actual versions tested. + +Credits / Contributors +---------------------- + +A list of contributors to shUnit2 can be found in the source archive in +``doc/contributors.txt``. Many thanks go out to all those who have contributed +to make this a better tool. + +shUnit2 is the original product of many hours of work by Kate Ward, the primary +author of the code. For other products by her, look up log4sh_ or shFlags_, or +visit her website at http://forestent.com/. + +Feedback +-------- + +Feedback is most certainly welcome for this document. Send your additions, +comments and criticisms to the shunit2-users@google.com mailing list. + +Quickstart +========== + +This section will give a very quick start to running unit tests with shUnit2. +More information is located in later sections. + +Here is a quick sample script to show how easy it is to write a unit test in +shell. *Note: the script as it stands expects that you are running it from the +``examples`` directory.* :: + + #! /bin/sh + # file: examples/equality_test.sh + + testEquality() + { + assertEquals 1 1 + } + + # load shunit2 + . ../src/shell/shunit2 + +Running the unit test should give results similar to the following. :: + + testEquality + + Ran 1 test. + + OK + +W00t! You've just run your first successful unit test. So, what just happened? +Quite a bit really, and it all happened simply by sourcing the ``shunit2`` +library. The basic functionality for the script above goes like this: + +- When shUnit2 is sourced, it will walk through any functions defined whose + namestart with the string ``test`` and add those to an internal list of tests + to execute. Once a list of test functions to be run has been determined, + shunit2 will go to work. +- Before any tests are executed, shUnit2 again looks for a function, this time + one named ``oneTimeSetUp()``. If it exists, it will be run. This function is + normally used to setup the environment for all tests to be run. Things like + creating directories for output or setting environment variables are good to + place here. Just so you know, you can also declare a corresponding function + named ``oneTimeTearDown()`` function that does the same thing, but once all + the tests have been completed. It is good for removing temporary directories, + etc. +- shUnit2 is now ready to run tests. Before doing so though, it again looks for + another function that might be declared, one named ``setUp()``. If the + function exists, it will be run before each test. It is good for resetting the + environment so that each test starts with a clean slate. At this stage, the + first test is finally run. The success of the test is recorded for a report + that will be generated later. After the test is run, shUnit2 looks for a final + function that might be declared, one named ``tearDown()``. If it exists, it + will be run after each test. It is a good place for cleaning up after each + test, maybe doing things like removing files that were created, or removing + directories. This set of steps, ``setUp()`` > ``test()`` > ``tearDown()``, is + repeated for all of the available tests. +- Once all the work is done, shUnit2 will generate the nice report you saw + above. A summary of all the successes and failures will be given so that you + know how well your code is doing. + +We should now try adding a test that fails. Change your unit test to look like +this. :: + + #! /bin/sh + # file: examples/party_test.sh + + testEquality() + { + assertEquals 1 1 + } + + testPartyLikeItIs1999() + { + year=`date '+%Y'` + assertEquals "It's not 1999 :-(" \ + '1999' "${year}" + } + + # load shunit2 + . ../src/shell/shunit2 + +So, what did you get? I guess it told you that this isn't 1999. Bummer, eh? +Hopefully, you noticed a couple of things that were different about the second +test. First, we added an optional message that the user will see if the assert +fails. Second, we did comparisons of strings instead of integers as in the first +test. It doesn't matter whether you are testing for equality of strings or +integers. Both work equally well with shUnit2. + +Hopefully, this is enough to get you started with unit testing. If you want a +ton more examples, take a look at the tests provided with log4sh_ or shFlags_. +Both provide excellent examples of more advanced usage. shUnit2 was after all +written to help with the unit testing problems that log4sh_ had. + +Function Reference +================== + +General Info +------------ + +Any string values passed should be properly quoted -- they should must be +surrounded by single-quote (') or double-quote (") characters -- so that the +shell will properly parse them. + +Asserts +------- + +``assertEquals [message] expected actual`` + Asserts that *expected* and *actual* are equal to one another. The *expected* + and *actual* values can be either strings or integer values as both will be + treated as strings. The *message* is optional, and must be quoted. + +``assertNotEquals [message] expected actual`` + Asserts that *unexpected* and *actual* are not equal to one another. The + *unexpected* and *actual* values can be either strings or integer values as + both will be treaded as strings. The *message* is optional, and must be + quoted. + +``assertSame [message] expected actual`` + This function is functionally equivalent to ``assertEquals``. + +``assertNotSame [message] unexpected actual`` + This function is functionally equivalent to ``assertNotEquals``. + +``assertNull [message] value`` + Asserts that *value* is *null*, or in shell terms, a zero-length string. The + *value* must be a string as an integer value does not translate into a + zero-length string. The *message* is optional, and must be quoted. + +``assertNotNull [message] value`` + Asserts that *value* is *not null*, or in shell terms, a non-empty string. The + *value* may be a string or an integer as the later will be parsed as a + non-empty string value. The *message* is optional, and must be quoted. + +``assertTrue [message] condition`` + Asserts that a given shell test *condition* is *true*. The condition can be as + simple as a shell *true* value (the value ``0`` -- equivalent to + ``${SHUNIT_TRUE}``), or a more sophisticated shell conditional expression. The + *message* is optional, and must be quoted. + + A sophisticated shell conditional expression is equivalent to what the **if** + or **while** shell built-ins would use (more specifically, what the **test** + command would use). Testing for example whether some value is greater than + another value can be done this way. :: + + assertTrue "[ 34 -gt 23 ]" + + Testing for the ability to read a file can also be done. This particular test + will fail. :: + + assertTrue 'test failed' "[ -r /some/non-existant/file' ]" + + As the expressions are standard shell **test** expressions, it is possible to + string multiple expressions together with ``-a`` and ``-o`` in the standard + fashion. This test will succeed as the entire expression evaluates to *true*. + :: + + assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]' + + *One word of warning: be very careful with your quoting as shell is not the + most forgiving of bad quoting, and things will fail in strange ways.* + +``assertFalse [message] condition`` + Asserts that a given shell test *condition* is *false*. The condition can be + as simple as a shell *false* value (the value ``1`` -- equivalent to + ``${SHUNIT_FALSE}``), or a more sophisticated shell conditional expression. + The *message* is optional, and must be quoted. + + *For examples of more sophisticated expressions, see ``assertTrue``.* + +Failures +-------- + +Just to clarify, failures **do not** test the various arguments against one +another. Failures simply fail, optionally with a message, and that is all they +do. If you need to test arguments against one another, use asserts. + +If all failures do is fail, why might one use them? There are times when you may +have some very complicated logic that you need to test, and the simple asserts +provided are simply not adequate. You can do your own validation of the code, +use an ``assertTrue ${SHUNIT_TRUE}`` if your own tests succeeded, and use a +failure to record a failure. + +``fail [message]`` + Fails the test immediately. The *message* is optional, and must be quoted. + +``failNotEquals [message] unexpected actual`` + Fails the test immediately, reporting that the *unexpected* and *actual* + values are not equal to one another. The *message* is optional, and must be + quoted. + + *Note: no actual comparison of unexpected and actual is done.* + +``failSame [message] expected actual`` + Fails the test immediately, reporting that the *expected* and *actual* values + are the same. The *message* is optional, and must be quoted. + + *Note: no actual comparison of expected and actual is done.* + +``failNotSame [message] expected actual`` + Fails the test immediately, reporting that the *expected* and *actual* values + are not the same. The *message* is optional, and must be quoted. + + *Note: no actual comparison of expected and actual is done.* + +Setup/Teardown +-------------- + +``oneTimeSetUp`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called once before any tests are run. It + is useful to prepare a common environment for all tests. + +``oneTimeTearDown`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called once after all tests are completed. + It is useful to clean up the environment after all tests. + +``setUp`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called before each test is run. It is + useful to reset the environment before each test. + +``tearDown`` + This function can be be optionally overridden by the user in their test suite. + + If this function exists, it will be called after each test completes. It is + useful to clean up the environment after each test. + +Skipping +-------- + +``startSkipping`` + This function forces the remaining *assert* and *fail* functions to be + "skipped", i.e. they will have no effect. Each function skipped will be + recorded so that the total of asserts and fails will not be altered. + +``endSkipping`` + This function returns calls to the *assert* and *fail* functions to their + default behavior, i.e. they will be called. + +``isSkipping`` + This function returns the current state of skipping. It can be compared + against ``${SHUNIT_TRUE}`` or ``${SHUNIT_FALSE}`` if desired. + +Suites +------ + +The default behavior of shUnit2 is that all tests will be found dynamically. If +you have a specific set of tests you want to run, or you don't want to use the +standard naming scheme of prefixing your tests with ``test``, these functions +are for you. Most users will never use them though. + +``suite`` + This function can be optionally overridden by the user in their test suite. + + If this function exists, it will be called when ``shunit2`` is sourced. If it + does not exist, shUnit2 will search the parent script for all functions + beginning with the word ``test``, and they will be added dynamically to the + test suite. + +``suite_addTest name`` + This function adds a function named *name* to the list of tests scheduled for + execution as part of this test suite. This function should only be called from + within the ``suite()`` function. + +Advanced Usage +============== + +This section covers several advanced usage topics. + +Some constants you can use +-------------------------- + +There are several constants provided by shUnit2 as variables that might be of +use to you. + +Predefined + +================== =========================================================== +``SHUNIT_VERSION`` The version of shUnit2 you are running. +``SHUNIT_TRUE`` Standard shell *true* value (the integer value 0). +``SHUNIT_FALSE`` Standard shell *false* value (the integer value 1). +``SHUNIT_ERROR`` The integer value 2. +``SHUNIT_TMPDIR`` Path to temporary directory that will be automatically + cleaned up upon exit of shUnit2. +================== =========================================================== + +User defined + +================== =========================================================== +``SHUNIT_PARENT`` The filename of the shell script containing the tests. This + is needed specifically for Zsh support. +================== =========================================================== + +Error handling +-------------- + +The constants values ``SHUNIT_TRUE``, ``SHUNIT_FALSE``, and ``SHUNIT_ERROR`` are +returned from nearly every function to indicate the success or failure of the +function. Additionally the variable ``flags_error`` is filled with a detailed +error message if any function returns with a ``SHUNIT_ERROR`` value. + +Including Line Numbers in Asserts (Macros) +------------------------------------------ + +If you include lots of assert statements in an individual test function, it can +become difficult to determine exactly which assert was thrown unless your +messages are unique. To help somewhat, line numbers can be included in the +assert messages. To enable this, a special shell "macro" must be used rather +than the standard assert calls. *Shell doesn't actually have macros; the name is +used here as the operation is similar to a standard macro.* + +For example, to include line numbers for a ``assertEquals()`` function call, +replace the ``assertEquals()`` with ``${_ASSERT_EQUALS_}``. + +Example--Asserts with and without line numbers :: + + #! /bin/sh + # file: examples/lineno_test.sh + + testLineNo() + { + # this assert will have line numbers included (e.g. "ASSERT:[123] ...") + echo "ae: ${_ASSERT_EQUALS_}" + ${_ASSERT_EQUALS_} 'not equal' 1 2 + + # this assert will not have line numbers included (e.g. "ASSERT: ...") + assertEquals 'not equal' 1 2 + } + + # load shunit2 + . ../src/shell/shunit2 + +Notes: + +#. Due to how shell parses command-line arguments, all strings used with macros + should be quoted twice. Namely, single-quotes must be converted to + single-double-quotes, and vice-versa. If the string being passed is + absolutely for sure not empty, the extra quoting is not necessary. + + Normal ``assertEquals`` call. :: + + assertEquals 'some message' 'x' '' + + Macro ``_ASSERT_EQUALS_`` call. Note the extra quoting around the *message* + and the *null* value. :: + + _ASSERT_EQUALS_ '"some message"' 'x' '""' + +#. Line numbers are not supported in all shells. If a shell does not support + them, no errors will be thrown. Supported shells include: **bash** (>=3.0), + **ksh**, **pdksh**, and **zsh**. + +Test Skipping +------------- + +There are times where the test code you have written is just not applicable to +the system you are running on. This section describes how to skip these tests +but maintain the total test count. + +Probably the easiest example would be shell code that is meant to run under the +**bash** shell, but the unit test is running under the Bourne shell. There are +things that just won't work. The following test code demonstrates two sample +functions, one that will be run under any shell, and the another that will run +only under the **bash** shell. + +Example-- math include :: + + # available as examples/math.inc + + add_generic() + { + num_a=$1 + num_b=$2 + + expr $1 + $2 + } + + add_bash() + { + num_a=$1 + num_b=$2 + + echo $(($1 + $2)) + } + +And here is a corresponding unit test that correctly skips the ``add_bash()`` +function when the unit test is not running under the **bash** shell. + +Example-- math unit test :: + + #! /bin/sh + # available as examples/math_test.sh + + testAdding() + { + result=`add_generic 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + + # disable non-generic tests + [ -z "${BASH_VERSION:-}" ] && startSkipping + + result=`add_bash 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + } + + oneTimeSetUp() + { + # load include to test + . ./math.inc + } + + # load and run shUnit2 + . ../src/shell/shunit2 + +Running the above test under the **bash** shell will result in the following +output. :: + + $ /bin/bash math_test.sh + testAdding + + Ran 1 test. + + OK + +But, running the test under any other Unix shell will result in the following +output. :: + + $ /bin/ksh math_test.sh + testAdding + + Ran 1 test. + + OK (skipped=1) + +As you can see, the total number of tests has not changed, but the report +indicates that some tests were skipped. + +Skipping can be controlled with the following functions: ``startSkipping()``, +``stopSkipping()``, and ``isSkipping()``. Once skipping is enabled, it will +remain enabled until the end of the current test function call, after which +skipping is disabled. + +Appendix +======== + +Getting help +------------ + +For help, please send requests to either the shunit2-users@googlegroups.com +mailing list (archives available on the web at +http://groups.google.com/group/shunit2-users) or directly to +Kate Ward . + +Zsh +--- + +For compatibility with Zsh, there is one requirement that must be met -- the +``shwordsplit`` option must be set. There are three ways to accomplish this. + +#. In the unit-test script, add the following shell code snippet before sourcing + the ``shunit2`` library. :: + + setopt shwordsplit + +#. When invoking **zsh** from either the command-line or as a script with + ``#!``, add the ``-y`` parameter. :: + + #! /bin/zsh -y + +#. When invoking **zsh** from the command-line, add ``-o shwordsplit --`` as + parameters before the script name. :: + + $ zsh -o shwordsplit -- some_script + +.. _log4sh: http://log4sh.sourceforge.net/ +.. _log4j: http://logging.apache.org/ +.. _JUnit: http://www.junit.org/ +.. _PyUnit: http://pyunit.sourceforge.net/ +.. _shFlags: http://shflags.googlecode.com/ +.. _shUnit2: http://shunit2.googlecode.com/ +.. _xUnit: http://en.wikipedia.org/wiki/XUnit + +.. generate HTML using rst2html from Docutils of +.. http://docutils.sourceforge.net/ +.. +.. vim:fileencoding=latin1:ft=rst:spell:sts=2:sw=2:tw=80 +.. $Revision: 233 $ diff --git a/test/shunit2-2.1.6/examples/equality_test.sh b/test/shunit2-2.1.6/examples/equality_test.sh new file mode 100755 index 0000000..e0d68a5 --- /dev/null +++ b/test/shunit2-2.1.6/examples/equality_test.sh @@ -0,0 +1,10 @@ +#! /bin/sh +# file: examples/equality_test.sh + +testEquality() +{ + assertEquals 1 1 +} + +# load shunit2 +. ../src/shunit2 diff --git a/test/shunit2-2.1.6/examples/lineno_test.sh b/test/shunit2-2.1.6/examples/lineno_test.sh new file mode 100755 index 0000000..9c05f1e --- /dev/null +++ b/test/shunit2-2.1.6/examples/lineno_test.sh @@ -0,0 +1,16 @@ +#! /bin/sh +# file: examples/lineno_test.sh + +testLineNo() +{ + # this assert will have line numbers included (e.g. "ASSERT:[123] ...") if + # they are supported. + echo "_ASSERT_EQUALS_ macro value: ${_ASSERT_EQUALS_}" + ${_ASSERT_EQUALS_} 'not equal' 1 2 + + # this assert will not have line numbers included (e.g. "ASSERT: ...") + assertEquals 'not equal' 1 2 +} + +# load shunit2 +. ../src/shunit2 diff --git a/test/shunit2-2.1.6/examples/math.inc b/test/shunit2-2.1.6/examples/math.inc new file mode 100644 index 0000000..4097106 --- /dev/null +++ b/test/shunit2-2.1.6/examples/math.inc @@ -0,0 +1,17 @@ +# available as examples/math.inc + +add_generic() +{ + num_a=$1 + num_b=$2 + + expr $1 + $2 +} + +add_bash() +{ + num_a=$1 + num_b=$2 + + echo $(($1 + $2)) +} diff --git a/test/shunit2-2.1.6/examples/math_test.sh b/test/shunit2-2.1.6/examples/math_test.sh new file mode 100755 index 0000000..41be5ff --- /dev/null +++ b/test/shunit2-2.1.6/examples/math_test.sh @@ -0,0 +1,27 @@ +#! /bin/sh +# available as examples/math_test.sh + +testAdding() +{ + result=`add_generic 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" + + # disable non-generic tests + [ -z "${BASH_VERSION:-}" ] && startSkipping + + result=`add_bash 1 2` + assertEquals \ + "the result of '${result}' was wrong" \ + 3 "${result}" +} + +oneTimeSetUp() +{ + # load include to test + . ./math.inc +} + +# load and run shUnit2 +. ../src/shunit2 diff --git a/test/shunit2-2.1.6/examples/mkdir_test.sh b/test/shunit2-2.1.6/examples/mkdir_test.sh new file mode 100755 index 0000000..28d8d94 --- /dev/null +++ b/test/shunit2-2.1.6/examples/mkdir_test.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# Example unit test for the mkdir command. +# +# There are times when an existing shell script needs to be tested. In this +# example, we will test several aspects of the the mkdir command, but the +# techniques could be used for any existing shell script. + +#----------------------------------------------------------------------------- +# suite tests +# + +testMissingDirectoryCreation() +{ + ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} + rtrn=$? + th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" + + assertTrue 'directory missing' "[ -d '${testDir}' ]" +} + +testExistingDirectoryCreationFails() +{ + # create a directory to test against + ${mkdirCmd} "${testDir}" + + # test for expected failure while trying to create directory that exists + ${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF} + rtrn=$? + assertFalse 'expecting return code of 1 (false)' ${rtrn} + assertNull 'unexpected output to stdout' "`cat ${stdoutF}`" + assertNotNull 'expected error message to stderr' "`cat ${stderrF}`" + + assertTrue 'directory missing' "[ -d '${testDir}' ]" +} + +testRecursiveDirectoryCreation() +{ + testDir2="${testDir}/test2" + + ${mkdirCmd} -p "${testDir2}" >${stdoutF} 2>${stderrF} + rtrn=$? + th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}" + + assertTrue 'first directory missing' "[ -d '${testDir}' ]" + assertTrue 'second directory missing' "[ -d '${testDir2}' ]" +} + +#----------------------------------------------------------------------------- +# suite functions +# + +th_assertTrueWithNoOutput() +{ + th_return_=$1 + th_stdout_=$2 + th_stderr_=$3 + + assertFalse 'unexpected output to STDOUT' "[ -s '${th_stdout_}' ]" + assertFalse 'unexpected output to STDERR' "[ -s '${th_stderr_}' ]" + + unset th_return_ th_stdout_ th_stderr_ +} + +oneTimeSetUp() +{ + outputDir="${SHUNIT_TMPDIR}/output" + mkdir "${outputDir}" + stdoutF="${outputDir}/stdout" + stderrF="${outputDir}/stderr" + + mkdirCmd='mkdir' # save command name in variable to make future changes easy + testDir="${SHUNIT_TMPDIR}/some_test_dir" +} + +tearDown() +{ + rm -fr "${testDir}" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ../src/shunit2 diff --git a/test/shunit2-2.1.6/examples/party_test.sh b/test/shunit2-2.1.6/examples/party_test.sh new file mode 100755 index 0000000..5ca2583 --- /dev/null +++ b/test/shunit2-2.1.6/examples/party_test.sh @@ -0,0 +1,17 @@ +#! /bin/sh +# file: examples/party_test.sh + +testEquality() +{ + assertEquals 1 1 +} + +testPartyLikeItIs1999() +{ + year=`date '+%Y'` + assertEquals "It's not 1999 :-(" \ + '1999' "${year}" +} + +# load shunit2 +. ../src/shunit2 diff --git a/test/shunit2-2.1.6/lib/shflags b/test/shunit2-2.1.6/lib/shflags new file mode 100644 index 0000000..d09867e --- /dev/null +++ b/test/shunit2-2.1.6/lib/shflags @@ -0,0 +1,1011 @@ +# $Id: shflags 138 2010-03-18 00:25:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shFlags -- Advanced command-line flag library for Unix shell scripts. +# http://code.google.com/p/shflags/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# This module implements something like the google-gflags library available +# from http://code.google.com/p/google-gflags/. +# +# FLAG TYPES: This is a list of the DEFINE_*'s that you can do. All flags take +# a name, default value, help-string, and optional 'short' name (one-letter +# name). Some flags have other arguments, which are described with the flag. +# +# DEFINE_string: takes any input, and intreprets it as a string. +# +# DEFINE_boolean: typically does not take any argument: say --myflag to set +# FLAGS_myflag to true, or --nomyflag to set FLAGS_myflag to false. +# Alternately, you can say +# --myflag=true or --myflag=t or --myflag=0 or +# --myflag=false or --myflag=f or --myflag=1 +# Passing an option has the same affect as passing the option once. +# +# DEFINE_float: takes an input and intreprets it as a floating point number. As +# shell does not support floats per-se, the input is merely validated as +# being a valid floating point value. +# +# DEFINE_integer: takes an input and intreprets it as an integer. +# +# SPECIAL FLAGS: There are a few flags that have special meaning: +# --help (or -?) prints a list of all the flags in a human-readable fashion +# --flagfile=foo read flags from foo. (not implemented yet) +# -- as in getopt(), terminates flag-processing +# +# EXAMPLE USAGE: +# +# -- begin hello.sh -- +# #! /bin/sh +# . ./shflags +# DEFINE_string name 'world' "somebody's name" n +# FLAGS "$@" || exit $? +# eval set -- "${FLAGS_ARGV}" +# echo "Hello, ${FLAGS_name}." +# -- end hello.sh -- +# +# $ ./hello.sh -n Kate +# Hello, Kate. +# +# NOTE: Not all systems include a getopt version that supports long flags. On +# these systems, only short flags are recognized. + +#============================================================================== +# shFlags +# +# Shared attributes: +# flags_error: last error message +# flags_return: last return value +# +# __flags_longNames: list of long names for all flags +# __flags_shortNames: list of short names for all flags +# __flags_boolNames: list of boolean flag names +# +# __flags_opts: options parsed by getopt +# +# Per-flag attributes: +# FLAGS_: contains value of flag named 'flag_name' +# __flags__default: the default flag value +# __flags__help: the flag help string +# __flags__short: the flag short name +# __flags__type: the flag type +# +# Notes: +# - lists of strings are space separated, and a null value is the '~' char. + +# return if FLAGS already loaded +[ -n "${FLAGS_VERSION:-}" ] && return 0 +FLAGS_VERSION='1.0.4pre' + +# return values +FLAGS_TRUE=0 +FLAGS_FALSE=1 +FLAGS_ERROR=2 + +# reserved flag names +FLAGS_RESERVED='ARGC ARGV ERROR FALSE HELP PARENT RESERVED TRUE VERSION' + +_flags_debug() { echo "flags:DEBUG $@" >&2; } +_flags_warn() { echo "flags:WARN $@" >&2; } +_flags_error() { echo "flags:ERROR $@" >&2; } +_flags_fatal() { echo "flags:FATAL $@" >&2; } + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${FLAGS_TRUE} ]; then + _flags_fatal 'zsh shwordsplit option is required for proper zsh operation' + exit ${FLAGS_ERROR} + fi + if [ -z "${FLAGS_PARENT:-}" ]; then + _flags_fatal "zsh does not pass \$0 through properly. please declare' \ +\"FLAGS_PARENT=\$0\" before calling shFlags" + exit ${FLAGS_ERROR} + fi +fi + +# +# constants +# + +# getopt version +__FLAGS_GETOPT_VERS_STD=0 +__FLAGS_GETOPT_VERS_ENH=1 +__FLAGS_GETOPT_VERS_BSD=2 + +getopt >/dev/null 2>&1 +case $? in + 0) __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} ;; # bsd getopt + 2) + # TODO(kward): look into '-T' option to test the internal getopt() version + if [ "`getopt --version`" = '-- ' ]; then + __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_STD} + else + __FLAGS_GETOPT_VERS=${__FLAGS_GETOPT_VERS_ENH} + fi + ;; + *) + _flags_fatal 'unable to determine getopt version' + exit ${FLAGS_ERROR} + ;; +esac + +# getopt optstring lengths +__FLAGS_OPTSTR_SHORT=0 +__FLAGS_OPTSTR_LONG=1 + +__FLAGS_NULL='~' + +# flag info strings +__FLAGS_INFO_DEFAULT='default' +__FLAGS_INFO_HELP='help' +__FLAGS_INFO_SHORT='short' +__FLAGS_INFO_TYPE='type' + +# flag lengths +__FLAGS_LEN_SHORT=0 +__FLAGS_LEN_LONG=1 + +# flag types +__FLAGS_TYPE_NONE=0 +__FLAGS_TYPE_BOOLEAN=1 +__FLAGS_TYPE_FLOAT=2 +__FLAGS_TYPE_INTEGER=3 +__FLAGS_TYPE_STRING=4 + +# set the constants readonly +__flags_constants=`set |awk -F= '/^FLAGS_/ || /^__FLAGS_/ {print $1}'` +for __flags_const in ${__flags_constants}; do + # skip certain flags + case ${__flags_const} in + FLAGS_HELP) continue ;; + FLAGS_PARENT) continue ;; + esac + # set flag readonly + if [ -z "${ZSH_VERSION:-}" ]; then + readonly ${__flags_const} + else # handle zsh + case ${ZSH_VERSION} in + [123].*) readonly ${__flags_const} ;; + *) readonly -g ${__flags_const} ;; # declare readonly constants globally + esac + fi +done +unset __flags_const __flags_constants + +# +# internal variables +# + +__flags_boolNames=' ' # space separated list of boolean flag names +__flags_longNames=' ' # space separated list of long flag names +__flags_shortNames=' ' # space separated list of short flag names + +__flags_columns='' # screen width in columns +__flags_opts='' # temporary storage for parsed getopt flags + +#------------------------------------------------------------------------------ +# private functions +# + +# Define a flag. +# +# Calling this function will define the following info variables for the +# specified flag: +# FLAGS_flagname - the name for this flag (based upon the long flag name) +# __flags__default - the default value +# __flags_flagname_help - the help string +# __flags_flagname_short - the single letter alias +# __flags_flagname_type - the type of flag (one of __FLAGS_TYPE_*) +# +# Args: +# _flags__type: integer: internal type of flag (__FLAGS_TYPE_*) +# _flags__name: string: long flag name +# _flags__default: default flag value +# _flags__help: string: help string +# _flags__short: string: (optional) short flag name +# Returns: +# integer: success of operation, or error +_flags_define() +{ + if [ $# -lt 4 ]; then + flags_error='DEFINE error: too few arguments' + flags_return=${FLAGS_ERROR} + _flags_error "${flags_error}" + return ${flags_return} + fi + + _flags_type_=$1 + _flags_name_=$2 + _flags_default_=$3 + _flags_help_=$4 + _flags_short_=${5:-${__FLAGS_NULL}} + + _flags_return_=${FLAGS_TRUE} + + # TODO(kward): check for validity of the flag name (e.g. dashes) + + # check whether the flag name is reserved + echo " ${FLAGS_RESERVED} " |grep " ${_flags_name_} " >/dev/null + if [ $? -eq 0 ]; then + flags_error="flag name (${_flags_name_}) is reserved" + _flags_return_=${FLAGS_ERROR} + fi + + # require short option for getopt that don't support long options + if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ + -a ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} \ + -a "${_flags_short_}" = "${__FLAGS_NULL}" ] + then + flags_error="short flag required for (${_flags_name_}) on this platform" + _flags_return_=${FLAGS_ERROR} + fi + + # check for existing long name definition + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + if _flags_itemInList "${_flags_name_}" \ + ${__flags_longNames} ${__flags_boolNames} + then + flags_error="flag name ([no]${_flags_name_}) already defined" + _flags_warn "${flags_error}" + _flags_return_=${FLAGS_FALSE} + fi + fi + + # check for existing short name definition + if [ ${_flags_return_} -eq ${FLAGS_TRUE} \ + -a "${_flags_short_}" != "${__FLAGS_NULL}" ] + then + if _flags_itemInList "${_flags_short_}" ${__flags_shortNames}; then + flags_error="flag short name (${_flags_short_}) already defined" + _flags_warn "${flags_error}" + _flags_return_=${FLAGS_FALSE} + fi + fi + + # handle default value. note, on several occasions the 'if' portion of an + # if/then/else contains just a ':' which does nothing. a binary reversal via + # '!' is not done because it does not work on all shells. + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + case ${_flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if _flags_validateBoolean "${_flags_default_}"; then + case ${_flags_default_} in + true|t|0) _flags_default_=${FLAGS_TRUE} ;; + false|f|1) _flags_default_=${FLAGS_FALSE} ;; + esac + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_FLOAT}) + if _flags_validateFloat "${_flags_default_}"; then + : + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_INTEGER}) + if _flags_validateInteger "${_flags_default_}"; then + : + else + flags_error="invalid default flag value '${_flags_default_}'" + _flags_return_=${FLAGS_ERROR} + fi + ;; + + ${__FLAGS_TYPE_STRING}) ;; # everything in shell is a valid string + + *) + flags_error="unrecognized flag type '${_flags_type_}'" + _flags_return_=${FLAGS_ERROR} + ;; + esac + fi + + if [ ${_flags_return_} -eq ${FLAGS_TRUE} ]; then + # store flag information + eval "FLAGS_${_flags_name_}='${_flags_default_}'" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}=${_flags_type_}" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}=\ +\"${_flags_default_}\"" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_HELP}=\"${_flags_help_}\"" + eval "__flags_${_flags_name_}_${__FLAGS_INFO_SHORT}='${_flags_short_}'" + + # append flag name(s) to list of names + __flags_longNames="${__flags_longNames}${_flags_name_} " + __flags_shortNames="${__flags_shortNames}${_flags_short_} " + [ ${_flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] && \ + __flags_boolNames="${__flags_boolNames}no${_flags_name_} " + fi + + flags_return=${_flags_return_} + unset _flags_default_ _flags_help_ _flags_name_ _flags_return_ _flags_short_ \ + _flags_type_ + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" + return ${flags_return} +} + +# Return valid getopt options using currently defined list of long options. +# +# This function builds a proper getopt option string for short (and long) +# options, using the current list of long options for reference. +# +# Args: +# _flags_optStr: integer: option string type (__FLAGS_OPTSTR_*) +# Output: +# string: generated option string for getopt +# Returns: +# boolean: success of operation (always returns True) +_flags_genOptStr() +{ + _flags_optStrType_=$1 + + _flags_opts_='' + + for _flags_flag_ in ${__flags_longNames}; do + _flags_type_=`_flags_getFlagInfo ${_flags_flag_} ${__FLAGS_INFO_TYPE}` + case ${_flags_optStrType_} in + ${__FLAGS_OPTSTR_SHORT}) + _flags_shortName_=`_flags_getFlagInfo \ + ${_flags_flag_} ${__FLAGS_INFO_SHORT}` + if [ "${_flags_shortName_}" != "${__FLAGS_NULL}" ]; then + _flags_opts_="${_flags_opts_}${_flags_shortName_}" + # getopt needs a trailing ':' to indicate a required argument + [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ + _flags_opts_="${_flags_opts_}:" + fi + ;; + + ${__FLAGS_OPTSTR_LONG}) + _flags_opts_="${_flags_opts_:+${_flags_opts_},}${_flags_flag_}" + # getopt needs a trailing ':' to indicate a required argument + [ ${_flags_type_} -ne ${__FLAGS_TYPE_BOOLEAN} ] && \ + _flags_opts_="${_flags_opts_}:" + ;; + esac + done + + echo "${_flags_opts_}" + unset _flags_flag_ _flags_opts_ _flags_optStrType_ _flags_shortName_ \ + _flags_type_ + return ${FLAGS_TRUE} +} + +# Returns flag details based on a flag name and flag info. +# +# Args: +# string: long flag name +# string: flag info (see the _flags_define function for valid info types) +# Output: +# string: value of dereferenced flag variable +# Returns: +# integer: one of FLAGS_{TRUE|FALSE|ERROR} +_flags_getFlagInfo() +{ + _flags_name_=$1 + _flags_info_=$2 + + _flags_nameVar_="__flags_${_flags_name_}_${_flags_info_}" + _flags_strToEval_="_flags_value_=\"\${${_flags_nameVar_}:-}\"" + eval "${_flags_strToEval_}" + if [ -n "${_flags_value_}" ]; then + flags_return=${FLAGS_TRUE} + else + # see if the _flags_name_ variable is a string as strings can be empty... + # note: the DRY principle would say to have this function call itself for + # the next three lines, but doing so results in an infinite loop as an + # invalid _flags_name_ will also not have the associated _type variable. + # Because it doesn't (it will evaluate to an empty string) the logic will + # try to find the _type variable of the _type variable, and so on. Not so + # good ;-) + _flags_typeVar_="__flags_${_flags_name_}_${__FLAGS_INFO_TYPE}" + _flags_strToEval_="_flags_type_=\"\${${_flags_typeVar_}:-}\"" + eval "${_flags_strToEval_}" + if [ "${_flags_type_}" = "${__FLAGS_TYPE_STRING}" ]; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_ERROR} + flags_error="invalid flag name (${_flags_nameVar_})" + fi + fi + + echo "${_flags_value_}" + unset _flags_info_ _flags_name_ _flags_strToEval_ _flags_type_ _flags_value_ \ + _flags_nameVar_ _flags_typeVar_ + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_error "${flags_error}" + return ${flags_return} +} + +# check for presense of item in a list. passed a string (e.g. 'abc'), this +# function will determine if the string is present in the list of strings (e.g. +# ' foo bar abc '). +# +# Args: +# _flags__str: string: string to search for in a list of strings +# unnamed: list: list of strings +# Returns: +# boolean: true if item is in the list +_flags_itemInList() +{ + _flags_str_=$1 + shift + + echo " ${*:-} " |grep " ${_flags_str_} " >/dev/null + if [ $? -eq 0 ]; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_FALSE} + fi + + unset _flags_str_ + return ${flags_return} +} + +# Returns the width of the current screen. +# +# Output: +# integer: width in columns of the current screen. +_flags_columns() +{ + if [ -z "${__flags_columns}" ]; then + # determine the value and store it + if eval stty size >/dev/null 2>&1; then + # stty size worked :-) + set -- `stty size` + __flags_columns=$2 + elif eval tput cols >/dev/null 2>&1; then + set -- `tput cols` + __flags_columns=$1 + else + __flags_columns=80 # default terminal width + fi + fi + echo ${__flags_columns} +} + +# Validate a boolean. +# +# Args: +# _flags__bool: boolean: value to validate +# Returns: +# bool: true if the value is a valid boolean +_flags_validateBoolean() +{ + _flags_bool_=$1 + + flags_return=${FLAGS_TRUE} + case "${_flags_bool_}" in + true|t|0) ;; + false|f|1) ;; + *) flags_return=${FLAGS_FALSE} ;; + esac + + unset _flags_bool_ + return ${flags_return} +} + +# Validate a float. +# +# Args: +# _flags__float: float: value to validate +# Returns: +# bool: true if the value is a valid float +_flags_validateFloat() +{ + _flags_float_=$1 + + if _flags_validateInteger ${_flags_float_}; then + flags_return=${FLAGS_TRUE} + else + flags_return=${FLAGS_TRUE} + case ${_flags_float_} in + -*) # negative floats + _flags_test_=`expr -- "${_flags_float_}" :\ + '\(-[0-9][0-9]*\.[0-9][0-9]*\)'` + ;; + *) # positive floats + _flags_test_=`expr -- "${_flags_float_}" :\ + '\([0-9][0-9]*\.[0-9][0-9]*\)'` + ;; + esac + [ "${_flags_test_}" != "${_flags_float_}" ] && flags_return=${FLAGS_FALSE} + fi + + unset _flags_float_ _flags_test_ + return ${flags_return} +} + +# Validate an integer. +# +# Args: +# _flags__integer: interger: value to validate +# Returns: +# bool: true if the value is a valid integer +_flags_validateInteger() +{ + _flags_int_=$1 + + flags_return=${FLAGS_TRUE} + case ${_flags_int_} in + -*) # negative ints + _flags_test_=`expr -- "${_flags_int_}" : '\(-[0-9][0-9]*\)'` + ;; + *) # positive ints + _flags_test_=`expr -- "${_flags_int_}" : '\([0-9][0-9]*\)'` + ;; + esac + [ "${_flags_test_}" != "${_flags_int_}" ] && flags_return=${FLAGS_FALSE} + + unset _flags_int_ _flags_test_ + return ${flags_return} +} + +# Parse command-line options using the standard getopt. +# +# Note: the flag options are passed around in the global __flags_opts so that +# the formatting is not lost due to shell parsing and such. +# +# Args: +# @: varies: command-line options to parse +# Returns: +# integer: a FLAGS success condition +_flags_getoptStandard() +{ + flags_return=${FLAGS_TRUE} + _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` + + # check for spaces in passed options + for _flags_opt_ in "$@"; do + # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 + _flags_match_=`echo "x${_flags_opt_}x" |sed 's/ //g'` + if [ "${_flags_match_}" != "x${_flags_opt_}x" ]; then + flags_error='the available getopt does not support spaces in options' + flags_return=${FLAGS_ERROR} + break + fi + done + + if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then + __flags_opts=`getopt ${_flags_shortOpts_} $@ 2>&1` + _flags_rtrn_=$? + if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then + _flags_warn "${__flags_opts}" + flags_error='unable to parse provided options with getopt.' + flags_return=${FLAGS_ERROR} + fi + fi + + unset _flags_match_ _flags_opt_ _flags_rtrn_ _flags_shortOpts_ + return ${flags_return} +} + +# Parse command-line options using the enhanced getopt. +# +# Note: the flag options are passed around in the global __flags_opts so that +# the formatting is not lost due to shell parsing and such. +# +# Args: +# @: varies: command-line options to parse +# Returns: +# integer: a FLAGS success condition +_flags_getoptEnhanced() +{ + flags_return=${FLAGS_TRUE} + _flags_shortOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_SHORT}` + _flags_boolOpts_=`echo "${__flags_boolNames}" \ + |sed 's/^ *//;s/ *$//;s/ /,/g'` + _flags_longOpts_=`_flags_genOptStr ${__FLAGS_OPTSTR_LONG}` + + __flags_opts=`getopt \ + -o ${_flags_shortOpts_} \ + -l "${_flags_longOpts_},${_flags_boolOpts_}" \ + -- "$@" 2>&1` + _flags_rtrn_=$? + if [ ${_flags_rtrn_} -ne ${FLAGS_TRUE} ]; then + _flags_warn "${__flags_opts}" + flags_error='unable to parse provided options with getopt.' + flags_return=${FLAGS_ERROR} + fi + + unset _flags_boolOpts_ _flags_longOpts_ _flags_rtrn_ _flags_shortOpts_ + return ${flags_return} +} + +# Dynamically parse a getopt result and set appropriate variables. +# +# This function does the actual conversion of getopt output and runs it through +# the standard case structure for parsing. The case structure is actually quite +# dynamic to support any number of flags. +# +# Args: +# argc: int: original command-line argument count +# @: varies: output from getopt parsing +# Returns: +# integer: a FLAGS success condition +_flags_parseGetopt() +{ + _flags_argc_=$1 + shift + + flags_return=${FLAGS_TRUE} + + if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then + set -- $@ + else + # note the quotes around the `$@' -- they are essential! + eval set -- "$@" + fi + + # provide user with number of arguments to shift by later + # NOTE: the FLAGS_ARGC variable is obsolete as of 1.0.3 because it does not + # properly give user access to non-flag arguments mixed in between flag + # arguments. Its usage was replaced by FLAGS_ARGV, and it is being kept only + # for backwards compatibility reasons. + FLAGS_ARGC=`expr $# - 1 - ${_flags_argc_}` + + # handle options. note options with values must do an additional shift + while true; do + _flags_opt_=$1 + _flags_arg_=${2:-} + _flags_type_=${__FLAGS_TYPE_NONE} + _flags_name_='' + + # determine long flag name + case "${_flags_opt_}" in + --) shift; break ;; # discontinue option parsing + + --*) # long option + _flags_opt_=`expr -- "${_flags_opt_}" : '--\(.*\)'` + _flags_len_=${__FLAGS_LEN_LONG} + if _flags_itemInList "${_flags_opt_}" ${__flags_longNames}; then + _flags_name_=${_flags_opt_} + else + # check for negated long boolean version + if _flags_itemInList "${_flags_opt_}" ${__flags_boolNames}; then + _flags_name_=`expr -- "${_flags_opt_}" : 'no\(.*\)'` + _flags_type_=${__FLAGS_TYPE_BOOLEAN} + _flags_arg_=${__FLAGS_NULL} + fi + fi + ;; + + -*) # short option + _flags_opt_=`expr -- "${_flags_opt_}" : '-\(.*\)'` + _flags_len_=${__FLAGS_LEN_SHORT} + if _flags_itemInList "${_flags_opt_}" ${__flags_shortNames}; then + # yes. match short name to long name. note purposeful off-by-one + # (too high) with awk calculations. + _flags_pos_=`echo "${__flags_shortNames}" \ + |awk 'BEGIN{RS=" ";rn=0}$0==e{rn=NR}END{print rn}' \ + e=${_flags_opt_}` + _flags_name_=`echo "${__flags_longNames}" \ + |awk 'BEGIN{RS=" "}rn==NR{print $0}' rn="${_flags_pos_}"` + fi + ;; + esac + + # die if the flag was unrecognized + if [ -z "${_flags_name_}" ]; then + flags_error="unrecognized option (${_flags_opt_})" + flags_return=${FLAGS_ERROR} + break + fi + + # set new flag value + [ ${_flags_type_} -eq ${__FLAGS_TYPE_NONE} ] && \ + _flags_type_=`_flags_getFlagInfo \ + "${_flags_name_}" ${__FLAGS_INFO_TYPE}` + case ${_flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if [ ${_flags_len_} -eq ${__FLAGS_LEN_LONG} ]; then + if [ "${_flags_arg_}" != "${__FLAGS_NULL}" ]; then + eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}" + else + eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}" + fi + else + _flags_strToEval_="_flags_val_=\ +\${__flags_${_flags_name_}_${__FLAGS_INFO_DEFAULT}}" + eval "${_flags_strToEval_}" + if [ ${_flags_val_} -eq ${FLAGS_FALSE} ]; then + eval "FLAGS_${_flags_name_}=${FLAGS_TRUE}" + else + eval "FLAGS_${_flags_name_}=${FLAGS_FALSE}" + fi + fi + ;; + + ${__FLAGS_TYPE_FLOAT}) + if _flags_validateFloat "${_flags_arg_}"; then + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + else + flags_error="invalid float value (${_flags_arg_})" + flags_return=${FLAGS_ERROR} + break + fi + ;; + + ${__FLAGS_TYPE_INTEGER}) + if _flags_validateInteger "${_flags_arg_}"; then + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + else + flags_error="invalid integer value (${_flags_arg_})" + flags_return=${FLAGS_ERROR} + break + fi + ;; + + ${__FLAGS_TYPE_STRING}) + eval "FLAGS_${_flags_name_}='${_flags_arg_}'" + ;; + esac + + # handle special case help flag + if [ "${_flags_name_}" = 'help' ]; then + if [ ${FLAGS_help} -eq ${FLAGS_TRUE} ]; then + flags_help + flags_error='help requested' + flags_return=${FLAGS_FALSE} + break + fi + fi + + # shift the option and non-boolean arguements out. + shift + [ ${_flags_type_} != ${__FLAGS_TYPE_BOOLEAN} ] && shift + done + + # give user back non-flag arguments + FLAGS_ARGV='' + while [ $# -gt 0 ]; do + FLAGS_ARGV="${FLAGS_ARGV:+${FLAGS_ARGV} }'$1'" + shift + done + + unset _flags_arg_ _flags_len_ _flags_name_ _flags_opt_ _flags_pos_ \ + _flags_strToEval_ _flags_type_ _flags_val_ + return ${flags_return} +} + +#------------------------------------------------------------------------------ +# public functions +# + +# A basic boolean flag. Boolean flags do not take any arguments, and their +# value is either 1 (false) or 0 (true). For long flags, the false value is +# specified on the command line by prepending the word 'no'. With short flags, +# the presense of the flag toggles the current value between true and false. +# Specifying a short boolean flag twice on the command results in returning the +# value back to the default value. +# +# A default value is required for boolean flags. +# +# For example, lets say a Boolean flag was created whose long name was 'update' +# and whose short name was 'x', and the default value was 'false'. This flag +# could be explicitly set to 'true' with '--update' or by '-x', and it could be +# explicitly set to 'false' with '--noupdate'. +DEFINE_boolean() { _flags_define ${__FLAGS_TYPE_BOOLEAN} "$@"; } + +# Other basic flags. +DEFINE_float() { _flags_define ${__FLAGS_TYPE_FLOAT} "$@"; } +DEFINE_integer() { _flags_define ${__FLAGS_TYPE_INTEGER} "$@"; } +DEFINE_string() { _flags_define ${__FLAGS_TYPE_STRING} "$@"; } + +# Parse the flags. +# +# Args: +# unnamed: list: command-line flags to parse +# Returns: +# integer: success of operation, or error +FLAGS() +{ + # define a standard 'help' flag if one isn't already defined + [ -z "${__flags_help_type:-}" ] && \ + DEFINE_boolean 'help' false 'show this help' 'h' + + # parse options + if [ $# -gt 0 ]; then + if [ ${__FLAGS_GETOPT_VERS} -ne ${__FLAGS_GETOPT_VERS_ENH} ]; then + _flags_getoptStandard "$@" + else + _flags_getoptEnhanced "$@" + fi + flags_return=$? + else + # nothing passed; won't bother running getopt + __flags_opts='--' + flags_return=${FLAGS_TRUE} + fi + + if [ ${flags_return} -eq ${FLAGS_TRUE} ]; then + _flags_parseGetopt $# "${__flags_opts}" + flags_return=$? + fi + + [ ${flags_return} -eq ${FLAGS_ERROR} ] && _flags_fatal "${flags_error}" + return ${flags_return} +} + +# This is a helper function for determining the `getopt` version for platforms +# where the detection isn't working. It simply outputs debug information that +# can be included in a bug report. +# +# Args: +# none +# Output: +# debug info that can be included in a bug report +# Returns: +# nothing +flags_getoptInfo() +{ + # platform info + _flags_debug "uname -a: `uname -a`" + _flags_debug "PATH: ${PATH}" + + # shell info + if [ -n "${BASH_VERSION:-}" ]; then + _flags_debug 'shell: bash' + _flags_debug "BASH_VERSION: ${BASH_VERSION}" + elif [ -n "${ZSH_VERSION:-}" ]; then + _flags_debug 'shell: zsh' + _flags_debug "ZSH_VERSION: ${ZSH_VERSION}" + fi + + # getopt info + getopt >/dev/null + _flags_getoptReturn=$? + _flags_debug "getopt return: ${_flags_getoptReturn}" + _flags_debug "getopt --version: `getopt --version 2>&1`" + + unset _flags_getoptReturn +} + +# Returns whether the detected getopt version is the enhanced version. +# +# Args: +# none +# Output: +# none +# Returns: +# bool: true if getopt is the enhanced version +flags_getoptIsEnh() +{ + test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} +} + +# Returns whether the detected getopt version is the standard version. +# +# Args: +# none +# Returns: +# bool: true if getopt is the standard version +flags_getoptIsStd() +{ + test ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} +} + +# This is effectively a 'usage()' function. It prints usage information and +# exits the program with ${FLAGS_FALSE} if it is ever found in the command line +# arguments. Note this function can be overridden so other apps can define +# their own --help flag, replacing this one, if they want. +# +# Args: +# none +# Returns: +# integer: success of operation (always returns true) +flags_help() +{ + if [ -n "${FLAGS_HELP:-}" ]; then + echo "${FLAGS_HELP}" >&2 + else + echo "USAGE: ${FLAGS_PARENT:-$0} [flags] args" >&2 + fi + if [ -n "${__flags_longNames}" ]; then + echo 'flags:' >&2 + for flags_name_ in ${__flags_longNames}; do + flags_flagStr_='' + flags_boolStr_='' + + flags_default_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_DEFAULT}` + flags_help_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_HELP}` + flags_short_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_SHORT}` + flags_type_=`_flags_getFlagInfo \ + "${flags_name_}" ${__FLAGS_INFO_TYPE}` + + [ "${flags_short_}" != "${__FLAGS_NULL}" ] \ + && flags_flagStr_="-${flags_short_}" + + if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_ENH} ]; then + [ "${flags_short_}" != "${__FLAGS_NULL}" ] \ + && flags_flagStr_="${flags_flagStr_}," + [ ${flags_type_} -eq ${__FLAGS_TYPE_BOOLEAN} ] \ + && flags_boolStr_='[no]' + flags_flagStr_="${flags_flagStr_}--${flags_boolStr_}${flags_name_}:" + fi + + case ${flags_type_} in + ${__FLAGS_TYPE_BOOLEAN}) + if [ ${flags_default_} -eq ${FLAGS_TRUE} ]; then + flags_defaultStr_='true' + else + flags_defaultStr_='false' + fi + ;; + ${__FLAGS_TYPE_FLOAT}|${__FLAGS_TYPE_INTEGER}) + flags_defaultStr_=${flags_default_} ;; + ${__FLAGS_TYPE_STRING}) flags_defaultStr_="'${flags_default_}'" ;; + esac + flags_defaultStr_="(default: ${flags_defaultStr_})" + + flags_helpStr_=" ${flags_flagStr_} ${flags_help_} ${flags_defaultStr_}" + flags_helpStrLen_=`expr -- "${flags_helpStr_}" : '.*'` + flags_columns_=`_flags_columns` + if [ ${flags_helpStrLen_} -lt ${flags_columns_} ]; then + echo "${flags_helpStr_}" >&2 + else + echo " ${flags_flagStr_} ${flags_help_}" >&2 + # note: the silliness with the x's is purely for ksh93 on Ubuntu 6.06 + # because it doesn't like empty strings when used in this manner. + flags_emptyStr_="`echo \"x${flags_flagStr_}x\" \ + |awk '{printf "%"length($0)-2"s", ""}'`" + flags_helpStr_=" ${flags_emptyStr_} ${flags_defaultStr_}" + flags_helpStrLen_=`expr -- "${flags_helpStr_}" : '.*'` + if [ ${__FLAGS_GETOPT_VERS} -eq ${__FLAGS_GETOPT_VERS_STD} \ + -o ${flags_helpStrLen_} -lt ${flags_columns_} ]; then + # indented to match help string + echo "${flags_helpStr_}" >&2 + else + # indented four from left to allow for longer defaults as long flag + # names might be used too, making things too long + echo " ${flags_defaultStr_}" >&2 + fi + fi + done + fi + + unset flags_boolStr_ flags_default_ flags_defaultStr_ flags_emptyStr_ \ + flags_flagStr_ flags_help_ flags_helpStr flags_helpStrLen flags_name_ \ + flags_columns_ flags_short_ flags_type_ + return ${FLAGS_TRUE} +} + +# Reset shflags back to an uninitialized state. +# +# Args: +# none +# Returns: +# nothing +flags_reset() +{ + for flags_name_ in ${__flags_longNames}; do + flags_strToEval_="unset FLAGS_${flags_name_}" + for flags_type_ in \ + ${__FLAGS_INFO_DEFAULT} \ + ${__FLAGS_INFO_HELP} \ + ${__FLAGS_INFO_SHORT} \ + ${__FLAGS_INFO_TYPE} + do + flags_strToEval_=\ +"${flags_strToEval_} __flags_${flags_name_}_${flags_type_}" + done + eval ${flags_strToEval_} + done + + # reset internal variables + __flags_boolNames=' ' + __flags_longNames=' ' + __flags_shortNames=' ' + + unset flags_name_ flags_type_ flags_strToEval_ +} diff --git a/test/shunit2-2.1.6/lib/shlib b/test/shunit2-2.1.6/lib/shlib new file mode 100644 index 0000000..b5d5779 --- /dev/null +++ b/test/shunit2-2.1.6/lib/shlib @@ -0,0 +1,39 @@ +# $Id: shlib 14 2007-02-18 19:43:41Z sfsetse $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License). +# Author: kate.ward@forestent.com (Kate Ward) +# +# Library of shell functions. + +# Convert a relative path into it's absolute equivalent. +# +# This function will automatically prepend the current working directory if the +# path is not already absolute. It then removes all parent references (../) to +# reconstruct the proper absolute path. +# +# Args: +# shlib_path_: string: relative path +# Outputs: +# string: absolute path +shlib_relToAbsPath() +{ + shlib_path_=$1 + + # prepend current directory to relative paths + echo "${shlib_path_}" |grep '^/' >/dev/null 2>&1 \ + || shlib_path_="`pwd`/${shlib_path_}" + + # clean up the path. if all seds supported true regular expressions, then + # this is what it would be: + shlib_old_=${shlib_path_} + while true; do + shlib_new_=`echo "${shlib_old_}" |sed 's/[^/]*\/\.\.\/*//g;s/\/\.\//\//'` + [ "${shlib_old_}" = "${shlib_new_}" ] && break + shlib_old_=${shlib_new_} + done + echo "${shlib_new_}" + + unset shlib_path_ shlib_old_ shlib_new_ +} diff --git a/test/shunit2-2.1.6/lib/versions b/test/shunit2-2.1.6/lib/versions new file mode 100755 index 0000000..b874d80 --- /dev/null +++ b/test/shunit2-2.1.6/lib/versions @@ -0,0 +1,227 @@ +#! /bin/sh +# $Id: versions 100 2008-11-15 20:24:03Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# This library provides reusable functions that determine actual names and +# versions of installed shells and the OS. The library can also be run as a +# script if set execuatable. + +ARGV0=`basename "$0"` +LSB_RELEASE='/etc/lsb-release' +VERSIONS_SHELLS="/bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/sh /bin/zsh" + +TRUE=0 +FALSE=1 +ERROR=2 + +__versions_haveStrings=${ERROR} + +#------------------------------------------------------------------------------ +# functions +# + +versions_osName() +{ + os_name_='unrecognized' + os_system_=`uname -s` + case ${os_system_} in + CYGWIN_NT-*) os_name_='Cygwin' ;; + Darwin) os_name_='Mac OS X' ;; + FreeBSD) os_name_='FreeBSD' ;; + Linux) os_name_='Linux' ;; + SunOS) + if grep 'OpenSolaris' /etc/release >/dev/null; then + os_name_='OpenSolaris' + else + os_name_='Solaris' + fi + ;; + esac + echo ${os_name_} + unset os_name_ os_system_ +} + +versions_osVersion() +{ + os_version_='unrecognized' + os_system_=`uname -s` + os_release_=`uname -r` + case ${os_system_} in + CYGWIN_NT-*) + os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]\.[0-9]*\).*'` + ;; + Darwin) + major_='10' + sub_=`echo ${os_release_} |sed 's/^[0-9]*\.\([0-9]*\)\.[0-9]*$/\1/'` + case ${os_release_} in + 8.*) minor_='4' ;; + 9.*) minor_='5' ;; + 10.*) minor_='6' ;; + *) minor_='X'; sub_='X' ;; + esac + os_version_="${major_}.${minor_}.${sub_}" + ;; + FreeBSD) + os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]*\)-.*'` + ;; + Linux) + if [ -r "${LSB_RELEASE}" ]; then + if grep -q 'DISTRIB_ID=Ubuntu' "${LSB_RELEASE}"; then + os_version_=`cat "${LSB_RELEASE}" \ + |awk -F= '$1~/DISTRIB_DESCRIPTION/{print $2}' \ + |sed 's/"//g;s/ /-/g'` + fi + elif [ -r '/etc/redhat-release' ]; then + os_version_=`cat /etc/redhat-release` + fi + ;; + SunOS) + if grep 'OpenSolaris' /etc/release >/dev/null; then + os_version_=`grep 'OpenSolaris' /etc/release |awk '{print $2"("$3")"}'` + else + major_=`echo ${os_release_} |sed 's/[0-9]*\.\([0-9]*\)/\1/'` + minor_=`grep Solaris /etc/release |sed 's/[^u]*\(u[0-9]*\).*/\1/'` + os_version_="${major_}${minor_}" + fi + ;; + esac + echo ${os_version_} + unset os_name_ os_release_ os_version_ major_ minor_ sub_ +} + +versions_shellVersion() +{ + shell_=$1 + + if [ ! -x "${shell_}" ]; then + echo 'not installed' + return + fi + + version_='' + case ${shell_} in + */sh) + # TODO(kward): fix this + ## this could be one of any number of shells. try until one fits. + #version_=`versions_shell_bash ${shell_}` + ## dash cannot be self determined yet + #[ -z "${version_}" ] && version_=`versions_shell_ksh ${shell_}` + ## pdksh is covered in versions_shell_ksh() + #[ -z "${version_}" ] && version_=`versions_shell_zsh ${shell_}` + ;; + */bash) version_=`versions_shell_bash ${shell_}` ;; + */dash) + # simply assuming Ubuntu Linux until somebody comes up with a better + # test. the following test will return an empty string if dash is not + # installed. + version_=`versions_shell_dash` + ;; + */ksh) version_=`versions_shell_ksh ${shell_}` ;; + */pdksh) version_=`versions_shell_pdksh ${shell_}` ;; + */zsh) version_=`versions_shell_zsh ${shell_}` ;; + *) version_='invalid' + esac + + echo ${version_:-unknown} + unset shell_ version_ +} + +versions_shell_bash() +{ + $1 --version 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/' +} + +versions_shell_dash() +{ + eval dpkg >/dev/null 2>&1 + [ $? -eq 127 ] && return # return if dpkg not found + + dpkg -l |grep ' dash ' |awk '{print $3}' +} + +versions_shell_ksh() +{ + versions_shell_=$1 + + # see if --version gives a result + versions_version_=`${versions_shell_} --version 2>&1 \ + |sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'` + + # --version didn't work... look into the binary + if [ $? -ne ${TRUE} ]; then + _versions_have_strings + versions_version_=`strings ${versions_shell_} 2>&1 \ + |grep Version \ + |sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'` + [ -z "${versions_version_}" ] \ + && versions_version_=`versions_shell_pdksh ${versions_shell_}` + fi + + echo ${versions_version_} + + unset versions_shell_ versions_version_ +} + +versions_shell_pdksh() +{ + _versions_have_strings + strings $1 2>&1 \ + |grep 'PD KSH' \ + |sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g' +} + +versions_shell_zsh() +{ + versions_shell_=$1 + + versions_version_=`${versions_shell_} --version 2>&1 |awk '{print $2}'` + + if [ $? -ne ${TRUE} ]; then + versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}` + fi + + echo ${versions_version_} + + unset versions_shell_ versions_version_ +} + +# Determine if the 'strings' binary installed. +_versions_have_strings() +{ + [ ${__versions_haveStrings} -ne ${ERROR} ] && return + eval strings /dev/null >/dev/null 2>&1 + if [ $? -eq 0 ]; then + __versions_haveStrings=${TRUE} + else + echo 'WARN: strings not installed. try installing binutils?' >&2 + __versions_haveStrings=${FALSE} + fi +} + +#------------------------------------------------------------------------------ +# main +# + +versions_main() +{ + # treat unset variables as an error + set -u + + os_name=`versions_osName` + os_version=`versions_osVersion` + echo "os: ${os_name} version: ${os_version}" + + for shell in ${VERSIONS_SHELLS}; do + shell_version=`versions_shellVersion ${shell}` + echo "shell: ${shell} version: ${shell_version}" + done +} + +if [ "${ARGV0}" = 'versions' ]; then + versions_main "$@" +fi diff --git a/test/shunit2-2.1.6/src/shunit2 b/test/shunit2-2.1.6/src/shunit2 new file mode 100755 index 0000000..8862ffd --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2 @@ -0,0 +1,1048 @@ +#! /bin/sh +# $Id: shunit2 335 2011-05-01 20:10:33Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# shUnit2 -- Unit testing framework for Unix shell scripts. +# http://code.google.com/p/shunit2/ +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 is a xUnit based unit test framework for Bourne shell scripts. It is +# based on the popular JUnit unit testing framework for Java. + +# return if shunit already loaded +[ -n "${SHUNIT_VERSION:-}" ] && exit 0 + +SHUNIT_VERSION='2.1.6' + +SHUNIT_TRUE=0 +SHUNIT_FALSE=1 +SHUNIT_ERROR=2 + +# enable strict mode by default +SHUNIT_STRICT=${SHUNIT_STRICT:-${SHUNIT_TRUE}} + +_shunit_warn() { echo "shunit2:WARN $@" >&2; } +_shunit_error() { echo "shunit2:ERROR $@" >&2; } +_shunit_fatal() { echo "shunit2:FATAL $@" >&2; exit ${SHUNIT_ERROR}; } + +# specific shell checks +if [ -n "${ZSH_VERSION:-}" ]; then + setopt |grep "^shwordsplit$" >/dev/null + if [ $? -ne ${SHUNIT_TRUE} ]; then + _shunit_fatal 'zsh shwordsplit option is required for proper operation' + fi + if [ -z "${SHUNIT_PARENT:-}" ]; then + _shunit_fatal "zsh does not pass \$0 through properly. please declare \ +\"SHUNIT_PARENT=\$0\" before calling shUnit2" + fi +fi + +# +# constants +# + +__SHUNIT_ASSERT_MSG_PREFIX='ASSERT:' +__SHUNIT_MODE_SOURCED='sourced' +__SHUNIT_MODE_STANDALONE='standalone' +__SHUNIT_PARENT=${SHUNIT_PARENT:-$0} + +# set the constants readonly +shunit_constants_=`set |grep '^__SHUNIT_' |cut -d= -f1` +echo "${shunit_constants_}" |grep '^Binary file' >/dev/null && \ + shunit_constants_=`set |grep -a '^__SHUNIT_' |cut -d= -f1` +for shunit_constant_ in ${shunit_constants_}; do + shunit_ro_opts_='' + case ${ZSH_VERSION:-} in + '') ;; # this isn't zsh + [123].*) ;; # early versions (1.x, 2.x, 3.x) + *) shunit_ro_opts_='-g' ;; # all later versions. declare readonly globally + esac + readonly ${shunit_ro_opts_} ${shunit_constant_} +done +unset shunit_constant_ shunit_constants_ shunit_ro_opts_ + +# variables +__shunit_lineno='' # line number of executed test +__shunit_mode=${__SHUNIT_MODE_SOURCED} # operating mode +__shunit_reportGenerated=${SHUNIT_FALSE} # is report generated +__shunit_script='' # filename of unittest script (standalone mode) +__shunit_skip=${SHUNIT_FALSE} # is skipping enabled +__shunit_suite='' # suite of tests to execute + +# counts of tests +__shunit_testSuccess=${SHUNIT_TRUE} +__shunit_testsTotal=0 +__shunit_testsPassed=0 +__shunit_testsFailed=0 + +# counts of asserts +__shunit_assertsTotal=0 +__shunit_assertsPassed=0 +__shunit_assertsFailed=0 +__shunit_assertsSkipped=0 + +# macros +_SHUNIT_LINENO_='eval __shunit_lineno=""; if [ "${1:-}" = "--lineno" ]; then [ -n "$2" ] && __shunit_lineno="[$2] "; shift 2; fi' + +#----------------------------------------------------------------------------- +# assert functions +# + +# Assert that two values are equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertEquals() requires two or three arguments; $# given" + _shunit_error "1: ${1:+$1} 2: ${2:+$2} 3: ${3:+$3}${4:+ 4: $4}" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" = "${shunit_actual_}" ]; then + _shunit_assertPass + else + failNotEquals "${shunit_message_}" "${shunit_expected_}" "${shunit_actual_}" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_EQUALS_='eval assertEquals --lineno "${LINENO:-}"' + +# Assert that two values are not equal to one another. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotEquals() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + shunit_return=${SHUNIT_TRUE} + if [ "${shunit_expected_}" != "${shunit_actual_}" ]; then + _shunit_assertPass + else + failSame "${shunit_message_}" "$@" + shunit_return=${SHUNIT_FALSE} + fi + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${shunit_return} +} +_ASSERT_NOT_EQUALS_='eval assertNotEquals --lineno "${LINENO:-}"' + +# Assert that a value is null (i.e. an empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertTrue "${shunit_message_}" "[ -z '$1' ]" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NULL_='eval assertNull --lineno "${LINENO:-}"' + +# Assert that a value is not null (i.e. a non-empty string) +# +# Args: +# message: string: failure message [optional] +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotNull() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then # allowing 0 arguments as $1 might actually be null + _shunit_error "assertNotNull() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_actual_=`_shunit_escapeCharactersInString "${1:-}"` + test -n "${shunit_actual_}" + assertTrue "${shunit_message_}" $? + shunit_return=$? + + unset shunit_actual_ shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_NULL_='eval assertNotNull --lineno "${LINENO:-}"' + +# Assert that two values are the same (i.e. equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + assertEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_SAME_='eval assertSame --lineno "${LINENO:-}"' + +# Assert that two values are not the same (i.e. not equal to one another). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "assertNotSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_:-}$1" + shift + fi + assertNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_ASSERT_NOT_SAME_='eval assertNotSame --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is true. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertTrue 0 +# assertTrue "[ 34 -gt 23 ]" +# The folloing test will fail with a message: +# assertTrue 123 +# assertTrue "test failed" "[ -r '/non/existant/file' ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertTrue() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 2 ]; then + _shunit_error "assertTrue() takes one two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -ne 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -ne 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_TRUE_='eval assertTrue --lineno "${LINENO:-}"' + +# Assert that a value or shell test condition is false. +# +# In shell, a value of 0 is true and a non-zero value is false. Any integer +# value passed can thereby be tested. +# +# Shell supports much more complicated tests though, and a means to support +# them was needed. As such, this function tests that conditions are true or +# false through evaluation rather than just looking for a true or false. +# +# The following test will succeed: +# assertFalse 1 +# assertFalse "[ 'apples' = 'oranges' ]" +# The folloing test will fail with a message: +# assertFalse 0 +# assertFalse "test failed" "[ 1 -eq 1 -a 2 -eq 2 ]" +# +# Args: +# message: string: failure message [optional] +# condition: string: integer value or shell conditional statement +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +assertFalse() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 1 -o $# -gt 2 ]; then + _shunit_error "assertFalse() quires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 2 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_condition_=$1 + + # see if condition is an integer, i.e. a return value + shunit_match_=`expr "${shunit_condition_}" : '\([0-9]*\)'` + shunit_return=${SHUNIT_TRUE} + if [ -z "${shunit_condition_}" ]; then + # null condition + shunit_return=${SHUNIT_FALSE} + elif [ -n "${shunit_match_}" -a "${shunit_condition_}" = "${shunit_match_}" ] + then + # possible return value. treating 0 as true, and non-zero as false. + [ ${shunit_condition_} -eq 0 ] && shunit_return=${SHUNIT_FALSE} + else + # (hopefully) a condition + ( eval ${shunit_condition_} ) >/dev/null 2>&1 + [ $? -eq 0 ] && shunit_return=${SHUNIT_FALSE} + fi + + # record the test + if [ ${shunit_return} -eq ${SHUNIT_TRUE} ]; then + _shunit_assertPass + else + _shunit_assertFail "${shunit_message_}" + fi + + unset shunit_message_ shunit_condition_ shunit_match_ + return ${shunit_return} +} +_ASSERT_FALSE_='eval assertFalse --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# failure functions +# + +# Records a test failure. +# +# Args: +# message: string: failure message [optional] +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +fail() +{ + ${_SHUNIT_LINENO_} + if [ $# -gt 1 ]; then + _shunit_error "fail() requires zero or one arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 1 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_}" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_='eval fail --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotEquals() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + shunit_expected_=$1 + shunit_actual_=$2 + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected:<${shunit_expected_}> but was:<${shunit_actual_}>" + + unset shunit_message_ shunit_expected_ shunit_actual_ + return ${SHUNIT_FALSE} +} +_FAIL_NOT_EQUALS_='eval failNotEquals --lineno "${LINENO:-}"' + +# Records a test failure, stating two values should have been the same. +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failSame() requires two or three arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + + _shunit_assertFail "${shunit_message_:+${shunit_message_} }expected not same" + + unset shunit_message_ + return ${SHUNIT_FALSE} +} +_FAIL_SAME_='eval failSame --lineno "${LINENO:-}"' + +# Records a test failure, stating two values were not equal. +# +# This is functionally equivalent to calling failNotEquals(). +# +# Args: +# message: string: failure message [optional] +# expected: string: expected value +# actual: string: actual value +# Returns: +# integer: success (TRUE/FALSE/ERROR constant) +failNotSame() +{ + ${_SHUNIT_LINENO_} + if [ $# -lt 2 -o $# -gt 3 ]; then + _shunit_error "failNotEquals() requires one or two arguments; $# given" + return ${SHUNIT_ERROR} + fi + _shunit_shouldSkip && return ${SHUNIT_TRUE} + + shunit_message_=${__shunit_lineno} + if [ $# -eq 3 ]; then + shunit_message_="${shunit_message_}$1" + shift + fi + failNotEquals "${shunit_message_}" "$1" "$2" + shunit_return=$? + + unset shunit_message_ + return ${shunit_return} +} +_FAIL_NOT_SAME_='eval failNotSame --lineno "${LINENO:-}"' + +#----------------------------------------------------------------------------- +# skipping functions +# + +# Force remaining assert and fail functions to be "skipped". +# +# This function forces the remaining assert and fail functions to be "skipped", +# i.e. they will have no effect. Each function skipped will be recorded so that +# the total of asserts and fails will not be altered. +# +# Args: +# None +startSkipping() +{ + __shunit_skip=${SHUNIT_TRUE} +} + +# Resume the normal recording behavior of assert and fail calls. +# +# Args: +# None +endSkipping() +{ + __shunit_skip=${SHUNIT_FALSE} +} + +# Returns the state of assert and fail call skipping. +# +# Args: +# None +# Returns: +# boolean: (TRUE/FALSE constant) +isSkipping() +{ + return ${__shunit_skip} +} + +#----------------------------------------------------------------------------- +# suite functions +# + +# Stub. This function should contains all unit test calls to be made. +# +# DEPRECATED (as of 2.1.0) +# +# This function can be optionally overridden by the user in their test suite. +# +# If this function exists, it will be called when shunit2 is sourced. If it +# does not exist, shunit2 will search the parent script for all functions +# beginning with the word 'test', and they will be added dynamically to the +# test suite. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#suite() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Adds a function name to the list of tests schedule for execution. +# +# This function should only be called from within the suite() function. +# +# Args: +# function: string: name of a function to add to current unit test suite +suite_addTest() +{ + shunit_func_=${1:-} + + __shunit_suite="${__shunit_suite:+${__shunit_suite} }${shunit_func_}" + __shunit_testsTotal=`expr ${__shunit_testsTotal} + 1` + + unset shunit_func_ +} + +# Stub. This function will be called once before any tests are run. +# +# Common one-time environment preparation tasks shared by all tests can be +# defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeSetUp() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called once after all tests are finished. +# +# Common one-time environment cleanup tasks shared by all tests can be defined +# here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#oneTimeTearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +# Stub. This function will be called before each test is run. +# +# Common environment preparation tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#setUp() { :; } + +# Note: see _shunit_mktempFunc() for actual implementation +# Stub. This function will be called after each test is run. +# +# Common environment cleanup tasks shared by all tests can be defined here. +# +# This function should be overridden by the user in their unit test suite. +# Note: see _shunit_mktempFunc() for actual implementation +# +# Args: +# None +#tearDown() { :; } # DO NOT UNCOMMENT THIS FUNCTION + +#------------------------------------------------------------------------------ +# internal shUnit2 functions +# + +# Create a temporary directory to store various run-time files in. +# +# This function is a cross-platform temporary directory creation tool. Not all +# OSes have the mktemp function, so one is included here. +# +# Args: +# None +# Outputs: +# string: the temporary directory that was created +_shunit_mktempDir() +{ + # try the standard mktemp function + ( exec mktemp -dqt shunit.XXXXXX 2>/dev/null ) && return + + # the standard mktemp didn't work. doing our own. + if [ -r '/dev/urandom' -a -x '/usr/bin/od' ]; then + _shunit_random_=`/usr/bin/od -vAn -N4 -tx4 "${_shunit_file_}" +#! /bin/sh +exit ${SHUNIT_TRUE} +EOF + chmod +x "${_shunit_file_}" + done + + unset _shunit_file_ +} + +# Final cleanup function to leave things as we found them. +# +# Besides removing the temporary directory, this function is in charge of the +# final exit code of the unit test. The exit code is based on how the script +# was ended (e.g. normal exit, or via Ctrl-C). +# +# Args: +# name: string: name of the trap called (specified when trap defined) +_shunit_cleanup() +{ + _shunit_name_=$1 + + case ${_shunit_name_} in + EXIT) _shunit_signal_=0 ;; + INT) _shunit_signal_=2 ;; + TERM) _shunit_signal_=15 ;; + *) + _shunit_warn "unrecognized trap value (${_shunit_name_})" + _shunit_signal_=0 + ;; + esac + + # do our work + rm -fr "${__shunit_tmpDir}" + + # exit for all non-EXIT signals + if [ ${_shunit_name_} != 'EXIT' ]; then + _shunit_warn "trapped and now handling the (${_shunit_name_}) signal" + # disable EXIT trap + trap 0 + # add 128 to signal and exit + exit `expr ${_shunit_signal_} + 128` + elif [ ${__shunit_reportGenerated} -eq ${SHUNIT_FALSE} ] ; then + _shunit_assertFail 'Unknown failure encountered running a test' + _shunit_generateReport + exit ${SHUNIT_ERROR} + fi + + unset _shunit_name_ _shunit_signal_ +} + +# The actual running of the tests happens here. +# +# Args: +# None +_shunit_execSuite() +{ + for _shunit_test_ in ${__shunit_suite}; do + __shunit_testSuccess=${SHUNIT_TRUE} + + # disable skipping + endSkipping + + # execute the per-test setup function + setUp + + # execute the test + echo "${_shunit_test_}" + eval ${_shunit_test_} + + # execute the per-test tear-down function + tearDown + + # update stats + if [ ${__shunit_testSuccess} -eq ${SHUNIT_TRUE} ]; then + __shunit_testsPassed=`expr ${__shunit_testsPassed} + 1` + else + __shunit_testsFailed=`expr ${__shunit_testsFailed} + 1` + fi + done + + unset _shunit_test_ +} + +# Generates the user friendly report with appropriate OK/FAILED message. +# +# Args: +# None +# Output: +# string: the report of successful and failed tests, as well as totals. +_shunit_generateReport() +{ + _shunit_ok_=${SHUNIT_TRUE} + + # if no exit code was provided one, determine an appropriate one + [ ${__shunit_testsFailed} -gt 0 \ + -o ${__shunit_testSuccess} -eq ${SHUNIT_FALSE} ] \ + && _shunit_ok_=${SHUNIT_FALSE} + + echo + if [ ${__shunit_testsTotal} -eq 1 ]; then + echo "Ran ${__shunit_testsTotal} test." + else + echo "Ran ${__shunit_testsTotal} tests." + fi + + _shunit_failures_='' + _shunit_skipped_='' + [ ${__shunit_assertsFailed} -gt 0 ] \ + && _shunit_failures_="failures=${__shunit_assertsFailed}" + [ ${__shunit_assertsSkipped} -gt 0 ] \ + && _shunit_skipped_="skipped=${__shunit_assertsSkipped}" + + if [ ${_shunit_ok_} -eq ${SHUNIT_TRUE} ]; then + _shunit_msg_='OK' + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_} (${_shunit_skipped_})" + else + _shunit_msg_="FAILED (${_shunit_failures_}" + [ -n "${_shunit_skipped_}" ] \ + && _shunit_msg_="${_shunit_msg_},${_shunit_skipped_}" + _shunit_msg_="${_shunit_msg_})" + fi + + echo + echo ${_shunit_msg_} + __shunit_reportGenerated=${SHUNIT_TRUE} + + unset _shunit_failures_ _shunit_msg_ _shunit_ok_ _shunit_skipped_ +} + +# Test for whether a function should be skipped. +# +# Args: +# None +# Returns: +# boolean: whether the test should be skipped (TRUE/FALSE constant) +_shunit_shouldSkip() +{ + [ ${__shunit_skip} -eq ${SHUNIT_FALSE} ] && return ${SHUNIT_FALSE} + _shunit_assertSkip +} + +# Records a successful test. +# +# Args: +# None +_shunit_assertPass() +{ + __shunit_assertsPassed=`expr ${__shunit_assertsPassed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Records a test failure. +# +# Args: +# message: string: failure message to provide user +_shunit_assertFail() +{ + _shunit_msg_=$1 + + __shunit_testSuccess=${SHUNIT_FALSE} + __shunit_assertsFailed=`expr ${__shunit_assertsFailed} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` + echo "${__SHUNIT_ASSERT_MSG_PREFIX}${_shunit_msg_}" + + unset _shunit_msg_ +} + +# Records a skipped test. +# +# Args: +# None +_shunit_assertSkip() +{ + __shunit_assertsSkipped=`expr ${__shunit_assertsSkipped} + 1` + __shunit_assertsTotal=`expr ${__shunit_assertsTotal} + 1` +} + +# Prepare a script filename for sourcing. +# +# Args: +# script: string: path to a script to source +# Returns: +# string: filename prefixed with ./ (if necessary) +_shunit_prepForSourcing() +{ + _shunit_script_=$1 + case "${_shunit_script_}" in + /*|./*) echo "${_shunit_script_}" ;; + *) echo "./${_shunit_script_}" ;; + esac + unset _shunit_script_ +} + +# Escape a character in a string. +# +# Args: +# c: string: unescaped character +# s: string: to escape character in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharInStr() +{ + [ -n "$2" ] || return # no point in doing work on an empty string + + # Note: using shorter variable names to prevent conflicts with + # _shunit_escapeCharactersInString(). + _shunit_c_=$1 + _shunit_s_=$2 + + + # escape the character + echo ''${_shunit_s_}'' |sed 's/\'${_shunit_c_}'/\\\'${_shunit_c_}'/g' + + unset _shunit_c_ _shunit_s_ +} + +# Escape a character in a string. +# +# Args: +# str: string: to escape characters in +# Returns: +# string: with escaped character(s) +_shunit_escapeCharactersInString() +{ + [ -n "$1" ] || return # no point in doing work on an empty string + + _shunit_str_=$1 + + # Note: using longer variable names to prevent conflicts with + # _shunit_escapeCharInStr(). + for _shunit_char_ in '"' '$' "'" '`'; do + _shunit_str_=`_shunit_escapeCharInStr "${_shunit_char_}" "${_shunit_str_}"` + done + + echo "${_shunit_str_}" + unset _shunit_char_ _shunit_str_ +} + +# Extract list of functions to run tests against. +# +# Args: +# script: string: name of script to extract functions from +# Returns: +# string: of function names +_shunit_extractTestFunctions() +{ + _shunit_script_=$1 + + # extract the lines with test function names, strip of anything besides the + # function name, and output everything on a single line. + _shunit_regex_='^[ ]*(function )*test[A-Za-z0-9_]* *\(\)' + egrep "${_shunit_regex_}" "${_shunit_script_}" \ + |sed 's/^[^A-Za-z0-9_]*//;s/^function //;s/\([A-Za-z0-9_]*\).*/\1/g' \ + |xargs + + unset _shunit_regex_ _shunit_script_ +} + +#------------------------------------------------------------------------------ +# main +# + +# determine the operating mode +if [ $# -eq 0 ]; then + __shunit_script=${__SHUNIT_PARENT} + __shunit_mode=${__SHUNIT_MODE_SOURCED} +else + __shunit_script=$1 + [ -r "${__shunit_script}" ] || \ + _shunit_fatal "unable to read from ${__shunit_script}" + __shunit_mode=${__SHUNIT_MODE_STANDALONE} +fi + +# create a temporary storage location +__shunit_tmpDir=`_shunit_mktempDir` + +# provide a public temporary directory for unit test scripts +# TODO(kward): document this +SHUNIT_TMPDIR="${__shunit_tmpDir}/tmp" +mkdir "${SHUNIT_TMPDIR}" + +# setup traps to clean up after ourselves +trap '_shunit_cleanup EXIT' 0 +trap '_shunit_cleanup INT' 2 +trap '_shunit_cleanup TERM' 15 + +# create phantom functions to work around issues with Cygwin +_shunit_mktempFunc +PATH="${__shunit_tmpDir}:${PATH}" + +# make sure phantom functions are executable. this will bite if /tmp (or the +# current $TMPDIR) points to a path on a partition that was mounted with the +# 'noexec' option. the noexec command was created with _shunit_mktempFunc(). +noexec 2>/dev/null || _shunit_fatal \ + 'please declare TMPDIR with path on partition with exec permission' + +# we must manually source the tests in standalone mode +if [ "${__shunit_mode}" = "${__SHUNIT_MODE_STANDALONE}" ]; then + . "`_shunit_prepForSourcing \"${__shunit_script}\"`" +fi + +# execute the oneTimeSetUp function (if it exists) +oneTimeSetUp + +# execute the suite function defined in the parent test script +# deprecated as of 2.1.0 +suite + +# if no suite function was defined, dynamically build a list of functions +if [ -z "${__shunit_suite}" ]; then + shunit_funcs_=`_shunit_extractTestFunctions "${__shunit_script}"` + for shunit_func_ in ${shunit_funcs_}; do + suite_addTest ${shunit_func_} + done +fi +unset shunit_func_ shunit_funcs_ + +# execute the tests +_shunit_execSuite + +# execute the oneTimeTearDown function (if it exists) +oneTimeTearDown + +# generate the report +_shunit_generateReport + +# that's it folks +[ ${__shunit_testsFailed} -eq 0 ] +exit $? diff --git a/test/shunit2-2.1.6/src/shunit2_test.sh b/test/shunit2-2.1.6/src/shunit2_test.sh new file mode 100755 index 0000000..f5a0ff8 --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test.sh @@ -0,0 +1,124 @@ +#! /bin/sh +# $Id: shunit2_test.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test suite runner. +# +# This script runs all the unit tests that can be found, and generates a nice +# report of the tests. + +MY_NAME=`basename $0` +MY_PATH=`dirname $0` + +PREFIX='shunit2_test_' +SHELLS='/bin/sh /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh' +TESTS='' +for test in ${PREFIX}[a-z]*.sh; do + TESTS="${TESTS} ${test}" +done + +# load common unit test functions +. ../lib/versions +. ./shunit2_test_helpers + +usage() +{ + echo "usage: ${MY_NAME} [-e key=val ...] [-s shell(s)] [-t test(s)]" +} + +env='' + +# process command line flags +while getopts 'e:hs:t:' opt; do + case ${opt} in + e) # set an environment variable + key=`expr "${OPTARG}" : '\([^=]*\)='` + val=`expr "${OPTARG}" : '[^=]*=\(.*\)'` + if [ -z "${key}" -o -z "${val}" ]; then + usage + exit 1 + fi + eval "${key}='${val}'" + export ${key} + env="${env:+${env} }${key}" + ;; + h) usage; exit 0 ;; # output help + s) shells=${OPTARG} ;; # list of shells to run + t) tests=${OPTARG} ;; # list of tests to run + *) usage; exit 1 ;; + esac +done +shift `expr ${OPTIND} - 1` + +# fill shells and/or tests +shells=${shells:-${SHELLS}} +tests=${tests:-${TESTS}} + +# error checking +if [ -z "${tests}" ]; then + th_error 'no tests found to run; exiting' + exit 1 +fi + +cat <&1; ) + done +done diff --git a/test/shunit2-2.1.6/src/shunit2_test_asserts.sh b/test/shunit2-2.1.6/src/shunit2_test_asserts.sh new file mode 100755 index 0000000..1f8040d --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test_asserts.sh @@ -0,0 +1,209 @@ +#! /bin/sh +# $Id: shunit2_test_asserts.sh 312 2011-03-14 22:41:29Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for assert functions + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +commonEqualsSame() +{ + fn=$1 + + ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal' $? "${stdoutF}" "${stderrF}" + + ( ${fn} "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal; with msg' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'abc def' 'abc def' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'equal with spaces' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not equal' $? "${stdoutF}" "${stderrF}" + + ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +commonNotEqualsSame() +{ + fn=$1 + + ( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( ${fn} "${MSG}" 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not same, with msg' $? "${stdoutF}" "${stderrF}" + + ( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertEquals() +{ + commonEqualsSame 'assertEquals' +} + +testAssertNotEquals() +{ + commonNotEqualsSame 'assertNotEquals' +} + +testAssertSame() +{ + commonEqualsSame 'assertSame' +} + +testAssertNotSame() +{ + commonNotEqualsSame 'assertNotSame' +} + +testAssertNull() +{ + ( assertNull '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null' $? "${stdoutF}" "${stderrF}" + + ( assertNull "${MSG}" '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'null, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertNull 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not null' $? "${stdoutF}" "${stderrF}" + + ( assertNull >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertNotNull() +{ + ( assertNotNull 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null' $? "${stdoutF}" "${stderrF}" + + ( assertNotNull "${MSG}" 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x"b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with double-quote' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull "x'b" >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with single-quote' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x$b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with dollar' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull 'x`b' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'not null, with backtick' $? \ + "${stdoutF}" "${stderrF}" + + ( assertNotNull '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" + + # there is no test for too few arguments as $1 might actually be null + + ( assertNotNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertTrue() +{ + ( assertTrue 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true' $? "${stdoutF}" "${stderrF}" + + ( assertTrue "${MSG}" 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertTrue 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'false' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'false condition' $? "${stdoutF}" "${stderrF}" + + ( assertTrue '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}" + + ( assertTrue >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertTrue arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testAssertFalse() +{ + ( assertFalse 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false' $? "${stdoutF}" "${stderrF}" + + ( assertFalse "${MSG}" 1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false, with msg' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertTrueWithNoOutput 'false condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse 0 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}" + + ( assertFalse >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( assertFalse arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +#------------------------------------------------------------------------------ +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" + + MSG='This is a test message' +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/test/shunit2-2.1.6/src/shunit2_test_failures.sh b/test/shunit2-2.1.6/src/shunit2_test_failures.sh new file mode 100755 index 0000000..4aec943 --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test_failures.sh @@ -0,0 +1,89 @@ +#! /bin/sh +# $Id: shunit2_test_failures.sh 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for failure functions + +# load common unit-test functions +. ./shunit2_test_helpers + +#----------------------------------------------------------------------------- +# suite tests +# + +testFail() +{ + ( fail >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'fail' $? "${stdoutF}" "${stderrF}" + + ( fail "${MSG}" >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'fail with msg' $? "${stdoutF}" "${stderrF}" + + ( fail arg1 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testFailNotEquals() +{ + ( failNotEquals 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( failNotEquals arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +testFailSame() +{ + ( failSame 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}" + + ( failSame "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}" + + ( failSame 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}" + + ( failSame '' '' >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}" + + ( failSame >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}" + + ( failSame arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" ) + th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}" +} + +#----------------------------------------------------------------------------- +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" + + MSG='This is a test message' +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/test/shunit2-2.1.6/src/shunit2_test_helpers b/test/shunit2-2.1.6/src/shunit2_test_helpers new file mode 100644 index 0000000..82a0eef --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test_helpers @@ -0,0 +1,177 @@ +# $Id: shunit2_test_helpers 286 2008-11-24 21:42:34Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test common functions + +# treat unset variables as an error when performing parameter expansion +set -u + +# set shwordsplit for zsh +[ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit + +# +# constants +# + +# path to shUnit2 library. can be overridden by setting SHUNIT_INC +TH_SHUNIT=${SHUNIT_INC:-./shunit2} + +# configure debugging. set the DEBUG environment variable to any +# non-empty value to enable debug output, or TRACE to enable trace +# output. +TRACE=${TRACE:+'th_trace '} +[ -n "${TRACE}" ] && DEBUG=1 +[ -z "${TRACE}" ] && TRACE=':' + +DEBUG=${DEBUG:+'th_debug '} +[ -z "${DEBUG}" ] && DEBUG=':' + +# +# variables +# + +th_RANDOM=0 + +# +# functions +# + +# message functions +th_trace() { echo "${MY_NAME}:TRACE $@" >&2; } +th_debug() { echo "${MY_NAME}:DEBUG $@" >&2; } +th_info() { echo "${MY_NAME}:INFO $@" >&2; } +th_warn() { echo "${MY_NAME}:WARN $@" >&2; } +th_error() { echo "${MY_NAME}:ERROR $@" >&2; } +th_fatal() { echo "${MY_NAME}:FATAL $@" >&2; } + +# output subtest name +th_subtest() { echo " $@" >&2; } + +# generate a random number +th_generateRandom() +{ + tfgr_random=${th_RANDOM} + + while [ "${tfgr_random}" = "${th_RANDOM}" ]; do + if [ -n "${RANDOM:-}" ]; then + # $RANDOM works + tfgr_random=${RANDOM}${RANDOM}${RANDOM}$$ + elif [ -r '/dev/urandom' ]; then + tfgr_random=`od -vAn -N4 -tu4 "${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testAssertNotEquals() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_EQUALS_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_EQUALS_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNotSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNull() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NULL_} 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NULL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NULL_} '"some msg"' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NULL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testNotNull() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_NOT_NULL_} '' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_NULL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_NOT_NULL_} '"some msg"' '""' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_NOT_NULL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stdoutF}" "${stderrF}" >&2 +} + +testAssertTrue() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_TRUE_} ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_TRUE_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + + ( ${_ASSERT_TRUE_} '"some msg"' ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_TRUE_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testAssertFalse() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_ASSERT_FALSE_} ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_FALSE_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_ASSERT_FALSE_} '"some msg"' ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_ASSERT_FALSE_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFail() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_} >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_} '"some msg"' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailNotEquals() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_NOT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_EQUALS_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_NOT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_EQUALS_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testFailNotSame() +{ + # start skipping if LINENO not available + [ -z "${LINENO:-}" ] && startSkipping + + ( ${_FAIL_NOT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_SAME_ failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 + + ( ${_FAIL_NOT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" ) + grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null + rtrn=$? + assertTrue '_FAIL_NOT_SAME_ w/ msg failure' ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +#------------------------------------------------------------------------------ +# suite functions +# + +oneTimeSetUp() +{ + tmpDir="${__shunit_tmpDir}/output" + mkdir "${tmpDir}" + stdoutF="${tmpDir}/stdout" + stderrF="${tmpDir}/stderr" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/test/shunit2-2.1.6/src/shunit2_test_misc.sh b/test/shunit2-2.1.6/src/shunit2_test_misc.sh new file mode 100755 index 0000000..e3be229 --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test_misc.sh @@ -0,0 +1,165 @@ +#! /bin/sh +# $Id: shunit2_test_misc.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2008 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit tests of miscellaneous things + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +# Note: the test script is prefixed with '#' chars so that shUnit2 does not +# incorrectly interpret the embedded functions as real functions. +testUnboundVariable() +{ + sed 's/^#//' >"${unittestF}" <"${stdoutF}" 2>"${stderrF}" ) + assertFalse 'expected a non-zero exit value' $? + grep '^ASSERT:Unknown failure' "${stdoutF}" >/dev/null + assertTrue 'assert message was not generated' $? + grep '^Ran [0-9]* test' "${stdoutF}" >/dev/null + assertTrue 'test count message was not generated' $? + grep '^FAILED' "${stdoutF}" >/dev/null + assertTrue 'failure message was not generated' $? +} + +testIssue7() +{ + ( assertEquals 'Some message.' 1 2 >"${stdoutF}" 2>"${stderrF}" ) + diff "${stdoutF}" - >/dev/null < but was:<2> +EOF + rtrn=$? + assertEquals ${SHUNIT_TRUE} ${rtrn} + [ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2 +} + +testPrepForSourcing() +{ + assertEquals '/abc' `_shunit_prepForSourcing '/abc'` + assertEquals './abc' `_shunit_prepForSourcing './abc'` + assertEquals './abc' `_shunit_prepForSourcing 'abc'` +} + +testEscapeCharInStr() +{ + actual=`_shunit_escapeCharInStr '\' ''` + assertEquals '' "${actual}" + assertEquals 'abc\\' `_shunit_escapeCharInStr '\' 'abc\'` + assertEquals 'abc\\def' `_shunit_escapeCharInStr '\' 'abc\def'` + assertEquals '\\def' `_shunit_escapeCharInStr '\' '\def'` + + actual=`_shunit_escapeCharInStr '"' ''` + assertEquals '' "${actual}" + assertEquals 'abc\"' `_shunit_escapeCharInStr '"' 'abc"'` + assertEquals 'abc\"def' `_shunit_escapeCharInStr '"' 'abc"def'` + assertEquals '\"def' `_shunit_escapeCharInStr '"' '"def'` + + actual=`_shunit_escapeCharInStr '$' ''` + assertEquals '' "${actual}" + assertEquals 'abc\$' `_shunit_escapeCharInStr '$' 'abc$'` + assertEquals 'abc\$def' `_shunit_escapeCharInStr '$' 'abc$def'` + assertEquals '\$def' `_shunit_escapeCharInStr '$' '$def'` + +# actual=`_shunit_escapeCharInStr "'" ''` +# assertEquals '' "${actual}" +# assertEquals "abc\\'" `_shunit_escapeCharInStr "'" "abc'"` +# assertEquals "abc\\'def" `_shunit_escapeCharInStr "'" "abc'def"` +# assertEquals "\\'def" `_shunit_escapeCharInStr "'" "'def"` + +# # must put the backtick in a variable so the shell doesn't misinterpret it +# # while inside a backticked sequence (e.g. `echo '`'` would fail). +# backtick='`' +# actual=`_shunit_escapeCharInStr ${backtick} ''` +# assertEquals '' "${actual}" +# assertEquals '\`abc' \ +# `_shunit_escapeCharInStr "${backtick}" ${backtick}'abc'` +# assertEquals 'abc\`' \ +# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}` +# assertEquals 'abc\`def' \ +# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}'def'` +} + +testEscapeCharInStr_specialChars() +{ + # make sure our forward slash doesn't upset sed + assertEquals '/' `_shunit_escapeCharInStr '\' '/'` + + # some shells escape these differently + #assertEquals '\\a' `_shunit_escapeCharInStr '\' '\a'` + #assertEquals '\\b' `_shunit_escapeCharInStr '\' '\b'` +} + +# Test the various ways of declaring functions. +# +# Prefixing (then stripping) with comment symbol so these functions aren't +# treated as real functions by shUnit2. +testExtractTestFunctions() +{ + f="${tmpD}/extract_test_functions" + sed 's/^#//' <"${f}" +#testABC() { echo 'ABC'; } +#test_def() { +# echo 'def' +#} +#testG3 () +#{ +# echo 'G3' +#} +#function test4() { echo '4'; } +# test5() { echo '5'; } +#some_test_function() { echo 'some func'; } +#func_with_test_vars() { +# testVariable=1234 +#} +EOF + + actual=`_shunit_extractTestFunctions "${f}"` + assertEquals 'testABC test_def testG3 test4 test5' "${actual}" +} + +#------------------------------------------------------------------------------ +# suite functions +# + +setUp() +{ + for f in ${expectedF} ${stdoutF} ${stderrF}; do + cp /dev/null ${f} + done + rm -fr "${tmpD}" + mkdir "${tmpD}" +} + +oneTimeSetUp() +{ + tmpD="${SHUNIT_TMPDIR}/tmp" + expectedF="${SHUNIT_TMPDIR}/expected" + stdoutF="${SHUNIT_TMPDIR}/stdout" + stderrF="${SHUNIT_TMPDIR}/stderr" + unittestF="${SHUNIT_TMPDIR}/unittest" +} + +# load and run shUnit2 +[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0 +. ${TH_SHUNIT} diff --git a/test/shunit2-2.1.6/src/shunit2_test_standalone.sh b/test/shunit2-2.1.6/src/shunit2_test_standalone.sh new file mode 100755 index 0000000..6df64b3 --- /dev/null +++ b/test/shunit2-2.1.6/src/shunit2_test_standalone.sh @@ -0,0 +1,41 @@ +#! /bin/sh +# $Id: shunit2_test_standalone.sh 303 2010-05-03 13:11:27Z kate.ward@forestent.com $ +# vim:et:ft=sh:sts=2:sw=2 +# +# Copyright 2010 Kate Ward. All Rights Reserved. +# Released under the LGPL (GNU Lesser General Public License) +# Author: kate.ward@forestent.com (Kate Ward) +# +# shUnit2 unit test for standalone operation. +# +# This unit test is purely to test that calling shunit2 directly, while passing +# the name of a unit test script, works. When run, this script determines if it +# is running as a standalone program, and calls main() if it is. + +ARGV0=`basename "$0"` + +# load test helpers +. ./shunit2_test_helpers + +#------------------------------------------------------------------------------ +# suite tests +# + +testStandalone() +{ + assertTrue ${SHUNIT_TRUE} +} + +#------------------------------------------------------------------------------ +# main +# + +main() +{ + ${TH_SHUNIT} "${ARGV0}" +} + +# are we running as a standalone? +if [ "${ARGV0}" = 'shunit2_test_standalone.sh' ]; then + if [ $# -gt 0 ]; then main "$@"; else main; fi +fi diff --git a/zsh-autosuggestions.plugin.zsh b/zsh-autosuggestions.plugin.zsh deleted file mode 120000 index 65220e1..0000000 --- a/zsh-autosuggestions.plugin.zsh +++ /dev/null @@ -1 +0,0 @@ -autosuggestions.zsh \ No newline at end of file