Mostly finish pytest to Bats conversion (#1200)

* Mostly finish pytest to Bats conversion

* Add Bats version note to testing docs

* Move Bats CI check to separate job
This commit is contained in:
Edwin Kofler 2025-03-25 20:19:30 -07:00 committed by GitHub
parent 18ecffef5e
commit c49ca70814
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 409 additions and 31 deletions

View file

@ -65,9 +65,9 @@ jobs:
grep -v -e 'History\.md' -e 'AUTHORS' -e 'man/.*\.1' -e 'man/.*\.html' | \ grep -v -e 'History\.md' -e 'AUTHORS' -e 'man/.*\.1' -e 'man/.*\.html' | \
xargs poetry run codespell --ignore-words=../.github/.ignore_words xargs poetry run codespell --ignore-words=../.github/.ignore_words
test: test-pytest:
name: 'Test with Pytest'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
@ -85,13 +85,23 @@ jobs:
run: | run: |
cd tests || exit cd tests || exit
poetry install --only test poetry install --only test
- name: Setup Bats
id: setup-bats
uses: bats-core/bats-action@3.0.0
- name: Test with Pytest - name: Test with Pytest
run: | run: |
cd tests cd tests
poetry run pytest poetry run pytest
test-bats:
name: 'Test with Bats'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Bats
id: setup-bats
uses: bats-core/bats-action@3.0.0
with:
bats-version: 'v1.8.1'
- name: Test with Bats - name: Test with Bats
env: env:
BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }} BATS_LIB_PATH: ${{ steps.setup-bats.outputs.lib-path }}

1
.gitignore vendored
View file

@ -1,2 +1,3 @@
.venv/ .venv/
__pycache__/ __pycache__/
coverage/

View file

