Unit tests

This commit is contained in:
Nathaniel Landau
2021-07-23 15:14:57 -04:00
parent 6cc7a24628
commit def3122a7c
7 changed files with 352 additions and 6 deletions

View File

@@ -129,6 +129,7 @@ Commonly used functions in many scripts
* `_progressBar_` Prints a progress bar within a for/while loop
* `_rootAvailable_` Validate we have superuser access as root (via sudo if requested)
* `_runAsRoot_` Run the requested command as root (via sudo if requested)
* `_safeExit_` Cleans up temporary files before exiting a script
* `_seekConfirmation_` Seek user input for yes/no question
* `_setPATH_` Add directories to $PATH so script can find executables
@@ -150,11 +151,9 @@ Common utilities for working with files.
* `_listFiles_` Find files in a directory. Use either glob or regex.
* `_backupFile_` Creates a backup of a specified file with .bak extension or optionally to a specified directory.
* `_cleanFilename_` Cleans a filename of all non-alphanumeric (or user specified) characters and overwrites original
* `_parseFilename_` Break a filename into its component parts which and place them into prefixed variables (dir, basename, extension, full path, etc.)
* `_parseFilename_` Break a filename into its component parts which and place them into prefixed variables for use in your script (dir, basename, extension, path, etc.)
* `_decryptFile_` Decrypts a file with `openssl`
* `_encryptFile_` Encrypts a file with `openssl`
* `_ext_` Extract the extension from a filename
* `_extract_` Extract a compressed file
* `_json2yaml_` Convert JSON to YAML uses python
* `_makeSymlink_` Creates a symlink and backs up a file which may be overwritten by the new symlink. If the exact same symlink already exists, nothing is done.

View File

