Merge pull request #63 from bats-core/pr/dsbibby/46

Enable extended regex in assert_file_contains
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index fa3c854..efa6be3 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -10,19 +10,29 @@
     branches: [ master ]
 
 jobs:
+  shellcheck:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout@v2
+    - run: shellcheck ./src/*
   build:
     strategy:
       matrix:
-        os: ['macos-10.15', 'ubuntu-latest']
+        os: ['macos-12', 'ubuntu-latest']
     runs-on: ${{ matrix.os }}
 
     steps:
     - uses: actions/checkout@v2
     - run: ./script/install-bats.sh
-    - run: git clone --depth 1 https://github.com/bats-core/bats-support ../bats-support
+    
+    - uses: actions/checkout@v2
+      with:
+        repository: bats-core/bats-support
+        path: bats-support
+          
     # set PATh to ensure we use bats from our local installation (looking at you Mac Runner!)
     - name: bats test
       run: |
         PATH="$HOME/.local/bin:$PATH"
         bats -v
-        bats test
\ No newline at end of file
+        BATS_LIB_PATH="$PWD" bats --print-output-on-failure test
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b4c1e46..c86d60e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,29 @@
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](http://semver.org/).
 
+## [0.4.0] - 2023-08-23
+
+### Added
+
+- add aliases for `assert_*_exist`**s** (#34, #43)
+- CI: run shellcheck, fixed found issues (#51)
+- `assert_file_contains`: print regex on error (#57)
+- add `assert_file_not_contains` (#61)
+
+### Fixed
+
+- various links and typos in README.md (#28, #26, #45)
+- migrated CI scripts to Github Actions (#42)
+- make `temp_*` functions compatible with `setup_file` (#36)
+- don't require `sudo` anymore for `assert_file_owner`/`assert_not_file_owner` (#38, #50)
+- fixed internal unset variable errors with `set -u` (#33)
+- make `temp_del` work even when contents are write protected (#31)
+- parameter documentation for `assert_file_permissions` (#47)
+- tests use `bats_load_library bats-support` (#48) 
+- fix `temp_make` template to work with Alpine's `mktemp` (#52)
+- removed `temp.bash`'s executable bit (#55)
+- use new `bats_sudo` helper to avoid running `sudo` as root/when not available (#53, 54)
+- fix `assert_symlink_to` for temp files in OSX (#56)
 
 ## [0.3.0] - 2018-10-28
 
diff --git a/README.md b/README.md
index 86c56b0..7700239 100644
--- a/README.md
+++ b/README.md
@@ -29,7 +29,7 @@
 | Test File Types | Test File Attributes | Test File Content |
 | ----------- | ----------- | ----------- |
 | _Check if a **file or directory** exists!_ <br/> - [assert_exists](#assert_exists) <br/> - [assert_not_exists](#assert_not_exists) | _Check if file is **executable**!_ <br/> - [assert_file_executable](#assert_file_executable) <br/> - [assert_file_not_executable](#assert_file_not_executable) | _Check if file is **empty**!_ <br/> - [assert_file_empty](#assert_file_empty) <br/> - [assert_file_not_empty](#assert_file_not_empty) |
-| _Check if a **file** exists!_ <br/> - [assert_file_exists](#assert_file_exists) <br/> - [assert_file_not_exists](#assert_file_not_exists) | _Check the **owner** of a file!_ <br/> - [assert_file_owner](#assert_file_owner) <br/> - [assert_file_not_owner](#assert_file_not_owner) | _Check if file **contains regex**!_ <br/>  - [assert_file_contains](#assert_file_contains) <br/> - ~~assert_file_not_contains~~ |
+| _Check if a **file** exists!_ <br/> - [assert_file_exists](#assert_file_exists) <br/> - [assert_file_not_exists](#assert_file_not_exists) | _Check the **owner** of a file!_ <br/> - [assert_file_owner](#assert_file_owner) <br/> - [assert_file_not_owner](#assert_file_not_owner) | _Check if file **contains regex**!_ <br/>  - [assert_file_contains](#assert_file_contains) <br/> - [assert_file_not_contains](#assert_file_not_contains) |
 | _Check if a **directory** exists!_ <br/> - [assert_dir_exists](#assert_dir_exists) <br/> - [assert_dir_not_exists](#assert_dir_not_exists) | _Check the **permission** of a file!_ <br/> - [assert_file_permission](#assert_file_permission) <br/> - [assert_not_file_permission](#assert_not_file_permission) | _Check if file is a **symlink to target**!_ <br/> - [assert_symlink_to](#assert_symlink_to) <br/> - [assert_not_symlink_to](#assert_not_symlink_to) |
 | _Check if a **link** exists!_ <br/> - [assert_link_exists](#assert_link_exists) <br/> - [assert_link_not_exists](#assert_link_not_exists) | _Check the **size** of a file **by bytes**!_ <br/> - [assert_file_size_equals](#assert_file_size_equals) |
 | _Check if a **block special file** exists!_ <br/> - [assert_block_exists](#assert_block_exists) <br/> - [assert_block_not_exists](#assert_block_not_exists) | _Check if a file have **zero bytes**!_ <br/> - [assert_size_zero](#assert_size_zero) <br/> - [assert_size_not_zero](#assert_size_not_zero) |
@@ -750,6 +750,19 @@
 
 ---
 
+### `assert_file_not_contains`
+Fail if the given file contains the regex or if the file does not exist.
+```bash
+@test 'assert_file_not_contains() {
+    assert_file_not_contains /path/to/non-empty-file regex
+}
+```
+On failure, the path and regex are displayed.
+
+[Back to index](#Index-of-all-functions)
+
+---
+
 ### `assert_symlink_to`
 Fail if the given file is not a symbolic to a defined target.
 ```bash
diff --git a/src/file.bash b/src/file.bash
index ca3afc3..a75ef6d 100644
--- a/src/file.bash
+++ b/src/file.bash
@@ -258,7 +258,7 @@
 assert_files_equal() {
   local -r file1="$1"
   local -r file2="$2"
-  if ! `cmp -s "$file1" "$file2"` ; then
+  if ! cmp -s "$file1" "$file2" >/dev/null ; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${file1/$rem/$add}" 'path' "${file2/$rem/$add}" \
@@ -267,6 +267,21 @@
   fi
 }
 
+# Get the owner of a file
+# Arguments:
+# $1 - output variable name
+# $2 - path to file
+_bats_get_file_owner() {
+  local -r output_var=$1
+  local -r file=$2
+  if [[ "$OSTYPE" == darwin* ]]; then
+      local -ra cmd_params=(-f %Su)
+  else
+      local -ra cmd_params=(-c %U)
+  fi
+  printf -v "$output_var" "%s" "$(stat "${cmd_params[@]}" "$file")"
+}
+
 # Fail and display path of the user is not the owner of a file. This
 # function is the logical complement of `assert_file_not_owner'.
 #
@@ -283,14 +298,12 @@
 assert_file_owner() {
   local -r owner="$1"
   local -r file="$2"
-  if [[ "$(uname)" == "Darwin" ]]; then
-    __cmd_param="-f %Su"
-  elif [[ "$(uname)" == "Linux" ]]; then
-    __cmd_param="-c %U"
-  fi
-  __o=$(stat $__cmd_param "$file")
+  
+  local actual_owner
+  _bats_get_file_owner actual_owner "$file"
+  readonly actual_owner
 
-  if [[ "$__o" != "$owner" ]]; then
+  if [[ "$actual_owner" != "$owner" ]]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
@@ -306,7 +319,8 @@
 #   BATSLIB_FILE_PATH_REM
 #   BATSLIB_FILE_PATH_ADD
 # Arguments:
-#   $1 - path
+#   $1 - permission
+#   $2 - path
 # Returns:
 #   0 - file has given permissions
 #   1 - otherwise
@@ -315,24 +329,20 @@
 assert_file_permission() {
   local -r permission="$1"
   local -r file="$2"
-  if [[ `uname` == "Darwin" ]]; then
-  if [ `stat -f '%A' "$file"` -ne "$permission" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "file does not have permissions $permission" \
-      | fail
-  fi
-  elif [[ `uname` == "Linux" ]]; then
-  if [ `stat -c "%a" "$file"` -ne "$permission" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "file does not have permissions $permission" \
-      | fail
+
+  if [[ "$OSTYPE" == darwin* ]]; then
+      local -r actual_permission=$(stat -f '%A' "$file")
+  else
+      local -r actual_permission=$(stat -c "%a" "$file")
   fi
 
-fi
+  if [[ "$actual_permission" != "$permission" ]]; then
+    local -r rem="${BATSLIB_FILE_PATH_REM-}"
+    local -r add="${BATSLIB_FILE_PATH_ADD-}"
+    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
+      | batslib_decorate "file does not have permissions $permission" \
+      | fail
+  fi
 }
 
 # Fail if file is not zero byte. This
@@ -350,25 +360,14 @@
 #   STDERR - details, on failure
 assert_size_zero() {
   local -r file="$1"
-    if [[ `uname` == "Darwin" ]]; then
-    mkfile 2k ${TEST_FIXTURE_ROOT}/dir/notzerobyte
-    if [ -s "$file" ]; then
+
+  if [ -s "$file" ]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
       | batslib_decorate 'file is greater than 0 byte' \
       | fail
   fi
-    elif [[ `uname` == "Linux" ]]; then
-    fallocate -l 2k ${TEST_FIXTURE_ROOT}/dir/notzerobyte
-    if [ -s "$file" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate 'file is greater than 0 byte' \
-      | fail
-  fi
-fi
 }
 
 # Fail if group if is not set on file. This
@@ -443,6 +442,24 @@
   fi
 }
 
+_bats_file_readlinkf_macos() {
+  local TARGET_FILE=$1
+  cd "$(dirname "$TARGET_FILE")" 2>/dev/null || return
+  TARGET_FILE=$(basename "$TARGET_FILE")
+  # Iterate down a (possible) chain of symlinks
+  while [ -L "$TARGET_FILE" ]
+  do
+    TARGET_FILE=$(readlink "$TARGET_FILE")
+    cd "$(dirname "$TARGET_FILE")" 2>/dev/null || return
+    TARGET_FILE=$(basename "$TARGET_FILE")
+  done
+  # Compute the canonicalized name by finding the physical path
+  # for the directory we're in and appending the target file.
+  local -r PHYS_DIR=$(pwd -P)
+
+  printf "%s/%s\n" "$PHYS_DIR" "$TARGET_FILE"
+}
+
 # Fail and display path of the file (or directory) if it is not a symlink to given destination.
 # function is the logical complement of `assert_not_symlink_to`
 #   $1 - source
@@ -455,58 +472,30 @@
 assert_symlink_to() {
   local -r sourcefile="$1"
   local -r link="$2"
-  # If OS is linux
-  if [[ `uname` == "Linux" ]]; then
-    if [ ! -L $link   ]; then
-      local -r rem="${BATSLIB_FILE_PATH_REM-}"
-      local -r add="${BATSLIB_FILE_PATH_ADD-}"
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
-        | batslib_decorate 'file is not a symbolic link' \
-        | fail
-    fi
-    local -r realsource=$( readlink -f "$link" )
-    if [ ! "$realsource" = "$sourcefile"  ]; then
-      local -r rem="${BATSLIB_FILE_PATH_REM-}"
-      local -r add="${BATSLIB_FILE_PATH_ADD-}"
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
-        | batslib_decorate 'symbolic link does not have the correct target' \
-        | fail
-    fi
-  # If OS is OSX
-  elif [[ `uname` == "Darwin" ]]; then
-    function readlinkf() {
-    TARGET_FILE=$1
-    cd `dirname $TARGET_FILE`
-    TARGET_FILE=`basename $TARGET_FILE`
-    # Iterate down a (possible) chain of symlinks
-    while [ -L "$TARGET_FILE" ]
-    do
-      TARGET_FILE=`readlink $TARGET_FILE`
-      cd `dirname $TARGET_FILE`
-      TARGET_FILE=`basename $TARGET_FILE`
-    done
-    # Compute the canonicalized name by finding the physical path
-    # for the directory we're in and appending the target file.
-    PHYS_DIR=`pwd -P`
-    RESULT=$PHYS_DIR/$TARGET_FILE
-    echo $RESULT
-  }
 
-  if [ ! -L $link   ]; then
+  # If OS is OSX, emulate readlink -f
+  if [[ $OSTYPE == "darwin"* ]]; then
+    local -ra readlink_command=(_bats_file_readlinkf_macos)
+  else
+    local -ra readlink_command=(readlink -f)
+  fi
+  
+  if [ ! -L "$link"   ]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
       | batslib_decorate 'file is not a symbolic link' \
       | fail
-    fi
-    local -r realsource=$( readlinkf "$link" )
-    if [ ! "$realsource" = "$sourcefile"  ]; then
-      local -r rem="${BATSLIB_FILE_PATH_REM-}"
-      local -r add="${BATSLIB_FILE_PATH_ADD-}"
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
+  fi
+
+  local realsource; realsource=$( "${readlink_command[@]}" "$link" ); readonly realsource
+  local realexpectedsource; realexpectedsource=$( "${readlink_command[@]}" "$sourcefile" ); readonly realexpectedsource
+  if [ ! "${realsource}" = "${realexpectedsource}"  ]; then
+    local -r rem="${BATSLIB_FILE_PATH_REM-}"
+    local -r add="${BATSLIB_FILE_PATH_ADD-}"
+    batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
       | batslib_decorate 'symbolic link does not have the correct target' \
       | fail
-    fi
   fi
 }
 # Fail and display path of the file (or directory) if it does not match a size.
@@ -569,11 +558,45 @@
   if ! "$cmd" -q "$regex" "$file"; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
+    batslib_print_kv_single 4 'path' "${file/$rem/$add}" 'regex' "$regex" \
       | batslib_decorate 'file does not contain regex' \
       | fail
   fi
 }
+# Fail and display path of the file (or directory) if it does contain a string.
+# This function is the logical complement of `assert_file_contains'.
+#
+# Globals:
+#   BATSLIB_FILE_PATH_REM
+#   BATSLIB_FILE_PATH_ADD
+# Arguments:
+#   $1 - path
+#   $2 - regex
+# Returns:
+#   0 - file does not contain regex
+#   1 - otherwise
+# Outputs:
+#   STDERR - details, on failure
+assert_file_not_contains() {
+  local -r file="$1"
+  local -r regex="$2"
+
+  if [[ ! -f "$file" ]]; then
+    local -r rem="${BATSLIB_FILE_PATH_REM-}"
+    local -r add="${BATSLIB_FILE_PATH_ADD-}"
+    batslib_print_kv_single 4 'path' "${file/$rem/$add}" 'regex' "$regex" \
+      | batslib_decorate 'file does not exist' \
+      | fail
+  
+  elif grep -q "$regex" "$file"; then
+    local -r rem="${BATSLIB_FILE_PATH_REM-}"
+    local -r add="${BATSLIB_FILE_PATH_ADD-}"
+    batslib_print_kv_single 4 'path' "${file/$rem/$add}" 'regex' "$regex" \
+      | batslib_decorate 'file contains regex' \
+      | fail
+
+  fi
+}
 # Fail and display path of the file (or directory) if it is not empty.
 # This function is the logical complement of `assert_file_not_empty'.
 #
@@ -595,7 +618,7 @@
     { local -ir width=8
       batslib_print_kv_single "$width" 'path' "${file/$rem/$add}"
       batslib_print_kv_single_or_multi "$width" \
-          'output' "$(cat $file)"
+          'output' "$(cat "$file")"
     } | batslib_decorate 'file is not empty' \
       | fail
   fi
@@ -830,29 +853,20 @@
 # Outputs:
 #   STDERR - details, on failure
 assert_not_file_owner() {
-  local -r owner="$1"
+  local -r expected_owner="$1"
   local -r file="$2"
-  if [[ `uname` == "Darwin" ]]; then
-  sudo chown root ${TEST_FIXTURE_ROOT}/dir/owner
-  sudo chown daemon ${TEST_FIXTURE_ROOT}/dir/notowner
-  if [ `stat -f '%Su' "$file"` = "$owner" ]; then
+
+  local actual_owner
+  _bats_get_file_owner actual_owner "$file"
+  readonly actual_owner
+
+  if [[ "$actual_owner" == "$expected_owner" ]]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "given user is the $owner, but it was expected not to be" \
+      | batslib_decorate "user $expected_owner is the owner of the file, but it was expected not to be" \
       | fail
   fi
-  elif [[ `uname` == "Linux" ]]; then
-  sudo chown root ${TEST_FIXTURE_ROOT}/dir/owner
-  sudo chown daemon ${TEST_FIXTURE_ROOT}/dir/notowner
-    if [ `stat -c "%U" "$file"` = "$owner" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "given user is the $owner, but it was expected not to be" \
-      | fail
-  fi
-fi
 }
 
 # Fail if the file has given permissions. This
@@ -871,24 +885,20 @@
 assert_not_file_permission() {
   local -r permission="$1"
   local -r file="$2"
-  if [[ `uname` == "Darwin" ]]; then
-    if [ `stat -f '%A' "$file"` -eq "$permission" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "file has permissions $permission, but it was expected not to have" \
-      | fail
-  fi
-  elif [[ `uname` == "Linux" ]]; then
-        if [ `stat -c "%a" "$file"` -eq "$permission" ]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate "file has permissions $permission, but it was expected not to have" \
-      | fail
-    fi
+
+  if [[ "$OSTYPE" == darwin* ]]; then
+      local -r actual_permission=$(stat -f '%A' "$file")
+  else
+      local -r actual_permission=$(stat -c "%a" "$file")
   fi
 
+  if [ "$actual_permission" -eq "$permission" ]; then
+    local -r rem="${BATSLIB_FILE_PATH_REM-}"
+    local -r add="${BATSLIB_FILE_PATH_ADD-}"
+    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
+      | batslib_decorate "file has permissions $permission, but it was expected not to have" \
+      | fail
+  fi
 }
 
 # This function is the logical complement of `assert_files_equal'.
@@ -902,7 +912,7 @@
 assert_files_not_equal() {
   local -r file1="$1"
   local -r file2="$2"
-  if `cmp -s "$file1" "$file2"` ; then
+  if cmp -s "$file1" "$file2" >/dev/null ; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${file1/$rem/$add}" 'path' "${file2/$rem/$add}" \
@@ -926,8 +936,6 @@
 #   STDERR - details, on failure
 assert_size_not_zero() {
   local -r file="$1"
-  if [[ `uname` == "Darwin" ]]; then
-  mkfile 2k ${TEST_FIXTURE_ROOT}/dir/notzerobyte
   if [[ ! -s "$file" ]]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
@@ -935,16 +943,6 @@
       | batslib_decorate 'file is 0 byte, but it was expected not to be' \
       | fail
   fi
-  elif [[ `uname` == "Linux" ]]; then
-  fallocate -l 2k ${TEST_FIXTURE_ROOT}/dir/notzerobyte
-  if [[ ! -s "$file" ]]; then
-    local -r rem="${BATSLIB_FILE_PATH_REM-}"
-    local -r add="${BATSLIB_FILE_PATH_ADD-}"
-    batslib_print_kv_single 4 'path' "${file/$rem/$add}" \
-      | batslib_decorate 'file is 0 byte, but it was expected not to be' \
-      | fail
-  fi
-fi
 }
 
 
@@ -1033,54 +1031,27 @@
 assert_not_symlink_to() {
   local -r sourcefile="$1"
   local -r link="$2"
-  # If OS is linux
-  if [[ `uname` == "Linux" ]]; then
-    if [ -L $link   ]; then
-      local -r rem="${BATSLIB_FILE_PATH_REM-}"
-      local -r add="${BATSLIB_FILE_PATH_ADD-}"
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
-        | batslib_decorate 'file is a symbolic link' \
-        | fail
-    fi
-    local -r realsource=$( readlink -f "$link" )
-    if [ "$realsource" = "$sourcefile"  ]; then
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
-        | batslib_decorate 'symbolic link does have the correct target' \
-        | fail
-    fi
-  # If OS is OSX
-  elif [[ `uname` == "Darwin" ]]; then
-  function readlinkf() {
-    TARGET_FILE=$1
-    cd `dirname $TARGET_FILE`
-    TARGET_FILE=`basename $TARGET_FILE`
-    # Iterate down a (possible) chain of symlinks
-    while [ -L "$TARGET_FILE" ]
-    do
-      TARGET_FILE=`readlink $TARGET_FILE`
-      cd `dirname $TARGET_FILE`
-      TARGET_FILE=`basename $TARGET_FILE`
-    done
-    # Compute the canonicalized name by finding the physical path
-    # for the directory we're in and appending the target file.
-    PHYS_DIR=`pwd -P`
-    RESULT=$PHYS_DIR/$TARGET_FILE
-    echo $RESULT
-  }
-
-  if [ -L $link   ]; then
+  
+  
+  if [[ $OSTYPE == darwin* ]]; then
+    local -ra readlink_command=(_bats_file_readlinkf_macos)
+  else
+    local -ra readlink_command=(readlink -f)
+  fi
+  
+  if [ -L "$link"   ]; then
     local -r rem="${BATSLIB_FILE_PATH_REM-}"
     local -r add="${BATSLIB_FILE_PATH_ADD-}"
     batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
       | batslib_decorate 'file is a symbolic link' \
       | fail
-    fi
-    local -r realsource=$( readlinkf "$link" )
-    if [ "$realsource" = "$sourcefile"  ]; then
-      batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
-        | batslib_decorate 'symbolic link does have the correct target' \
-        | fail
-    fi
+  fi
+
+  local -r realsource=$( "${readlink_command[@]}" "$link" )
+  if [ "$realsource" = "$sourcefile"  ]; then
+    batslib_print_kv_single 4 'path' "${link/$rem/$add}" \
+      | batslib_decorate 'symbolic link does have the correct target' \
+      | fail
   fi
 }
 # Fail and display path of the file (or directory) if it is empty. This
diff --git a/src/temp.bash b/src/temp.bash
old mode 100755
new mode 100644
index db0daaa..d4d06ea
--- a/src/temp.bash
+++ b/src/temp.bash
@@ -98,11 +98,10 @@
   local template="$prefix"
   template+="${BATS_TEST_FILENAME##*/}"
   template+="-${BATS_TEST_NUMBER}"
