https://github.com/ishbguy/baux
BAUX is a bash auxiliary library for writing script.
https://github.com/ishbguy/baux
assertion bash library log shell test testing unit-test
Last synced: about 2 months ago
JSON representation
BAUX is a bash auxiliary library for writing script.
- Host: GitHub
- URL: https://github.com/ishbguy/baux
- Owner: ishbguy
- License: mit
- Created: 2018-03-10T17:16:32.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2019-03-19T14:56:42.000Z (over 7 years ago)
- Last Synced: 2026-05-03T21:37:16.815Z (about 2 months ago)
- Topics: assertion, bash, library, log, shell, test, testing, unit-test
- Language: Shell
- Homepage:
- Size: 142 KB
- Stars: 3
- Watchers: 1
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# [BAUX](https://github.com/ishbguy/baux)
[![Travis][travissvg]][travis] [![Codecov][codecovsvg]][codecov] [![Codacy][codacysvg]][codacy] [![Version][versvg]][ver] [![License][licsvg]][lic]
[travissvg]: https://travis-ci.org/ishbguy/baux.svg?branch=master
[travis]: https://travis-ci.org/ishbguy/baux
[codecovsvg]: https://codecov.io/gh/ishbguy/baux/branch/master/graph/badge.svg
[codecov]: https://codecov.io/gh/ishbguy/baux
[codacysvg]: https://api.codacy.com/project/badge/Grade/9a7820362a97474b87652d1519714e1b
[codacy]: https://www.codacy.com/app/ishbguy/baux?utm_source=github.com&utm_medium=referral&utm_content=ishbguy/baux&utm_campaign=Badge_Grade
[versvg]: https://img.shields.io/badge/version-v0.0.1-lightgrey.svg
[ver]: https://img.shields.io/badge/version-v0.1.0-lightgrey.svg
[licsvg]: https://img.shields.io/badge/license-MIT-green.svg
[lic]: https://github.com/ishbguy/baux/blob/master/LICENSE
**BAUX** is a bash auxiliary library for writing script.
## Table of Contents
+ [:art: Features](#art-features)
+ [:straight_ruler: Prerequisite](#straight_ruler-prerequisite)
+ [:rocket: Installation](#rocket-installation)
+ [:notebook: Usage](#notebook-usage)
+ [:hibiscus: Contributing](#hibiscus-contributing)
+ [:boy: Authors](#boy-authors)
+ [:scroll: License](#scroll-license)
## :art: Features
+ [**Helper**](#helper-functions-bauxsh): Basic script writing helper functions, such as getting script's name, version and help message, importing other script once, warning or exit when get a wrong status. (`baux.sh`)
+ [**Assertion**](#assertion-ensuresh): Functions for writing reliable APIs, ensuring the pre- or post-condition. (`ensure.sh`)
+ [**Utility**](#utility-utilish): Useful utility functions for getting options, reading a simple config file, printing message with color and so on. (`utils.sh`)
+ [**Debugging**](#debugging-logsh-tracesh): Simple functions for logging (`log.sh`) and print callstack when failed (`trace.sh`).
+ [**Testing**](#testing-varsh-testsh): Functions for check a variable (`var.sh`) and writing unit tests (`test.sh`).
+ [**Exception**](#exception-exceptsh): (Not yet finished)
- `try()`, `catch()`, `throw()`.
+ [**Array**](#array-arraysh): Functions for array manipulation. (`array.sh`)
- Data structure: stack, queue.
- Sort and search: `sort()`, `bsearch()`.
+ [**Pattern**](#pattern-patternsh): POSIX compatible characters patterns and other common regex. (`pattern.sh`)
- Pattern match: IP, URL, tele-number, etc.
- `is` pattern check.
## :straight_ruler: Prerequisite
> + [`bash`](https://www.gnu.org/software/bash/bash.html)
> + [`sed`](https://www.gnu.org/software/sed/)
## :rocket: Installation
You can get this program with `git`:
```
$ git clone https://github.com/ishbguy/baux
```
## :notebook: Usage
### Library Hierarchy
```bash
lib
├── array.sh # array manipulate functions
├── baux.sh # basic helper functions
├── pattern.sh # POSIX compatible characters patterns and other common regex
├── ensure.sh # assertion functions
├── except.sh # not yet finished
├── log.sh # simple logging
├── test.sh # unit test functions
├── trace.sh # simple callstack function
├── utils.sh # useful tools
└── var.sh # checking variables
```
### Library Dependence Diagram
```bash
except.sh
|-----------------------------------------------+
V |
array.sh test.sh |
| |-----------------------------------|
V V V
var.sh utils.sh pattern.sh log.sh trace.sh
| | | | |
+-----------+-----------+-----------+-----------+
V
baux.sh <-> ensure.sh
```
### How to Use BAUX Library?
As the [Library Dependence Diagram](#library-dependence-diagram) above, you can easily source one of the library file to include the functions you need, for example:
```bash
# in your script
source /path/to/baux/lib/baux.sh
[[ -e $file ]] || die "$file not exist."
```
### Helper Functions (`baux.sh`)
#### Warning
```bash
# your script
source /path/to/baux/lib/baux.sh
[[ -e $opt_file ]] || warn "Just warn you that $opt_file does not exsit"
[[ -e $need_file ]] || die "$need_file not found! This will exit with $BAUX_EXIT_CODE"
echo "Can not be here."
```
**PS**: Though `warn` runs successfully, it does `return ((++BAUX_EXIT_CODE))` in the end, so `warn` returns an **none-zero** when it finished!
#### Information
```bash
#! /usr/bin/env bash
# your script
source /path/to/baux/lib/baux.sh
echo "The script name is $(proname)" # will print the script name
VERSION="v0.0.1" # need to define VERSION first, or version will warn
echo "The script version is $(version)" # will print the script version
HELP="This is a help message." # need to define HELP first, or usage will warn
usage # print help message
```
**PS**: `usage` call `version` first to print version message, then print help message, so, both `VERSION` and `HELP` should be predefined when call `usage`.
#### Importation
`baux.sh` includes an `import` function to ensure source a file for only one time.
```bash
source /path/to/baux/lib/baux.sh
import /path/to/your/lib.sh # this will import once
import /path/to/your/lib.sh # OK, but will not import lib.sh again
cmd_from_lib_sh
import /file/not/exsit.sh # this will fail, and make you script die
echo "Can not be here!"
```
### Assertion (`ensure.sh`)
Assertion functions are useful for writing APIs, and they can be sorted in 3 catogories: general, explicit and implicit assertion.
#### General Assertion
`ensure` can make an assertion with a given expression, if the expression is true, it will continue to run the following commands, or it will die and print a given message.
```bash
source /path/to/baux/lib/ensure.sh
# the first arg is expression, the second arg is error message, which is optional
NUM=1
ensure "$NUM == 1" "$NUM must be equal 1" # OK
ensure "2 -gt $NUM" "2 must greater than $NUM" # OK
ensure "$NUM == 1.0" "$NUM must be 1.0" # this will die, for $NUM act as string '1' not '1.0'
```
The expression given to `ensure` will be `eval [[ $expr ]]` inside `ensure`.
`ensure_not_empty` can test all given args wheather they are not empty, if anyone of them is empty, it will die.
```bash
source /path/to/baux/lib/ensure.sh
one=1
two=2
empty=
ensure_not_empty "$one" "$two" # OK
ensure_not_empty "$empty" # will die
echo "Can not be here."
```
It is a best practice to wrap each arg with double qoute.
#### Explicit Assertion
`ensure_is "$1" "$2"` is equivalent to `ensure "$1 == $2".`
```bash
source /path/to/baux/lib/ensure.sh
one=1
ensure_is "$one" "1" "$one is not 1" # OK
ensure_is "$one" "1.0" "$one is not 1" # will die
echo "Can not be here."
```
`ensure_isnt "$1" "$2"` is equivalent to `ensure "$1 != $2".`
```bash
source /path/to/baux/lib/ensure.sh
one=1
ensure_isnt "$one" "1.0" "$one is not 1" # OK
ensure_isnt "$one" "1" "$one is not 1" # will die
echo "Can not be here."
```
#### Implicit Assertion
`ensure_like "$1" "$2"` is equivalent to `ensure "$1 =~ $2"`
```bash
source /path/to/baux/lib/ensure.sh
str="This is a test"
ensure_like "$str" "a" "$str does not like a" # OK
ensure_like "$str" "test" "$str does not like test" # OK
ensure_like "$str" "check" "$str does not like check" # will die
echo "Can not be here."
```
`ensure_unlike "$1" "$2"` is equivalent to `ensure "! $1 =~ $2"`
```bash
source /path/to/baux/lib/ensure.sh
str="This is a test"
ensure_unlike "$str" "TEST" "$str like TEST" # OK
ensure_unlike "$str" "IS" "$str like IS" # OK
ensure_unlike "$str" "test" "$str like test" # will die
echo "Can not be here."
```
#### Assertion Switch
The `BAUX_ENSURE_DEBUG` variable act as a switch to turn on or off the assertion, its default value is `1`, which means turn on assertion, if you want to turn off, you can set `BAUX_ENSURE_DEBUG` to `0` before sourcing the `ensure.sh`.
### Utility (`utils.sh`)
#### Get Options
```bash
source /path/to/baux/lib/utils.sh
# need to declare two associative arrays
# one for options and one for arguments
declare -A opts args
# The first arg is array NAME for options
# The second arg is array NAME for arguments
# The third arg is the options string, a letter for an option,
# letter follow with ':' means a option argument
# The remain args are needed to be parsed
getoptions opts args "n:vh" "$@"
# after getoptions, need to correct the option index
shift $((OPTIND - 1))
# now you can check options and arguments
[[ ${opts[h]} -eq 1 ]] && echo "Option 'h' invoke"
[[ ${opts[v]} -eq 1 ]] && echo "Option 'v' invoke"
[[ ${opts[n]} -eq 1 ]] && echo "Option 'n' invoke, argument is ${args[n]}"
# an invoked option will be assigned with 1
# an invoked option with an argument, the argument value will be stored
```
#### Read Config File
```bash
source /path/to/baux/lib/utils.sh
# need to declare an associative array for storing config value
declare -A CONFIGS
# config name and value are seperated with '='
# strings follow '#' means comment
# each line allows one name-value pair
# leading and tailing spaces is allowed
# spaces on both sides of '=' is allowed, too
echo "NAME=ishbguy" >>my.config
echo "EMAIL=ishbguy@hotmail.com" >>my.config
read_config CONFIGS my.config
# you will notice that all config name will convert to lower case
echo "my name is ${CONFIGS[name]}"
echo "my email is ${CONFIGS[email]}"
read_config CONFIGS file-not-exsit # will not fail, just return 1
```
#### Other Utilities
```bash
source /path/to/baux/lib/utils.sh
cecho red "This message will print in red" # color can be: black, red, green
# yellow, blue, magenta, cyan, white
realdir /path/to/script # similar to realpath, this will print /path/to
realdir /p1/script1 /p2/script2 # will print /p1 /p2
check_tool sed awk realpath # check needed tools in PATH
check_tool tools-not-exsit # will die
```
### Debugging (`log.sh, trace.sh`)
`BAUX` has a simple `log` function which can accept a log level and message string args, then print the log mesages to `stdout` or a specified log file.
`BAUX` also has a simple `callstack` function to print out the call stack when encountering error.
#### Logging (`log.sh`)
```bash
source /path/to/baux/lib/log.sh
# log has 5 log level and priority from low to high is:
#
# debug < info < warn < error < fatal < panic < quiet
#
# default log output level is debug, means that the log priority higher than
# debug will be printed.
log debug "This is a log test" # this will print a log message to stdout
BAUX_LOG_OUTPUT_LEVEL=info # set log output level to info
log debug "a debug message" # will not print
log info "a info message" # will print into stdout
# set a log output file, default is empty which will print into stdout
# if test.log is not exsit, log will create it
BAUX_LOG_OUTPUT_FILE=test.log
log info "write into a log file" # this will write into test.log
```
#### Callstack (`trace.sh`)
```bash
source /path/to/baux/lib/trace.sh
# callstack need a start index of the function stack array
# if index is 0, which will print also the callstack 0, if index is 1,
# which will not print callstack line, and start to print from function
# three.
one() {
two
}
two() {
three
}
three() {
callstack 0
}
one
```
Run the above test script, will print the callstack to stdout like:
```bash
+ callstack 0 [./test.sh:16:three]
+ three [./test.sh:13:two]
+ two [./test.sh:10:one]
+ one [./test.sh:19:main]
```
### Testing (`var.sh, test.sh`)
#### Variable Type Check (`var.sh`)
```bash
source /path/to/baux/lib/var.sh
declare -a var
type_array var && echo "this is an index array"
type_map var && echo "this is an associative array"
type_int var && echo "this is an integer var"
type_func var && echo "this is a function name"
type_ref var && echo "this is a var reference"
type_export var && echo "this is an exported var"
type_lower var && echo "var's value has lower case attribute"
type_upper var && echo "var's value has upper case attribute"
```
#### Unit Test (`test.sh`)
`BAUX`'s test functions are similar to `Perl`'s [`Test::More`](https://metacpan.org/pod/Test::More) module.
##### Simple test
```bash
source /path/to/baux/lib/test.sh
# ok $expr test is equivalent to [[ $expr ]]
ok '1 == 1' 'Test equal' # pass
ok '1 != 0' 'Test not equal' # pass
# is $a $b test is equivalent to [[ $a == $b ]]
is 1 1 "Test equal" # pass
is 1 0 "Test not equal" # fail
# isnt $a $b test is equivalent to [[ $a != $b ]]
isnt 1 1 "Test equal" # fail
isnt 1 0 "Test not equal" # pass
# like $a $b test is equivalent to [[ $a =~ $b ]]
like "apple" "app" "Test like" # pass
like "apple" "App" "Test not like" # fail
# unlike $a $b test is equivalent to [[ ! $a =~ $b ]]
unlike "apple" "app" "Test like" # fail
unlike "apple" "App" "Test not like" # pass
# each test status will print when that test finish
# finally, report a summary with the numbers of:
# total, pass, fail and skip
summary
```
##### Run command test with `run_ok`
```bash
source /path/to/baux/lib/test.sh
# run_ok like ok, but run_ok provide $status, $output inside to test the
# exit status and cmd output. When use these 2 variables, you need to single
# quote the expr to avoid expanded outside run_ok. And the given cmd is run
# in a subshell like output=$(eval "$cmd" 2>&1), you can check both nomral
# and error message in $output.
run_ok '$status -eq 0' exit 0 # pass
run_ok '$status -eq 1' exit 1 # pass
run_ok '$output =~ "command not found"' cmd_not_found # pass
run_ok '$output =~ "hello world"' echo "hello world" # pass
# you can also do like this for the test statement inside run_ok is equivalent
# to [[ $expr ]]
run_ok '$status -eq 0 && $(echo $output | wc -l) -eq 1' echo "test" # pass
summary
```
##### Run `subtest`
`subtest` will group the your tests in a single sub-test, if one of the tests in `subtest` fails, the `subtest` will fail, and the total and fail counters will increase 1.
```bash
source /path/to/baux/lib/test.sh
# format like: subtest "test name" 'tests cmds'
subtest 'subtest PASS' "
is 1 1 'test equal'
isnt 1 0 'test not equal'
"
summary
```
##### `skip` a following test
```bash
source /path/to/baux/lib/test.sh
is 1 1 # pass
skip
isnt 1 1 # this will skip
isnt 0 1 # this will run and pass
summary
```
##### Customize test outputs
You can customize test's total, pass, fail, skip prompt strings and colors.
```bash
source /path/to/baux/lib/test.sh
# these are default prompt strings
BAUX_TEST_PROMPTS[TOTAL]="TOTAL"
BAUX_TEST_PROMPTS[PASS]="PASS"
BAUX_TEST_PROMPTS[FAIL]="FAIL"
BAUX_TEST_PROMPTS[SKIP]="SKIP"
# these are default colors, you can change color which cecho accept
BAUX_TEST_COLORS[TOTAL]="blue"
BAUX_TEST_COLORS[PASS]="green"
BAUX_TEST_COLORS[FAIL]="red"
BAUX_TEST_COLORS[SKIP]="yellow"
BAUX_TEST_COLORS[EMSG]="red"
```
### Exception (`except.sh`)
### Array (`array.sh`)
### Pattern (`pattern.sh`)
## :hibiscus: Contributing
1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
## :boy: Authors
+ [ishbguy](https://github.com/ishbguy)
## :scroll: License
Released under the terms of [MIT License](https://opensource.org/licenses/MIT).