@ -1,7 +1,28 @@
# Test for git-extras # Testing
The git-extras has its own testcases now, and the more is on the way! So let's introduce it.
We choose python to help us to reach to other shore cause **python is life saver**. Originally, the tests were written in pytest. However, tests are in the process of being converted to Bats so coverage can be calculated.
## Bats Testing
We require a somewhat recent version of Bats. Version v1.8.1 is tested in CI. Once it is installed, the tests can be executed like so:
```sh
bats ./tests
```
We highly recommend adding tests for new features and fixes.
### Code Coverage
Coverage can be calculated with [bashcov](https://github.com/infertux/bashcov) like so:
```sh
bashcov -- bats ./tests
```
By default, the report will be generated in `./coverage/index.html`.
## Python Testing
The test part depends on: The test part depends on:
@ -12,7 +33,8 @@ The test part depends on:
So the versions are higher than above is recommended. So the versions are higher than above is recommended.
# How to run the tests ### How to run the tests
1. Install `poetry` 1. Install `poetry`
2. Install the dependencies via `poetry install` 2. Install the dependencies via `poetry install`
3. Run `poetry run pytest` 3. Run `poetry run pytest`
@ -27,7 +49,8 @@ It is done or go without `poetry`,
The second way maybe blocked the some missing dependencies at someday, so the first one is recommended. The second way maybe blocked the some missing dependencies at someday, so the first one is recommended.
# What and how to create a unit test ### What and how to create a unit test
One command has a unit test, because one `git-*` command is just do one thing, so we can eat a piece of `git-*` command in one time. One command has a unit test, because one `git-*` command is just do one thing, so we can eat a piece of `git-*` command in one time.
For example, For example,
@ -39,7 +62,8 @@ For example,
* `named_temp_repo` is just same as `temp_repo` except the custom directory renaming. * `named_temp_repo` is just same as `temp_repo` except the custom directory renaming.
4. Loop the third step until the 100% coverage of the function of the `git-alias` 4. Loop the third step until the 100% coverage of the function of the `git-alias`
# References ### References
* [poetry](https://github.com/python-poetry/poetry) * [poetry](https://github.com/python-poetry/poetry)
* [pytest](https://github.com/pytest-dev/pytest/) * [pytest](https://github.com/pytest-dev/pytest/)
* [git python](https://github.com/gitpython-developers/GitPython) * [git python](https://github.com/gitpython-developers/GitPython)

2
tests/bin/open Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
printf '%s\n' "open $*"

2
tests/bin/powershell.exe Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
printf '%s\n' "powershell.exe $*"

2
tests/bin/start Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
printf '%s\n' "start $*"

2
tests/bin/xdg-open Executable file
View file

@ -0,0 +1,2 @@
#!/usr/bin/env bash
printf '%s\n' "xdg-open $*"

View file

@ -9,7 +9,7 @@ setup_file() {
setup() { setup() {
test_util.cd_test test_util.cd_test
git init test_util.git_init
git commit --allow-empty -m "Initial commit" git commit --allow-empty -m "Initial commit"
git branch A git branch A
git branch B git branch B
@ -24,7 +24,7 @@ setup() {
git status git status
} }
@test "cherry pick" { @test "works with cherry pick" {
run git cherry-pick A run git cherry-pick A
assert_failure assert_failure
@ -41,7 +41,7 @@ setup() {
assert_success assert_success
} }
@test "merge" { @test "works with merge" {
run git merge A run git merge A
assert_failure assert_failure
@ -58,7 +58,7 @@ setup() {
assert_success assert_success
} }
@test "rebase" { @test "works with rebase" {
run git rebase A run git rebase A
assert_failure assert_failure
@ -75,7 +75,7 @@ setup() {
assert_success assert_success
} }
@test "revert" { @test "works with revert" {
run git revert A run git revert A
assert_failure assert_failure

View file

@ -9,7 +9,7 @@ setup_file() {
setup() { setup() {
test_util.cd_test test_util.cd_test
git init test_util.git_init
git config --global alias.globalalias status git config --global alias.globalalias status
git config --global alias.x status git config --global alias.x status
git config --local alias.localalias status git config --local alias.localalias status

View file

@ -9,7 +9,7 @@ setup_file() {
setup() { setup() {
test_util.cd_test test_util.cd_test
git init test_util.git_init
printf '%s\n' 'data' > tmpfile printf '%s\n' 'data' > tmpfile
git add . git add .
git commit -m 'test: add data' git commit -m 'test: add data'

View file

@ -10,17 +10,22 @@ setup_file() {
setup() { setup() {
test_util.cd_test test_util.cd_test
git init test_util.git_init
GIT_CONFIG_VALUE_0='test@example.com'
GIT_CONFIG_VALUE_1='test' git config user.name 'test'
git config user.email 'test@example.com'
printf '%s\n' 'A' > tmpfile printf '%s\n' 'A' > tmpfile
git add . git add .
git commit -m 'test: add data A' git commit -m 'test: add data A'
GIT_CONFIG_VALUE_0='testagain@example.com'
GIT_CONFIG_VALUE_1='testagain' git config user.name 'testagain'
git config user.email 'testagain@example.com'
printf '%s\n' 'B' > tmpfile printf '%s\n' 'B' > tmpfile
git add . git add .
git commit -m 'test: add data B' git commit -m 'test: add data B'
# git config unset user.name
# git config unset user.email
} }
@test "output authors has email without any parameter" { @test "output authors has email without any parameter" {

117
tests/git-browse-ci.bats Normal file
View file

@ -0,0 +1,117 @@
# shellcheck shell=bash
source "$BATS_TEST_DIRNAME/test_util.sh"
setup_file() {
test_util.setup_file
PATH="$BATS_TEST_DIRNAME/bin:$PATH"
}
setup() {
test_util.cd_test
test_util.git_init
}
get_ci_uri() {
local mode=$1
if [ "$mode" = 'github' ]; then
REPLY="https://github.com/tj/git-extras/actions"
elif [ "$mode" = 'gitlab' ]; then
REPLY="https://gitlab.com/tj/git-extras/-/pipelines"
elif [ "$mode" = 'bitbucket' ]; then
REPLY="https://bitbucket.org/tj/git-extras/addon/pipelines/home"
fi
}
@test "works with mac and github" {
get_ci_uri 'github'
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=darwin run git browse-ci upstream
assert_output "open $expected_url"
assert_success
}
@test "works with mac and gitlab" {
get_ci_uri 'gitlab'
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=darwin run git browse-ci upstream
assert_output "open $expected_url"
assert_success
}
@test "works with mac and bitbucket" {
get_ci_uri 'bitbucket'
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=darwin run git browse-ci upstream
assert_output "open $expected_url"
assert_success
}
@test "works with windows and github" {
get_ci_uri 'github'
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=msys run git browse-ci upstream
assert_output "start $expected_url"
assert_success
}
@test "works with windows and gitlab" {
get_ci_uri 'gitlab'
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=msys run git browse-ci upstream
assert_output "start $expected_url"
assert_success
}
@test "works with windows and bitbucket" {
get_ci_uri 'bitbucket'
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=msys run git browse-ci upstream
assert_output "start $expected_url"
assert_success
}
@test "works with linux and github" {
get_ci_uri 'github'
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=linux-gnu run git browse-ci upstream
assert_output "xdg-open $expected_url"
assert_success
}
@test "works with linux and gitlab" {
get_ci_uri 'gitlab'
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=linux-gnu run git browse-ci upstream
assert_output "xdg-open $expected_url"
assert_success
}
@test "works with linux and bitbucket" {
get_ci_uri 'bitbucket'
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=linux-gnu run git browse-ci upstream
assert_output "xdg-open $expected_url"
assert_success
}

123
tests/git-browse.bats Normal file
View file

@ -0,0 +1,123 @@
# shellcheck shell=bash
source "$BATS_TEST_DIRNAME/test_util.sh"
setup_file() {
test_util.setup_file
PATH="$BATS_TEST_DIRNAME/bin:$PATH"
}
setup() {
test_util.cd_test
test_util.git_init
touch ./browse_this
git add ./browse_this
git commit -m 'Add test file'
}
get_file_uri() {
local mode=$1
local filename=$2
local commit_hash=
commit_hash=$(git rev-parse HEAD)
if [ "$mode" = 'github' ]; then
REPLY="https://github.com/tj/git-extras/blob/$commit_hash/${filename}"
elif [ "$mode" = 'gitlab' ]; then
REPLY="https://gitlab.com/tj/git-extras/-/blob/${commit_hash}/${filename}"
elif [ "$mode" = 'bitbucket' ]; then
REPLY="https://bitbucket.org/tj/git-extras/src/${commit_hash}/${filename}"
fi
}
@test "works with mac and github" {
get_file_uri github ./browse_this
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=darwin run git browse upstream ./browse_this
assert_output "open $expected_url"
assert_success
}
@test "works with mac and gitlab" {
get_file_uri gitlab ./browse_this
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=darwin run git browse upstream ./browse_this
assert_output "open $expected_url"
assert_success
}
@test "works with mac and bitbucket" {
get_file_uri bitbucket ./browse_this
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=darwin run git browse upstream ./browse_this
assert_output "open $expected_url"
assert_success
}
@test "works with windows and github" {
get_file_uri github ./browse_this
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=msys run git browse upstream ./browse_this
assert_output "start $expected_url"
assert_success
}
@test "works with windows and gitlab" {
get_file_uri gitlab ./browse_this
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=msys run git browse upstream ./browse_this
assert_output "start $expected_url"
assert_success
}
@test "works with windows and bitbucket" {
get_file_uri bitbucket ./browse_this
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=msys run git browse upstream ./browse_this
assert_output "start $expected_url"
assert_success
}
@test "works with linux and github" {
get_file_uri github ./browse_this
local expected_url=$REPLY
git remote add upstream https://github.com/tj/git-extras
OSTYPE=linux-gnu run git browse upstream ./browse_this
assert_output "xdg-open $expected_url"
assert_success
}
@test "works with linux and gitlab" {
get_file_uri gitlab ./browse_this
local expected_url=$REPLY
git remote add upstream https://gitlab.com/tj/git-extras
OSTYPE=linux-gnu run git browse upstream ./browse_this
assert_output "xdg-open $expected_url"
assert_success
}
@test "works with linux and bitbucket" {
get_file_uri bitbucket ./browse_this
local expected_url=$REPLY
git remote add upstream https://bitbucket.org/tj/git-extras
OSTYPE=linux-gnu run git browse upstream ./browse_this
assert_output "xdg-open $expected_url"
assert_success
}

92
tests/git-continue.bats Executable file
View file

@ -0,0 +1,92 @@
#!/usr/bin/env bats
source "$BATS_TEST_DIRNAME/test_util.sh"
setup_file() {
test_util.setup_file
}
setup() {
test_util.cd_test
test_util.git_init
git commit -m 'Initial commit' --allow-empty
git switch -c A main
printf '%s\n' 'a' >> ./tmp_file
git add ./tmp_file
git commit -m 'A'
git switch -c B main
printf '%s\n' 'b' >> ./tmp_file
git add ./tmp_file
git commit -m 'B'
}
@test "works with cherry pick" {
run git cherry-pick A
assert_failure
run git status
assert_line -p 'Unmerged paths:'
assert_success
git add .
GIT_EDITOR=cat run git continue
assert_success
run git status
assert_line -p 'nothing to commit, working tree clean'
assert_success
}
@test "works with merge" {
run git merge A
assert_failure
run git status
assert_line -p 'Unmerged paths:'
assert_success
git add .
GIT_EDITOR=cat run git continue
assert_success
run git status
assert_line -p 'nothing to commit, working tree clean'
assert_success
}
@test "works with rebase" {
run git rebase A
assert_failure
run git status
assert_line -p 'Unmerged paths:'
assert_success
git add .
GIT_EDITOR=cat run git continue
assert_success
run git status
assert_line -p 'nothing to commit, working tree clean'
assert_success
}
@test "works with revert" {
run git revert A
assert_failure
run git status
assert_line -p 'Unmerged paths:'
assert_success
git add .
GIT_EDITOR=cat run git continue
assert_failure # TODO: Git seems to do nothing and error out?
run git status
assert_line -p 'nothing to commit, working tree clean'
assert_success
}

View file

@ -7,14 +7,6 @@ test_util.setup_file() {
export GIT_CONFIG_NOSYSTEM=1 export GIT_CONFIG_NOSYSTEM=1
export GIT_CONFIG_GLOBAL="$PWD/git_config" export GIT_CONFIG_GLOBAL="$PWD/git_config"
export GIT_CONFIG_COUNT=3
export GIT_CONFIG_KEY_0="user.email"
export GIT_CONFIG_VALUE_0="name@example.com"
export GIT_CONFIG_KEY_1="user.name"
export GIT_CONFIG_VALUE_1="Name"
# This removes default warning about default "master" branch on some Git versions.
export GIT_CONFIG_KEY_2="init.defaultBranch"
export GIT_CONFIG_VALUE_2="main"
# Append to path so that we can access all commands included from git-extras # Append to path so that we can access all commands included from git-extras
# TODO: This currently breaks with commands that are included in "not_needed_git_repo" etc. # TODO: This currently breaks with commands that are included in "not_needed_git_repo" etc.
@ -24,3 +16,9 @@ test_util.setup_file() {
test_util.cd_test() { test_util.cd_test() {
cd "$BATS_TEST_TMPDIR" cd "$BATS_TEST_TMPDIR"
} }
test_util.git_init() {
git init --initial-branch main
git config user.name 'Name'
git config user.email 'name@example.com'
}