-  template+='-XXXXXXXXXX'
+  template+='-XXXXXX'
 
   local path
-  path="$(mktemp -d  --  "${BATS_TMPDIR}/${template}" 2>&1)"
-  if (( $? )); then
+  if ! path="$(mktemp -d  --  "${BATS_TMPDIR}/${template}" 2>&1)"; then
     echo "$path" \
       | batslib_decorate 'ERROR: temp_make' \
       | fail
@@ -172,8 +171,7 @@
 
   # Delete directory.
   local result
-  result="$(rm -r -- "$path" 2>&1 </dev/null)"
-  if (( $? )); then
+  if ! result="$(rm -r -- "$path" 2>&1 >/dev/null )"; then
     echo "$result" \
       | batslib_decorate 'ERROR: temp_del' \
       | fail
diff --git a/test/54-assert-10-assert_character_exists.bats b/test/54-assert-10-assert_character_exists.bats
index e613ba9..c92a1a3 100644
--- a/test/54-assert-10-assert_character_exists.bats
+++ b/test/54-assert-10-assert_character_exists.bats
@@ -4,7 +4,7 @@
 fixtures 'exist'
 
 setup () {
- sudo mknod ${TEST_FIXTURE_ROOT}/dir/test_device c 89 1
+  bats_sudo mknod ${TEST_FIXTURE_ROOT}/dir/test_device c 89 1
 }
 teardown () {
     rm -f ${TEST_FIXTURE_ROOT}/dir/test_device
diff --git a/test/54-assert-11-assert_character_not_exists.bats b/test/54-assert-11-assert_character_not_exists.bats
index b75e703..6586a7f 100644
--- a/test/54-assert-11-assert_character_not_exists.bats
+++ b/test/54-assert-11-assert_character_not_exists.bats
@@ -4,7 +4,7 @@
 fixtures 'exist'
 
 setup () {
- sudo mknod ${TEST_FIXTURE_ROOT}/dir/test_device c 89 1
+  bats_sudo mknod ${TEST_FIXTURE_ROOT}/dir/test_device c 89 1
 }
 teardown () {
     rm -f ${TEST_FIXTURE_ROOT}/dir/test_device
diff --git a/test/55-assert-10-assert_block_exists.bats b/test/55-assert-10-assert_block_exists.bats
index d3e8357..2211a3b 100644
--- a/test/55-assert-10-assert_block_exists.bats
+++ b/test/55-assert-10-assert_block_exists.bats
@@ -3,7 +3,7 @@
 fixtures 'exist'
 
 setup () {
- sudo mknod ${TEST_FIXTURE_ROOT}/dir/blockfile b 89 1
+  bats_sudo mknod ${TEST_FIXTURE_ROOT}/dir/blockfile b 89 1
 }
 teardown () {
     rm -f ${TEST_FIXTURE_ROOT}/dir/blockfile
@@ -59,4 +59,4 @@
   [ "${lines[0]}" == '-- block special file does not exist --' ]
   [ "${lines[1]}" == "path : ${TEST_FIXTURE_ROOT}/.." ]
   [ "${lines[2]}" == '--' ]
-}
\ No newline at end of file
+}
diff --git a/test/55-assert-11-assert_block_not_exists.bats b/test/55-assert-11-assert_block_not_exists.bats
index d469f1a..9bff904 100644
--- a/test/55-assert-11-assert_block_not_exists.bats
+++ b/test/55-assert-11-assert_block_not_exists.bats
@@ -4,7 +4,7 @@
 fixtures 'exist'
 
 setup () {
- sudo mknod ${TEST_FIXTURE_ROOT}/dir/blockfile b 89 1
+  bats_sudo mknod ${TEST_FIXTURE_ROOT}/dir/blockfile b 89 1
 }
 teardown () {
     rm -f ${TEST_FIXTURE_ROOT}/dir/blockfile
diff --git a/test/58-assert-10-assert_equal_files.bats b/test/58-assert-10-assert_equal_files.bats
index 42b57cb..b391122 100644
--- a/test/58-assert-10-assert_equal_files.bats
+++ b/test/58-assert-10-assert_equal_files.bats
@@ -40,7 +40,8 @@
   run assert_files_equal "$file1" "$file2"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 5 ]
-  [ "${lines[0]}" == "cmp: ${TEST_FIXTURE_ROOT}/dir: Is a directory" ]
+  REGEX="cmp: ${TEST_FIXTURE_ROOT}/dir: (Is a directory|I/O error)"
+  [[ "${lines[0]}" =~ $REGEX ]] || false
   [ "${lines[1]}" == "-- files are not the same --" ]
   [ "${lines[2]}" == "path : $file1" ]
   [ "${lines[3]}" == "path : $file2" ]
diff --git a/test/58-assert-11-assert_not_equal_files.bats b/test/58-assert-11-assert_not_equal_files.bats
index cb758d9..f7e719f 100644
--- a/test/58-assert-11-assert_not_equal_files.bats
+++ b/test/58-assert-11-assert_not_equal_files.bats
@@ -39,7 +39,8 @@
   run assert_files_not_equal "$file1" "$file2"
   [ "$status" -eq 0 ]
   [ "${#lines[@]}" -eq 1 ]
-  [ "${lines[0]}" == "cmp: ${TEST_FIXTURE_ROOT}/dir: Is a directory" ]
+  REGEX="cmp: ${TEST_FIXTURE_ROOT}/dir: (Is a directory|I/O error)"
+  [[ "${lines[0]}" =~ $REGEX ]] || false
 }
 
 @test 'assert_files_not_equal() <file>: replace prefix of displayed path' {
diff --git a/test/59-assert-10-assert_file_owner.bats b/test/59-assert-10-assert_file_owner.bats
index ec24089..f1a2f35 100644
--- a/test/59-assert-10-assert_file_owner.bats
+++ b/test/59-assert-10-assert_file_owner.bats
@@ -5,27 +5,15 @@
 
 setup () {
   touch ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
-  sudo_path=$(command -v sudo 2>/dev/null)
   # There is PATH addition to /usr/sbin which won't come by default on bash3
   # on macOS
   chown_path=$(PATH="$PATH:/usr/sbin" command -v chown 2>/dev/null)
-  if [[ "$(whoami)" != 'root' ]] && [ -x "$sudo_path" ]; then
-    __cmd="$sudo_path $chown_path"
-  else
-    __cmd="$chown_path"
-  fi
-  $__cmd root ${TEST_FIXTURE_ROOT}/dir/owner
-  $__cmd daemon ${TEST_FIXTURE_ROOT}/dir/notowner
+  bats_sudo "$chown_path" root ${TEST_FIXTURE_ROOT}/dir/owner
+  bats_sudo "$chown_path" daemon ${TEST_FIXTURE_ROOT}/dir/notowner
 }
 
 teardown () {
-  sudo_path=$(command -v sudo 2>/dev/null)
-  if [[ "$(whoami)" != 'root' ]] && [ -x "$sudo_path" ]; then
-    __cmd="$sudo_path rm -f"
-  else
-    __cmd="rm -f"
-  fi
-  $__cmd ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
+  bats_sudo rm -f ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
 }
 
 # Correctness
diff --git a/test/59-assert-11-assert_not_file_owner.bats b/test/59-assert-11-assert_not_file_owner.bats
index c80480e..5518941 100644
--- a/test/59-assert-11-assert_not_file_owner.bats
+++ b/test/59-assert-11-assert_not_file_owner.bats
@@ -5,27 +5,15 @@
 
 setup () {
   touch ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
-  sudo_path=$(command -v sudo 2>/dev/null)
   # There is PATH addition to /usr/sbin which won't come by default on bash3
   # on macOS
   chown_path=$(PATH="$PATH:/usr/sbin" command -v chown 2>/dev/null)
-  if [[ "$(whoami)" != 'root' ]] && [ -x "$sudo_path" ]; then
-    __cmd="$sudo_path $chown_path"
-  else
-    __cmd="$chown_path"
-  fi
-  $__cmd root ${TEST_FIXTURE_ROOT}/dir/owner
-  $__cmd daemon ${TEST_FIXTURE_ROOT}/dir/notowner
+  bats_sudo "$chown_path" root ${TEST_FIXTURE_ROOT}/dir/owner
+  bats_sudo "$chown_path" daemon ${TEST_FIXTURE_ROOT}/dir/notowner
 }
 
 teardown () {
-  sudo_path=$(command -v sudo 2>/dev/null)
-  if [[ "$(whoami)" != 'root' ]] && [ -x "$sudo_path" ]; then
-    __cmd="$sudo_path rm -f"
-  else
-    __cmd="rm -f"
-  fi
-  $__cmd ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
+  bats_sudo rm -f ${TEST_FIXTURE_ROOT}/dir/owner ${TEST_FIXTURE_ROOT}/dir/notowner
 }
 
 # Correctness
@@ -37,13 +25,13 @@
   [ "${#lines[@]}" -eq 0 ]
 }
 