@@ -52,6 +52,8 @@ setup() {
VERBOSE=false
FORCE=false
DRYRUN=false
PASS=123
}
teardown() {
@@ -62,8 +64,6 @@ teardown() {
######## FIXTURES ########
YAML1="${BATS_TEST_DIRNAME}/fixtures/yaml1.yaml"
YAML1parse="${BATS_TEST_DIRNAME}/fixtures/yaml1.yaml.txt"
YAML2="${BATS_TEST_DIRNAME}/fixtures/yaml2.yaml"
JSON="${BATS_TEST_DIRNAME}/fixtures/json.json"
unencrypted="${BATS_TEST_DIRNAME}/fixtures/test.md"
encrypted="${BATS_TEST_DIRNAME}/fixtures/test.md.enc"
@@ -75,6 +75,24 @@ encrypted="${BATS_TEST_DIRNAME}/fixtures/test.md.enc"
assert_output ""
}
@test "_decryptFile_" {
run _decryptFile_ "${encrypted}" "test-decrypted.md"
assert_success
assert_file_exist "test-decrypted.md"
run cat "test-decrypted.md"
assert_success
assert_line --index 0 "# About"
assert_line --index 1 "This repository contains everything needed to bootstrap and configure new Mac computer. Included here are:"
}
@test "_encryptFile_" {
run _encryptFile_ "${unencrypted}" "test-encrypted.md.enc"
assert_success
assert_file_exist "test-encrypted.md.enc"
run cat "test-encrypted.md.enc"
assert_line --index 0 --partial "Salted__"
}
_testBackupFile_() {
@test "_backupFile_: no source" {
@@ -152,19 +170,223 @@ _testListFiles_() {
refute_output --partial "yestest1.txt"
assert_output --partial "notest1.txt"
}
@test "_listFiles: fail no args" {
run _listFiles_
assert_failure
}
@test "_listFiles: fail one arg" {
run _listFiles_ "g"
assert_failure
}
}
_testParseFilename_() {
@test "_parseFilename_: fail with no file" {
run _parseFilename_ "somenonexistantfile"
assert_failure
assert_output --partial "Can't locate a file to parse"
}
@test "_parseFilename_: file with one extension" {
touch "testfile.txt"
VERBOSE=true
run _parseFilename_ "testfile.txt"
assert_success
assert_line --index 0 --regexp "\[ debug\].*{PARSE_FULL}: /.*testfile\.txt$"
assert_line --index 1 --regexp "\[ debug\].*${PARSE_BASE}: testfile\.txt$"
assert_line --index 2 --regexp "\[ debug\].*${PARSE_PATH}: /.*"
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: txt$"
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
}
@test "_parseFilename_: file with dots in name" {
touch "testfile.for.testing.txt"
VERBOSE=true
run _parseFilename_ "testfile.for.testing.txt"
assert_success
assert_line --index 0 --regexp "\[ debug\].*{PARSE_FULL}: /.*testfile\.for\.testing\.txt$"
assert_line --index 1 --regexp "\[ debug\].*${PARSE_BASE}: testfile\.for\.testing\.txt$"
assert_line --index 2 --regexp "\[ debug\].*${PARSE_PATH}: /.*"
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: txt$"
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile\.for\.testing$"
}
@test "_parseFilename_: file with no extension" {
touch "testfile"
VERBOSE=true
run _parseFilename_ "testfile"
assert_success
assert_line --index 0 --regexp "\[ debug\].*{PARSE_FULL}: /.*testfile$"
assert_line --index 1 --regexp "\[ debug\].*${PARSE_BASE}: testfile$"
assert_line --index 2 --regexp "\[ debug\].*${PARSE_PATH}: /.*"
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: $"
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
}
@test "_parseFilename_: file with tar.gz" {
touch "testfile.tar.gz"
VERBOSE=true
run _parseFilename_ "testfile.tar.gz"
assert_success
assert_line --index 0 --regexp "\[ debug\].*{PARSE_FULL}: /.*testfile\.tar\.gz$"
assert_line --index 1 --regexp "\[ debug\].*${PARSE_BASE}: testfile\.tar\.gz$"
assert_line --index 2 --regexp "\[ debug\].*${PARSE_PATH}: /.*"
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: tar\.gz$"
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
}
@test "_parseFilename_: file with three extensions" {
touch "testfile.tar.gzip.bzip"
VERBOSE=true
run _parseFilename_ -n3 "testfile.tar.gzip.bzip"
assert_success
assert_line --index 0 --regexp "\[ debug\].*{PARSE_FULL}: /.*testfile\.tar\.gzip\.bzip$"
assert_line --index 1 --regexp "\[ debug\].*${PARSE_BASE}: testfile\.tar\.gzip\.bzip$"
assert_line --index 2 --regexp "\[ debug\].*${PARSE_PATH}: /.*"
assert_line --index 3 --regexp "\[ debug\].*${PARSE_EXT}: tar\.gzip\.bzip$"
assert_line --index 4 --regexp "\[ debug\].*${PARSE_BASENOEXT}: testfile$"
}
# _parseFilename_ "test.tar.gz"
# _parseFilename_ "test.tar.gzip"
}
_testMakeSymlink_() {
@test "_makeSymlink_: Fail with no source fire" {
run _makeSymlink_ "sourceFile" "destFile"
assert_failure
}
@test "_makeSymlink_: fail with no specified destination" {
touch "test.txt"
run _makeSymlink_ "test.txt"
assert_failure
}
@test "_makeSymlink_: make link" {
touch "test.txt"
touch "test2.txt"
run _makeSymlink_ "${TESTDIR}/test.txt" "${TESTDIR}/test2.txt"
assert_success
assert_output --regexp "\[ info\] symlink /.*/test\.txt → /.*/test2\.txt"
assert_link_exist "test2.txt"
assert_file_exist "test2.txt.bak"
}
@test "_makeSymlink_: Ignore already existing links" {
touch "test.txt"
ln -s "$(realpath test.txt)" "${TESTDIR}/test2.txt"
run _makeSymlink_ "$(realpath test.txt)" "${TESTDIR}/test2.txt"
assert_success
assert_link_exist "test2.txt"
assert_output --regexp "\[ info\] Symlink already exists: /.*/test\.txt → /.*/test2\.txt"
}
@test "_makeSymlink_: Don't make backup" {
touch "test.txt"
touch "test2.txt"
run _makeSymlink_ -n "${TESTDIR}/test.txt" "${TESTDIR}/test2.txt"
assert_success
assert_output --regexp "\[ info\] symlink /.*/test\.txt → /.*/test2\.txt"
assert_link_exist "test2.txt"
assert_file_not_exist "test2.txt.bak"
}
}
_testParseYAML_() {
@test "_parseYAML: success" {
run _parseYAML_ "$YAML1"
assert_success
assert_output "$( cat "$YAML1parse")"
}
@test "_parseYAML_: empty file" {
touch empty.yaml
run _parseYAML_ "empty.yaml"
assert_failure
}
@test "_parseYAML_: no file" {
run _parseYAML_ "empty.yaml"
assert_failure
}
}
@test "_readFile_: Failure" {
run _readFile_ "testfile.txt"
assert_failure
}
@test "_readFile_: Reads files line by line" {
echo -e "line 1\nline 2\nline 3" > testfile.txt
run _readFile_ "testfile.txt"
assert_line --index 0 'line 1'
assert_line --index 2 'line 3'
}
@test "_sourceFile_ failure" {
run _sourceFile_ "someNonExistantFile"
assert_failure
assert_output --partial "[ fatal] Attempted to source 'someNonExistantFile'. Not found"
}
@test "_sourceFile_ success" {
echo "echo 'hello world'" > "testSourceFile.txt"
run _sourceFile_ "testSourceFile.txt"
assert_success
assert_output "hello world"
}
@test "_uniqueFileName_: Count to 3" {
touch "test.txt"
touch "test.txt.1"
touch "test.txt.2"
run _uniqueFileName_ "test.txt"
assert_output --regexp ".*/test\.txt\.3$"
}
@test "_uniqueFileName_: Don't confuse existing numbers" {
touch "test-2.txt"
run _uniqueFileName_ "test-2.txt"
assert_output --regexp ".*/test-2\.txt\.1$"
}
@test "_uniqueFileName_: User specified separator" {
touch "test.txt"
run _uniqueFileName_ "test.txt" " "
assert_output --regexp ".*/test\.txt 1$"
}
@test "_uniqueFileName_: failure" {
run _uniqueFileName_
assert_failure
}
_testBackupFile_
_testListFiles_
_testParseFilename_
_testMakeSymlink_
_testParseYAML_

79
test/fixtures/test.md vendored Normal file
View File

@@ -0,0 +1,79 @@
# About
This repository contains everything needed to bootstrap and configure new Mac computer. Included here are:
* dotfiles
* ~/bin/ scripts
* Configuration files
* Scripting templates and utilities
* `install.sh`, a script to put everything where it needs to go
**Disclaimer:** *I am not a professional programmer and I bear no responsibility whatsoever if any of these scripts wipes your computer, destroys your data, crashes your car, or otherwise causes mayhem and destruction. USE AT YOUR OWN RISK.*
## install.sh
This script runs through a series of tasks to configure a new computer. There are three distinct areas of `install.sh` which are executed in order. These are:
1. **Bootstrapping** - Installing base components such as Command Line Tools, Homebrew, Node, RVM, etc.
2. **Installation** - Symlinking dotfiles and installing executables such as NPM Packages, Homebrew Casks, etc.
3. **Configuration** - Configures installed packages and apps.
The files are organized into three subdirectories.
```
dotfiles
├── bin/
├── config/
│   ├── bash/
│   └── shell/
├── install.sh
├── install-config.yaml
├── lib/
│ ├── bootstrap/
│ └── configure/
└── scripting/
```
* **bin** - Symlinked to `~/bin` and is added to your `$PATH`.
* **config** - Contains the elements needed to configure your environment and specific apps.
* config/**bash** - Files in this directory are *sourced* by `.bash_profile`.
* config/**shell** - Files here are symlinked to your local environment. Ahem, dotfiles.
* **lib** - Contains the scripts and configuration for `install.sh`
* lib/**bootstrap** - Scripts here are executed by `install.sh` first.
* lib/**configure** - Scripts here are exectuted by `install.sh` after packages have been installed
* **config-install.yaml** - This YAML file contains the list of symlinks to be created, as well as the packages to be installed.
* **scripting** - This directory contains bash scripting utilities and templates which I re-use often.
**IMPORTANT:** Unless you want to use my defaults, make sure you do the following:
* Edit `config-install.yaml` to reflect your preferred packages
* Review the files in `config/` to configure your own aliases, preferences, etc.
#### Private Files
Sometimes there are files which contain private information. These might be API keys, local directory structures, or anything else you want to keep hidden.
Private files are held in a separate folder named `private`. This repository is added as a git-submodule and files within it are symlinked to `$HOME` or sourced to the Bash terminal.
Since you're not me, you should **fork this repository and replace the `private` directory with a git submodule of your own.**
Within the private directory you can write your own install script to configure and install your own files. This script should be named: `privateInstall.sh`
If `private/privateInstall.sh` exists, `install.sh` will invoke it.
## Cloning this repo to a new computer
The first step needed to use these dotfiles is to clone this repo into the $HOME directory. To make this easy, I created [a gist](https://gist.github.com/natelandau/b6ec165862277f3a7a4beff76da53a9c) which can easily be run with the following command:
```
curl -SL https://gist.githubusercontent.com/natelandau/b3e1dfba7491137f0a0f5e25721fffc2/raw/d98763695a0ddef1de9db2383f43149005423f20/bootstrapNewMac | bash
```
This gist creates a script `~/bootstrap.sh` in your home directory which completes the following tasks
1. Creates a new public SSH key if needed
2. Copies your public key to your clipboard
3. Opens Github to allow you to add this public key to your 'known keys'
4. Clones this dotfiles repo to your home directory
See. Easy. Now you're ready to run `~/dotfiles/install.sh` and get your new computer working.
### A Note on Code Reuse
Many of the scripts, configuration files, and other information herein were created by me over many years without ever having the intention to make them public. As a novice programmer, I have Googled, GitHubbed, and StackExchanged a path to solve my own scripting needs. Quite often I would lift a function whole-cloth from a GitHub repo and not keep track of it's original location. I have done my best within these files to recreate my footsteps and give credit to the original creators of the code when possible. Unfortunately, I fear that I missed as many as I found. My goal of making this repository public is not to take credit for the wonderful code written by others. If you recognize or wrote something here that I didn't credit, please let me know.

BIN
test/fixtures/test.md.enc vendored Normal file

Binary file not shown.

29
test/fixtures/yaml1.yaml vendored Normal file
View File

@@ -0,0 +1,29 @@
# A list of tasty fruits
fruits:
- Apple
- Orange
- Strawberry
- Mango
# An single record
employee:
name: Jimmy veloper
job: Developer
skill: Elite
# Multiple records
employees:
martin:
name: Martin D'vloper
job: Developer
skills:
- python
- perl
- pascal
tabitha:
name: Tabitha Bitumen
job: Developer
skills:
- lisp
- fortran
- erlang

17
test/fixtures/yaml1.yaml.txt vendored Normal file
View File

@@ -0,0 +1,17 @@
fruits+=("Apple")
fruits+=("Orange")
fruits+=("Strawberry")
fruits+=("Mango")
employee_name=("Jimmy veloper")
employee_job=("Developer")
employee_skill=("Elite")
employees_martin_name=("Martin D'vloper")
employees_martin_job=("Developer")
employees_martin_skills+=("python")
employees_martin_skills+=("perl")
employees_martin_skills+=("pascal")
employees_tabitha_name=("Tabitha Bitumen")
employees_tabitha_job=("Developer")
employees_tabitha_skills+=("lisp")
employees_tabitha_skills+=("fortran")
employees_tabitha_skills+=("erlang")

View File

@@ -512,7 +512,7 @@ _sourceFile_() {
[ ! -f "$c" ] \
&& {
fatal "Attempted to source '$c' Not found"
fatal "Attempted to source '$c'. Not found"
return 1
}