aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormerakor <cem@ckyln.com>2021-02-04 10:11:35 +0000
committermerakor <cem@ckyln.com>2021-02-04 10:11:35 +0000
commit63c4051197cfcad2231de6eb9874055d668f47df (patch)
tree53d3b3e340570e1dda7d763a5071bafe0ad56543
parent37d93c5413b1025c8490b57edf2dea821320d2ca (diff)
parent8d5398a76eda8beec3e7458a1400b9a363afce3d (diff)
downloadcpt-63c4051197cfcad2231de6eb9874055d668f47df.tar.gz
Merge branch 'shellspec'
FossilOrigin-Name: 9f02ac446d6b0e692389a85882df0ff8b2ac54ea40c0f040c5c4dd1713456a21
-rw-r--r--.github/workflows/main.yml19
-rw-r--r--.gitignore6
-rw-r--r--.shellspec5
-rw-r--r--CHANGELOG.md5
-rwxr-xr-xcontrib/cpt-export22
-rwxr-xr-xcontrib/cpt-new6
-rw-r--r--spec/01_lib_spec.sh201
-rw-r--r--spec/02_src_spec.sh130
-rw-r--r--spec/03_contrib_spec.sh122
-rw-r--r--spec/spec_helper.sh20
l---------tests/etc/cpt-hook1
-rw-r--r--tests/hook-file3
-rwxr-xr-xtests/repository/contrib-dummy-pkg/build1
-rw-r--r--tests/repository/contrib-dummy-pkg/checksums0
-rw-r--r--tests/repository/contrib-dummy-pkg/depends1
-rw-r--r--tests/repository/contrib-dummy-pkg/sources0
-rw-r--r--tests/repository/contrib-dummy-pkg/version1
-rwxr-xr-xtests/repository/dummy-pkg/build4
-rw-r--r--tests/repository/dummy-pkg/checksums0
-rw-r--r--tests/repository/dummy-pkg/version1
20 files changed, 530 insertions, 18 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 48b29d9..add1470 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -1,13 +1,20 @@
-name: test
-
+name: main
on: [push, pull_request]
-
jobs:
build:
-
runs-on: ubuntu-latest
-
steps:
- uses: actions/checkout@v1
- - name: Run tests.
+ - name: Run do
+ run: ./tools/do
+ test:
+ runs-on: ubuntu-latest
+ needs: build
+ steps:
+ - uses: actions/checkout@v1
+ - name: Install shellspec
+ run: curl -fsSL https://git.io/shellspec | sudo sh -s -- -p /usr/local -y
+ - name: Run tests
run: ./tools/do test
+ - name: Run shellspec
+ run: shellspec
diff --git a/.gitignore b/.gitignore
index efe4341..e9c6fcb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,3 +25,9 @@ cpt-lib
### Texinfo ###
*.info
+
+### Shellspec files ###
+/.shellspec-local
+/.shellspec-quick.log
+/report/
+/coverage/
diff --git a/.shellspec b/.shellspec
new file mode 100644
index 0000000..85e0590
--- /dev/null
+++ b/.shellspec
@@ -0,0 +1,5 @@
+--require spec_helper
+
+--kcov-options "--include-pattern=cpt-lib"
+--kcov-options "--include-pattern=/src/cpt,/contrib/cpt-"
+--kcov-options "--exclude-pattern=.in"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9445f59..8669f81 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,10 +17,15 @@ UNRELEASED
### Added
- Added basic installation instructions to an `INSTALL` file.
+- Added code coverage and unit tests using `shellspec`.
### Changed
- All `src` scripts now exit with success after being called with `--help`.
- Minor optimizations on `contrib` scripts.
+- Huge speed improvement on `cpt-export`
+
+### Fixed
+- Fixed `cpt-cat` not using the `CPT_ROOT` value.
### Removed
- Removed C binaries `cpt-readlink` and `cpt-stat` and instead replaced them
diff --git a/contrib/cpt-export b/contrib/cpt-export
index 9b4edd1..d0ce36a 100755
--- a/contrib/cpt-export
+++ b/contrib/cpt-export
@@ -3,7 +3,7 @@
case "$1" in
--help|-h)
- printf '\033[1;33m-> \033[m%s\n' "usage: ${0##*/} [pkg]"
+ printf 'usage: %s [pkg]\n' "${0##*/}"
exit 0
;;
'') set -- "${PWD##*/}"
@@ -15,23 +15,27 @@ cpt-list "${1:-null}" >/dev/null
read -r ver rel 2>/dev/null < \
"$CPT_ROOT/var/db/cpt/installed/$1/version"
+# Fallback to gzip if there is a typo
+case "$CPT_COMPRESS" in bz2|gz|xz|zst) ;; *) CPT_COMPRESS=gz; esac
+
# Reset the argument list.
pkg=$1
+tarball="$PWD/$1#$ver-$rel.tar.$CPT_COMPRESS"
set --
# Construct the argument list using each file.
-while read -r file; do
- [ -d "$CPT_ROOT/$file" ] || set -- "$@" ".$file"
-done < "$CPT_ROOT/var/db/cpt/installed/$pkg/manifest"
+eval set -- "$(sed '/\/$/d;s|^|".|;s|$|"|' \
+ "$CPT_ROOT/var/db/cpt/installed/$pkg/manifest" | tr '\n' ' ')"
# Turn the list of files back into a package.
-: "${CPT_COMPRESS:=gz}"
-tar cf - -C / -- "$@" | case "$CPT_COMPRESS" in
+cd "$CPT_ROOT/"
+tar cf - -- "$@" |
+
+case "$CPT_COMPRESS" in
bz2) bzip2 -z ;;
gz) gzip -6 ;;
xz) xz -zT 0 ;;
zst) zstd -3 ;;
- *) gzip -6 ;; # Fallback to gzip
-esac > "$pkg#$ver-$rel.tar.$CPT_COMPRESS"
+esac > "$tarball"
-printf 'tarball created in %s\n' "$PWD/$pkg#$ver-$rel.tar.$CPT_COMPRESS"
+printf 'tarball created in %s\n' "$tarball"
diff --git a/contrib/cpt-new b/contrib/cpt-new
index 00b99c2..b5eac9c 100755
--- a/contrib/cpt-new
+++ b/contrib/cpt-new
@@ -1,10 +1,10 @@
#!/bin/sh -e
# Create a boilerplate CPT package
-out() { printf '\033[1;33m-> \033[m%s\n' "$@" >&2 ;}
+out() { printf '%s\n' "$@" ;}
die() { printf '\033[1;31m!> \033[m%s\n' "$@" >&2 ; exit 1 ;}
-case "$1" in ''|--help|-h) out "usage: ${0##*/} [name] [version] [source]"; exit 0; esac
+case "$1" in ''|--help|-h) out "usage: ${0##*/} [pkg] [version] [source]"; exit 0; esac
[ -d "$1" ] && die "Package '$1' already exists."
@@ -20,4 +20,4 @@ printf '%s\n' "$2 1" > "$1/version"
# Create the sources file
printf '%s\n' "$3" > "$1/sources"
-out "Package '$1' created to '$PWD/$1'"
+out "Package '${1##*/}' created to '$PWD/$1'" >&2
diff --git a/spec/01_lib_spec.sh b/spec/01_lib_spec.sh
new file mode 100644
index 0000000..6deef06
--- /dev/null
+++ b/spec/01_lib_spec.sh
@@ -0,0 +1,201 @@
+# shellcheck disable=2091
+
+Describe 'CPT Library'
+ export CPT_COLOR=0
+ Include ./src/cpt-lib
+ Describe '--help'
+ It 'prints usage information when called as a standalone script'
+ When run script src/cpt-lib --help
+ The word 1 of output should eq "usage:"
+ End
+ End
+ Describe 'version()'
+ VERSION=$(grep VERSION ./config.rc | sed 's/.* //g')
+ It 'prints version information'
+ When run script src/cpt-lib version
+ The stderr should eq "-> Carbs Packaging Tools $VERSION"
+ End
+ End
+ Describe 'text functions'
+ Describe 'out()'
+ It 'outputs a message with every argument triggering a newline'
+ When call out Line1 Line2
+ The output should eq "$(printf 'Line1\nLine2\n')"
+ End
+ End
+
+ Describe 'log()'
+ Parameters
+ "#1" "-> hello " hello
+ "#2" "-> hello world" hello world
+ "#3" "hello test world" test world hello
+ End
+ It "prints a message prettily ($1)"
+ When call log "$3" "$4" "$5"
+ The stderr should eq "$2"
+ End
+ End
+
+ Describe 'die()'
+ It "exits the script by printing the given message"
+ When run script src/cpt-lib die "Exiting"
+ The stderr should eq "!> Exiting "
+ The status should be failure
+ End
+ End
+
+ Describe 'warn()'
+ Parameters
+ "#1" "WARNING notice " "notice"
+ "#2" "WARNING package not found" "package" "not found"
+ "#3" "!!! package not found" "package" "not found" "!!!"
+ End
+ It "displays a warning message ($1)"
+ When call warn "$3" "$4" "$5"
+ The stderr should eq "$2"
+ End
+ End
+
+ Describe 'contains()'
+ Parameters
+ "#1" "foo bar" baz failure
+ "#2" "foo bar baz" baz success
+ End
+ It "checks whether the given string list contains a word ($1)"
+ When call contains "$2" "$3"
+ The status should be "$4"
+ End
+ End
+
+ Describe 'pop()'
+ It "removes the first item from the following items"
+ When call pop baz from foo bar baz
+ The output should eq " foo bar "
+ End
+ End
+
+ Describe 'regesc()'
+ Parameters
+ "#1" '^[\\test$' '\^\[\\\\test\$'
+ "#2" '\.*$' '\\\.\*\$'
+ End
+ It "escapes POSIX BRE sequences ($1)"
+ When call regesc "$2"
+ The output should eq "$3"
+ End
+ End
+
+ Describe 'sepchar()'
+ It 'seperates the output of given string'
+ When call sepchar test
+ The output should eq "$(printf 't\ne\ns\nt\n')"
+ End
+ End
+ End
+
+
+ Describe 'helper functions'
+ Describe '_seq()'
+ It 'counts to the given number'
+ When call _seq 3
+ The output should eq " 1 2 3 "
+ End
+ End
+
+ Describe '_stat()'
+ It 'outputs the owner of the given file'
+ When call _stat README
+ The output should eq "$(id -un)"
+ End
+ End
+
+ Describe '_readlinkf()'
+ mklink() { :> testfile; ln -s testfile testfile2 ;}
+ rmlink() { rm -f testfile testfile2 ;}
+ RPWD=$(cd -P .||:; printf %s "$PWD")
+ Before mklink
+ After rmlink
+ Parameters
+ "#1" . "$RPWD"
+ "#2" "$PWD/testfile2" "$RPWD/testfile"
+ End
+ It "outputs the real location of the given file ($1)"
+ When call _readlinkf "$2"
+ The output should eq "$3"
+ End
+ End
+
+ Describe 'sh256()'
+ It 'outputs an sha256 digest of the given file'
+ # This should cover our bases for a long time.
+ When call sh256 .editorconfig
+ The output should eq "da42265df733ca05a08d77405c35aa3dd5b8b7fefcc2da915f508067a49351da .editorconfig"
+ End
+ End
+ End
+
+ Describe 'system functions'
+ Describe 'as_root()'
+ as_root_env() { user=$1 as_root env ;}
+ Parameters
+ root
+ "$(id -un)"
+ End
+ It "runs the given command as user: '$1'"
+ When call as_root_env "$1"
+ The output should not eq ""
+ The stderr should not eq ""
+ The status should be success
+ End
+ End
+ End
+
+ Describe 'package functions'
+ Describe 'run_hook()'
+ CPT_HOOK=$PWD/tests/hook-file
+ CPT_ROOT=$PWD/tests
+ It "runs the given hook file"
+ When call run_hook 1 test-package destination
+ The stderr should eq "-> test-package Running 1 hook"
+ The output should eq "$CPT_HOOK 1 test-package destination"
+ End
+ It "doesn't log 'running hook' if no package is given"
+ When call run_hook 2 '' destination
+ The stderr should eq ""
+ The output should eq "$CPT_HOOK 2 null destination"
+ End
+ It "uses the /etc/cpt-hook file of the root when called with a fourth arg"
+ When call run_hook 3 cpt destdir root
+ The stderr should eq "-> cpt Running 3 hook"
+ The output should eq "$CPT_ROOT/etc/cpt-hook 3 cpt destdir"
+ The variable CPT_HOOK should eq "$PWD/tests/hook-file"
+ End
+ It "returns with success even when the file doesn't exist"
+ CPT_HOOK=$PWD/some-non-existent-file
+ When call run_hook 4 thiswillnotrun
+ The variable CPT_HOOK should not be exist
+ The stderr should eq ""
+ The status should be success
+ End
+ It "restores the \$CPT_HOOK variable when called with root"
+ CPT_ROOT=$PWD/nonexistentdir
+ When call run_hook 5 cpt dest root
+ The variable CPT_ROOT should not be exist
+ The stderr should eq ""
+ The status should be success
+ The variable CPT_HOOK should eq "$PWD/tests/hook-file"
+ End
+ End
+ Describe 'create_cache()'
+ After pkg_clean
+ It 'creates cache directories'
+ When call create_cache
+ The variable mak_dir should be a directory
+ End
+ It "doesn't create build directories if an argument is passed"
+ When call create_cache nobuild
+ The variable mak_dir should be undefined
+ End
+ End
+ End
+End
diff --git a/spec/02_src_spec.sh b/spec/02_src_spec.sh
new file mode 100644
index 0000000..c5584ec
--- /dev/null
+++ b/spec/02_src_spec.sh
@@ -0,0 +1,130 @@
+Describe 'Main toolchain'
+ export PATH=$PWD/src:$PATH
+ export CPT_ROOT=$PWD/tests/02
+ export CPT_PATH=$PWD/tests/repository
+ install_dummy() { CPT_HOOK='' ./src/cpt bi dummy-pkg >/dev/null 2>&1 ;}
+ remove_dummy() { rm -rf "${CPT_ROOT:?}/var" ;}
+ BeforeAll install_dummy
+ AfterAll remove_dummy
+
+ Describe 'cpt'
+
+ Describe '--version'
+ VERSION=$(grep VERSION config.rc | sed 's/.* //g')
+ It 'outputs cpt version'
+ When run script src/cpt --version
+ The stderr should eq "-> Carbs Packaging Tools $VERSION"
+ End
+ End
+
+ Describe '--help'
+ It 'outputs usage information'
+ When run script src/cpt --help
+ The line 1 of stderr should eq "-> Carbs Packaging Tool "
+ End
+ End
+
+ Describe 'prefix completion'
+ Describe 'single key expansion'
+ Parameters
+ a alternatives
+ b build
+ c checksum
+ d download
+ i install
+ l list
+ r remove
+ s search
+ u update
+ End
+ It "completes '$1' single key prefix to '$2'"
+ When run script src/cpt "$1" --help
+ The status should eq 0
+ The word 1 of line 1 should eq "usage:"
+ The word 2 of line 1 should eq "cpt-$2"
+ End
+ End
+ Describe 'shortcut expansion'
+ Parameters
+ bi "build install"
+ cbi "checksum build install"
+ End
+ It "expands the '$1' shortcut to '$2'"
+ When run script src/cpt "$1" --help
+ The status should be success
+ The word 2 of line 1 should eq "cpt-${2%% *}"
+ End
+ End
+ End
+
+
+ It 'fails when a given subcommand is not valid'
+ When run script src/cpt somerandomcommand
+ The stderr should eq "!> 'cpt somerandomcommand' is not a valid command "
+ The status should be failure
+ End
+ End
+
+ Describe 'cpt-list'
+ no_db_dir() {
+ [ "$(pkgnum)" -eq 0 ]
+ }
+ Skip if "there are no installed packages" no_db_dir
+ It 'lists all packages when called without arguments'
+ When run script src/cpt-list
+ The lines of output should eq "$(pkgnum)"
+ End
+ firstpkg=$(getfirstpkg)
+ It 'only lists the packages given in the arguments'
+ When run script src/cpt-list "$firstpkg"
+ The word 1 of stdout should eq "$firstpkg"
+ End
+ It 'fails when the package supplied in the arguments does not exist'
+ When run script src/cpt-list somerandompackage
+ The stderr should eq "-> somerandompackage not installed"
+ The status should be failure
+ End
+ Parameters
+ "$firstpkg" success
+ somerandompackage failure
+ End
+ It "can print a $2 message with 'cpt-list --check PKG TRUE FALSE'"
+ When run script src/cpt-list --check "$1" success failure
+ The output should eq "$2"
+ End
+ End
+ Describe 'cpt-search'
+ It "searches packages inside the \$CPT_PATH and the system database"
+ When run script src/cpt-search dummy-pkg
+ The line 1 of output should eq "$CPT_PATH/dummy-pkg"
+ The line 2 of output should eq "$CPT_ROOT/var/db/cpt/installed/dummy-pkg"
+ End
+ It "only shows the first instance of a package with the '-s' flag"
+ When run script src/cpt-search -s dummy-pkg
+ The output should eq "$CPT_PATH/dummy-pkg"
+ End
+ It "only shows the first instance of a package with the '--single' flag"
+ When run script src/cpt-search --single dummy-pkg
+ The output should eq "$CPT_PATH/dummy-pkg"
+ End
+ It "shows other locations of the package inside a package directory with the '-o' flag"
+ cd "$CPT_PATH/dummy-pkg" || return 1
+ When run script "$(command -v cpt-search)" -o
+ The output should eq "$CPT_ROOT/var/db/cpt/installed/dummy-pkg"
+ End
+ It "shows other locations of the package inside a package directory with the '--others' flag"
+ cd "$CPT_PATH/dummy-pkg" || return 1
+ When run script "$(command -v cpt-search)" --others
+ The output should eq "$CPT_ROOT/var/db/cpt/installed/dummy-pkg"
+ End
+ Parameters
+ 'd*'
+ 'd???y-?kg'
+ '[Dd][uU]*-?*g*'
+ End
+ It "accepts regular expressions"
+ When run script src/cpt-search -s "$1"
+ The output should eq "$CPT_PATH/dummy-pkg"
+ End
+ End
+End
diff --git a/spec/03_contrib_spec.sh b/spec/03_contrib_spec.sh
new file mode 100644
index 0000000..9c7589b
--- /dev/null
+++ b/spec/03_contrib_spec.sh
@@ -0,0 +1,122 @@
+Describe 'contrib scripts'
+ export PATH=$PWD/src:$PWD/contrib:$PATH
+ export CPT_ROOT=$PWD/tests/03
+ export CPT_PATH=$PWD/tests/repository
+ export CPT_COMPRESS=''
+ install_tmp() {
+ CPT_HOOK='' ./src/cpt b -y contrib-dummy-pkg >/dev/null 2>&1
+ CPT_HOOK='' ./src/cpt-install -y contrib-dummy-pkg >/dev/null 2>&1
+ mkdir -p "$CPT_ROOT/tmp"
+ }
+ remove_tmp() { rm -rf "${CPT_ROOT:?}/var" "$CPT_ROOT/tmp" ;}
+ BeforeAll install_tmp
+ AfterAll remove_tmp
+
+ Describe 'cpt-cat'
+ firstpkg=$(getfirstpkg)
+ It 'outputs the file contents in the given package directory'
+ When run script ./contrib/cpt-cat "$firstpkg"
+ The stdout should not eq ""
+ The line 1 of stderr should eq "$(printf '\033[1mbuild:\033[m\n')"
+ End
+ It "uses the current directory for the package name if none is supplied (contrib-dummy-pkg)"
+ cd "$CPT_PATH/contrib-dummy-pkg" || return 1
+ When run script "$(command -v cpt-cat)"
+ The stdout should not eq ""
+ The line 1 of stderr should eq "$(printf '\033[1mbuild:\033[m\n')"
+ End
+ It "exits with error if the package isn't installed"
+ When run script ./contrib/cpt-cat somerandompackage
+ The stderr should eq "-> somerandompackage not installed"
+ The status should be failure
+ End
+ It "prints usage information when called with --help"
+ When run script ./contrib/cpt-cat --help
+ The word 1 of stdout should eq "usage:"
+ The status should be success
+ End
+ Parameters
+ build
+ checksums
+ manifest
+ version
+ End
+ It "outputs the given file contents in the given package directory ($1)"
+ When run script ./contrib/cpt-cat "$firstpkg" "$1"
+ The stdout should eq "$(cat "$CPT_ROOT/var/db/cpt/installed/$firstpkg/$1")"
+ The stderr should eq "$(printf '\033[1m%s:\033[m\n' "$1")"
+ End
+ It "outputs the given file contents for the name of the current directory (contrib-dummy-pkg - $1)"
+ cd "$CPT_PATH/contrib-dummy-pkg" || return 1
+ When run script "$(command -v cpt-cat)" "" "$1"
+ The stdout should eq "$(cat "$CPT_ROOT/var/db/cpt/installed/${PWD##*/}/$1")"
+ The stderr should eq "$(printf '\033[1m%s:\033[m\n' "$1")"
+ End
+ End
+ Describe 'cpt-depends'
+ firstpkg=$(getfirstpkg)
+ It "outputs the dependencies of the given package"
+ When run script ./contrib/cpt-depends "$firstpkg"
+ The stdout should eq "$(cat "$CPT_ROOT/var/db/cpt/installed/$firstpkg/depends" 2>/dev/null ||:)"
+ The status should be success
+ End
+ It "uses the current directory for the package name if none is supplied (contrib-dummy-pkg)"
+ cd "$CPT_PATH/contrib-dummy-pkg" || return 1
+ When run script "$(command -v cpt-depends)"
+ The stdout should eq "$(cat "$CPT_ROOT/var/db/cpt/installed/contrib-dummy-pkg/depends" 2>/dev/null ||:)"
+ The status should be success
+ End
+ It "prints usage information when called with --help"
+ When run script ./contrib/cpt-depends --help
+ The word 1 of stdout should eq usage:
+ End
+ End
+ Describe 'cpt-export'
+ chtmp() { cd "$CPT_ROOT/tmp" || return 1 ;}
+ cleanpkg() { rm -f "$CPT_PATH/contrib-dummy-pkg/contrib-dummy-pkg#1-1.tar.gz" ;}
+ Before chtmp
+ AfterAll cleanpkg
+ firstpkg=$(getfirstpkg)
+ It "exports a tarball of the given package"
+ When run script "$(command -v cpt-export)" contrib-dummy-pkg
+ The stdout should eq "tarball created in $CPT_ROOT/tmp/contrib-dummy-pkg#1-1.tar.gz"
+ End
+ It "exports the package of the current directory when called without arguments"
+ cd "$CPT_PATH/contrib-dummy-pkg" || return 1
+ When run script "$(command -v cpt-export)"
+ The stdout should eq "tarball created in $CPT_PATH/contrib-dummy-pkg/contrib-dummy-pkg#1-1.tar.gz"
+ End
+ It "prints usage information when called with --help"
+ When run script "$(command -v cpt-export)" --help
+ The word 1 of stdout should eq usage:
+ End
+ It "fallbacks to gz when CPT_COMPRESS has a typo"
+ export CPT_COMPRESS=typo
+ When run script "$(command -v cpt-export)" contrib-dummy-pkg
+ The stdout should eq "tarball created in $CPT_ROOT/tmp/contrib-dummy-pkg#1-1.tar.gz"
+ End
+ Parameters
+ bz2 bzip2
+ gz gzip
+ xz xz
+ zst zstd
+ End
+ Mock bzip2
+ cat
+ End
+ Mock gzip
+ cat
+ End
+ Mock xz
+ cat
+ End
+ Mock zstd
+ cat
+ End
+ It "uses the given CPT_COMPRESS value ($1)"
+ export "CPT_COMPRESS=$1"
+ When run script "$(command -v cpt-export)" contrib-dummy-pkg
+ The stdout should eq "tarball created in $CPT_ROOT/tmp/contrib-dummy-pkg#1-1.tar.$1"
+ End
+ End
+End
diff --git a/spec/spec_helper.sh b/spec/spec_helper.sh
new file mode 100644
index 0000000..f62d9f6
--- /dev/null
+++ b/spec/spec_helper.sh
@@ -0,0 +1,20 @@
+# shellcheck shell=sh
+
+pkgnum() {
+ i=0
+ cd "$CPT_ROOT/var/db/cpt/installed" || { printf '%s\n' 0; return 1 ;}
+ for pkg in ./*; do
+ [ -d "$pkg" ] || break
+ i=$(( i + 1 ))
+ done
+ printf '%s\n' "$i"
+}
+
+getfirstpkg() {
+ cd "$CPT_ROOT/var/db/cpt/installed" || return 1
+ for pkg in ./*; do
+ [ -d "$pkg" ] || return 1
+ printf '%s\n' "${pkg##*/}"
+ break
+ done
+}
diff --git a/tests/etc/cpt-hook b/tests/etc/cpt-hook
new file mode 120000
index 0000000..e95622a
--- /dev/null
+++ b/tests/etc/cpt-hook
@@ -0,0 +1 @@
+../hook-file \ No newline at end of file
diff --git a/tests/hook-file b/tests/hook-file
new file mode 100644
index 0000000..4b8a2ce
--- /dev/null
+++ b/tests/hook-file
@@ -0,0 +1,3 @@
+# -*- mode: sh -*-
+# This a test hook file that only returns back the $TYPE, $PKG, and $DEST
+out "$CPT_HOOK $TYPE $PKG $DEST"
diff --git a/tests/repository/contrib-dummy-pkg/build b/tests/repository/contrib-dummy-pkg/build
new file mode 100755
index 0000000..270ae64
--- /dev/null
+++ b/tests/repository/contrib-dummy-pkg/build
@@ -0,0 +1 @@
+#!/bin/sh -e
diff --git a/tests/repository/contrib-dummy-pkg/checksums b/tests/repository/contrib-dummy-pkg/checksums
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/repository/contrib-dummy-pkg/checksums
diff --git a/tests/repository/contrib-dummy-pkg/depends b/tests/repository/contrib-dummy-pkg/depends
new file mode 100644
index 0000000..153ede1
--- /dev/null
+++ b/tests/repository/contrib-dummy-pkg/depends
@@ -0,0 +1 @@
+dummy-pkg
diff --git a/tests/repository/contrib-dummy-pkg/sources b/tests/repository/contrib-dummy-pkg/sources
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/repository/contrib-dummy-pkg/sources
diff --git a/tests/repository/contrib-dummy-pkg/version b/tests/repository/contrib-dummy-pkg/version
new file mode 100644
index 0000000..2fb73a0
--- /dev/null
+++ b/tests/repository/contrib-dummy-pkg/version
@@ -0,0 +1 @@
+1 1
diff --git a/tests/repository/dummy-pkg/build b/tests/repository/dummy-pkg/build
new file mode 100755
index 0000000..d37d964
--- /dev/null
+++ b/tests/repository/dummy-pkg/build
@@ -0,0 +1,4 @@
+#!/bin/sh -e
+
+# Check that we are receiving 3 arguments
+[ "$3" ] || exit 1
diff --git a/tests/repository/dummy-pkg/checksums b/tests/repository/dummy-pkg/checksums
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/repository/dummy-pkg/checksums
diff --git a/tests/repository/dummy-pkg/version b/tests/repository/dummy-pkg/version
new file mode 100644
index 0000000..2fb73a0
--- /dev/null
+++ b/tests/repository/dummy-pkg/version
@@ -0,0 +1 @@
+1 1