-@test 'assert_not_file_owner() <file>: returns 1 and displays path if <file> given user is the root, but it was expected not to be' {
+@test 'assert_not_file_owner() <file>: returns 1 and displays path if <file> user root is the owner of the file, but it was expected not to be' {
   local -r owner="root"
   local -r file="${TEST_FIXTURE_ROOT}/dir/owner"
   run assert_not_file_owner "$owner" "$file"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
-  [ "${lines[0]}" == '-- given user is the root, but it was expected not to be --' ]
+  [ "${lines[0]}" == '-- user root is the owner of the file, but it was expected not to be --' ]
   [ "${lines[1]}" == "path : $file" ]
   [ "${lines[2]}" == '--' ]
 }
@@ -58,7 +46,7 @@
   run assert_not_file_owner "$owner" "$file"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
-  [ "${lines[0]}" == '-- given user is the root, but it was expected not to be --' ]
+  [ "${lines[0]}" == '-- user root is the owner of the file, but it was expected not to be --' ]
   [ "${lines[1]}" == "path : ../dir/owner" ]
   [ "${lines[2]}" == '--' ]
 }
@@ -71,7 +59,7 @@
   run assert_not_file_owner "$owner" "$file"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
-  [ "${lines[0]}" == '-- given user is the root, but it was expected not to be --' ]
+  [ "${lines[0]}" == '-- user root is the owner of the file, but it was expected not to be --' ]
   [ "${lines[1]}" == "path : ${TEST_FIXTURE_ROOT}/.." ]
   [ "${lines[2]}" == '--' ]
 }
@@ -84,7 +72,7 @@
   run assert_not_file_owner "$owner" "$file"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
-  [ "${lines[0]}" == '-- given user is the root, but it was expected not to be --' ]
+  [ "${lines[0]}" == '-- user root is the owner of the file, but it was expected not to be --' ]
   [ "${lines[1]}" == "path : ${TEST_FIXTURE_ROOT}/.." ]
   [ "${lines[2]}" == '--' ]
 }
diff --git a/test/60-assert-10-assert_file_permission.bats b/test/60-assert-10-assert_file_permission.bats
index cecafb9..020a362 100644
--- a/test/60-assert-10-assert_file_permission.bats
+++ b/test/60-assert-10-assert_file_permission.bats
@@ -5,10 +5,9 @@
 
 setup () {
   touch ${TEST_FIXTURE_ROOT}/dir/permission
-  sudo chmod 777 ${TEST_FIXTURE_ROOT}/dir/permission
+  chmod 777 ${TEST_FIXTURE_ROOT}/dir/permission
 }
 teardown () {
-  
   rm -f ${TEST_FIXTURE_ROOT}/dir/permission
 }
 
diff --git a/test/60-assert-11-assert_file_no_permissions.bats b/test/60-assert-11-assert_file_no_permissions.bats
index 58435b4..fea656a 100644
--- a/test/60-assert-11-assert_file_no_permissions.bats
+++ b/test/60-assert-11-assert_file_no_permissions.bats
@@ -5,11 +5,10 @@
 
 setup () {
   touch ${TEST_FIXTURE_ROOT}/dir/permission ${TEST_FIXTURE_ROOT}/dir/nopermission
-  sudo chmod 777 ${TEST_FIXTURE_ROOT}/dir/permission 
-  sudo chmod 644 ${TEST_FIXTURE_ROOT}/dir/nopermission
+  chmod 777 ${TEST_FIXTURE_ROOT}/dir/permission
+  chmod 644 ${TEST_FIXTURE_ROOT}/dir/nopermission
 }
 teardown () {
-  
   rm -f ${TEST_FIXTURE_ROOT}/dir/permission ${TEST_FIXTURE_ROOT}/dir/nopermission
 }
 
diff --git a/test/61-assert-10-size_zero.bats b/test/61-assert-10-size_zero.bats
index e2047f0..5a11e6d 100644
--- a/test/61-assert-10-size_zero.bats
+++ b/test/61-assert-10-size_zero.bats
@@ -4,7 +4,11 @@
 fixtures 'exist'
 
 setup () {
-  touch ${TEST_FIXTURE_ROOT}/dir/zerobyte  
+  readonly ZERO_FILE=${TEST_FIXTURE_ROOT}/dir/zerobyte  
+  touch "$ZERO_FILE"
+
+  readonly NOTZERO_FILE="${TEST_FIXTURE_ROOT}/dir/notzerobyte"
+  echo "not empty" > "$NOTZERO_FILE"
 } 
 
 teardown () {  
@@ -14,19 +18,17 @@
 
 # Correctness
 @test 'assert_size_zero() <file>: returns 0 if <file> file is 0 byte' {
-  local -r file="${TEST_FIXTURE_ROOT}/dir/zerobyte"
-  run assert_size_zero "$file"
+  run assert_size_zero "$ZERO_FILE"
   [ "$status" -eq 0 ]
   [ "${#lines[@]}" -eq 0 ]
 }
 
 @test 'assert_size_zero() <file>: returns 1 and displays path if <file> file is greater than 0 byte' {
-  local -r file="${TEST_FIXTURE_ROOT}/dir/notzerobyte"
-  run assert_size_zero "$file"
+  run assert_size_zero "$NOTZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is greater than 0 byte --' ]
-  [ "${lines[1]}" == "path : $file" ]
+  [ "${lines[1]}" == "path : $NOTZERO_FILE" ]
   [ "${lines[2]}" == '--' ]
 }
 
@@ -36,7 +38,7 @@
 @test 'assert_size_zero() <file>: replace prefix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM="#${TEST_FIXTURE_ROOT}"
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_zero "${TEST_FIXTURE_ROOT}/dir/notzerobyte"
+  run assert_size_zero "$NOTZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is greater than 0 byte --' ]
@@ -47,7 +49,7 @@
 @test 'assert_size_zero() <file>: replace suffix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM='%dir/notzerobyte'
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_zero "${TEST_FIXTURE_ROOT}/dir/notzerobyte"
+  run assert_size_zero "$NOTZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is greater than 0 byte --' ]
@@ -58,7 +60,7 @@
 @test 'assert_size_zero() <file>: replace infix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM='dir/notzerobyte'
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_zero "${TEST_FIXTURE_ROOT}/dir/notzerobyte"
+  run assert_size_zero "$NOTZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is greater than 0 byte --' ]
diff --git a/test/61-assert-11-size_not_zero.bats b/test/61-assert-11-size_not_zero.bats
index bd80a61..70be0af 100644
--- a/test/61-assert-11-size_not_zero.bats
+++ b/test/61-assert-11-size_not_zero.bats
@@ -4,29 +4,30 @@
 fixtures 'exist'
 
 setup () {
-  touch ${TEST_FIXTURE_ROOT}/dir/zerobyte 
+  readonly ZERO_FILE="${TEST_FIXTURE_ROOT}/dir/zerobyte"
+  touch "$ZERO_FILE"
+  readonly NOTZERO_FILE="${TEST_FIXTURE_ROOT}/dir/notzerobyte"
+  echo "not empty" > "$NOTZERO_FILE"
 }
 
 teardown () {  
-  rm -f ${TEST_FIXTURE_ROOT}/dir/zerobyte ${TEST_FIXTURE_ROOT}/dir/notzerobyte
+  rm -f "$ZERO_FILE" "$NOTZERO_FILE"
 }
 
 
 # Correctness
 @test 'assert_size_not_zero() <file>: returns 0 if <file> file is greater than 0 byte' {
-  local -r file="${TEST_FIXTURE_ROOT}/dir/notzerobyte"
-  run assert_size_not_zero "$file"
+  run assert_size_not_zero "$NOTZERO_FILE"
   [ "$status" -eq 0 ]
   [ "${#lines[@]}" -eq 0 ]
 }
 
 @test 'assert_size_not_zero() <file>: returns 1 and displays path if <file> file is 0 byte, but it was expected not to be' {
-  local -r file="${TEST_FIXTURE_ROOT}/dir/zerobyte"
-  run assert_size_not_zero "$file"
+  run assert_size_not_zero "$ZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is 0 byte, but it was expected not to be --' ]
-  [ "${lines[1]}" == "path : $file" ]
+  [ "${lines[1]}" == "path : $ZERO_FILE" ]
   [ "${lines[2]}" == '--' ]
 }
 
@@ -35,7 +36,7 @@
 @test 'assert_size_not_zero() <file>: replace prefix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM="#${TEST_FIXTURE_ROOT}"
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_not_zero "${TEST_FIXTURE_ROOT}/dir/zerobyte"
+  run assert_size_not_zero "$ZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is 0 byte, but it was expected not to be --' ]
@@ -46,7 +47,7 @@
 @test 'assert_size_not_zero() <file>: replace suffix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM='%dir/zerobyte'
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_not_zero "${TEST_FIXTURE_ROOT}/dir/zerobyte"
+  run assert_size_not_zero "$ZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is 0 byte, but it was expected not to be --' ]
@@ -57,7 +58,7 @@
 @test 'assert_size_not_zero() <file>: replace infix of displayed path' {
   local -r BATSLIB_FILE_PATH_REM='dir/zerobyte'
   local -r BATSLIB_FILE_PATH_ADD='..'
-  run assert_size_not_zero "${TEST_FIXTURE_ROOT}/dir/zerobyte"
+  run assert_size_not_zero "$ZERO_FILE"
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- file is 0 byte, but it was expected not to be --' ]
diff --git a/test/65-assert-10-assert_symlink_to.bats b/test/65-assert-10-assert_symlink_to.bats
index 592a8e8..0466ea3 100644
--- a/test/65-assert-10-assert_symlink_to.bats
+++ b/test/65-assert-10-assert_symlink_to.bats
@@ -3,29 +3,39 @@
 fixtures 'symlink'
 
 setup () {
- touch ${TEST_FIXTURE_ROOT}/file ${TEST_FIXTURE_ROOT}/notasymlink
- ln -s ${TEST_FIXTURE_ROOT}/file ${TEST_FIXTURE_ROOT}/symlink
- 
+ touch "${TEST_FIXTURE_ROOT}/file" "${TEST_FIXTURE_ROOT}/notasymlink"
+ ln -s "${TEST_FIXTURE_ROOT}/file" "${TEST_FIXTURE_ROOT}/symlink"
+ TEMP_FOLDER="$(temp_make)"
 }
 teardown () {
-    rm -f ${TEST_FIXTURE_ROOT}/file ${TEST_FIXTURE_ROOT}/notasymlink ${TEST_FIXTURE_ROOT}/symlink
+  rm -f "${TEST_FIXTURE_ROOT}/file" "${TEST_FIXTURE_ROOT}/notasymlink" "${TEST_FIXTURE_ROOT}/symlink"
+  temp_del "${TEMP_FOLDER}"
 }
 
 # Correctness
 @test 'assert_symlink_to() <file> <link>: returns 0 if <link> exists and is a symbolic link to <file>' {
   local -r file="${TEST_FIXTURE_ROOT}/file"
   local -r link="${TEST_FIXTURE_ROOT}/symlink"
-  run assert_symlink_to $file $link
-  [ "$status" -eq 0 ]
+  run assert_symlink_to "${file}" "${link}"
+  [ "${status}" -eq 0 ]
   [ "${#lines[@]}" -eq 0 ]
 }
 @test 'assert_symlink_to() <file> <link>: returns 1 and displays path if <link> is not a symbolic link to <file>' {
   local -r file="${TEST_FIXTURE_ROOT}/dir/file.does_not_exists"
   local -r link="${TEST_FIXTURE_ROOT}/symlink"
-  run assert_symlink_to $file $link
-  [ "$status" -eq 1 ]
+  run assert_symlink_to "${file}" "${link}"
+  [ "${status}" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- symbolic link does not have the correct target --' ]
-  [ "${lines[1]}" == "path : $link" ]
+  [ "${lines[1]}" == "path : ${link}" ]
   [ "${lines[2]}" == '--' ]
 }
+@test 'assert_symlink_to() <temp_file> <link>: returns 0 if <link> exists and is a symbolic link to <temp_file>' {
+  touch "${TEMP_FOLDER}/file" "${TEMP_FOLDER}/notasymlink"
+  ln -s "${TEMP_FOLDER}/file" "${TEMP_FOLDER}/symlink"
+  local -r file="${TEMP_FOLDER}/file"
+  local -r link="${TEMP_FOLDER}/symlink"
+  run assert_symlink_to "${file}" "${link}"
+  [ "${status}" -eq 0 ]
+  [ "${#lines[@]}" -eq 0 ]
+}
diff --git a/test/67-assert-10-assert_file_contains.bats b/test/67-assert-10-assert_file_contains.bats
index 338e8e2..4dfffe8 100644
--- a/test/67-assert-10-assert_file_contains.bats
+++ b/test/67-assert-10-assert_file_contains.bats
@@ -31,3 +31,16 @@
   run assert_file_contains "${TEST_FIXTURE_ROOT}/dir/non-empty-file" "XXX"
   [ "$status" -eq 1 ]
 }
+@test 'assert_file_contains() <file>: show missing regex in case of failure' {
+  local -r file="${TEST_FIXTURE_ROOT}/dir/non-empty-file"
+  run assert_file_contains "$file" "XXX"
+  [ "$status" -eq 1 ]
+  [ "${#lines[@]}" -eq 4 ]
+  [ "${lines[0]}" == '-- file does not contain regex --' ]
+  [ "${lines[1]}" == "path : $file" ]
+  [ "${lines[2]}" == "regex : XXX" ]
+  [ "${lines[3]}" == '--' ]
+}
+
+
+  
\ No newline at end of file
diff --git a/test/67-assert-10-assert_file_not_contains.bats b/test/67-assert-10-assert_file_not_contains.bats
new file mode 100644
index 0000000..e92c272
--- /dev/null
+++ b/test/67-assert-10-assert_file_not_contains.bats
@@ -0,0 +1,53 @@
+#!/usr/bin/env bats
+load 'test_helper'
+fixtures 'empty'
+# Correctness
+@test 'assert_file_not_contains() <file>: returns 0 and displays content if <file> does not match string' {
+  local -r file="${TEST_FIXTURE_ROOT}/dir/non-empty-file"
+  run assert_file_not_contains "$file" "XXX"
+  [ "$status" -eq 0 ]
+}
+@test 'assert_file_not_contains() <file>: returns 1 and displays content if <file> does match string' {
+  local -r file="${TEST_FIXTURE_ROOT}/dir/non-empty-file"
+  run assert_file_not_contains "$file" "Not empty"
+  [ "$status" -eq 1 ]
+}
+# Transforming path
+@test 'assert_file_not_contains() <file>: replace prefix of displayed path' {
+  local -r BATSLIB_FILE_PATH_REM="#${TEST_FIXTURE_ROOT}"
+  local -r BATSLIB_FILE_PATH_ADD='..'
+  run assert_file_not_contains "${TEST_FIXTURE_ROOT}/dir/non-empty-file" "Not empty"
+  [ "$status" -eq 1 ]
+}
+@test 'assert_file_not_contains() <file>: replace suffix of displayed path' {
+  local -r BATSLIB_FILE_PATH_REM='%non-empty-file'
+  local -r BATSLIB_FILE_PATH_ADD='..'
+  run assert_file_not_contains "${TEST_FIXTURE_ROOT}/dir/non-empty-file" "Not empty"
+  [ "$status" -eq 1 ]
+}
+@test 'assert_file_not_contains() <file>: replace infix of displayed path' {
+  local -r BATSLIB_FILE_PATH_REM='dir'
+  local -r BATSLIB_FILE_PATH_ADD='..'
+  run assert_file_not_contains "${TEST_FIXTURE_ROOT}/dir/non-empty-file" "Not empty"
+  [ "$status" -eq 1 ]
+}
+@test 'assert_file_not_contains() <file>: show missing regex in case of failure' {
+  local -r file="${TEST_FIXTURE_ROOT}/dir/non-empty-file"
+  run assert_file_not_contains "$file" "Not empty"
+  [ "$status" -eq 1 ]
+  [ "${#lines[@]}" -eq 4 ]
+  [ "${lines[0]}" == '-- file contains regex --' ]
+  [ "${lines[1]}" == "path : $file" ]
+  [ "${lines[2]}" == "regex : Not empty" ]
+  [ "${lines[3]}" == '--' ]
+}
+@test 'assert_file_not_contains() <file>: returns 1 and displays path if <file> does not exist' {
+  local -r file="${TEST_FIXTURE_ROOT}/missing"
+  run assert_file_not_contains "$file" "XXX"
+  [ "$status" -eq 1 ]
+  [ "${#lines[@]}" -eq 4 ]
+  [ "${lines[0]}" == '-- file does not exist --' ]
+  [ "${lines[1]}" == "path : $file" ]
+  [ "${lines[2]}" == "regex : XXX" ]
+  [ "${lines[3]}" == '--' ]
+}
diff --git a/test/70-temp-10-temp_make.bats b/test/70-temp-10-temp_make.bats
index ae535e2..36554b6 100755
--- a/test/70-temp-10-temp_make.bats
+++ b/test/70-temp-10-temp_make.bats
@@ -9,9 +9,10 @@
   teardown() { rm -r -- "$TEST_TEMP_DIR"; }
 
   TEST_TEMP_DIR="$(temp_make)"
+  echo $TEST_TEMP_DIR
 
   local -r literal="${BATS_TMPDIR}/${BATS_TEST_FILENAME##*/}-"
-  local -r pattern='[1-9][0-9]*-.{10}'
+  local -r pattern='[1-9][0-9]*-.{6}'
   [[ $TEST_TEMP_DIR =~ ^"${literal}"${pattern}$ ]] || false
   [ -e "$TEST_TEMP_DIR" ]
 }
@@ -23,7 +24,12 @@
   [ "$status" -eq 1 ]
   [ "${#lines[@]}" -eq 3 ]
   [ "${lines[0]}" == '-- ERROR: temp_make --' ]
-  [[ ${lines[1]} == 'mktemp: failed to create directory via template'* ]]
+  if [[ "$OSTYPE" == darwin* ]]; then
+    REGEX="mktemp: mkdtemp failed on $BATS_TMPDIR/.*: No such file or directory"
+  else
+    REGEX="mktemp: (failed to create directory via template|(\(null\): )?No such file or directory)"
+  fi
+  [[ ${lines[1]} =~ $REGEX ]] || false
   [ "${lines[2]}" == '--' ]
 }
 
@@ -51,10 +57,8 @@
   run bats "${TEST_FIXTURE_ROOT}/temp_make-main.bats"
 
   [ "$status" -eq 1 ]
-  [ "${#lines[@]}" -eq 9 ]
-  [ "${lines[5]}" == '# -- ERROR: temp_make --' ]
-  [ "${lines[6]}" == "# Must be called from \`setup', \`@test' or \`teardown'" ]
-  [ "${lines[7]}" == '# --' ]
+  [[ "${output}" == *'-- ERROR: temp_make --'* ]] || false
+  [[ "${output}" == *"Must be called from \`setup', \`@test' or \`teardown'"* ]] || false
 }
 
 # Options
@@ -64,7 +68,7 @@
   TEST_TEMP_DIR="$(temp_make "$@" 'test-')"
 
   local -r literal="${BATS_TMPDIR}/test-${BATS_TEST_FILENAME##*/}-"
-  local -r pattern='[1-9][0-9]*-.{10}'
+  local -r pattern='[1-9][0-9]*-.{6}'
   [[ $TEST_TEMP_DIR =~ ^"${literal}"${pattern}$ ]] || false
   [ -e "$TEST_TEMP_DIR" ]
 }
diff --git a/test/70-temp-11-temp_del.bats b/test/70-temp-11-temp_del.bats
index 0d795cb..1eb9991 100755
--- a/test/70-temp-11-temp_del.bats
+++ b/test/70-temp-11-temp_del.bats
@@ -37,7 +37,7 @@
   [ "${lines[0]}" == '-- ERROR: temp_del --' ]
   # Travis CI's Ubuntu 12.04, quotes the path with a backtick and an
   # apostrophe, instead of just apostrophes.
-  [[ ${lines[1]} =~ 'rm: cannot remove '.${path}.': No such file or directory' ]]
+  [[ ${lines[1]} == 'rm:'*"${path}"*': No such file or directory' ]] || false
   [ "${lines[2]}" == '--' ]
 }
 
@@ -122,10 +122,8 @@
   run bats "${TEST_FIXTURE_ROOT}/temp_del-main.bats"
 
   [ "$status" -eq 1 ]
-  [ "${#lines[@]}" -eq 10 ]
-  [ "${lines[6]}" == '# -- ERROR: temp_del --' ]
-  [ "${lines[7]}" == "# Must be called from \`teardown' or \`teardown_file' when using \`BATSLIB_TEMP_PRESERVE_ON_FAILURE'" ]
-  [ "${lines[8]}" == '# --' ]
+  [[ "$output" == *'-- ERROR: temp_del --'* ]] || false
+  [[ "$output" == *"Must be called from \`teardown' or \`teardown_file' when using \`BATSLIB_TEMP_PRESERVE_ON_FAILURE'"* ]] || false
 }
 
 @test "temp_del() <path>: \`BATSLIB_TEMP_PRESERVE_ON_FAILURE' does not work when called from \`setup'" {
diff --git a/test/fixtures/temp/test_helper.bash b/test/fixtures/temp/test_helper.bash
index d6e0846..b8e5ecc 100644
--- a/test/fixtures/temp/test_helper.bash
+++ b/test/fixtures/temp/test_helper.bash
@@ -2,7 +2,7 @@
 export TEST_DEPS_DIR="${TEST_DEPS_DIR-${TEST_MAIN_DIR}/..}"
 
 # Load dependencies.
-load "${TEST_DEPS_DIR}/bats-support/load.bash"
+bats_load_library "bats-support"
 
 # Load library.
 load "${TEST_MAIN_DIR}/load.bash"
diff --git a/test/test_helper.bash b/test/test_helper.bash
index 120905b..890c7ad 100644
--- a/test/test_helper.bash
+++ b/test/test_helper.bash
@@ -13,6 +13,15 @@
   TEST_RELATIVE_FIXTURE_ROOT=$(bats_trim_filename "${TEST_FIXTURE_ROOT}" TEST_RELATIVE_FIXTURE_ROOT)
 }
 
+bats_sudo() {
+  local sudo_path=$(command -v sudo 2>/dev/null)
+  if [[ "$(whoami)" != 'root' ]] && [ -x "$sudo_path" ]; then
+    "$sudo_path" "$@"
+  else
+    "$@"
+  fi
+}
+
 export TEST_MAIN_DIR="${BATS_TEST_DIRNAME}/.."
 export TEST_DEPS_DIR="${TEST_DEPS_DIR-${TEST_MAIN_DIR}/..}"
 
@@ -20,6 +29,6 @@
 set -u
 
 # Load dependencies.
-load "${TEST_DEPS_DIR}/bats-support/load.bash"
+bats_load_library 'bats-support'
 # Load library.
 load '../load'