mirror of
https://github.com/zsh-users/zsh-autosuggestions.git
synced 2025-04-17 11:35:31 +08:00
Compare commits
445 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0e810e5afa | ||
![]() |
f9526195c5 | ||
![]() |
e52ee8ca55 | ||
![]() |
f8907cf32b | ||
![]() |
a50468ef4b | ||
![]() |
9aceef9646 | ||
![]() |
11d17e7fea | ||
![]() |
a593f4dfec | ||
![]() |
2c9e57fd50 | ||
![]() |
c3d4e576c9 | ||
![]() |
23f2943455 | ||
![]() |
95602e2dea | ||
![]() |
39aa7bed3a | ||
![]() |
27c298cf1a | ||
![]() |
a84d78f8b5 | ||
![]() |
309d32ac9e | ||
![]() |
9908eb49a3 | ||
![]() |
2b97cf3b30 | ||
![]() |
9b0272944f | ||
![]() |
c5044edd48 | ||
![]() |
2cc34c015e | ||
![]() |
f29bb7f032 | ||
![]() |
c14ad9fc46 | ||
![]() |
fc391d6bf6 | ||
![]() |
7795a357e6 | ||
![]() |
56f10c3b5d | ||
![]() |
8072e52d96 | ||
![]() |
69bf058c23 | ||
![]() |
a411ef3e09 | ||
![]() |
fcca87555f | ||
![]() |
74ba3739bb | ||
![]() |
3ecc53dfe2 | ||
![]() |
aa05920a4a | ||
![]() |
89c600c873 | ||
![]() |
3474c87d67 | ||
![]() |
590c1cd84c | ||
![]() |
58c98a7739 | ||
![]() |
bb18c4f677 | ||
![]() |
9ad305c906 | ||
![]() |
eff0894a13 | ||
![]() |
e0b96e1bd6 | ||
![]() |
05f22fa8a3 | ||
![]() |
e715ffb1ae | ||
![]() |
9ad039443f | ||
![]() |
a32fe24acc | ||
![]() |
e3897c25c0 | ||
![]() |
ee18c7ce24 | ||
![]() |
a83c7cf9d6 | ||
![]() |
6c634c1e35 | ||
![]() |
19e375bbc8 | ||
![]() |
c114bd2298 | ||
![]() |
7682c13860 | ||
![]() |
f90d040784 | ||
![]() |
ae315ded4d | ||
![]() |
ff298e57c0 | ||
![]() |
a5affac6f1 | ||
![]() |
03f59df502 | ||
![]() |
cf445d08b0 | ||
![]() |
0d2c9de2ea | ||
![]() |
8f3f59542a | ||
![]() |
6ec95379fa | ||
![]() |
7afb7364f1 | ||
![]() |
54d7a9a84c | ||
![]() |
5217ed5269 | ||
![]() |
ef657cb38c | ||
![]() |
d43c309f88 | ||
![]() |
c6b636ea4f | ||
![]() |
0f0f221180 | ||
![]() |
4016ff795b | ||
![]() |
bdbe43e667 | ||
![]() |
eab0e9b574 | ||
![]() |
24655d9328 | ||
![]() |
43f3bc4010 | ||
![]() |
fdc4292a7f | ||
![]() |
3baf9468c2 | ||
![]() |
3da421aa47 | ||
![]() |
b87a4972c8 | ||
![]() |
01dce8999f | ||
![]() |
ac4f0b2418 | ||
![]() |
324aad0ac9 | ||
![]() |
146020d9b2 | ||
![]() |
0636a39b51 | ||
![]() |
6769c941ba | ||
![]() |
371d6441c0 | ||
![]() |
78e4379711 | ||
![]() |
c80605595c | ||
![]() |
cb52adf429 | ||
![]() |
cdf6be4f06 | ||
![]() |
66a6de3fb5 | ||
![]() |
2498dbab75 | ||
![]() |
676aebdf44 | ||
![]() |
ec43fcfccf | ||
![]() |
f5236c4351 | ||
![]() |
d27983b7ca | ||
![]() |
d14b17fb09 | ||
![]() |
b24b607fbf | ||
![]() |
a437544cc5 | ||
![]() |
112dd3e3c7 | ||
![]() |
8a812bdfd2 | ||
![]() |
f178efb847 | ||
![]() |
48ffc1bf92 | ||
![]() |
adb02c44a2 | ||
![]() |
3654b83ec0 | ||
![]() |
b3b34eab49 | ||
![]() |
19c976f62a | ||
![]() |
3250778ce8 | ||
![]() |
43ba841742 | ||
![]() |
86f64c30ca | ||
![]() |
f543ba08c3 | ||
![]() |
68343c8de4 | ||
![]() |
e263845bed | ||
![]() |
d94475ca1b | ||
![]() |
c04e015d13 | ||
![]() |
e9ce05c4c1 | ||
![]() |
fdf4502c5c | ||
![]() |
7e048c3f53 | ||
![]() |
2b05f5ed2d | ||
![]() |
5339d2703d | ||
![]() |
0d3bbaf8e6 | ||
![]() |
848aa741f4 | ||
![]() |
15bcfd7126 | ||
![]() |
9ceeacc797 | ||
![]() |
1c3e3fd939 | ||
![]() |
527fd17ffc | ||
![]() |
1912726460 | ||
![]() |
de266574d3 | ||
![]() |
48d04447cc | ||
![]() |
b714f6667c | ||
![]() |
474c577f3c | ||
![]() |
e9d8231ba7 | ||
![]() |
ce6ee94f30 | ||
![]() |
e7c7efe2e2 | ||
![]() |
733abd4af0 | ||
![]() |
152d2c6b31 | ||
![]() |
528e338e57 | ||
![]() |
c1910348c7 | ||
![]() |
937d6fc241 | ||
![]() |
b9fee8a324 | ||
![]() |
db290c518b | ||
![]() |
d8ba53678e | ||
![]() |
4cd210b70d | ||
![]() |
586b51366b | ||
![]() |
e405afab29 | ||
![]() |
a5dc4a8db4 | ||
![]() |
543f2b5477 | ||
![]() |
a36a9aca44 | ||
![]() |
cbf0e24b18 | ||
![]() |
f94e667f59 | ||
![]() |
3ee91c731c | ||
![]() |
0b13f663da | ||
![]() |
4a82ff1ead | ||
![]() |
f76472272e | ||
![]() |
50579b3371 | ||
![]() |
66b842579a | ||
![]() |
aee1b10db6 | ||
![]() |
ebc2c07ac8 | ||
![]() |
e937e89267 | ||
![]() |
11251d97ca | ||
![]() |
41657e3565 | ||
![]() |
70f36c007d | ||
![]() |
a7f0106b31 | ||
![]() |
286656635c | ||
![]() |
0d994d4732 | ||
![]() |
9e4d3c337f | ||
![]() |
f0f1332e6b | ||
![]() |
a78ea16c50 | ||
![]() |
62f5f14f2f | ||
![]() |
4540304fa0 | ||
![]() |
df6f6f9ff4 | ||
![]() |
4097d6e0ae | ||
![]() |
822a1f30e0 | ||
![]() |
0f80f9511d | ||
![]() |
4838222dde | ||
![]() |
35c286de9a | ||
![]() |
be6b22b864 | ||
![]() |
69d7fa14d3 | ||
![]() |
e61442161e | ||
![]() |
4b28d92e01 | ||
![]() |
b512a1b040 | ||
![]() |
affe7c687e | ||
![]() |
fa5d9c0ff5 | ||
![]() |
681ffc7b28 | ||
![]() |
b8bf86f6ab | ||
![]() |
7ab2124904 | ||
![]() |
88fe824ddf | ||
![]() |
93877f6b76 | ||
![]() |
0ee5b0a5c9 | ||
![]() |
bd1fd97738 | ||
![]() |
ebaf409002 | ||
![]() |
2d0ae6044c | ||
![]() |
106bf02d49 | ||
![]() |
f1c3b98774 | ||
![]() |
4869a757c8 | ||
![]() |
302bd7c059 | ||
![]() |
245f5d2ba2 | ||
![]() |
8ae0283c90 | ||
![]() |
07b37fd9ce | ||
![]() |
7c83775bc7 | ||
![]() |
e97d132b3b | ||
![]() |
c0315e96d8 | ||
![]() |
5529102afc | ||
![]() |
dad6be4d5e | ||
![]() |
7d968869e3 | ||
![]() |
8593624996 | ||
![]() |
1ec43c7291 | ||
![]() |
43a011026f | ||
![]() |
cd81522b30 | ||
![]() |
4a268da1df | ||
![]() |
d7171232c3 | ||
![]() |
faf0f9a698 | ||
![]() |
9cb0101512 | ||
![]() |
b0ffc34fb8 | ||
![]() |
4e466f0e4e | ||
![]() |
bcbdad83e9 | ||
![]() |
949c374195 | ||
![]() |
973205005c | ||
![]() |
7d19f8f9b2 | ||
![]() |
cf458d2a3b | ||
![]() |
3dbd9afaec | ||
![]() |
6ffaec725a | ||
![]() |
0a548c62f4 | ||
![]() |
4cca26ec84 | ||
![]() |
f63afd5969 | ||
![]() |
c5551daabc | ||
![]() |
82b08e2dc8 | ||
![]() |
5549b68e6e | ||
![]() |
63789e96b5 | ||
![]() |
d7c796719e | ||
![]() |
aa0b10db44 | ||
![]() |
72ccee33b4 | ||
![]() |
c113e49fe2 | ||
![]() |
3b39b9561c | ||
![]() |
b003b2238a | ||
![]() |
df5fb858aa | ||
![]() |
726bc4eb5c | ||
![]() |
59c72c6805 | ||
![]() |
393f7b8bb9 | ||
![]() |
42f5a06f7f | ||
![]() |
51fef255da | ||
![]() |
19ad3ba7cd | ||
![]() |
b2b9bf3b8c | ||
![]() |
67a364bc17 | ||
![]() |
afc14f79cc | ||
![]() |
60aff2d944 | ||
![]() |
6dfe9c8cd8 | ||
![]() |
3136700ccf | ||
![]() |
2202ed7bac | ||
![]() |
c978004c0e | ||
![]() |
c7d4a85031 | ||
![]() |
15931f04ff | ||
![]() |
9f1046727a | ||
![]() |
f462410b3c | ||
![]() |
4ea825faf8 | ||
![]() |
a1babef972 | ||
![]() |
be8bba6f38 | ||
![]() |
dda220f140 | ||
![]() |
9f9237ab8a | ||
![]() |
29257230fe | ||
![]() |
940e10a691 | ||
![]() |
9f1f322979 | ||
![]() |
680ce21f26 | ||
![]() |
256293cbb6 | ||
![]() |
977e70e21b | ||
![]() |
218acf2fbe | ||
![]() |
0681a1c121 | ||
![]() |
9e3f1bd359 | ||
![]() |
ae4c344e82 | ||
![]() |
7f8ff2867c | ||
![]() |
33b91a9dea | ||
![]() |
802f53a10a | ||
![]() |
5e4487ed4a | ||
![]() |
9e110406fa | ||
![]() |
1915e28882 | ||
![]() |
d6d9a46981 | ||
![]() |
706499838c | ||
![]() |
e304365745 | ||
![]() |
4e72f7a91e | ||
![]() |
2cb6eb6e29 | ||
![]() |
14179d869d | ||
![]() |
281ed9bbf7 | ||
![]() |
83129dd796 | ||
![]() |
40b96f6cfd | ||
![]() |
a2f0ffb122 | ||
![]() |
7d4a1d9a4a | ||
![]() |
e1959d0f61 | ||
![]() |
c52c428793 | ||
![]() |
ea505b01e5 | ||
![]() |
502fb4a174 | ||
![]() |
ce362248fa | ||
![]() |
cb93366d0e | ||
![]() |
39762ecd97 | ||
![]() |
468b7403e9 | ||
![]() |
c9a51e0c4c | ||
![]() |
48a21bf79e | ||
![]() |
4afbbbadda | ||
![]() |
e3fa4e4904 | ||
![]() |
2cd99e64b7 | ||
![]() |
c70d685d15 | ||
![]() |
255359dbb8 | ||
![]() |
4321fc097c | ||
![]() |
75e850577d | ||
![]() |
a0fcd81ce1 | ||
![]() |
39ca3dac45 | ||
![]() |
dcce973287 | ||
![]() |
0c940e70f2 | ||
![]() |
a109f52fe4 | ||
![]() |
23ef16c297 | ||
![]() |
938144530c | ||
![]() |
c4bfd8e2c6 | ||
![]() |
c959408305 | ||
![]() |
06fca77ffb | ||
![]() |
9feac573c9 | ||
![]() |
ed8056c5e8 | ||
![]() |
38eb7cdafd | ||
![]() |
64e7ec5bf8 | ||
![]() |
98f926d53d | ||
![]() |
51e8755634 | ||
![]() |
5151adfe40 | ||
![]() |
2c465a932a | ||
![]() |
e3eb286ea2 | ||
![]() |
c3425870f1 | ||
![]() |
89dd69d517 | ||
![]() |
40bb2e7804 | ||
![]() |
16666da488 | ||
![]() |
f33b605a63 | ||
![]() |
78ba07179a | ||
![]() |
3f57198d07 | ||
![]() |
2dbd261989 | ||
![]() |
6c5cd42331 | ||
![]() |
54e1eee924 | ||
![]() |
21d9eda5dd | ||
![]() |
50e6832b8c | ||
![]() |
0305908adf | ||
![]() |
8e06a54b1c | ||
![]() |
b3208b08af | ||
![]() |
ab2742537f | ||
![]() |
e5a5b0c1e0 | ||
![]() |
0337005eb0 | ||
![]() |
b530b0c996 | ||
![]() |
5c891afd48 | ||
![]() |
e33eb570c4 | ||
![]() |
fba20b042e | ||
![]() |
0308ed797e | ||
![]() |
e72c2d87e5 | ||
![]() |
ab8f295225 | ||
![]() |
debbffc79a | ||
![]() |
4850119887 | ||
![]() |
c22ab0e399 | ||
![]() |
07a6768fcb | ||
![]() |
e6591d5de0 | ||
![]() |
af671fb406 | ||
![]() |
fedc22e9bb | ||
![]() |
9cfaf5d342 | ||
![]() |
9333f0653f | ||
![]() |
b377c39d0e | ||
![]() |
a44aa59321 | ||
![]() |
25f4afb058 | ||
![]() |
472394681e | ||
![]() |
a9c8efa048 | ||
![]() |
cdf56a3305 | ||
![]() |
2450c95d8a | ||
![]() |
7b81eb79b8 | ||
![]() |
63816c5da8 | ||
![]() |
b4b3a82ee3 | ||
![]() |
85ea943789 | ||
![]() |
ca70612d3c | ||
![]() |
62cdba4e0f | ||
![]() |
cce68de46d | ||
![]() |
4a2d9f9049 | ||
![]() |
7c688ec20c | ||
![]() |
96eb0fae77 | ||
![]() |
5e5bfdb659 | ||
![]() |
0a6c34947c | ||
![]() |
e87bc74654 | ||
![]() |
964773aa75 | ||
![]() |
945c660856 | ||
![]() |
011d8bdfd1 | ||
![]() |
c5f57da2b8 | ||
![]() |
c477db2696 | ||
![]() |
d7001f2c34 | ||
![]() |
6d6e7820f3 | ||
![]() |
9bef50fac1 | ||
![]() |
1d4f7e157e | ||
![]() |
2acf25e065 | ||
![]() |
ba7109169d | ||
![]() |
a28e72e84a | ||
![]() |
87facd9b85 | ||
![]() |
dc822c54f8 | ||
![]() |
15c5db898f | ||
![]() |
46d5fe174d | ||
![]() |
6c31a02892 | ||
![]() |
9ec62a1a23 | ||
![]() |
1ed9155f89 | ||
![]() |
97b51a2c57 | ||
![]() |
b54c8a15c6 | ||
![]() |
2a6d401106 | ||
![]() |
a314a01a6a | ||
![]() |
e5cdbb6c33 | ||
![]() |
dffd9beae1 | ||
![]() |
d202b32ae9 | ||
![]() |
ab0f4c0bd0 | ||
![]() |
ee6dde9ee8 | ||
![]() |
73f774bd5d | ||
![]() |
976acc708c | ||
![]() |
83f78d0760 | ||
![]() |
9df362f783 | ||
![]() |
125f48c7f2 | ||
![]() |
8c3fdea75d | ||
![]() |
aa597eea6d | ||
![]() |
f0a745576f | ||
![]() |
8935a39e9b | ||
![]() |
c7c9929490 | ||
![]() |
985de56f6e | ||
![]() |
0a42f872b8 | ||
![]() |
dd54925b06 | ||
![]() |
c761dc8150 | ||
![]() |
cc921994e6 | ||
![]() |
0242c7eff1 | ||
![]() |
9d100f4f32 | ||
![]() |
ddb7284852 | ||
![]() |
2a5791710a | ||
![]() |
03fac1f0d7 | ||
![]() |
aa859a282d | ||
![]() |
f08a5a1baa | ||
![]() |
70438d233d | ||
![]() |
ba029e83d0 | ||
![]() |
acc129de6c | ||
![]() |
aa5ceee256 | ||
![]() |
113ca0ad10 | ||
![]() |
2b449a62f8 | ||
![]() |
6d25df6864 | ||
![]() |
0faa2b6584 | ||
![]() |
a2d8d91196 | ||
![]() |
dd9a8789a7 | ||
![]() |
1b98af5b33 | ||
![]() |
45ab49d1f2 | ||
![]() |
41f15d5c9f | ||
![]() |
3ce1adb55d | ||
![]() |
2461a98857 | ||
![]() |
76f415bf43 | ||
![]() |
5e419da326 | ||
![]() |
cd71081303 | ||
![]() |
9788c2ee49 | ||
![]() |
ebcfc46b72 | ||
![]() |
b49d002888 |
@ -8,3 +8,11 @@ indent_size = 4
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
|
||||
[*.rb]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[*.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
36
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
36
.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Describe the bug
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
### To Reproduce
|
||||
Steps to reproduce the behavior:
|
||||
|
||||
<!-- If you are not able to reproduce it by running `zsh -df` and sourcing the plugin manually, it means there that the issue is caused by something in your local config file(s). Temporarily comment out or remove sections of your config and restart `zsh` until you narrow down exactly what is causing the issue. -->
|
||||
|
||||
```sh
|
||||
% zsh -df
|
||||
% source path/to/zsh-autosuggestions.zsh
|
||||
% ... # what do you do to reproduce?
|
||||
```
|
||||
|
||||
### Expected behavior
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
### Screenshots
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
### Desktop
|
||||
- OS + distribution: <!-- e.g. Arch Linux 2019.07.01 -->
|
||||
- Zsh version: <!-- `echo $ZSH_VERSION` -->
|
||||
- Plugin version: <!-- or git commit hash if installed via git -->
|
||||
|
||||
### Additional context
|
||||
<!-- Add any other context about the problem here. -->
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
### Is your feature request related to a problem? Please describe.
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
### Describe the solution you'd like
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
### Describe alternatives you've considered
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
### Additional context
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
51
.github/workflows/integration.yml
vendored
Normal file
51
.github/workflows/integration.yml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
on: [push, pull_request]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
env:
|
||||
IMAGE_CACHE_PATH: /tmp/.image-cache
|
||||
IMAGE_CACHE_NAME: zsh-autosuggestions-test
|
||||
jobs:
|
||||
determine-versions:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
versions: ${{ steps.set-versions.outputs.versions }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- id: set-versions
|
||||
run: |
|
||||
echo "versions=$(
|
||||
grep "^[^#]" ZSH_VERSIONS \
|
||||
| sed -E 's/(^|$)/"/g' \
|
||||
| paste -sd ',' - \
|
||||
| sed -e 's/^/[/' -e 's/$/]/'
|
||||
)" >> $GITHUB_OUTPUT
|
||||
test:
|
||||
needs: determine-versions
|
||||
runs-on: ubuntu-22.04
|
||||
strategy:
|
||||
matrix:
|
||||
version: ${{ fromJson(needs.determine-versions.outputs.versions) }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Docker image cache
|
||||
id: image-cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ env.IMAGE_CACHE_PATH }}
|
||||
key: image-cache-${{ matrix.version }}-${{ hashFiles('Dockerfile', 'install_test_zsh.sh', 'Gemfile.lock') }}
|
||||
- name: Load cached docker image if available
|
||||
if: ${{ steps.image-cache.outputs.cache-hit }}
|
||||
run: gunzip < $IMAGE_CACHE_PATH/$IMAGE_CACHE_NAME.tar.gz | docker load
|
||||
- name: Build the docker image if necessary
|
||||
if: ${{ !steps.image-cache.outputs.cache-hit }}
|
||||
run: |
|
||||
docker build --build-arg TEST_ZSH_VERSION=${{ matrix.version }} -t $IMAGE_CACHE_NAME .
|
||||
mkdir -p $IMAGE_CACHE_PATH
|
||||
docker save $IMAGE_CACHE_NAME | gzip > $IMAGE_CACHE_PATH/$IMAGE_CACHE_NAME.tar.gz
|
||||
- name: Run the tests
|
||||
run: |
|
||||
docker run --rm \
|
||||
-v $PWD:/zsh-autosuggestions \
|
||||
$IMAGE_CACHE_NAME \
|
||||
make test
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# zsh word code files
|
||||
*.zwc
|
30
.rubocop.yml
Normal file
30
.rubocop.yml
Normal file
@ -0,0 +1,30 @@
|
||||
# Rails:
|
||||
# Enabled: true
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
Include:
|
||||
- '**/Rakefile'
|
||||
- '**/config.ru'
|
||||
- '**/Gemfile'
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
||||
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
Style/DotPosition:
|
||||
EnforcedStyle: trailing
|
||||
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
||||
Style/Lambda:
|
||||
Enabled: false
|
||||
|
||||
Style/MultilineMethodCallIndentation:
|
||||
EnforcedStyle: indented
|
||||
|
||||
Style/TrailingUnderscoreVariable:
|
||||
Enabled: false
|
1
.ruby-version
Normal file
1
.ruby-version
Normal file
@ -0,0 +1 @@
|
||||
2.5.3
|
124
CHANGELOG.md
Normal file
124
CHANGELOG.md
Normal file
@ -0,0 +1,124 @@
|
||||
# Changelog
|
||||
|
||||
## v0.7.1
|
||||
- Clear POSTDISPLAY instead of unsetting (#634)
|
||||
- Always reset async file descriptor after consuming it (#630)
|
||||
- Always use builtin `exec` (#628)
|
||||
- Add `history-beginning-search-*-end` widgets to clear widget list (#619)
|
||||
- Switch CI from Circle CI to GitHub Actions
|
||||
|
||||
## v0.7.0
|
||||
- Enable asynchronous mode by default (#498)
|
||||
- No longer wrap user widgets starting with `autosuggest-` prefix (#496)
|
||||
- Fix a bug wrapping widgets that modify the buffer (#541)
|
||||
|
||||
|
||||
## v0.6.4
|
||||
- Fix `vi-forward-char` triggering a bell when using it to accept a suggestion (#488)
|
||||
- New configuration option to skip completion suggestions when buffer matches a pattern (#487)
|
||||
- New configuration option to ignore history entries matching a pattern (#456)
|
||||
|
||||
## v0.6.3
|
||||
- Fixed bug moving cursor to end of buffer after accepting suggestion (#453)
|
||||
|
||||
## v0.6.2
|
||||
- Fixed bug deleting the last character in the buffer in vi mode (#450)
|
||||
- Degrade gracefully when user doesn't have `zsh/system` module installed (#447)
|
||||
|
||||
## v0.6.1
|
||||
- Fixed bug occurring when `_complete` had been aliased (#443)
|
||||
|
||||
## v0.6.0
|
||||
- Added `completion` suggestion strategy powered by completion system (#111)
|
||||
- Allow setting `ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE` to an empty string (#422)
|
||||
- Don't fetch suggestions after copy-earlier-word (#439)
|
||||
- Allow users to unignore zle-\* widgets (e.g. zle-line-init) (#432)
|
||||
|
||||
|
||||
## v0.5.2
|
||||
- Allow disabling automatic widget re-binding for better performance (#418)
|
||||
- Fix async suggestions when `SH_WORD_SPLIT` is set
|
||||
- Refactor async mode to use process substitution instead of zpty (#417)
|
||||
|
||||
## v0.5.1
|
||||
- Speed up widget rebinding (#413)
|
||||
- Clean up global variable creations (#403)
|
||||
- Respect user's set options when running original widget (#402)
|
||||
|
||||
## v0.5.0
|
||||
- Don't overwrite config with default values (#335)
|
||||
- Support fallback strategies by supplying array to suggestion config var
|
||||
- Rename "default" suggestion strategy to "history" to name it based on what it actually does
|
||||
- Reset opts in some functions affected by `GLOB_SUBST` (#334)
|
||||
- Support widgets starting with dashes (ex: `-a-widget`) (#337)
|
||||
- Skip async tests in zsh versions less than 5.0.8 because of reliability issues
|
||||
- Fix handling of newline + carriage return in async pty (#333)
|
||||
|
||||
|
||||
## v0.4.3
|
||||
- Avoid bell when accepting suggestions with `autosuggest-accept` (#228)
|
||||
- Don't fetch suggestions after [up,down]-line-or-beginning-search (#227, #241)
|
||||
- We are now running CI against new 5.5.1 version
|
||||
- Fix partial-accept in vi mode (#188)
|
||||
- Fix suggestion disappearing on fast movement after switching to `vicmd` mode (#290)
|
||||
- Fix issue rotating through kill ring with `yank-pop` (#301)
|
||||
- Fix issue creating new pty for async mode when previous pty is not properly cleaned up (#249)
|
||||
|
||||
## v0.4.2
|
||||
- Fix bug in zsh versions older than 5.0.8 (#296)
|
||||
- Officially support back to zsh v4.3.11
|
||||
|
||||
## v0.4.1
|
||||
- Switch to [[ and (( conditionals instead of [ (#257)
|
||||
- Avoid warnnestedvar warnings with `typeset -g` (#275)
|
||||
- Replace tabs with spaces in yaml (#268)
|
||||
- Clean up and fix escaping of special characters (#267)
|
||||
- Add `emacs-forward-word` to default list of partial accept widgets (#246)
|
||||
|
||||
## v0.4.0
|
||||
- High-level integration tests using RSpec and tmux
|
||||
- Add continuous integration with Circle CI
|
||||
- Experimental support for asynchronous suggestions (#170)
|
||||
- Fix problems with multi-line suggestions (#225)
|
||||
- Optimize case where manually typing in suggestion
|
||||
- Avoid wrapping any zle-\* widgets (#206)
|
||||
- Remove support for deprecated options from v0.0.x
|
||||
- Handle history entries that begin with dashes
|
||||
- Gracefully handle being sourced multiple times (#126)
|
||||
- Add enable/disable/toggle widgets to disable/enable suggestions (#219)
|
||||
|
||||
|
||||
## v0.3.3
|
||||
- Switch from $history array to fc builtin for better performance with large HISTFILEs (#164)
|
||||
- Fix tilde handling when extended_glob is set (#168)
|
||||
- Add config option for maximum buffer length to fetch suggestions for (#178)
|
||||
- Add config option for list of widgets to ignore (#184)
|
||||
- Don't fetch a new suggestion unless a modification widget actually modifies the buffer (#183)
|
||||
|
||||
## v0.3.2
|
||||
- Test runner now supports running specific tests and choosing zsh binary
|
||||
- Return code from original widget is now correctly passed through (#135)
|
||||
- Add `vi-add-eol` to list of accept widgets (#143)
|
||||
- Escapes widget names within evals to fix problems with irregular widget names (#152)
|
||||
- Plugin now clears suggestion while within a completion menu (#149)
|
||||
- .plugin file no longer relies on symbolic link support, fixing issues on Windows (#156)
|
||||
|
||||
## v0.3.1
|
||||
|
||||
- Fixes issue with `vi-next-char` not accepting suggestion (#137).
|
||||
- Fixes global variable warning when WARN_CREATE_GLOBAL option enabled (#133).
|
||||
- Split out a separate test file for each widget.
|
||||
|
||||
## v0.3.0
|
||||
|
||||
- Adds `autosuggest-execute` widget (PR #124).
|
||||
- Adds concept of suggestion "strategies" for different ways of fetching suggestions.
|
||||
- Adds "match_prev_cmd" strategy (PR #131).
|
||||
- Uses git submodules for testing dependencies.
|
||||
- Lots of test cleanup.
|
||||
- Various bug fixes for zsh 5.0.x and `sh_word_split` option.
|
||||
|
||||
|
||||
## v0.2.17
|
||||
|
||||
Start of changelog.
|
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@ -0,0 +1,21 @@
|
||||
FROM ruby:2.5.3-alpine
|
||||
|
||||
ARG TEST_ZSH_VERSION
|
||||
RUN : "${TEST_ZSH_VERSION:?}"
|
||||
|
||||
RUN apk add --no-cache autoconf
|
||||
RUN apk add --no-cache libtool
|
||||
RUN apk add --no-cache libcap-dev
|
||||
RUN apk add --no-cache pcre-dev
|
||||
RUN apk add --no-cache curl
|
||||
RUN apk add --no-cache build-base
|
||||
RUN apk add --no-cache ncurses-dev
|
||||
RUN apk add --no-cache tmux
|
||||
|
||||
WORKDIR /zsh-autosuggestions
|
||||
|
||||
ADD install_test_zsh.sh ./
|
||||
RUN ./install_test_zsh.sh
|
||||
|
||||
ADD Gemfile Gemfile.lock ./
|
||||
RUN bundle install
|
5
Gemfile
Normal file
5
Gemfile
Normal file
@ -0,0 +1,5 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem 'rspec'
|
||||
gem 'rspec-wait'
|
||||
gem 'pry-byebug'
|
41
Gemfile.lock
Normal file
41
Gemfile.lock
Normal file
@ -0,0 +1,41 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
byebug (9.0.5)
|
||||
coderay (1.1.1)
|
||||
diff-lcs (1.3)
|
||||
method_source (0.8.2)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pry-byebug (3.4.0)
|
||||
byebug (~> 9.0)
|
||||
pry (~> 0.10)
|
||||
rspec (3.5.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
rspec-expectations (~> 3.5.0)
|
||||
rspec-mocks (~> 3.5.0)
|
||||
rspec-core (3.5.4)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-expectations (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-mocks (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-support (3.5.0)
|
||||
rspec-wait (0.0.9)
|
||||
rspec (>= 3, < 4)
|
||||
slop (3.6.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
pry-byebug
|
||||
rspec
|
||||
rspec-wait
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.6
|
81
INSTALL.md
Normal file
81
INSTALL.md
Normal file
@ -0,0 +1,81 @@
|
||||
# Installation
|
||||
|
||||
* [Packages](#packages)
|
||||
* [Antigen](#antigen)
|
||||
* [Oh My Zsh](#oh-my-zsh)
|
||||
* [HomeBrew](#homebrew)
|
||||
* [Manual](#manual-git-clone)
|
||||
|
||||
## Packages
|
||||
|
||||
| System | Package |
|
||||
| ------------- | ------------- |
|
||||
| Alpine Linux | [zsh-autosuggestions](https://pkgs.alpinelinux.org/packages?name=zsh-autosuggestions) |
|
||||
| Debian / Ubuntu | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
|
||||
| Fedora / CentOS / RHEL / Scientific Linux | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
|
||||
| OpenSUSE / SLE | [zsh-autosuggestions OBS repository](https://software.opensuse.org/download.html?project=shells%3Azsh-users%3Azsh-autosuggestions&package=zsh-autosuggestions) |
|
||||
| Arch Linux / Manjaro / Antergos / Hyperbola | [zsh-autosuggestions](https://www.archlinux.org/packages/zsh-autosuggestions), [zsh-autosuggestions-git](https://aur.archlinux.org/packages/zsh-autosuggestions-git) |
|
||||
| NixOS | [zsh-autosuggestions](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/zs/zsh-autosuggestions/package.nix) |
|
||||
| Void Linux | [zsh-autosuggestions](https://github.com/void-linux/void-packages/blob/master/srcpkgs/zsh-autosuggestions/template) |
|
||||
| Mac OS | [homebrew](https://github.com/Homebrew/homebrew-core/blob/master/Formula/z/zsh-autosuggestions.rb) |
|
||||
| NetBSD | [pkgsrc](http://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/shells/zsh-autosuggestions/README.html) |
|
||||
|
||||
## Antigen
|
||||
|
||||
1. Add the following to your `.zshrc`:
|
||||
|
||||
```sh
|
||||
antigen bundle zsh-users/zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. Start a new terminal session.
|
||||
|
||||
## Oh My Zsh
|
||||
|
||||
1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
|
||||
|
||||
```sh
|
||||
git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. Add the plugin to the list of plugins for Oh My Zsh to load (inside `~/.zshrc`):
|
||||
|
||||
```sh
|
||||
plugins=(
|
||||
# other plugins...
|
||||
zsh-autosuggestions
|
||||
)
|
||||
```
|
||||
|
||||
3. Start a new terminal session.
|
||||
|
||||
## Homebrew
|
||||
|
||||
1. Install command:
|
||||
```sh
|
||||
brew install zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. To activate the autosuggestions, add the following at the end of your .zshrc:
|
||||
|
||||
```sh
|
||||
source $(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
```
|
||||
|
||||
3. Start a new terminal session.
|
||||
|
||||
## Manual (Git Clone)
|
||||
|
||||
1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. Add the following to your `.zshrc`:
|
||||
|
||||
```sh
|
||||
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
```
|
||||
|
||||
3. Start a new terminal session.
|
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
Copyright (c) 2013 Thiago de Arruda
|
||||
Copyright (c) 2016 Eric Freese
|
||||
Copyright (c) 2016-2021 Eric Freese
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
24
Makefile
24
Makefile
@ -1,13 +1,14 @@
|
||||
SRC_DIR := ./src
|
||||
SCRIPT_DIR := ./script
|
||||
SRC_DIR := ./src
|
||||
|
||||
SRC_FILES := \
|
||||
$(SRC_DIR)/config.zsh \
|
||||
$(SRC_DIR)/deprecated.zsh \
|
||||
$(SRC_DIR)/util.zsh \
|
||||
$(SRC_DIR)/bind.zsh \
|
||||
$(SRC_DIR)/highlight.zsh \
|
||||
$(SRC_DIR)/widgets.zsh \
|
||||
$(SRC_DIR)/suggestion.zsh \
|
||||
$(SRC_DIR)/strategies/*.zsh \
|
||||
$(SRC_DIR)/fetch.zsh \
|
||||
$(SRC_DIR)/async.zsh \
|
||||
$(SRC_DIR)/start.zsh
|
||||
|
||||
HEADER_FILES := \
|
||||
@ -17,25 +18,18 @@ HEADER_FILES := \
|
||||
LICENSE
|
||||
|
||||
PLUGIN_TARGET := zsh-autosuggestions.zsh
|
||||
OH_MY_ZSH_LINK_TARGET := zsh-autosuggestions.plugin.zsh
|
||||
|
||||
ALL_TARGETS := \
|
||||
$(PLUGIN_TARGET) \
|
||||
$(OH_MY_ZSH_LINK_TARGET)
|
||||
|
||||
all: $(ALL_TARGETS)
|
||||
all: $(PLUGIN_TARGET)
|
||||
|
||||
$(PLUGIN_TARGET): $(HEADER_FILES) $(SRC_FILES)
|
||||
cat $(HEADER_FILES) | sed -e 's/^/# /g' > $@
|
||||
cat $(SRC_FILES) >> $@
|
||||
|
||||
$(OH_MY_ZSH_LINK_TARGET): $(PLUGIN_TARGET)
|
||||
ln -s $(PLUGIN_TARGET) $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm $(ALL_TARGETS)
|
||||
rm $(PLUGIN_TARGET)
|
||||
|
||||
.PHONY: test
|
||||
test: all
|
||||
$(SCRIPT_DIR)/test.zsh
|
||||
@test -n "$$TEST_ZSH_BIN" && echo "Testing zsh binary: $(TEST_ZSH_BIN)" || true
|
||||
bundle exec rspec $(TESTS)
|
||||
|
163
README.md
163
README.md
@ -2,45 +2,18 @@
|
||||
|
||||
_[Fish](http://fishshell.com/)-like fast/unobtrusive autosuggestions for zsh._
|
||||
|
||||
It suggests commands as you type, based on command history.
|
||||
It suggests commands as you type based on history and completions.
|
||||
|
||||
Requirements: Zsh v4.3.11 or later
|
||||
|
||||
[](https://gitter.im/zsh-users/zsh-autosuggestions)
|
||||
|
||||
<a href="https://asciinema.org/a/37390" target="_blank"><img src="https://asciinema.org/a/37390.png" width="400" /></a>
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
### Manual
|
||||
|
||||
1. Clone this repository somewhere on your machine. This guide will assume `~/.zsh/zsh-autosuggestions`.
|
||||
|
||||
```sh
|
||||
git clone git://github.com/tarruda/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. Add the following to your `.zshrc`:
|
||||
|
||||
```sh
|
||||
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
```
|
||||
|
||||
3. Start a new terminal session.
|
||||
|
||||
|
||||
### Oh My Zsh
|
||||
|
||||
1. Clone this repository into `$ZSH_CUSTOM/plugins` (by default `~/.oh-my-zsh/custom/plugins`)
|
||||
|
||||
```sh
|
||||
git clone git://github.com/tarruda/zsh-autosuggestions $ZSH_CUSTOM/plugins/zsh-autosuggestions
|
||||
```
|
||||
|
||||
2. Add the plugin to the list of plugins for Oh My Zsh to load:
|
||||
|
||||
```sh
|
||||
plugins=(zsh-autosuggestions)
|
||||
```
|
||||
|
||||
3. Start a new terminal session.
|
||||
|
||||
**Note:** There is an open issue ([#102](https://github.com/tarruda/zsh-autosuggestions/issues/102)) when using this plugin with `bracketed-paste-magic`, which is enabled by default by Oh My Zsh. See the comments in that issue for a workaround.
|
||||
See [INSTALL.md](INSTALL.md).
|
||||
|
||||
|
||||
## Usage
|
||||
@ -54,14 +27,35 @@ If you invoke the `forward-word` widget, it will partially accept the suggestion
|
||||
|
||||
## Configuration
|
||||
|
||||
You may want to override the default global config variables after sourcing the plugin. Default values of these variables can be found [here](src/config.zsh).
|
||||
You may want to override the default global config variables. Default values of these variables can be found [here](src/config.zsh).
|
||||
|
||||
**Note:** If you are using Oh My Zsh, you can put this configuration in a file in the `$ZSH_CUSTOM` directory. See their comments on [overriding internals](https://github.com/robbyrussell/oh-my-zsh/wiki/Customization#overriding-internals).
|
||||
|
||||
|
||||
### Suggestion Highlight Style
|
||||
|
||||
Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion is shown with. The default is `fg=8`.
|
||||
Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion is shown with. The default is `fg=8`, which will set the foreground color to color 8 from the [256-color palette](https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg). If your terminal only supports 8 colors, you will need to use a number between 0 and 7.
|
||||
|
||||
Background color can also be set, and the suggestion can be styled bold, underlined, or standout. For example, this would show suggestions with bold, underlined, pink text on a cyan background:
|
||||
|
||||
```sh
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=#ff00ff,bg=cyan,bold,underline"
|
||||
```
|
||||
|
||||
For more info, read the Character Highlighting section of the zsh manual: `man zshzle` or [online](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Character-Highlighting).
|
||||
|
||||
**Note:** Some iTerm2 users have reported [not being able to see the suggestions](https://github.com/zsh-users/zsh-autosuggestions/issues/416#issuecomment-486516333). If this affects you, the problem is likely caused by incorrect color settings. In order to correct this, go into iTerm2's setting, navigate to profile > colors and make sure that the colors for Basic Colors > Background and ANSI Colors > Bright Black are **different**.
|
||||
|
||||
|
||||
### Suggestion Strategy
|
||||
|
||||
`ZSH_AUTOSUGGEST_STRATEGY` is an array that specifies how suggestions should be generated. The strategies in the array are tried successively until a suggestion is found. There are currently three built-in strategies to choose from:
|
||||
|
||||
- `history`: Chooses the most recent match from history.
|
||||
- `completion`: Chooses a suggestion based on what tab-completion would suggest. (requires `zpty` module, which is included with zsh since 4.0.1)
|
||||
- `match_prev_cmd`: Like `history`, but chooses the most recent match whose preceding history item matches the most recently executed command ([more info](src/strategies/match_prev_cmd.zsh)). Note that this strategy won't work as expected with ZSH options that don't preserve the history order such as `HIST_IGNORE_ALL_DUPS` or `HIST_EXPIRE_DUPS_FIRST`.
|
||||
|
||||
For example, setting `ZSH_AUTOSUGGEST_STRATEGY=(history completion)` will first try to find a suggestion from your history, but, if it can't find a match, will find a suggestion from the completion engine.
|
||||
|
||||
|
||||
### Widget Mapping
|
||||
@ -69,19 +63,55 @@ Set `ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE` to configure the style that the suggestion
|
||||
This plugin works by triggering custom behavior when certain [zle widgets](http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets) are invoked. You can add and remove widgets from these arrays to change the behavior of this plugin:
|
||||
|
||||
- `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`: Widgets in this array will clear the suggestion when invoked.
|
||||
- `ZSH_AUTOSUGGEST_MODIFY_WIDGETS`: Widgets in this array will modify the buffer and fetch a new suggestion when invoked.
|
||||
- `ZSH_AUTOSUGGEST_ACCEPT_WIDGETS`: Widgets in this array will accept the suggestion when invoked.
|
||||
- `ZSH_AUTOSUGGEST_EXECUTE_WIDGETS`: Widgets in this array will execute the suggestion when invoked.
|
||||
- `ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS`: Widgets in this array will partially accept the suggestion when invoked.
|
||||
- `ZSH_AUTOSUGGEST_IGNORE_WIDGETS`: Widgets in this array will not trigger any custom behavior.
|
||||
|
||||
Widgets that modify the buffer and are not found in any of these arrays will fetch a new suggestion after they are invoked.
|
||||
|
||||
**Note:** A widget shouldn't belong to more than one of the above arrays.
|
||||
|
||||
|
||||
### Disabling suggestion for large buffers
|
||||
|
||||
Set `ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE` to an integer value to disable autosuggestion for large buffers. The default is unset, which means that autosuggestion will be tried for any buffer size. Recommended value is 20.
|
||||
This can be useful when pasting large amount of text in the terminal, to avoid triggering autosuggestion for strings that are too long.
|
||||
|
||||
### Asynchronous Mode
|
||||
|
||||
Suggestions are fetched asynchronously by default in zsh versions 5.0.8 and greater. To disable asynchronous suggestions and fetch them synchronously instead, `unset ZSH_AUTOSUGGEST_USE_ASYNC` after sourcing the plugin.
|
||||
|
||||
Alternatively, if you are using a version of zsh older than 5.0.8 and want to enable asynchronous mode, set the `ZSH_AUTOSUGGEST_USE_ASYNC` variable after sourcing the plugin (it can be set to anything). Note that there is [a bug](https://github.com/zsh-users/zsh-autosuggestions/issues/364#issuecomment-481423232) in versions of zsh older than 5.0.8 where <kbd>ctrl</kbd> + <kbd>c</kbd> will fail to reset the prompt immediately after fetching a suggestion asynchronously.
|
||||
|
||||
### Disabling automatic widget re-binding
|
||||
|
||||
Set `ZSH_AUTOSUGGEST_MANUAL_REBIND` (it can be set to anything) to disable automatic widget re-binding on each precmd. This can be a big boost to performance, but you'll need to handle re-binding yourself if any of the widget lists change or if you or another plugin wrap any of the autosuggest widgets. To re-bind widgets, run `_zsh_autosuggest_bind_widgets`.
|
||||
|
||||
### Ignoring history suggestions that match a pattern
|
||||
|
||||
Set `ZSH_AUTOSUGGEST_HISTORY_IGNORE` to a [glob pattern](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators) to prevent offering suggestions for history entries that match the pattern. For example, set it to `"cd *"` to never suggest any `cd` commands from history. Or set to `"?(#c50,)"` to never suggest anything 50 characters or longer.
|
||||
|
||||
**Note:** This only affects the `history` and `match_prev_cmd` suggestion strategies.
|
||||
|
||||
### Skipping completion suggestions for certain cases
|
||||
|
||||
Set `ZSH_AUTOSUGGEST_COMPLETION_IGNORE` to a [glob pattern](http://zsh.sourceforge.net/Doc/Release/Expansion.html#Glob-Operators) to prevent offering completion suggestions when the buffer matches that pattern. For example, set it to `"git *"` to disable completion suggestions for git subcommands.
|
||||
|
||||
**Note:** This only affects the `completion` suggestion strategy.
|
||||
|
||||
|
||||
### Key Bindings
|
||||
|
||||
This plugin provides two widgets that you can use with `bindkey`:
|
||||
This plugin provides a few widgets that you can use with `bindkey`:
|
||||
|
||||
1. `autosuggest-accept`: Accepts the current suggestion.
|
||||
2. `autosuggest-clear`: Clears the current suggestion.
|
||||
2. `autosuggest-execute`: Accepts and executes the current suggestion.
|
||||
3. `autosuggest-clear`: Clears the current suggestion.
|
||||
4. `autosuggest-fetch`: Fetches a suggestion (works even when suggestions are disabled).
|
||||
5. `autosuggest-disable`: Disables suggestions.
|
||||
6. `autosuggest-enable`: Re-enables suggestions.
|
||||
7. `autosuggest-toggle`: Toggles between enabled/disabled suggestions.
|
||||
|
||||
For example, this would bind <kbd>ctrl</kbd> + <kbd>space</kbd> to accept the current suggestion.
|
||||
|
||||
@ -90,41 +120,9 @@ bindkey '^ ' autosuggest-accept
|
||||
```
|
||||
|
||||
|
||||
## Compatibility With Other ZLE Plugins
|
||||
|
||||
### [`zsh-history-substring-search`](https://github.com/zsh-users/zsh-history-substring-search)
|
||||
|
||||
When the buffer is empty and one of the `history-substring-search-up/down` widgets is invoked, it will call the `up/down-line-or-history` widget. If the `up/down-line-or-history` widgets are in `ZSH_AUTOSUGGEST_CLEAR_WIDGETS` (the list of widgets that clear the suggestion), this can create an infinite recursion, crashing the shell session.
|
||||
|
||||
For best results, you'll want to remove `up-line-or-history` and `down-line-or-history` from `ZSH_AUTOSUGGEST_CLEAR_WIDGETS`:
|
||||
|
||||
```
|
||||
# Remove *-line-or-history widgets from list of widgets that clear the autosuggestion to avoid conflict with history-substring-search-* widgets
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=("${(@)ZSH_AUTOSUGGEST_CLEAR_WIDGETS:#(up|down)-line-or-history}")
|
||||
```
|
||||
|
||||
Additionally, the `history-substring-search-up` and `history-substring-search-down` widgets are not bound by default. You'll probably want to add them to `ZSH_AUTOSUGGEST_CLEAR_WIDGETS` so that the suggestion will be cleared when you start searching through history:
|
||||
|
||||
```sh
|
||||
# Add history-substring-search-* widgets to list of widgets that clear the autosuggestion
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(history-substring-search-up history-substring-search-down)
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```sh
|
||||
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
|
||||
source ~/Code/zsh-history-substring-search/zsh-history-substring-search.zsh
|
||||
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=("${(@)ZSH_AUTOSUGGEST_CLEAR_WIDGETS:#(up|down)-line-or-history}")
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(history-substring-search-up history-substring-search-down)
|
||||
```
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If you have a problem, please search through [the list of issues on GitHub](https://github.com/tarruda/zsh-autosuggestions/issues) to see if someone else has already reported it.
|
||||
|
||||
If you have a problem, please search through [the list of issues on GitHub](https://github.com/zsh-users/zsh-autosuggestions/issues?q=) to see if someone else has already reported it.
|
||||
|
||||
### Reporting an Issue
|
||||
|
||||
@ -132,7 +130,7 @@ Before reporting an issue, please try temporarily disabling sections of your con
|
||||
|
||||
When reporting an issue, please include:
|
||||
|
||||
- The smallest, simplest `.zshrc` configuration that will reproduce the problem
|
||||
- The smallest, simplest `.zshrc` configuration that will reproduce the problem. See [this comment](https://github.com/zsh-users/zsh-autosuggestions/issues/102#issuecomment-180944764) for a good example of what this means.
|
||||
- The version of zsh you're using (`zsh --version`)
|
||||
- Which operating system you're running
|
||||
|
||||
@ -159,6 +157,7 @@ Edit the source files in `src/`. Run `make` to build `zsh-autosuggestions.zsh` f
|
||||
|
||||
Pull requests are welcome! If you send a pull request, please:
|
||||
|
||||
- Request to merge into the `develop` branch (*NOT* `master`)
|
||||
- Match the existing coding conventions.
|
||||
- Include helpful comments to keep the barrier-to-entry low for people new to the project.
|
||||
- Write tests that cover your code as much as possible.
|
||||
@ -166,9 +165,21 @@ Pull requests are welcome! If you send a pull request, please:
|
||||
|
||||
### Testing
|
||||
|
||||
Testing is performed with [`shunit2`](https://github.com/kward/shunit2) (v2.1.6). Documentation can be found [here](http://shunit2.googlecode.com/svn/trunk/source/2.1/doc/shunit2.html).
|
||||
Tests are written in ruby using the [`rspec`](http://rspec.info/) framework. They use [`tmux`](https://tmux.github.io/) to drive a pseudoterminal, sending simulated keystrokes and making assertions on the terminal content.
|
||||
|
||||
The test script lives at `script/test.zsh`. To run the tests, run `make test`.
|
||||
Test files live in `spec/`. To run the tests, run `make test`. To run a specific test, run `TESTS=spec/some_spec.rb make test`. You can also specify a `zsh` binary to use by setting the `TEST_ZSH_BIN` environment variable (ex: `TEST_ZSH_BIN=/bin/zsh make test`).
|
||||
|
||||
It's possible to run the tests for any supported version of zsh in a Docker image by building an image from the provided Dockerfile. To build the docker image for a specific version of zsh (where `<version>` below is substituted with the contents of a line from the [`ZSH_VERSIONS`](ZSH_VERSIONS) file), run:
|
||||
|
||||
```sh
|
||||
docker build --build-arg TEST_ZSH_VERSION=<version> -t zsh-autosuggestions-test .
|
||||
```
|
||||
|
||||
After building the image, run the tests via:
|
||||
|
||||
```sh
|
||||
docker run -it -v $PWD:/zsh-autosuggestions zsh-autosuggestions-test make test
|
||||
```
|
||||
|
||||
|
||||
## License
|
||||
|
2
URL
2
URL
@ -1 +1 @@
|
||||
https://github.com/tarruda/zsh-autosuggestions
|
||||
https://github.com/zsh-users/zsh-autosuggestions
|
||||
|
14
ZSH_VERSIONS
Normal file
14
ZSH_VERSIONS
Normal file
@ -0,0 +1,14 @@
|
||||
# Zsh releases to run tests against
|
||||
# See https://github.com/zsh-users/zsh/releases
|
||||
4.3.11
|
||||
5.0.2
|
||||
5.0.8
|
||||
5.1.1
|
||||
5.2
|
||||
5.3.1
|
||||
5.4.2
|
||||
5.5.1
|
||||
5.6.2
|
||||
5.7.1
|
||||
5.8.1
|
||||
5.9
|
23
install_test_zsh.sh
Executable file
23
install_test_zsh.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -ex
|
||||
|
||||
mkdir zsh-build
|
||||
cd zsh-build
|
||||
|
||||
curl -L https://api.github.com/repos/zsh-users/zsh/tarball/zsh-$TEST_ZSH_VERSION | tar xz --strip=1
|
||||
|
||||
./Util/preconfig
|
||||
./configure --enable-pcre \
|
||||
--enable-cap \
|
||||
--enable-multibyte \
|
||||
--with-term-lib='ncursesw tinfo' \
|
||||
--with-tcsetpgrp
|
||||
|
||||
make install.bin
|
||||
make install.modules
|
||||
make install.fns
|
||||
|
||||
cd ..
|
||||
|
||||
rm -rf zsh-build
|
288
script/test.zsh
288
script/test.zsh
@ -1,288 +0,0 @@
|
||||
#!/usr/bin/env zsh
|
||||
|
||||
SCRIPT_DIR=$(dirname "$0")
|
||||
TEST_DIR=$SCRIPT_DIR/../test
|
||||
DIST_DIR=$SCRIPT_DIR/../
|
||||
|
||||
# Use stub.sh for stubbing/mocking
|
||||
source $TEST_DIR/stub-1.0.2.sh
|
||||
|
||||
source $DIST_DIR/zsh-autosuggestions.zsh
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Highlighting #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
testHighlightDefaultStyle() {
|
||||
assertEquals \
|
||||
"fg=8" \
|
||||
"$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
|
||||
}
|
||||
|
||||
testHighlightApplyWithSuggestion() {
|
||||
orig_style=ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=4"
|
||||
|
||||
BUFFER="ec"
|
||||
POSTDISPLAY="ho hello"
|
||||
region_highlight=("0 2 fg=1")
|
||||
|
||||
_zsh_autosuggest_highlight_apply
|
||||
|
||||
assertEquals \
|
||||
"highlight did not use correct style" \
|
||||
"0 2 fg=1 2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \
|
||||
"$region_highlight"
|
||||
|
||||
assertEquals \
|
||||
"higlight was not saved to be removed later" \
|
||||
"2 10 $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" \
|
||||
"$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
|
||||
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=orig_style
|
||||
}
|
||||
|
||||
testHighlightApplyWithoutSuggestion() {
|
||||
BUFFER="echo hello"
|
||||
POSTDISPLAY=""
|
||||
region_highlight=("0 4 fg=1")
|
||||
|
||||
_zsh_autosuggest_highlight_apply
|
||||
|
||||
assertEquals \
|
||||
"region_highlight was modified" \
|
||||
"0 4 fg=1" \
|
||||
"$region_highlight"
|
||||
|
||||
assertNull \
|
||||
"last highlight region was not cleared" \
|
||||
"$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
|
||||
}
|
||||
|
||||
testHighlightReset() {
|
||||
BUFFER="ec"
|
||||
POSTDISPLAY="ho hello"
|
||||
region_highlight=("0 1 fg=1" "2 10 fg=8" "1 2 fg=1")
|
||||
_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="2 10 fg=8"
|
||||
|
||||
_zsh_autosuggest_highlight_reset
|
||||
|
||||
assertEquals \
|
||||
"last highlight region was not removed" \
|
||||
"0 1 fg=1 1 2 fg=1" \
|
||||
"$region_highlight"
|
||||
|
||||
assertNull \
|
||||
"last highlight variable was not cleared" \
|
||||
"$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT"
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Widgets #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
testWidgetFunctionClear() {
|
||||
BUFFER="ec"
|
||||
POSTDISPLAY="ho hello"
|
||||
|
||||
_zsh_autosuggest_clear
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was modified" \
|
||||
"ec" \
|
||||
"$BUFFER"
|
||||
|
||||
assertNull \
|
||||
"POSTDISPLAY was not cleared" \
|
||||
"$POSTDISPLAY"
|
||||
}
|
||||
|
||||
testWidgetFunctionModify() {
|
||||
BUFFER=""
|
||||
POSTDISPLAY=""
|
||||
|
||||
stub_and_eval \
|
||||
_zsh_autosuggest_invoke_original_widget \
|
||||
'BUFFER+="e"'
|
||||
|
||||
stub_and_echo \
|
||||
_zsh_autosuggest_suggestion \
|
||||
"echo hello"
|
||||
|
||||
_zsh_autosuggest_modify
|
||||
|
||||
assertTrue \
|
||||
"original widget not invoked" \
|
||||
"stub_called _zsh_autosuggest_invoke_original_widget"
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was not modified" \
|
||||
"e" \
|
||||
"$BUFFER"
|
||||
|
||||
assertEquals \
|
||||
"POSTDISPLAY does not contain suggestion" \
|
||||
"cho hello" \
|
||||
"$POSTDISPLAY"
|
||||
|
||||
restore _zsh_autosuggest_invoke_original_widget
|
||||
restore _zsh_autosuggest_suggestion
|
||||
}
|
||||
|
||||
testWidgetFunctionAcceptCursorAtEnd() {
|
||||
BUFFER="echo"
|
||||
POSTDISPLAY=" hello"
|
||||
CURSOR=4
|
||||
|
||||
stub _zsh_autosuggest_invoke_original_widget
|
||||
|
||||
_zsh_autosuggest_accept
|
||||
|
||||
assertTrue \
|
||||
"original widget not invoked" \
|
||||
"stub_called _zsh_autosuggest_invoke_original_widget"
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was not modified" \
|
||||
"echo hello" \
|
||||
"$BUFFER"
|
||||
|
||||
assertEquals \
|
||||
"POSTDISPLAY was not cleared" \
|
||||
"" \
|
||||
"$POSTDISPLAY"
|
||||
}
|
||||
|
||||
testWidgetFunctionAcceptCursorNotAtEnd() {
|
||||
BUFFER="echo"
|
||||
POSTDISPLAY=" hello"
|
||||
CURSOR=2
|
||||
|
||||
stub _zsh_autosuggest_invoke_original_widget
|
||||
|
||||
_zsh_autosuggest_accept
|
||||
|
||||
assertTrue \
|
||||
"original widget not invoked" \
|
||||
"stub_called _zsh_autosuggest_invoke_original_widget"
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was modified" \
|
||||
"echo" \
|
||||
"$BUFFER"
|
||||
|
||||
assertEquals \
|
||||
"POSTDISPLAY was modified" \
|
||||
" hello" \
|
||||
"$POSTDISPLAY"
|
||||
}
|
||||
|
||||
testWidgetFunctionPartialAcceptCursorMovesOutOfBuffer() {
|
||||
BUFFER="ec"
|
||||
POSTDISPLAY="ho hello"
|
||||
CURSOR=1
|
||||
|
||||
stub_and_eval \
|
||||
_zsh_autosuggest_invoke_original_widget \
|
||||
'CURSOR=5; LBUFFER="echo "; RBUFFER="hello"'
|
||||
|
||||
_zsh_autosuggest_partial_accept
|
||||
|
||||
assertTrue \
|
||||
"original widget not invoked" \
|
||||
"stub_called _zsh_autosuggest_invoke_original_widget"
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was not modified correctly" \
|
||||
"echo " \
|
||||
"$BUFFER"
|
||||
|
||||
assertEquals \
|
||||
"POSTDISPLAY was not modified correctly" \
|
||||
"hello" \
|
||||
"$POSTDISPLAY"
|
||||
}
|
||||
|
||||
testWidgetFunctionPartialAcceptCursorStaysInBuffer() {
|
||||
BUFFER="echo hello"
|
||||
POSTDISPLAY=" world"
|
||||
CURSOR=1
|
||||
|
||||
stub_and_eval \
|
||||
_zsh_autosuggest_invoke_original_widget \
|
||||
'CURSOR=5; LBUFFER="echo "; RBUFFER="hello"'
|
||||
|
||||
_zsh_autosuggest_partial_accept
|
||||
|
||||
assertTrue \
|
||||
"original widget not invoked" \
|
||||
"stub_called _zsh_autosuggest_invoke_original_widget"
|
||||
|
||||
assertEquals \
|
||||
"BUFFER was modified" \
|
||||
"echo hello" \
|
||||
"$BUFFER"
|
||||
|
||||
assertEquals \
|
||||
"POSTDISPLAY was modified" \
|
||||
" world" \
|
||||
"$POSTDISPLAY"
|
||||
}
|
||||
|
||||
testWidgetAccept() {
|
||||
stub _zsh_autosuggest_highlight_reset
|
||||
stub _zsh_autosuggest_accept
|
||||
stub _zsh_autosuggest_highlight_apply
|
||||
|
||||
# Call the function pointed to by the widget since we can't call
|
||||
# the widget itself when zle is not active
|
||||
${widgets[autosuggest-accept]#*:}
|
||||
|
||||
assertTrue \
|
||||
"autosuggest-accept widget does not exist" \
|
||||
"zle -l autosuggest-accept"
|
||||
|
||||
assertTrue \
|
||||
"highlight_reset was not called" \
|
||||
"stub_called _zsh_autosuggest_highlight_reset"
|
||||
|
||||
assertTrue \
|
||||
"widget function was not called" \
|
||||
"stub_called _zsh_autosuggest_accept"
|
||||
|
||||
assertTrue \
|
||||
"highlight_apply was not called" \
|
||||
"stub_called _zsh_autosuggest_highlight_apply"
|
||||
}
|
||||
|
||||
testWidgetClear() {
|
||||
stub _zsh_autosuggest_highlight_reset
|
||||
stub _zsh_autosuggest_clear
|
||||
stub _zsh_autosuggest_highlight_apply
|
||||
|
||||
# Call the function pointed to by the widget since we can't call
|
||||
# the widget itself when zle is not active
|
||||
${widgets[autosuggest-clear]#*:}
|
||||
|
||||
assertTrue \
|
||||
"autosuggest-clear widget does not exist" \
|
||||
"zle -l autosuggest-clear"
|
||||
|
||||
assertTrue \
|
||||
"highlight_reset was not called" \
|
||||
"stub_called _zsh_autosuggest_highlight_reset"
|
||||
|
||||
assertTrue \
|
||||
"widget function was not called" \
|
||||
"stub_called _zsh_autosuggest_clear"
|
||||
|
||||
assertTrue \
|
||||
"highlight_apply was not called" \
|
||||
"stub_called _zsh_autosuggest_highlight_apply"
|
||||
}
|
||||
|
||||
# For zsh compatibility
|
||||
setopt shwordsplit
|
||||
SHUNIT_PARENT=$0
|
||||
|
||||
source $TEST_DIR/shunit2-2.1.6/src/shunit2
|
70
spec/async_spec.rb
Normal file
70
spec/async_spec.rb
Normal file
@ -0,0 +1,70 @@
|
||||
context 'with asynchronous suggestions enabled' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_USE_ASYNC="] }
|
||||
|
||||
describe '`up-line-or-beginning-search`' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('autoload -U up-line-or-beginning-search').
|
||||
run_command('zle -N up-line-or-beginning-search').
|
||||
send_string('bindkey "').
|
||||
send_keys('C-v').send_keys('up').
|
||||
send_string('" up-line-or-beginning-search').
|
||||
send_keys('enter')
|
||||
end
|
||||
end
|
||||
|
||||
it 'should show previous history entries' do
|
||||
with_history(
|
||||
'echo foo',
|
||||
'echo bar',
|
||||
'echo baz'
|
||||
) do
|
||||
session.clear_screen
|
||||
3.times { session.send_keys('up') }
|
||||
wait_for { session.content }.to eq("echo foo")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '`copy-earlier-word`' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('autoload -Uz copy-earlier-word').
|
||||
run_command('zle -N copy-earlier-word').
|
||||
run_command('bindkey "^N" copy-earlier-word')
|
||||
end
|
||||
end
|
||||
|
||||
it 'should cycle through previous words in the buffer' do
|
||||
session.clear_screen
|
||||
session.send_string('foo bar baz')
|
||||
sleep 0.5
|
||||
session.send_keys('C-n')
|
||||
wait_for { session.content }.to eq('foo bar bazbaz')
|
||||
session.send_keys('C-n')
|
||||
wait_for { session.content }.to eq('foo bar bazbar')
|
||||
session.send_keys('C-n')
|
||||
wait_for { session.content }.to eq('foo bar bazfoo')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'pressing ^C after fetching a suggestion' do
|
||||
before do
|
||||
skip 'Workaround does not work below v5.0.8' if session.zsh_version < Gem::Version.new('5.0.8')
|
||||
end
|
||||
|
||||
it 'terminates the prompt and begins a new one' do
|
||||
session.send_keys('e')
|
||||
sleep 0.5
|
||||
session.send_keys('C-c')
|
||||
sleep 0.5
|
||||
session.send_keys('echo')
|
||||
|
||||
wait_for { session.content }.to eq("e\necho")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
14
spec/integrations/auto_cd_spec.rb
Normal file
14
spec/integrations/auto_cd_spec.rb
Normal file
@ -0,0 +1,14 @@
|
||||
describe 'with `AUTO_CD` option set' do
|
||||
let(:after_sourcing) do
|
||||
-> {
|
||||
session.run_command('setopt AUTO_CD')
|
||||
session.run_command('autoload compinit && compinit')
|
||||
}
|
||||
end
|
||||
|
||||
it 'directory names are still completed' do
|
||||
session.send_string('sr')
|
||||
session.send_keys('C-i')
|
||||
wait_for { session.content }.to eq('src/')
|
||||
end
|
||||
end
|
43
spec/integrations/bracketed_paste_magic_spec.rb
Normal file
43
spec/integrations/bracketed_paste_magic_spec.rb
Normal file
@ -0,0 +1,43 @@
|
||||
describe 'pasting using bracketed-paste-magic' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('autoload -Uz bracketed-paste-magic').
|
||||
run_command('zle -N bracketed-paste bracketed-paste-magic')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with suggestions disabled while pasting' do
|
||||
before do
|
||||
session.
|
||||
run_command('bpm_init() { zle autosuggest-disable }').
|
||||
run_command('bpm_finish() { zle autosuggest-enable }').
|
||||
run_command('zstyle :bracketed-paste-magic paste-init bpm_init').
|
||||
run_command('zstyle :bracketed-paste-magic paste-finish bpm_finish')
|
||||
end
|
||||
|
||||
it 'does not show an incorrect suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.paste_string("echo #{'a' * 60}")
|
||||
sleep 1
|
||||
expect(session.content).to eq("echo #{'a' * 60}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with `bracketed-paste` added to the list of widgets that clear the suggestion' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(bracketed-paste)'] }
|
||||
|
||||
it 'does not retain an old suggestion' do
|
||||
with_history ('echo foo') do
|
||||
session.send_string('echo ')
|
||||
wait_for { session.content }.to eq('echo foo')
|
||||
session.paste_string('bar')
|
||||
wait_for { session.content }.to eq('echo bar')
|
||||
session.send_keys('C-a') # Any cursor movement works
|
||||
sleep 1
|
||||
expect(session.content).to eq('echo bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
14
spec/integrations/client_zpty_spec.rb
Normal file
14
spec/integrations/client_zpty_spec.rb
Normal file
@ -0,0 +1,14 @@
|
||||
describe 'a running zpty command' do
|
||||
let(:before_sourcing) { -> { session.run_command('zmodload zsh/zpty && zpty -b kitty cat') } }
|
||||
|
||||
context 'when using `completion` strategy' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_STRATEGY=completion"] }
|
||||
|
||||
it 'is not affected' do
|
||||
session.send_keys('a').send_keys('C-h')
|
||||
session.run_command('zpty -t kitty; echo $?')
|
||||
|
||||
wait_for { session.content }.to end_with("\n0")
|
||||
end
|
||||
end
|
||||
end
|
12
spec/integrations/glob_subst_spec.rb
Normal file
12
spec/integrations/glob_subst_spec.rb
Normal file
@ -0,0 +1,12 @@
|
||||
describe 'with `GLOB_SUBST` option set' do
|
||||
let(:after_sourcing) do
|
||||
-> {
|
||||
session.run_command('setopt GLOB_SUBST')
|
||||
}
|
||||
end
|
||||
|
||||
it 'error messages are not printed' do
|
||||
session.send_string('[[')
|
||||
wait_for { session.content }.to eq('[[')
|
||||
end
|
||||
end
|
13
spec/integrations/rebound_bracket_spec.rb
Normal file
13
spec/integrations/rebound_bracket_spec.rb
Normal file
@ -0,0 +1,13 @@
|
||||
describe 'rebinding [' do
|
||||
context 'initialized before sourcing the plugin' do
|
||||
before do
|
||||
session.run_command("function [ { $commands[\\[] \"$@\" }")
|
||||
session.clear_screen
|
||||
end
|
||||
|
||||
it 'executes the custom behavior and the built-in behavior' do
|
||||
session.send_string('asdf')
|
||||
wait_for { session.content }.to eq('asdf')
|
||||
end
|
||||
end
|
||||
end
|
80
spec/integrations/vi_mode_spec.rb
Normal file
80
spec/integrations/vi_mode_spec.rb
Normal file
@ -0,0 +1,80 @@
|
||||
describe 'when using vi mode' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.run_command('bindkey -v')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'moving the cursor after exiting insert mode' do
|
||||
it 'should not clear the current suggestion' do
|
||||
with_history('foobar foo') do
|
||||
session.
|
||||
send_string('foo').
|
||||
send_keys('escape').
|
||||
send_keys('h')
|
||||
|
||||
wait_for { session.content }.to eq('foobar foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '`vi-forward-word-end`' do
|
||||
it 'should accept through the end of the current word' do
|
||||
with_history('foobar foo') do
|
||||
session.
|
||||
send_string('foo').
|
||||
send_keys('escape').
|
||||
send_keys('e'). # vi-forward-word-end
|
||||
send_keys('a'). # vi-add-next
|
||||
send_string('baz')
|
||||
|
||||
wait_for { session.content }.to eq('foobarbaz')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '`vi-forward-word`' do
|
||||
it 'should accept through the first character of the next word' do
|
||||
with_history('foobar foo') do
|
||||
session.
|
||||
send_string('foo').
|
||||
send_keys('escape').
|
||||
send_keys('w'). # vi-forward-word
|
||||
send_keys('a'). # vi-add-next
|
||||
send_string('az')
|
||||
|
||||
wait_for { session.content }.to eq('foobar faz')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '`vi-find-next-char`' do
|
||||
it 'should accept through the next occurrence of the character' do
|
||||
with_history('foobar foo') do
|
||||
session.
|
||||
send_string('foo').
|
||||
send_keys('escape').
|
||||
send_keys('f'). # vi-find-next-char
|
||||
send_keys('o').
|
||||
send_keys('a'). # vi-add-next
|
||||
send_string('b')
|
||||
|
||||
wait_for { session.content }.to eq('foobar fob')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '`vi-delete`' do
|
||||
it 'should be able to remove the last character in the buffer' do
|
||||
skip 'deleting last char did not work below zsh version 5.0.8' if session.zsh_version < Gem::Version.new('5.0.8')
|
||||
|
||||
session.
|
||||
send_string('echo foo').
|
||||
send_keys('escape').
|
||||
send_keys('d').
|
||||
send_keys('l')
|
||||
|
||||
wait_for { session.content }.to eq('echo fo')
|
||||
end
|
||||
end
|
||||
end
|
39
spec/integrations/wrapped_widget_spec.rb
Normal file
39
spec/integrations/wrapped_widget_spec.rb
Normal file
@ -0,0 +1,39 @@
|
||||
describe 'a wrapped widget' do
|
||||
let(:widget) { 'backward-delete-char' }
|
||||
|
||||
context 'initialized before sourcing the plugin' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command("_orig_#{widget}() { zle .#{widget} }").
|
||||
run_command("zle -N orig-#{widget} _orig_#{widget}").
|
||||
run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
|
||||
run_command("zle -N #{widget} #{widget}-magic")
|
||||
end
|
||||
end
|
||||
|
||||
it 'executes the custom behavior and the built-in behavior' do
|
||||
with_history('foobar', 'foodar') do
|
||||
session.send_string('food').send_keys('C-h')
|
||||
wait_for { session.content }.to eq('foobar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'initialized after sourcing the plugin' do
|
||||
before do
|
||||
session.
|
||||
run_command("zle -N orig-#{widget} ${widgets[#{widget}]#*:}").
|
||||
run_command("#{widget}-magic() { zle orig-#{widget}; BUFFER+=b }").
|
||||
run_command("zle -N #{widget} #{widget}-magic").
|
||||
clear_screen
|
||||
end
|
||||
|
||||
it 'executes the custom behavior and the built-in behavior' do
|
||||
with_history('foobar', 'foodar') do
|
||||
session.send_string('food').send_keys('C-h')
|
||||
wait_for { session.content }.to eq('foobar')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
spec/integrations/zle_input_stack_spec.rb
Normal file
24
spec/integrations/zle_input_stack_spec.rb
Normal file
@ -0,0 +1,24 @@
|
||||
describe 'using `zle -U`' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('_zsh_autosuggest_strategy_test() { sleep 1; _zsh_autosuggest_strategy_history "$1" }').
|
||||
run_command('foo() { zle -U - "echo hello" }; zle -N foo; bindkey ^B foo')
|
||||
end
|
||||
end
|
||||
|
||||
let(:options) { ['unset ZSH_AUTOSUGGEST_USE_ASYNC', 'ZSH_AUTOSUGGEST_STRATEGY=test'] }
|
||||
|
||||
# TODO: This is only possible with the $KEYS_QUEUED_COUNT widget parameter, coming soon...
|
||||
xit 'does not fetch a suggestion for every inserted character' do
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
end
|
||||
|
||||
it 'shows a suggestion when the widget completes' do
|
||||
with_history('echo hello world') do
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content(esc_seqs: true) }.to match(/\Aecho hello\e\[[0-9]+m world/)
|
||||
end
|
||||
end
|
||||
end
|
23
spec/kill_ring_spec.rb
Normal file
23
spec/kill_ring_spec.rb
Normal file
@ -0,0 +1,23 @@
|
||||
context 'with some items in the kill ring' do
|
||||
before do
|
||||
session.
|
||||
send_string('echo foo').
|
||||
send_keys('C-u').
|
||||
send_string('echo bar').
|
||||
send_keys('C-u')
|
||||
end
|
||||
|
||||
describe '`yank-pop`' do
|
||||
it 'should cycle through all items in the kill ring' do
|
||||
session.send_keys('C-y')
|
||||
wait_for { session.content }.to eq('echo bar')
|
||||
|
||||
session.send_keys('escape').send_keys('y')
|
||||
wait_for { session.content }.to eq('echo foo')
|
||||
|
||||
session.send_keys('escape').send_keys('y')
|
||||
wait_for { session.content }.to eq('echo bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
17
spec/line_init_spec.rb
Normal file
17
spec/line_init_spec.rb
Normal file
@ -0,0 +1,17 @@
|
||||
context 'with zle-line-init unignored' do
|
||||
let(:after_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('setopt extendedglob').
|
||||
run_command('ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(${(@)ZSH_AUTOSUGGEST_IGNORE_WIDGETS:#zle-\*} zle-\^line-init)').
|
||||
run_command('zle-line-init() { BUFFER="echo" }')
|
||||
end
|
||||
end
|
||||
|
||||
it 'should fetch a suggestion on each line initialization' do
|
||||
with_history('echo foo') do
|
||||
session.run_command('zle -N zle-line-init')
|
||||
wait_for { session.content }.to end_with('echo foo')
|
||||
end
|
||||
end
|
||||
end
|
8
spec/multi_line_spec.rb
Normal file
8
spec/multi_line_spec.rb
Normal file
@ -0,0 +1,8 @@
|
||||
describe 'a multi-line suggestion' do
|
||||
it 'should be displayed on multiple lines' do
|
||||
with_history("echo \"\n\"") do
|
||||
session.send_keys('e')
|
||||
wait_for { session.content }.to eq("echo \"\n\"")
|
||||
end
|
||||
end
|
||||
end
|
30
spec/options/buffer_max_size_spec.rb
Normal file
30
spec/options/buffer_max_size_spec.rb
Normal file
@ -0,0 +1,30 @@
|
||||
describe 'a suggestion' do
|
||||
let(:term_opts) { { width: 200 } }
|
||||
let(:long_command) { "echo #{'a' * 100}" }
|
||||
|
||||
around do |example|
|
||||
with_history(long_command) { example.run }
|
||||
end
|
||||
|
||||
it 'is provided for any buffer length' do
|
||||
session.send_string(long_command[0...-1])
|
||||
wait_for { session.content }.to eq(long_command)
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE is specified' do
|
||||
let(:buffer_max_size) { 10 }
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE=#{buffer_max_size}"] }
|
||||
|
||||
it 'is provided when the buffer is shorter than the specified length' do
|
||||
session.send_string(long_command[0...(buffer_max_size - 1)])
|
||||
wait_for { session.content }.to eq(long_command)
|
||||
end
|
||||
|
||||
it 'is provided when the buffer is equal to the specified length' do
|
||||
session.send_string(long_command[0...(buffer_max_size)])
|
||||
wait_for { session.content }.to eq(long_command)
|
||||
end
|
||||
|
||||
it 'is not provided when the buffer is longer than the specified length'
|
||||
end
|
||||
end
|
7
spec/options/highlight_style_spec.rb
Normal file
7
spec/options/highlight_style_spec.rb
Normal file
@ -0,0 +1,7 @@
|
||||
describe 'a displayed suggestion' do
|
||||
it 'is shown in the default style'
|
||||
|
||||
describe 'when ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE is set to a zle_highlight string' do
|
||||
it 'is shown in the specified style'
|
||||
end
|
||||
end
|
7
spec/options/original_widget_prefix_spec.rb
Normal file
7
spec/options/original_widget_prefix_spec.rb
Normal file
@ -0,0 +1,7 @@
|
||||
describe 'an original zle widget' do
|
||||
context 'is accessible with the default prefix'
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX is set' do
|
||||
it 'is accessible with the specified prefix'
|
||||
end
|
||||
end
|
55
spec/options/strategy_spec.rb
Normal file
55
spec/options/strategy_spec.rb
Normal file
@ -0,0 +1,55 @@
|
||||
describe 'a suggestion for a given prefix' do
|
||||
let(:history_strategy) { '_zsh_autosuggest_strategy_history() { suggestion="history" }' }
|
||||
let(:foobar_strategy) { '_zsh_autosuggest_strategy_foobar() { [[ "foobar baz" = $1* ]] && suggestion="foobar baz" }' }
|
||||
let(:foobaz_strategy) { '_zsh_autosuggest_strategy_foobaz() { [[ "foobaz bar" = $1* ]] && suggestion="foobaz bar" }' }
|
||||
|
||||
let(:after_sourcing) do
|
||||
-> do
|
||||
session.run_command(history_strategy)
|
||||
end
|
||||
end
|
||||
|
||||
it 'by default is determined by calling the `history` strategy function' do
|
||||
session.send_string('h')
|
||||
wait_for { session.content }.to eq('history')
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_STRATEGY is set to an array' do
|
||||
let(:after_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command(foobar_strategy).
|
||||
run_command(foobaz_strategy).
|
||||
run_command('ZSH_AUTOSUGGEST_STRATEGY=(foobar foobaz)')
|
||||
end
|
||||
end
|
||||
|
||||
it 'is determined by the first strategy function to return a suggestion' do
|
||||
session.send_string('foo')
|
||||
wait_for { session.content }.to eq('foobar baz')
|
||||
|
||||
session.send_string('baz')
|
||||
wait_for { session.content }.to eq('foobaz bar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_STRATEGY is set to a string' do
|
||||
let(:after_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command(foobar_strategy).
|
||||
run_command(foobaz_strategy).
|
||||
run_command('ZSH_AUTOSUGGEST_STRATEGY="foobar foobaz"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'is determined by the first strategy function to return a suggestion' do
|
||||
session.send_string('foo')
|
||||
wait_for { session.content }.to eq('foobar baz')
|
||||
|
||||
session.send_string('baz')
|
||||
wait_for { session.content }.to eq('foobaz bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
121
spec/options/widget_lists_spec.rb
Normal file
121
spec/options/widget_lists_spec.rb
Normal file
@ -0,0 +1,121 @@
|
||||
describe 'a zle widget' do
|
||||
let(:widget) { 'my-widget' }
|
||||
let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
|
||||
|
||||
context 'when added to ZSH_AUTOSUGGEST_ACCEPT_WIDGETS' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})"] }
|
||||
|
||||
it 'accepts the suggestion and moves the cursor to the end of the buffer when invoked' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
|
||||
wait_for { session.cursor }.to eq([10, 0])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when added to ZSH_AUTOSUGGEST_CLEAR_WIDGETS' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_CLEAR_WIDGETS+=(#{widget})"] }
|
||||
|
||||
it 'clears the suggestion when invoked' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('e')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when added to ZSH_AUTOSUGGEST_EXECUTE_WIDGETS' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_EXECUTE_WIDGETS+=(#{widget})"] }
|
||||
|
||||
it 'executes the suggestion when invoked' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to end_with("\nhello")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when added to ZSH_AUTOSUGGEST_IGNORE_WIDGETS' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(#{widget})"] }
|
||||
|
||||
it 'should not be wrapped with an autosuggest widget' do
|
||||
session.run_command("echo $widgets[#{widget}]")
|
||||
wait_for { session.content }.to end_with("\nuser:#{widget}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'that moves the cursor forward' do
|
||||
before { session.run_command("#{widget}() { zle forward-char }") }
|
||||
|
||||
context 'when added to ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(#{widget})"] }
|
||||
|
||||
it 'accepts the suggestion as far as the cursor is moved when invoked' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to start_with('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content(esc_seqs: true) }.to match(/\Aec\e\[[0-9]+mho hello/)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'that modifies the buffer' do
|
||||
before { session.run_command("#{widget}() { BUFFER=\"foo\" }") }
|
||||
|
||||
context 'when not added to any of the widget lists' do
|
||||
it 'modifies the buffer and fetches a new suggestion' do
|
||||
with_history('foobar') do
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('foobar')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'a modification to the widget lists' do
|
||||
let(:widget) { 'my-widget' }
|
||||
let(:before_sourcing) { -> { session.run_command("#{widget}() {}; zle -N #{widget}; bindkey ^B #{widget}") } }
|
||||
before { session.run_command("ZSH_AUTOSUGGEST_ACCEPT_WIDGETS+=(#{widget})") }
|
||||
|
||||
it 'takes effect on the next cmd line' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when manual rebind is enabled' do
|
||||
let(:options) { ["ZSH_AUTOSUGGEST_MANUAL_REBIND=true"] }
|
||||
|
||||
it 'does not take effect until bind command is re-run' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
sleep 1
|
||||
expect(session.content(esc_seqs: true)).not_to eq('echo hello')
|
||||
|
||||
session.send_keys('C-c')
|
||||
session.run_command('_zsh_autosuggest_bind_widgets').clear_screen
|
||||
wait_for { session.content }.to eq('')
|
||||
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content(esc_seqs: true) }.to eq('echo hello')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
54
spec/spec_helper.rb
Normal file
54
spec/spec_helper.rb
Normal file
@ -0,0 +1,54 @@
|
||||
require 'pry'
|
||||
require 'rspec/wait'
|
||||
require 'terminal_session'
|
||||
require 'tempfile'
|
||||
|
||||
RSpec.shared_context 'terminal session' do
|
||||
let(:term_opts) { {} }
|
||||
let(:session) { TerminalSession.new(term_opts) }
|
||||
let(:before_sourcing) { -> {} }
|
||||
let(:after_sourcing) { -> {} }
|
||||
let(:options) { [] }
|
||||
|
||||
around do |example|
|
||||
before_sourcing.call
|
||||
session.run_command(['source zsh-autosuggestions.zsh', *options].join('; '))
|
||||
after_sourcing.call
|
||||
session.clear_screen
|
||||
|
||||
example.run
|
||||
|
||||
session.destroy
|
||||
end
|
||||
|
||||
def with_history(*commands, &block)
|
||||
Tempfile.create do |f|
|
||||
f.write(commands.map{|c| c.gsub("\n", "\\\n")}.join("\n"))
|
||||
f.flush
|
||||
|
||||
session.run_command('fc -p')
|
||||
session.run_command("fc -R #{f.path}")
|
||||
|
||||
session.clear_screen
|
||||
|
||||
yield block
|
||||
|
||||
session.send_keys('C-c')
|
||||
session.run_command('fc -P')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.expect_with :rspec do |expectations|
|
||||
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
||||
end
|
||||
|
||||
config.mock_with :rspec do |mocks|
|
||||
mocks.verify_partial_doubles = true
|
||||
end
|
||||
|
||||
config.wait_timeout = 2
|
||||
|
||||
config.include_context 'terminal session'
|
||||
end
|
72
spec/strategies/completion_spec.rb
Normal file
72
spec/strategies/completion_spec.rb
Normal file
@ -0,0 +1,72 @@
|
||||
describe 'the `completion` suggestion strategy' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=completion'] }
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('autoload compinit && compinit').
|
||||
run_command('_foo() { compadd bar; compadd bat }').
|
||||
run_command('_num() { compadd two; compadd three }').
|
||||
run_command('compdef _foo baz').
|
||||
run_command('compdef _num one')
|
||||
end
|
||||
end
|
||||
|
||||
it 'suggests the first completion result' do
|
||||
session.send_string('baz ')
|
||||
wait_for { session.content }.to eq('baz bar')
|
||||
end
|
||||
|
||||
it 'does not add extra carriage returns when prefix has a line feed' do
|
||||
skip '`stty` does not work inside zpty below zsh version 5.0.3' if session.zsh_version < Gem::Version.new('5.0.3')
|
||||
session.send_string('baz \\').send_keys('C-v', 'C-j')
|
||||
wait_for { session.content }.to eq("baz \\\nbar")
|
||||
end
|
||||
|
||||
context 'when `_complete` is aliased' do
|
||||
let(:before_sourcing) do
|
||||
-> do
|
||||
session.
|
||||
run_command('autoload compinit && compinit').
|
||||
run_command('_foo() { compadd bar; compadd bat }').
|
||||
run_command('compdef _foo baz').
|
||||
run_command('alias _complete=_complete')
|
||||
end
|
||||
end
|
||||
|
||||
it 'suggests the first completion result' do
|
||||
session.send_string('baz ')
|
||||
wait_for { session.content }.to eq('baz bar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_COMPLETION_IGNORE is set to a pattern' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=completion', 'ZSH_AUTOSUGGEST_COMPLETION_IGNORE="one *"'] }
|
||||
|
||||
it 'makes suggestions when the buffer does not match the pattern' do
|
||||
session.send_string('baz ')
|
||||
wait_for { session.content }.to eq('baz bar')
|
||||
end
|
||||
|
||||
it 'does not make suggestions when the buffer matches the pattern' do
|
||||
session.send_string('one t')
|
||||
sleep 1
|
||||
expect(session.content).to eq('one t')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when async mode is enabled' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_USE_ASYNC=true', 'ZSH_AUTOSUGGEST_STRATEGY=completion'] }
|
||||
|
||||
it 'suggests the first completion result' do
|
||||
session.send_string('baz ')
|
||||
wait_for { session.content }.to eq('baz bar')
|
||||
end
|
||||
|
||||
it 'does not add extra carriage returns when prefix has a line feed' do
|
||||
skip '`stty` does not work inside zpty below zsh version 5.0.3' if session.zsh_version < Gem::Version.new('5.0.3')
|
||||
session.send_string('baz \\').send_keys('C-v', 'C-j')
|
||||
wait_for { session.content }.to eq("baz \\\nbar")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
23
spec/strategies/history_spec.rb
Normal file
23
spec/strategies/history_spec.rb
Normal file
@ -0,0 +1,23 @@
|
||||
require 'strategies/special_characters_helper'
|
||||
|
||||
describe 'the `history` suggestion strategy' do
|
||||
it 'suggests the last matching history entry' do
|
||||
with_history('ls foo', 'ls bar', 'echo baz') do
|
||||
session.send_string('ls')
|
||||
wait_for { session.content }.to eq('ls bar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] }
|
||||
|
||||
it 'does not make suggestions that match the pattern' do
|
||||
with_history('ls foo', 'ls bar', 'echo baz') do
|
||||
session.send_string('ls')
|
||||
wait_for { session.content }.to eq('ls foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'special characters'
|
||||
end
|
34
spec/strategies/match_prev_cmd_spec.rb
Normal file
34
spec/strategies/match_prev_cmd_spec.rb
Normal file
@ -0,0 +1,34 @@
|
||||
require 'strategies/special_characters_helper'
|
||||
|
||||
describe 'the `match_prev_cmd` strategy' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd'] }
|
||||
|
||||
let(:history) { [
|
||||
'echo what',
|
||||
'ls foo',
|
||||
'echo what',
|
||||
'ls bar',
|
||||
'ls baz',
|
||||
'echo what'
|
||||
] }
|
||||
|
||||
it 'suggests the last matching history entry after the previous command' do
|
||||
with_history(*history) do
|
||||
session.send_string('ls')
|
||||
wait_for { session.content }.to eq('ls bar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ZSH_AUTOSUGGEST_HISTORY_IGNORE is set to a pattern' do
|
||||
let(:options) { ['ZSH_AUTOSUGGEST_STRATEGY=match_prev_cmd', 'ZSH_AUTOSUGGEST_HISTORY_IGNORE="* bar"'] }
|
||||
|
||||
it 'does not make suggestions that match the pattern' do
|
||||
with_history(*history) do
|
||||
session.send_string('ls')
|
||||
wait_for { session.content }.to eq('ls foo')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
include_examples 'special characters'
|
||||
end
|
75
spec/strategies/special_characters_helper.rb
Normal file
75
spec/strategies/special_characters_helper.rb
Normal file
@ -0,0 +1,75 @@
|
||||
shared_examples 'special characters' do
|
||||
describe 'a special character in the buffer should be treated like any other character' do
|
||||
it 'asterisk' do
|
||||
with_history('echo "hello*"', 'echo "hello."') do
|
||||
session.send_string('echo "hello*')
|
||||
wait_for { session.content }.to eq('echo "hello*"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'question mark' do
|
||||
with_history('echo "hello?"', 'echo "hello."') do
|
||||
session.send_string('echo "hello?')
|
||||
wait_for { session.content }.to eq('echo "hello?"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'backslash' do
|
||||
with_history('echo "hello\nworld"') do
|
||||
session.send_string('echo "hello\\')
|
||||
wait_for { session.content }.to eq('echo "hello\nworld"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'double backslash' do
|
||||
with_history('echo "\\\\"') do
|
||||
session.send_string('echo "\\\\')
|
||||
wait_for { session.content }.to eq('echo "\\\\"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'tilde' do
|
||||
with_history('echo ~/foo') do
|
||||
session.send_string('echo ~')
|
||||
wait_for { session.content }.to eq('echo ~/foo')
|
||||
end
|
||||
end
|
||||
|
||||
it 'parentheses' do
|
||||
with_history('echo "$(ls foo)"') do
|
||||
session.send_string('echo "$(')
|
||||
wait_for { session.content }.to eq('echo "$(ls foo)"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'square bracket' do
|
||||
with_history('echo "$history[123]"') do
|
||||
session.send_string('echo "$history[')
|
||||
wait_for { session.content }.to eq('echo "$history[123]"')
|
||||
session.send_string('123]')
|
||||
wait_for { session.content }.to eq('echo "$history[123]"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'octothorpe' do
|
||||
with_history('echo "#yolo"') do
|
||||
session.send_string('echo "#')
|
||||
wait_for { session.content }.to eq('echo "#yolo"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'caret' do
|
||||
with_history('echo "^A"', 'echo "^B"') do
|
||||
session.send_string('echo "^A')
|
||||
wait_for { session.content }.to eq('echo "^A"')
|
||||
end
|
||||
end
|
||||
|
||||
it 'dash' do
|
||||
with_history('-foo() {}') do
|
||||
session.send_string('-')
|
||||
wait_for { session.content }.to eq('-foo() {}')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
99
spec/terminal_session.rb
Normal file
99
spec/terminal_session.rb
Normal file
@ -0,0 +1,99 @@
|
||||
require 'securerandom'
|
||||
|
||||
class TerminalSession
|
||||
ZSH_BIN = ENV['TEST_ZSH_BIN'] || 'zsh'
|
||||
|
||||
def initialize(opts = {})
|
||||
opts = {
|
||||
width: 80,
|
||||
height: 24,
|
||||
prompt: '',
|
||||
term: 'xterm-256color',
|
||||
zsh_bin: ZSH_BIN
|
||||
}.merge(opts)
|
||||
|
||||
@opts = opts
|
||||
|
||||
cmd="PS1=\"#{opts[:prompt]}\" TERM=#{opts[:term]} #{ZSH_BIN} -f"
|
||||
tmux_command("new-session -d -x #{opts[:width]} -y #{opts[:height]} '#{cmd}'")
|
||||
end
|
||||
|
||||
def zsh_version
|
||||
@zsh_version ||= Gem::Version.new(`#{ZSH_BIN} -c 'echo -n $ZSH_VERSION'`)
|
||||
end
|
||||
|
||||
def tmux_socket_name
|
||||
@tmux_socket_name ||= SecureRandom.hex(6)
|
||||
end
|
||||
|
||||
def run_command(command)
|
||||
send_string(command)
|
||||
send_keys('enter')
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def send_string(str)
|
||||
tmux_command("send-keys -t 0 -l -- '#{str.gsub("'", "\\'")}'")
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def send_keys(*keys)
|
||||
tmux_command("send-keys -t 0 #{keys.join(' ')}")
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def paste_string(str)
|
||||
tmux_command("set-buffer -- '#{str}'")
|
||||
tmux_command("paste-buffer -dpr -t 0")
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def content(esc_seqs: false)
|
||||
cmd = 'capture-pane -p -t 0'
|
||||
cmd += ' -e' if esc_seqs
|
||||
tmux_command(cmd).strip
|
||||
end
|
||||
|
||||
def clear_screen
|
||||
send_keys('C-l')
|
||||
|
||||
i = 0
|
||||
until content == opts[:prompt] || i > 20 do
|
||||
sleep(0.1)
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
self
|
||||
end
|
||||
|
||||
def destroy
|
||||
tmux_command('kill-session')
|
||||
end
|
||||
|
||||
def cursor
|
||||
tmux_command("display-message -t 0 -p '\#{cursor_x},\#{cursor_y}'").
|
||||
strip.
|
||||
split(',').
|
||||
map(&:to_i)
|
||||
end
|
||||
|
||||
def attach!
|
||||
tmux_command('attach-session')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :opts
|
||||
|
||||
def tmux_command(cmd)
|
||||
out = `tmux -u -L #{tmux_socket_name} #{cmd}`
|
||||
|
||||
raise("tmux error running: '#{cmd}'") unless $?.success?
|
||||
|
||||
out
|
||||
end
|
||||
end
|
19
spec/widgets/disable_spec.rb
Normal file
19
spec/widgets/disable_spec.rb
Normal file
@ -0,0 +1,19 @@
|
||||
describe 'the `autosuggest-disable` widget' do
|
||||
before do
|
||||
session.run_command('bindkey ^B autosuggest-disable')
|
||||
end
|
||||
|
||||
it 'disables suggestions and clears the suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('echo')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('echo')
|
||||
|
||||
session.send_string(' h')
|
||||
sleep 1
|
||||
expect(session.content).to eq('echo h')
|
||||
end
|
||||
end
|
||||
end
|
42
spec/widgets/enable_spec.rb
Normal file
42
spec/widgets/enable_spec.rb
Normal file
@ -0,0 +1,42 @@
|
||||
describe 'the `autosuggest-enable` widget' do
|
||||
before do
|
||||
session.
|
||||
run_command('typeset -g _ZSH_AUTOSUGGEST_DISABLED').
|
||||
run_command('bindkey ^B autosuggest-enable')
|
||||
end
|
||||
|
||||
it 'enables suggestions and fetches a suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
sleep 1
|
||||
expect(session.content).to eq('e')
|
||||
|
||||
session.send_keys('C-b')
|
||||
session.send_string('c')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invoked on an empty buffer' do
|
||||
it 'does not fetch a suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.send_keys('C-b')
|
||||
sleep 1
|
||||
expect(session.content).to eq('')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'invoked on a non-empty buffer' do
|
||||
it 'fetches a suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('e')
|
||||
sleep 1
|
||||
expect(session.content).to eq('e')
|
||||
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
24
spec/widgets/fetch_spec.rb
Normal file
24
spec/widgets/fetch_spec.rb
Normal file
@ -0,0 +1,24 @@
|
||||
describe 'the `autosuggest-fetch` widget' do
|
||||
context 'when suggestions are disabled' do
|
||||
before do
|
||||
session.
|
||||
run_command('bindkey ^B autosuggest-disable').
|
||||
run_command('bindkey ^F autosuggest-fetch').
|
||||
send_keys('C-b')
|
||||
end
|
||||
|
||||
it 'will fetch and display a suggestion' do
|
||||
with_history('echo hello') do
|
||||
session.send_string('echo h')
|
||||
sleep 1
|
||||
expect(session.content).to eq('echo h')
|
||||
|
||||
session.send_keys('C-f')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
|
||||
session.send_string('e')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
26
spec/widgets/toggle_spec.rb
Normal file
26
spec/widgets/toggle_spec.rb
Normal file
@ -0,0 +1,26 @@
|
||||
describe 'the `autosuggest-toggle` widget' do
|
||||
before do
|
||||
session.run_command('bindkey ^B autosuggest-toggle')
|
||||
end
|
||||
|
||||
it 'toggles suggestions' do
|
||||
with_history('echo world', 'echo hello') do
|
||||
session.send_string('echo')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('echo')
|
||||
|
||||
session.send_string(' h')
|
||||
sleep 1
|
||||
expect(session.content).to eq('echo h')
|
||||
|
||||
session.send_keys('C-b')
|
||||
wait_for { session.content }.to eq('echo hello')
|
||||
|
||||
session.send_keys('C-h')
|
||||
session.send_string('w')
|
||||
wait_for { session.content }.to eq('echo world')
|
||||
end
|
||||
end
|
||||
end
|
77
src/async.zsh
Normal file
77
src/async.zsh
Normal file
@ -0,0 +1,77 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Async #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
_zsh_autosuggest_async_request() {
|
||||
zmodload zsh/system 2>/dev/null # For `$sysparams`
|
||||
|
||||
typeset -g _ZSH_AUTOSUGGEST_ASYNC_FD _ZSH_AUTOSUGGEST_CHILD_PID
|
||||
|
||||
# If we've got a pending request, cancel it
|
||||
if [[ -n "$_ZSH_AUTOSUGGEST_ASYNC_FD" ]] && { true <&$_ZSH_AUTOSUGGEST_ASYNC_FD } 2>/dev/null; then
|
||||
# Close the file descriptor and remove the handler
|
||||
builtin exec {_ZSH_AUTOSUGGEST_ASYNC_FD}<&-
|
||||
zle -F $_ZSH_AUTOSUGGEST_ASYNC_FD
|
||||
|
||||
# We won't know the pid unless the user has zsh/system module installed
|
||||
if [[ -n "$_ZSH_AUTOSUGGEST_CHILD_PID" ]]; then
|
||||
# Zsh will make a new process group for the child process only if job
|
||||
# control is enabled (MONITOR option)
|
||||
if [[ -o MONITOR ]]; then
|
||||
# Send the signal to the process group to kill any processes that may
|
||||
# have been forked by the suggestion strategy
|
||||
kill -TERM -$_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
|
||||
else
|
||||
# Kill just the child process since it wasn't placed in a new process
|
||||
# group. If the suggestion strategy forked any child processes they may
|
||||
# be orphaned and left behind.
|
||||
kill -TERM $_ZSH_AUTOSUGGEST_CHILD_PID 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fork a process to fetch a suggestion and open a pipe to read from it
|
||||
builtin exec {_ZSH_AUTOSUGGEST_ASYNC_FD}< <(
|
||||
# Tell parent process our pid
|
||||
echo $sysparams[pid]
|
||||
|
||||
# Fetch and print the suggestion
|
||||
local suggestion
|
||||
_zsh_autosuggest_fetch_suggestion "$1"
|
||||
echo -nE "$suggestion"
|
||||
)
|
||||
|
||||
# There's a weird bug here where ^C stops working unless we force a fork
|
||||
# See https://github.com/zsh-users/zsh-autosuggestions/issues/364
|
||||
autoload -Uz is-at-least
|
||||
is-at-least 5.8 || command true
|
||||
|
||||
# Read the pid from the child process
|
||||
read _ZSH_AUTOSUGGEST_CHILD_PID <&$_ZSH_AUTOSUGGEST_ASYNC_FD
|
||||
|
||||
# When the fd is readable, call the response handler
|
||||
zle -F "$_ZSH_AUTOSUGGEST_ASYNC_FD" _zsh_autosuggest_async_response
|
||||
}
|
||||
|
||||
# Called when new data is ready to be read from the pipe
|
||||
# First arg will be fd ready for reading
|
||||
# Second arg will be passed in case of error
|
||||
_zsh_autosuggest_async_response() {
|
||||
emulate -L zsh
|
||||
|
||||
local suggestion
|
||||
|
||||
if [[ -z "$2" || "$2" == "hup" ]]; then
|
||||
# Read everything from the fd and give it as a suggestion
|
||||
IFS='' read -rd '' -u $1 suggestion
|
||||
zle autosuggest-suggest -- "$suggestion"
|
||||
|
||||
# Close the fd
|
||||
builtin exec {1}<&-
|
||||
fi
|
||||
|
||||
# Always remove the handler
|
||||
zle -F "$1"
|
||||
_ZSH_AUTOSUGGEST_ASYNC_FD=
|
||||
}
|
106
src/bind.zsh
106
src/bind.zsh
@ -1,80 +1,106 @@
|
||||
|
||||
#----------------#
|
||||
# Widget Helpers #
|
||||
#----------------#
|
||||
#--------------------------------------------------------------------#
|
||||
# Widget Helpers #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
_zsh_autosuggest_incr_bind_count() {
|
||||
typeset -gi bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]+1))
|
||||
_ZSH_AUTOSUGGEST_BIND_COUNTS[$1]=$bind_count
|
||||
}
|
||||
|
||||
# Bind a single widget to an autosuggest widget, saving a reference to the original widget
|
||||
_zsh_autosuggest_bind_widget() {
|
||||
local widget=$1
|
||||
local autosuggest_function=$2
|
||||
local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
|
||||
local action
|
||||
typeset -gA _ZSH_AUTOSUGGEST_BIND_COUNTS
|
||||
|
||||
local widget=$1
|
||||
local autosuggest_action=$2
|
||||
local prefix=$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX
|
||||
|
||||
local -i bind_count
|
||||
|
||||
# Save a reference to the original widget
|
||||
case $widgets[$widget] in
|
||||
# Already bound
|
||||
user:_zsh_autosuggest_(bound|orig)_*);;
|
||||
user:_zsh_autosuggest_(bound|orig)_*)
|
||||
bind_count=$((_ZSH_AUTOSUGGEST_BIND_COUNTS[$widget]))
|
||||
;;
|
||||
|
||||
# User-defined widget
|
||||
user:*)
|
||||
zle -N $prefix$widget ${widgets[$widget]#*:}
|
||||
_zsh_autosuggest_incr_bind_count $widget
|
||||
zle -N $prefix$bind_count-$widget ${widgets[$widget]#*:}
|
||||
;;
|
||||
|
||||
# Built-in widget
|
||||
builtin)
|
||||
eval "_zsh_autosuggest_orig_$widget() { zle .$widget }"
|
||||
zle -N $prefix$widget _zsh_autosuggest_orig_$widget
|
||||
_zsh_autosuggest_incr_bind_count $widget
|
||||
eval "_zsh_autosuggest_orig_${(q)widget}() { zle .${(q)widget} }"
|
||||
zle -N $prefix$bind_count-$widget _zsh_autosuggest_orig_$widget
|
||||
;;
|
||||
|
||||
# Completion widget
|
||||
completion:*)
|
||||
eval "zle -C $prefix$widget ${${widgets[$widget]#*:}/:/ }"
|
||||
_zsh_autosuggest_incr_bind_count $widget
|
||||
eval "zle -C $prefix$bind_count-${(q)widget} ${${(s.:.)widgets[$widget]}[2,3]}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set up widget to call $autosuggest_function if it exists
|
||||
# Otherwise just call the original widget
|
||||
if [ -n "$autosuggest_function" ]; then;
|
||||
action="$autosuggest_function \$@";
|
||||
else;
|
||||
action="zle $prefix$widget -- \$@"
|
||||
fi
|
||||
|
||||
# Create new function for the widget that highlights and calls the action
|
||||
eval "_zsh_autosuggest_bound_$widget() {
|
||||
_zsh_autosuggest_highlight_reset
|
||||
$action
|
||||
_zsh_autosuggest_highlight_apply
|
||||
# Pass the original widget's name explicitly into the autosuggest
|
||||
# function. Use this passed in widget name to call the original
|
||||
# widget instead of relying on the $WIDGET variable being set
|
||||
# correctly. $WIDGET cannot be trusted because other plugins call
|
||||
# zle without the `-w` flag (e.g. `zle self-insert` instead of
|
||||
# `zle self-insert -w`).
|
||||
eval "_zsh_autosuggest_bound_${bind_count}_${(q)widget}() {
|
||||
_zsh_autosuggest_widget_$autosuggest_action $prefix$bind_count-${(q)widget} \$@
|
||||
}"
|
||||
|
||||
# Create the bound widget
|
||||
zle -N $widget _zsh_autosuggest_bound_$widget
|
||||
zle -N -- $widget _zsh_autosuggest_bound_${bind_count}_$widget
|
||||
}
|
||||
|
||||
# Map all configured widgets to the right autosuggest widgets
|
||||
_zsh_autosuggest_bind_widgets() {
|
||||
local widget;
|
||||
emulate -L zsh
|
||||
|
||||
local widget
|
||||
local ignore_widgets
|
||||
|
||||
ignore_widgets=(
|
||||
.\*
|
||||
_\*
|
||||
${_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS/#/autosuggest-}
|
||||
$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX\*
|
||||
$ZSH_AUTOSUGGEST_IGNORE_WIDGETS
|
||||
)
|
||||
|
||||
# Find every widget we might want to bind and bind it appropriately
|
||||
for widget in ${${(f)"$(builtin zle -la)"}:#(.*|_*|orig-*|autosuggest-*|$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX*|run-help|which-command|beep|set-local-history|yank)}; do
|
||||
if [ ${ZSH_AUTOSUGGEST_MODIFY_WIDGETS[(r)$widget]} ]; then
|
||||
_zsh_autosuggest_bind_widget $widget _zsh_autosuggest_modify
|
||||
elif [ ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]; then
|
||||
_zsh_autosuggest_bind_widget $widget _zsh_autosuggest_clear
|
||||
elif [ ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]; then
|
||||
_zsh_autosuggest_bind_widget $widget _zsh_autosuggest_accept
|
||||
elif [ ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]; then
|
||||
_zsh_autosuggest_bind_widget $widget _zsh_autosuggest_partial_accept
|
||||
for widget in ${${(f)"$(builtin zle -la)"}:#${(j:|:)~ignore_widgets}}; do
|
||||
if [[ -n ${ZSH_AUTOSUGGEST_CLEAR_WIDGETS[(r)$widget]} ]]; then
|
||||
_zsh_autosuggest_bind_widget $widget clear
|
||||
elif [[ -n ${ZSH_AUTOSUGGEST_ACCEPT_WIDGETS[(r)$widget]} ]]; then
|
||||
_zsh_autosuggest_bind_widget $widget accept
|
||||
elif [[ -n ${ZSH_AUTOSUGGEST_EXECUTE_WIDGETS[(r)$widget]} ]]; then
|
||||
_zsh_autosuggest_bind_widget $widget execute
|
||||
elif [[ -n ${ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS[(r)$widget]} ]]; then
|
||||
_zsh_autosuggest_bind_widget $widget partial_accept
|
||||
else
|
||||
_zsh_autosuggest_bind_widget $widget
|
||||
# Assume any unspecified widget might modify the buffer
|
||||
_zsh_autosuggest_bind_widget $widget modify
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Given the name of a widget, invoke the original we saved, if it exists
|
||||
# Given the name of an original widget and args, invoke it, if it exists
|
||||
_zsh_autosuggest_invoke_original_widget() {
|
||||
local original_widget_name="$ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX$WIDGET"
|
||||
# Do nothing unless called with at least one arg
|
||||
(( $# )) || return 0
|
||||
|
||||
if [ $widgets[$original_widget_name] ]; then
|
||||
local original_widget_name="$1"
|
||||
|
||||
shift
|
||||
|
||||
if (( ${+widgets[$original_widget_name]} )); then
|
||||
zle $original_widget_name -- $@
|
||||
fi
|
||||
}
|
||||
|
130
src/config.zsh
130
src/config.zsh
@ -1,61 +1,95 @@
|
||||
|
||||
#--------------------------------#
|
||||
# Global Configuration Variables #
|
||||
#--------------------------------#
|
||||
#--------------------------------------------------------------------#
|
||||
# Global Configuration Variables #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
# Color to use when highlighting suggestion
|
||||
# Uses format of `region_highlight`
|
||||
# More info: http://zsh.sourceforge.net/Doc/Release/Zsh-Line-Editor.html#Zle-Widgets
|
||||
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'
|
||||
(( ! ${+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE} )) &&
|
||||
typeset -g ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE='fg=8'
|
||||
|
||||
# Prefix to use when saving original versions of bound widgets
|
||||
ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
|
||||
(( ! ${+ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX} )) &&
|
||||
typeset -g ZSH_AUTOSUGGEST_ORIGINAL_WIDGET_PREFIX=autosuggest-orig-
|
||||
|
||||
# Strategies to use to fetch a suggestion
|
||||
# Will try each strategy in order until a suggestion is returned
|
||||
(( ! ${+ZSH_AUTOSUGGEST_STRATEGY} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_STRATEGY
|
||||
ZSH_AUTOSUGGEST_STRATEGY=(history)
|
||||
}
|
||||
|
||||
# Widgets that clear the suggestion
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
|
||||
history-search-forward
|
||||
history-search-backward
|
||||
history-beginning-search-forward
|
||||
history-beginning-search-backward
|
||||
up-line-or-history
|
||||
down-line-or-history
|
||||
accept-line
|
||||
)
|
||||
|
||||
# Widgets that modify the suggestion
|
||||
ZSH_AUTOSUGGEST_MODIFY_WIDGETS=(
|
||||
list-choices
|
||||
complete-word
|
||||
menu-complete
|
||||
menu-expand-or-complete
|
||||
reverse-menu-complete
|
||||
expand-or-complete
|
||||
expand-or-complete-prefix
|
||||
self-insert
|
||||
magic-space
|
||||
bracketed-paste
|
||||
expand-cmd-path
|
||||
accept-and-menu-complete
|
||||
backward-delete-char
|
||||
vi-backward-delete-char
|
||||
delete-char
|
||||
vi-delete-char
|
||||
delete-char-or-list
|
||||
)
|
||||
(( ! ${+ZSH_AUTOSUGGEST_CLEAR_WIDGETS} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_CLEAR_WIDGETS
|
||||
ZSH_AUTOSUGGEST_CLEAR_WIDGETS=(
|
||||
history-search-forward
|
||||
history-search-backward
|
||||
history-beginning-search-forward
|
||||
history-beginning-search-backward
|
||||
history-beginning-search-forward-end
|
||||
history-beginning-search-backward-end
|
||||
history-substring-search-up
|
||||
history-substring-search-down
|
||||
up-line-or-beginning-search
|
||||
down-line-or-beginning-search
|
||||
up-line-or-history
|
||||
down-line-or-history
|
||||
accept-line
|
||||
copy-earlier-word
|
||||
)
|
||||
}
|
||||
|
||||
# Widgets that accept the entire suggestion
|
||||
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
|
||||
forward-char
|
||||
end-of-line
|
||||
vi-forward-char
|
||||
vi-end-of-line
|
||||
)
|
||||
(( ! ${+ZSH_AUTOSUGGEST_ACCEPT_WIDGETS} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_ACCEPT_WIDGETS
|
||||
ZSH_AUTOSUGGEST_ACCEPT_WIDGETS=(
|
||||
forward-char
|
||||
end-of-line
|
||||
vi-forward-char
|
||||
vi-end-of-line
|
||||
vi-add-eol
|
||||
)
|
||||
}
|
||||
|
||||
# Widgets that accept the entire suggestion and execute it
|
||||
(( ! ${+ZSH_AUTOSUGGEST_EXECUTE_WIDGETS} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_EXECUTE_WIDGETS
|
||||
ZSH_AUTOSUGGEST_EXECUTE_WIDGETS=(
|
||||
)
|
||||
}
|
||||
|
||||
# Widgets that accept the suggestion as far as the cursor moves
|
||||
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
|
||||
forward-word
|
||||
vi-forward-word
|
||||
vi-forward-word-end
|
||||
vi-forward-blank-word
|
||||
vi-forward-blank-word-end
|
||||
)
|
||||
(( ! ${+ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS
|
||||
ZSH_AUTOSUGGEST_PARTIAL_ACCEPT_WIDGETS=(
|
||||
forward-word
|
||||
emacs-forward-word
|
||||
vi-forward-word
|
||||
vi-forward-word-end
|
||||
vi-forward-blank-word
|
||||
vi-forward-blank-word-end
|
||||
vi-find-next-char
|
||||
vi-find-next-char-skip
|
||||
)
|
||||
}
|
||||
|
||||
# Widgets that should be ignored (globbing supported but must be escaped)
|
||||
(( ! ${+ZSH_AUTOSUGGEST_IGNORE_WIDGETS} )) && {
|
||||
typeset -ga ZSH_AUTOSUGGEST_IGNORE_WIDGETS
|
||||
ZSH_AUTOSUGGEST_IGNORE_WIDGETS=(
|
||||
orig-\*
|
||||
beep
|
||||
run-help
|
||||
set-local-history
|
||||
which-command
|
||||
yank
|
||||
yank-pop
|
||||
zle-\*
|
||||
)
|
||||
}
|
||||
|
||||
# Pty name for capturing completions for completion suggestion strategy
|
||||
(( ! ${+ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME} )) &&
|
||||
typeset -g ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME=zsh_autosuggest_completion_pty
|
||||
|
@ -1,39 +0,0 @@
|
||||
|
||||
#-------------------------------------#
|
||||
# Handle Deprecated Variables/Widgets #
|
||||
#-------------------------------------#
|
||||
|
||||
unset _ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN
|
||||
|
||||
_zsh_autosuggest_check_deprecated_config() {
|
||||
if [ -n "$AUTOSUGGESTION_HIGHLIGHT_COLOR" ]; then
|
||||
_zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_COLOR is deprecated. Use ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE instead."
|
||||
[ -z "$ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE" ] && ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE=$AUTOSUGGESTION_HIGHLIGHT_STYLE
|
||||
unset AUTOSUGGESTION_HIGHLIGHT_STYLE
|
||||
fi
|
||||
|
||||
if [ -n "$AUTOSUGGESTION_HIGHLIGHT_CURSOR" ]; then
|
||||
_zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_HIGHLIGHT_CURSOR is deprecated."
|
||||
unset AUTOSUGGESTION_HIGHLIGHT_CURSOR
|
||||
fi
|
||||
|
||||
if [ -n "$AUTOSUGGESTION_ACCEPT_RIGHT_ARROW" ]; then
|
||||
_zsh_autosuggest_deprecated_warning "AUTOSUGGESTION_ACCEPT_RIGHT_ARROW is deprecated. The right arrow now accepts the suggestion by default."
|
||||
unset AUTOSUGGESTION_ACCEPT_RIGHT_ARROW
|
||||
fi
|
||||
}
|
||||
|
||||
_zsh_autosuggest_deprecated_warning() {
|
||||
>&2 echo "zsh-autosuggestions: $@"
|
||||
}
|
||||
|
||||
_zsh_autosuggest_deprecated_start_widget() {
|
||||
if [ -z "$_ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN" ]; then
|
||||
_zsh_autosuggest_deprecated_warning "The autosuggest-start widget is deprecated. Use the autosuggest_start function instead. For more info, see README at https://github.com/tarruda/zsh-autosuggestions."
|
||||
_ZSH_AUTOSUGGEST_DEPRECATED_START_WIDGET_WARNING_SHOWN=true
|
||||
fi
|
||||
|
||||
autosuggest_start
|
||||
}
|
||||
|
||||
zle -N autosuggest-start _zsh_autosuggest_deprecated_start_widget
|
27
src/fetch.zsh
Normal file
27
src/fetch.zsh
Normal file
@ -0,0 +1,27 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Fetch Suggestion #
|
||||
#--------------------------------------------------------------------#
|
||||
# Loops through all specified strategies and returns a suggestion
|
||||
# from the first strategy to provide one.
|
||||
#
|
||||
|
||||
_zsh_autosuggest_fetch_suggestion() {
|
||||
typeset -g suggestion
|
||||
local -a strategies
|
||||
local strategy
|
||||
|
||||
# Ensure we are working with an array
|
||||
strategies=(${=ZSH_AUTOSUGGEST_STRATEGY})
|
||||
|
||||
for strategy in $strategies; do
|
||||
# Try to get a suggestion from this strategy
|
||||
_zsh_autosuggest_strategy_$strategy "$1"
|
||||
|
||||
# Ensure the suggestion matches the prefix
|
||||
[[ "$suggestion" != "$1"* ]] && unset suggestion
|
||||
|
||||
# Break once we've found a valid suggestion
|
||||
[[ -n "$suggestion" ]] && break
|
||||
done
|
||||
}
|
@ -1,11 +1,13 @@
|
||||
|
||||
#--------------#
|
||||
# Highlighting #
|
||||
#--------------#
|
||||
#--------------------------------------------------------------------#
|
||||
# Highlighting #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
# If there was a highlight, remove it
|
||||
_zsh_autosuggest_highlight_reset() {
|
||||
if [ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]; then
|
||||
typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
|
||||
if [[ -n "$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT" ]]; then
|
||||
region_highlight=("${(@)region_highlight:#$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT}")
|
||||
unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
fi
|
||||
@ -13,9 +15,11 @@ _zsh_autosuggest_highlight_reset() {
|
||||
|
||||
# If there's a suggestion, highlight it
|
||||
_zsh_autosuggest_highlight_apply() {
|
||||
if [ $#POSTDISPLAY -gt 0 ]; then
|
||||
_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
|
||||
region_highlight+=($_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT)
|
||||
typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
|
||||
if (( $#POSTDISPLAY )); then
|
||||
typeset -g _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT="$#BUFFER $(($#BUFFER + $#POSTDISPLAY)) $ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE"
|
||||
region_highlight+=("$_ZSH_AUTOSUGGEST_LAST_HIGHLIGHT")
|
||||
else
|
||||
unset _ZSH_AUTOSUGGEST_LAST_HIGHLIGHT
|
||||
fi
|
||||
|
@ -1,13 +1,33 @@
|
||||
|
||||
#-------#
|
||||
# Start #
|
||||
#-------#
|
||||
#--------------------------------------------------------------------#
|
||||
# Start #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
# Start the autosuggestion widgets
|
||||
_zsh_autosuggest_start() {
|
||||
_zsh_autosuggest_check_deprecated_config
|
||||
# By default we re-bind widgets on every precmd to ensure we wrap other
|
||||
# wrappers. Specifically, highlighting breaks if our widgets are wrapped by
|
||||
# zsh-syntax-highlighting widgets. This also allows modifications to the
|
||||
# widget list variables to take effect on the next precmd. However this has
|
||||
# a decent performance hit, so users can set ZSH_AUTOSUGGEST_MANUAL_REBIND
|
||||
# to disable the automatic re-binding.
|
||||
if (( ${+ZSH_AUTOSUGGEST_MANUAL_REBIND} )); then
|
||||
add-zsh-hook -d precmd _zsh_autosuggest_start
|
||||
fi
|
||||
|
||||
_zsh_autosuggest_bind_widgets
|
||||
}
|
||||
|
||||
autoload -Uz add-zsh-hook
|
||||
# Mark for auto-loading the functions that we use
|
||||
autoload -Uz add-zsh-hook is-at-least
|
||||
|
||||
# Automatically enable asynchronous mode in newer versions of zsh. Disable for
|
||||
# older versions because there is a bug when using async mode where ^C does not
|
||||
# work immediately after fetching a suggestion.
|
||||
# See https://github.com/zsh-users/zsh-autosuggestions/issues/364
|
||||
if is-at-least 5.0.8; then
|
||||
typeset -g ZSH_AUTOSUGGEST_USE_ASYNC=
|
||||
fi
|
||||
|
||||
# Start the autosuggestion widgets on the next precmd
|
||||
add-zsh-hook precmd _zsh_autosuggest_start
|
||||
|
137
src/strategies/completion.zsh
Normal file
137
src/strategies/completion.zsh
Normal file
@ -0,0 +1,137 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Completion Suggestion Strategy #
|
||||
#--------------------------------------------------------------------#
|
||||
# Fetches a suggestion from the completion engine
|
||||
#
|
||||
|
||||
_zsh_autosuggest_capture_postcompletion() {
|
||||
# Always insert the first completion into the buffer
|
||||
compstate[insert]=1
|
||||
|
||||
# Don't list completions
|
||||
unset 'compstate[list]'
|
||||
}
|
||||
|
||||
_zsh_autosuggest_capture_completion_widget() {
|
||||
# Add a post-completion hook to be called after all completions have been
|
||||
# gathered. The hook can modify compstate to affect what is done with the
|
||||
# gathered completions.
|
||||
local -a +h comppostfuncs
|
||||
comppostfuncs=(_zsh_autosuggest_capture_postcompletion)
|
||||
|
||||
# Only capture completions at the end of the buffer
|
||||
CURSOR=$#BUFFER
|
||||
|
||||
# Run the original widget wrapping `.complete-word` so we don't
|
||||
# recursively try to fetch suggestions, since our pty is forked
|
||||
# after autosuggestions is initialized.
|
||||
zle -- ${(k)widgets[(r)completion:.complete-word:_main_complete]}
|
||||
|
||||
if is-at-least 5.0.3; then
|
||||
# Don't do any cr/lf transformations. We need to do this immediately before
|
||||
# output because if we do it in setup, onlcr will be re-enabled when we enter
|
||||
# vared in the async code path. There is a bug in zpty module in older versions
|
||||
# where the tty is not properly attached to the pty slave, resulting in stty
|
||||
# getting stopped with a SIGTTOU. See zsh-workers thread 31660 and upstream
|
||||
# commit f75904a38
|
||||
stty -onlcr -ocrnl -F /dev/tty
|
||||
fi
|
||||
|
||||
# The completion has been added, print the buffer as the suggestion
|
||||
echo -nE - $'\0'$BUFFER$'\0'
|
||||
}
|
||||
|
||||
zle -N autosuggest-capture-completion _zsh_autosuggest_capture_completion_widget
|
||||
|
||||
_zsh_autosuggest_capture_setup() {
|
||||
# There is a bug in zpty module in older zsh versions by which a
|
||||
# zpty that exits will kill all zpty processes that were forked
|
||||
# before it. Here we set up a zsh exit hook to SIGKILL the zpty
|
||||
# process immediately, before it has a chance to kill any other
|
||||
# zpty processes.
|
||||
if ! is-at-least 5.4; then
|
||||
zshexit() {
|
||||
# The zsh builtin `kill` fails sometimes in older versions
|
||||
# https://unix.stackexchange.com/a/477647/156673
|
||||
kill -KILL $$ 2>&- || command kill -KILL $$
|
||||
|
||||
# Block for long enough for the signal to come through
|
||||
sleep 1
|
||||
}
|
||||
fi
|
||||
|
||||
# Try to avoid any suggestions that wouldn't match the prefix
|
||||
zstyle ':completion:*' matcher-list ''
|
||||
zstyle ':completion:*' path-completion false
|
||||
zstyle ':completion:*' max-errors 0 not-numeric
|
||||
|
||||
bindkey '^I' autosuggest-capture-completion
|
||||
}
|
||||
|
||||
_zsh_autosuggest_capture_completion_sync() {
|
||||
_zsh_autosuggest_capture_setup
|
||||
|
||||
zle autosuggest-capture-completion
|
||||
}
|
||||
|
||||
_zsh_autosuggest_capture_completion_async() {
|
||||
_zsh_autosuggest_capture_setup
|
||||
|
||||
zmodload zsh/parameter 2>/dev/null || return # For `$functions`
|
||||
|
||||
# Make vared completion work as if for a normal command line
|
||||
# https://stackoverflow.com/a/7057118/154703
|
||||
autoload +X _complete
|
||||
functions[_original_complete]=$functions[_complete]
|
||||
function _complete() {
|
||||
unset 'compstate[vared]'
|
||||
_original_complete "$@"
|
||||
}
|
||||
|
||||
# Open zle with buffer set so we can capture completions for it
|
||||
vared 1
|
||||
}
|
||||
|
||||
_zsh_autosuggest_strategy_completion() {
|
||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||
emulate -L zsh
|
||||
|
||||
# Enable extended glob for completion ignore pattern
|
||||
setopt EXTENDED_GLOB
|
||||
|
||||
typeset -g suggestion
|
||||
local line REPLY
|
||||
|
||||
# Exit if we don't have completions
|
||||
whence compdef >/dev/null || return
|
||||
|
||||
# Exit if we don't have zpty
|
||||
zmodload zsh/zpty 2>/dev/null || return
|
||||
|
||||
# Exit if our search string matches the ignore pattern
|
||||
[[ -n "$ZSH_AUTOSUGGEST_COMPLETION_IGNORE" ]] && [[ "$1" == $~ZSH_AUTOSUGGEST_COMPLETION_IGNORE ]] && return
|
||||
|
||||
# Zle will be inactive if we are in async mode
|
||||
if zle; then
|
||||
zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_sync
|
||||
else
|
||||
zpty $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME _zsh_autosuggest_capture_completion_async "\$1"
|
||||
zpty -w $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME $'\t'
|
||||
fi
|
||||
|
||||
{
|
||||
# The completion result is surrounded by null bytes, so read the
|
||||
# content between the first two null bytes.
|
||||
zpty -r $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME line '*'$'\0''*'$'\0'
|
||||
|
||||
# Extract the suggestion from between the null bytes. On older
|
||||
# versions of zsh (older than 5.3), we sometimes get extra bytes after
|
||||
# the second null byte, so trim those off the end.
|
||||
# See http://www.zsh.org/mla/workers/2015/msg03290.html
|
||||
suggestion="${${(@0)line}[2]}"
|
||||
} always {
|
||||
# Destroy the pty
|
||||
zpty -d $ZSH_AUTOSUGGEST_COMPLETIONS_PTY_NAME
|
||||
}
|
||||
}
|
32
src/strategies/history.zsh
Normal file
32
src/strategies/history.zsh
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# History Suggestion Strategy #
|
||||
#--------------------------------------------------------------------#
|
||||
# Suggests the most recent history item that matches the given
|
||||
# prefix.
|
||||
#
|
||||
|
||||
_zsh_autosuggest_strategy_history() {
|
||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||
emulate -L zsh
|
||||
|
||||
# Enable globbing flags so that we can use (#m) and (x~y) glob operator
|
||||
setopt EXTENDED_GLOB
|
||||
|
||||
# Escape backslashes and all of the glob operators so we can use
|
||||
# this string as a pattern to search the $history associative array.
|
||||
# - (#m) globbing flag enables setting references for match data
|
||||
# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
|
||||
local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
|
||||
|
||||
# Get the history items that match the prefix, excluding those that match
|
||||
# the ignore pattern
|
||||
local pattern="$prefix*"
|
||||
if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
|
||||
pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
|
||||
fi
|
||||
|
||||
# Give the first history item matching the pattern as the suggestion
|
||||
# - (r) subscript flag makes the pattern match on values
|
||||
typeset -g suggestion="${history[(r)$pattern]}"
|
||||
}
|
66
src/strategies/match_prev_cmd.zsh
Normal file
66
src/strategies/match_prev_cmd.zsh
Normal file
@ -0,0 +1,66 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Match Previous Command Suggestion Strategy #
|
||||
#--------------------------------------------------------------------#
|
||||
# Suggests the most recent history item that matches the given
|
||||
# prefix and whose preceding history item also matches the most
|
||||
# recently executed command.
|
||||
#
|
||||
# For example, suppose your history has the following entries:
|
||||
# - pwd
|
||||
# - ls foo
|
||||
# - ls bar
|
||||
# - pwd
|
||||
#
|
||||
# Given the history list above, when you type 'ls', the suggestion
|
||||
# will be 'ls foo' rather than 'ls bar' because your most recently
|
||||
# executed command (pwd) was previously followed by 'ls foo'.
|
||||
#
|
||||
# Note that this strategy won't work as expected with ZSH options that don't
|
||||
# preserve the history order such as `HIST_IGNORE_ALL_DUPS` or
|
||||
# `HIST_EXPIRE_DUPS_FIRST`.
|
||||
|
||||
_zsh_autosuggest_strategy_match_prev_cmd() {
|
||||
# Reset options to defaults and enable LOCAL_OPTIONS
|
||||
emulate -L zsh
|
||||
|
||||
# Enable globbing flags so that we can use (#m) and (x~y) glob operator
|
||||
setopt EXTENDED_GLOB
|
||||
|
||||
# TODO: Use (b) flag when we can drop support for zsh older than v5.0.8
|
||||
local prefix="${1//(#m)[\\*?[\]<>()|^~#]/\\$MATCH}"
|
||||
|
||||
# Get the history items that match the prefix, excluding those that match
|
||||
# the ignore pattern
|
||||
local pattern="$prefix*"
|
||||
if [[ -n $ZSH_AUTOSUGGEST_HISTORY_IGNORE ]]; then
|
||||
pattern="($pattern)~($ZSH_AUTOSUGGEST_HISTORY_IGNORE)"
|
||||
fi
|
||||
|
||||
# Get all history event numbers that correspond to history
|
||||
# entries that match the pattern
|
||||
local history_match_keys
|
||||
history_match_keys=(${(k)history[(R)$~pattern]})
|
||||
|
||||
# By default we use the first history number (most recent history entry)
|
||||
local histkey="${history_match_keys[1]}"
|
||||
|
||||
# Get the previously executed command
|
||||
local prev_cmd="$(_zsh_autosuggest_escape_command "${history[$((HISTCMD-1))]}")"
|
||||
|
||||
# Iterate up to the first 200 history event numbers that match $prefix
|
||||
for key in "${(@)history_match_keys[1,200]}"; do
|
||||
# Stop if we ran out of history
|
||||
[[ $key -gt 1 ]] || break
|
||||
|
||||
# See if the history entry preceding the suggestion matches the
|
||||
# previous command, and use it if it does
|
||||
if [[ "${history[$((key - 1))]}" == "$prev_cmd" ]]; then
|
||||
histkey="$key"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Give back the matched history entry
|
||||
typeset -g suggestion="$history[$histkey]"
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
|
||||
#------------#
|
||||
# Suggestion #
|
||||
#------------#
|
||||
|
||||
# Get a suggestion from history that matches a given prefix
|
||||
_zsh_autosuggest_suggestion() {
|
||||
setopt localoptions extendedglob
|
||||
|
||||
# Escape the prefix (requires EXTENDED_GLOB)
|
||||
local prefix=${1//(#m)[\][()|\\*?#<>~^]/\\$MATCH}
|
||||
|
||||
# Get all history items (reversed) that match pattern $prefix*
|
||||
local history_matches
|
||||
history_matches=(${history[(R)$prefix*]})
|
||||
|
||||
# Echo the first item that matches
|
||||
echo ${history_matches[1]}
|
||||
}
|
11
src/util.zsh
Normal file
11
src/util.zsh
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
# Utility Functions #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
_zsh_autosuggest_escape_command() {
|
||||
setopt localoptions EXTENDED_GLOB
|
||||
|
||||
# Escape special chars in the string (requires EXTENDED_GLOB)
|
||||
echo -E "${1//(#m)[\"\'\\()\[\]|*?~]/\\$MATCH}"
|
||||
}
|
224
src/widgets.zsh
224
src/widgets.zsh
@ -1,87 +1,231 @@
|
||||
|
||||
#------------------------------------#
|
||||
# Autosuggest Widget Implementations #
|
||||
#------------------------------------#
|
||||
#--------------------------------------------------------------------#
|
||||
# Autosuggest Widget Implementations #
|
||||
#--------------------------------------------------------------------#
|
||||
|
||||
# Disable suggestions
|
||||
_zsh_autosuggest_disable() {
|
||||
typeset -g _ZSH_AUTOSUGGEST_DISABLED
|
||||
_zsh_autosuggest_clear
|
||||
}
|
||||
|
||||
# Enable suggestions
|
||||
_zsh_autosuggest_enable() {
|
||||
unset _ZSH_AUTOSUGGEST_DISABLED
|
||||
|
||||
if (( $#BUFFER )); then
|
||||
_zsh_autosuggest_fetch
|
||||
fi
|
||||
}
|
||||
|
||||
# Toggle suggestions (enable/disable)
|
||||
_zsh_autosuggest_toggle() {
|
||||
if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
||||
_zsh_autosuggest_enable
|
||||
else
|
||||
_zsh_autosuggest_disable
|
||||
fi
|
||||
}
|
||||
|
||||
# Clear the suggestion
|
||||
_zsh_autosuggest_clear() {
|
||||
# Remove the suggestion
|
||||
unset POSTDISPLAY
|
||||
POSTDISPLAY=
|
||||
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
}
|
||||
|
||||
# Modify the buffer and get a new suggestion
|
||||
_zsh_autosuggest_modify() {
|
||||
# Original widget modifies the buffer
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
local -i retval
|
||||
|
||||
# Get a new suggestion if the buffer is not empty after modification
|
||||
local suggestion
|
||||
if [ $#BUFFER -gt 0 ]; then
|
||||
suggestion=$(_zsh_autosuggest_suggestion $BUFFER)
|
||||
# Only available in zsh >= 5.4
|
||||
local -i KEYS_QUEUED_COUNT
|
||||
|
||||
# Save the contents of the buffer/postdisplay
|
||||
local orig_buffer="$BUFFER"
|
||||
local orig_postdisplay="$POSTDISPLAY"
|
||||
|
||||
# Clear suggestion while waiting for next one
|
||||
POSTDISPLAY=
|
||||
|
||||
# Original widget may modify the buffer
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
retval=$?
|
||||
|
||||
emulate -L zsh
|
||||
|
||||
# Don't fetch a new suggestion if there's more input to be read immediately
|
||||
if (( $PENDING > 0 || $KEYS_QUEUED_COUNT > 0 )); then
|
||||
POSTDISPLAY="$orig_postdisplay"
|
||||
return $retval
|
||||
fi
|
||||
|
||||
# Add the suggestion to the POSTDISPLAY
|
||||
if [ -n "$suggestion" ]; then
|
||||
POSTDISPLAY=${suggestion#$BUFFER}
|
||||
# Optimize if manually typing in the suggestion or if buffer hasn't changed
|
||||
if [[ "$BUFFER" = "$orig_buffer"* && "$orig_postdisplay" = "${BUFFER:$#orig_buffer}"* ]]; then
|
||||
POSTDISPLAY="${orig_postdisplay:$(($#BUFFER - $#orig_buffer))}"
|
||||
return $retval
|
||||
fi
|
||||
|
||||
# Bail out if suggestions are disabled
|
||||
if (( ${+_ZSH_AUTOSUGGEST_DISABLED} )); then
|
||||
return $?
|
||||
fi
|
||||
|
||||
# Get a new suggestion if the buffer is not empty after modification
|
||||
if (( $#BUFFER > 0 )); then
|
||||
if [[ -z "$ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE" ]] || (( $#BUFFER <= $ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE )); then
|
||||
_zsh_autosuggest_fetch
|
||||
fi
|
||||
fi
|
||||
|
||||
return $retval
|
||||
}
|
||||
|
||||
# Fetch a new suggestion based on what's currently in the buffer
|
||||
_zsh_autosuggest_fetch() {
|
||||
if (( ${+ZSH_AUTOSUGGEST_USE_ASYNC} )); then
|
||||
_zsh_autosuggest_async_request "$BUFFER"
|
||||
else
|
||||
unset POSTDISPLAY
|
||||
local suggestion
|
||||
_zsh_autosuggest_fetch_suggestion "$BUFFER"
|
||||
_zsh_autosuggest_suggest "$suggestion"
|
||||
fi
|
||||
}
|
||||
|
||||
# Offer a suggestion
|
||||
_zsh_autosuggest_suggest() {
|
||||
emulate -L zsh
|
||||
|
||||
local suggestion="$1"
|
||||
|
||||
if [[ -n "$suggestion" ]] && (( $#BUFFER )); then
|
||||
POSTDISPLAY="${suggestion#$BUFFER}"
|
||||
else
|
||||
POSTDISPLAY=
|
||||
fi
|
||||
}
|
||||
|
||||
# Accept the entire suggestion
|
||||
_zsh_autosuggest_accept() {
|
||||
# Only accept if the cursor is at the end of the buffer
|
||||
if [ $CURSOR -eq $#BUFFER ]; then
|
||||
# Add the suggestion to the buffer
|
||||
BUFFER="$BUFFER$POSTDISPLAY"
|
||||
local -i retval max_cursor_pos=$#BUFFER
|
||||
|
||||
# Remove the suggestion
|
||||
unset POSTDISPLAY
|
||||
|
||||
# Move the cursor to the end of the buffer
|
||||
CURSOR=${#BUFFER}
|
||||
# When vicmd keymap is active, the cursor can't move all the way
|
||||
# to the end of the buffer
|
||||
if [[ "$KEYMAP" = "vicmd" ]]; then
|
||||
max_cursor_pos=$((max_cursor_pos - 1))
|
||||
fi
|
||||
|
||||
# If we're not in a valid state to accept a suggestion, just run the
|
||||
# original widget and bail out
|
||||
if (( $CURSOR != $max_cursor_pos || !$#POSTDISPLAY )); then
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
return
|
||||
fi
|
||||
|
||||
# Only accept if the cursor is at the end of the buffer
|
||||
# Add the suggestion to the buffer
|
||||
BUFFER="$BUFFER$POSTDISPLAY"
|
||||
|
||||
# Remove the suggestion
|
||||
POSTDISPLAY=
|
||||
|
||||
# Run the original widget before manually moving the cursor so that the
|
||||
# cursor movement doesn't make the widget do something unexpected
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
retval=$?
|
||||
|
||||
# Move the cursor to the end of the buffer
|
||||
if [[ "$KEYMAP" = "vicmd" ]]; then
|
||||
CURSOR=$(($#BUFFER - 1))
|
||||
else
|
||||
CURSOR=$#BUFFER
|
||||
fi
|
||||
|
||||
return $retval
|
||||
}
|
||||
|
||||
# Accept the entire suggestion and execute it
|
||||
_zsh_autosuggest_execute() {
|
||||
# Add the suggestion to the buffer
|
||||
BUFFER="$BUFFER$POSTDISPLAY"
|
||||
|
||||
# Remove the suggestion
|
||||
POSTDISPLAY=
|
||||
|
||||
# Call the original `accept-line` to handle syntax highlighting or
|
||||
# other potential custom behavior
|
||||
_zsh_autosuggest_invoke_original_widget "accept-line"
|
||||
}
|
||||
|
||||
# Partially accept the suggestion
|
||||
_zsh_autosuggest_partial_accept() {
|
||||
local -i retval cursor_loc
|
||||
|
||||
# Save the contents of the buffer so we can restore later if needed
|
||||
local original_buffer=$BUFFER
|
||||
local original_buffer="$BUFFER"
|
||||
|
||||
# Temporarily accept the suggestion.
|
||||
BUFFER="$BUFFER$POSTDISPLAY"
|
||||
|
||||
# Original widget moves the cursor
|
||||
_zsh_autosuggest_invoke_original_widget $@
|
||||
retval=$?
|
||||
|
||||
# Normalize cursor location across vi/emacs modes
|
||||
cursor_loc=$CURSOR
|
||||
if [[ "$KEYMAP" = "vicmd" ]]; then
|
||||
cursor_loc=$((cursor_loc + 1))
|
||||
fi
|
||||
|
||||
# If we've moved past the end of the original buffer
|
||||
if [ $CURSOR -gt $#original_buffer ]; then
|
||||
if (( $cursor_loc > $#original_buffer )); then
|
||||
# Set POSTDISPLAY to text right of the cursor
|
||||
POSTDISPLAY=$RBUFFER
|
||||
POSTDISPLAY="${BUFFER[$(($cursor_loc + 1)),$#BUFFER]}"
|
||||
|
||||
# Clip the buffer at the cursor
|
||||
BUFFER=$LBUFFER
|
||||
BUFFER="${BUFFER[1,$cursor_loc]}"
|
||||
else
|
||||
# Restore the original buffer
|
||||
BUFFER=$original_buffer
|
||||
BUFFER="$original_buffer"
|
||||
fi
|
||||
|
||||
return $retval
|
||||
}
|
||||
|
||||
_zsh_autosuggest_widget_accept() {
|
||||
_zsh_autosuggest_highlight_reset
|
||||
_zsh_autosuggest_accept $@
|
||||
_zsh_autosuggest_highlight_apply
|
||||
}
|
||||
() {
|
||||
typeset -ga _ZSH_AUTOSUGGEST_BUILTIN_ACTIONS
|
||||
|
||||
_zsh_autosuggest_widget_clear() {
|
||||
_zsh_autosuggest_highlight_reset
|
||||
_zsh_autosuggest_clear $@
|
||||
_zsh_autosuggest_highlight_apply
|
||||
}
|
||||
_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS=(
|
||||
clear
|
||||
fetch
|
||||
suggest
|
||||
accept
|
||||
execute
|
||||
enable
|
||||
disable
|
||||
toggle
|
||||
)
|
||||
|
||||
zle -N autosuggest-accept _zsh_autosuggest_widget_accept
|
||||
zle -N autosuggest-clear _zsh_autosuggest_widget_clear
|
||||
local action
|
||||
for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS modify partial_accept; do
|
||||
eval "_zsh_autosuggest_widget_$action() {
|
||||
local -i retval
|
||||
|
||||
_zsh_autosuggest_highlight_reset
|
||||
|
||||
_zsh_autosuggest_$action \$@
|
||||
retval=\$?
|
||||
|
||||
_zsh_autosuggest_highlight_apply
|
||||
|
||||
zle -R
|
||||
|
||||
return \$retval
|
||||
}"
|
||||
done
|
||||
|
||||
for action in $_ZSH_AUTOSUGGEST_BUILTIN_ACTIONS; do
|
||||
zle -N autosuggest-$action _zsh_autosuggest_widget_$action
|
||||
done
|
||||
}
|
||||
|
@ -1,62 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: gen_test_results.sh 54 2008-10-21 23:29:23Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# This script runs the provided unit tests and sends the output to the
|
||||
# appropriate file.
|
||||
#
|
||||
|
||||
# treat unset variables as an error
|
||||
set -u
|
||||
|
||||
die()
|
||||
{
|
||||
[ $# -gt 0 ] && echo "error: $@" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
BASE_DIR="`dirname $0`/.."
|
||||
LIB_DIR="${BASE_DIR}/lib"
|
||||
|
||||
# load libraries
|
||||
. ${LIB_DIR}/shflags || die 'unable to load shflags library'
|
||||
. ${LIB_DIR}/shlib || die 'unable to load shlib library'
|
||||
. ${LIB_DIR}/versions || die 'unable to load versions library'
|
||||
|
||||
BASE_DIR=`shlib_relToAbsPath "${BASE_DIR}"`
|
||||
SRC_DIR="${BASE_DIR}/src"
|
||||
|
||||
os_name=`versions_osName |sed 's/ /_/g'`
|
||||
os_version=`versions_osVersion`
|
||||
|
||||
DEFINE_boolean force false 'force overwrite' f
|
||||
DEFINE_string output_dir "`pwd`" 'output dir' d
|
||||
DEFINE_string output_file "${os_name}-${os_version}.txt" 'output file' o
|
||||
DEFINE_string suite 'shunit2_test.sh' 'unit test suite' s
|
||||
FLAGS "${@:-}" || exit $?; shift ${FLAGS_ARGC}
|
||||
|
||||
# determine output filename
|
||||
output="${FLAGS_output_dir:+${FLAGS_output_dir}/}${FLAGS_output_file}"
|
||||
output=`shlib_relToAbsPath "${output}"`
|
||||
|
||||
# checks
|
||||
if [ -f "${output}" ]; then
|
||||
if [ ${FLAGS_force} -eq ${FLAGS_TRUE} ]; then
|
||||
rm -f "${output}"
|
||||
else
|
||||
echo "not overwriting '${output}'" >&2
|
||||
exit ${FLAGS_ERROR}
|
||||
fi
|
||||
fi
|
||||
touch "${output}" 2>/dev/null || die "unable to write to '${output}'"
|
||||
|
||||
# run tests
|
||||
( cd "${SRC_DIR}"; ./${FLAGS_suite} |tee "${output}" )
|
||||
|
||||
echo >&2
|
||||
echo "output written to '${output}'" >&2
|
@ -1,36 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: which 12 2007-02-18 03:31:14Z sfsetse $
|
||||
#
|
||||
# This is a simple implementation of the 'which' command for those OSes that
|
||||
# don't have one.
|
||||
#
|
||||
|
||||
true; TRUE=$?
|
||||
false; FALSE=$?
|
||||
|
||||
showAll=${FALSE}
|
||||
|
||||
# process command line flags
|
||||
while getopts 'a' opt; do
|
||||
case ${opt} in
|
||||
a) showAll=${TRUE}
|
||||
esac
|
||||
done
|
||||
shift `expr ${OPTIND} - 1`
|
||||
|
||||
# exit if no arguments were given
|
||||
[ $# -eq 0 ] && exit 1
|
||||
|
||||
command=$1
|
||||
|
||||
# search for command
|
||||
out=`echo "${PATH}" |sed "s/:/\n/g" |\
|
||||
while read path; do
|
||||
fullPath="${path}/${command}"
|
||||
if [ -x "${fullPath}" ]; then
|
||||
echo "${fullPath}"
|
||||
[ ${showAll} -eq ${FALSE} ] && break
|
||||
fi
|
||||
done`
|
||||
[ -z "${out}" ] && exit 1
|
||||
echo "${out}"
|
@ -1,214 +0,0 @@
|
||||
Changes in shUnit2 2.1.X
|
||||
========================
|
||||
|
||||
Changes with 2.1.6
|
||||
------------------
|
||||
|
||||
Removed all references to the DocBook documentation.
|
||||
|
||||
Simplified the 'src' structure.
|
||||
|
||||
Fixed error message in fail() that stated wrong number of required arguments.
|
||||
|
||||
Updated lib/versions.
|
||||
|
||||
Fixed bug in _shunit_mktempDir() where a failure occurred when the 'od' command was not present in /usr/bin.
|
||||
|
||||
Renamed shunit_tmpDir variable to SHUNIT_TMPDIR to closer match the standard
|
||||
TMPDIR variable.
|
||||
|
||||
Added support for calling shunit2 as an executable, in addition to the existing
|
||||
method of sourcing it in as a library. This allows users to keep tests working
|
||||
despite the location of the shunit2 executable being different for each OS
|
||||
distribution.
|
||||
|
||||
Issue #14: Improved handling of some strange chars (e.g. single and double
|
||||
quotes) in messages.
|
||||
|
||||
Issue# 27: Fixed error message for assertSame().
|
||||
|
||||
Issue# 25: Added check and error message to user when phantom functions are
|
||||
written to a partition mounted with noexec.
|
||||
|
||||
Issue# 11: Added support for defining functions like 'function someFunction()'.
|
||||
|
||||
|
||||
Changes with 2.1.5
|
||||
------------------
|
||||
|
||||
Issue# 1: Fixed bug pointed out by R Bernstein in the trap code where certain
|
||||
types of exit conditions did not generate the ending report.
|
||||
|
||||
Issue# 2: Added assertNotEquals() assert.
|
||||
|
||||
Issue# 3: Moved check for unset variables out of shUnit2 into the unit tests.
|
||||
Testing poorly written software blows up if this check is in, but it is only
|
||||
interesting for shUnit2 itself. Added shunit_test_output.sh unit test for this.
|
||||
Some shells still do not catch such errors properly (e.g. Bourne shell and BASH
|
||||
2.x).
|
||||
|
||||
Added new custom assert in test_helpers to check for output to STDOUT, and none
|
||||
to STDERR.
|
||||
|
||||
Replaced fatal message in the temp directory creation with a _shunit_fatal()
|
||||
function call.
|
||||
|
||||
Fixed test_output unit test so it works now that the 'set -u' stuff was removed
|
||||
for Issue# 3.
|
||||
|
||||
Flushed out the coding standards in the README.txt a bit more, and brought the
|
||||
shunit2 code up to par with the documented standards.
|
||||
|
||||
Issue# 4: Completely changed the reporting output to be a closer match for
|
||||
JUnit and PyUnit. As a result, tests are counted separately from assertions.
|
||||
|
||||
Provide public shunit_tmpDir variable that can be used by unit test scripts that
|
||||
need automated and guaranteed cleanup.
|
||||
|
||||
Issue# 7: Fixed duplicated printing of messages passed to asserts.
|
||||
|
||||
Per code review, fixed wording of failSame() and failNotSame() messages.
|
||||
|
||||
Replaced version_info.sh with versions library and made appropriate changes in
|
||||
other scripts to use it.
|
||||
|
||||
Added gen_test_results.sh to make releases easier.
|
||||
|
||||
Fixed bugs in shlib_relToAbsPath() in shlib.
|
||||
|
||||
Converted DocBook documentation to reStructuredText for easier maintenance. The
|
||||
DocBook documentation is now considered obsolete, and will be removed in a
|
||||
future release.
|
||||
|
||||
Issue# 5: Fixed the documentation around the usage of failures.
|
||||
|
||||
Issue# 9: Added unit tests and updated documentation to demonstrate the
|
||||
requirement of quoting values twice when macros are used. This is due to how
|
||||
shell parses arguments.
|
||||
|
||||
When an invalid number of arguments is passed to a function, the invalid number
|
||||
is returned to the user so they are more aware of what the cause might be.
|
||||
|
||||
|
||||
Changes with 2.1.4
|
||||
------------------
|
||||
|
||||
Removed the _shunit_functionExists() function as it was dead code.
|
||||
|
||||
Fixed zsh version number check in version_info.
|
||||
|
||||
Fixed bug in last resort temporary directory creation.
|
||||
|
||||
Fixed off-by-one in exit value for scripts caught by the trap handler.
|
||||
|
||||
Added argument count error checking to all functions.
|
||||
|
||||
Added mkdir_test.sh example.
|
||||
|
||||
Moved src/test into src/shell to better match structure used with shFlags.
|
||||
|
||||
Fixed problem where null values were not handled properly under ksh.
|
||||
|
||||
Added support for outputting line numbers as part of assert messages.
|
||||
|
||||
Started documenting the coding standards, and changed some variable names as a
|
||||
result.
|
||||
|
||||
Improved zsh version and option checks.
|
||||
|
||||
Renamed the __SHUNIT_VERSION variable to SHUNIT_VERSION.
|
||||
|
||||
|
||||
Changes with 2.1.3
|
||||
------------------
|
||||
|
||||
Added some explicit variable defaults, even though the variables are set, as
|
||||
they sometimes behave strange when the script is canceled.
|
||||
|
||||
Additional workarounds for zsh compatibility.
|
||||
|
||||
shUnit2 now exits with a non-zero exit code if any of the tests failed. This was
|
||||
done for automated testing frameworks. Tests that were skipped are not
|
||||
considered failures, and do not affect the exit code.
|
||||
|
||||
Changed detection of STDERR output in unit tests.
|
||||
|
||||
|
||||
Changes with 2.1.2
|
||||
------------------
|
||||
|
||||
Unset additional variables that were missed.
|
||||
|
||||
Added checks and workarounds to improve zsh compatibility.
|
||||
|
||||
Added some argument count checks ``assertEquals()``, ``assertNull()``, and
|
||||
``assertSame()``
|
||||
|
||||
|
||||
Changes with 2.1.1
|
||||
------------------
|
||||
|
||||
Fixed bug where ``fail()`` was not honoring skipping.
|
||||
|
||||
Fixed problem with ``docs-docbook-prep`` target that prevented it from working.
|
||||
(Thanks to Bryan Larsen for pointing this out.)
|
||||
|
||||
Changed the test in ``assertFalse()`` so that any non-zero value registers as
|
||||
false. (Credits to Bryan Larsen)
|
||||
|
||||
Major fiddling to bring more in line with `JUnit <http://junit.org/>`. Asserts
|
||||
give better output when no message is given, and failures now just fail.
|
||||
|
||||
It was pointed out that the simple 'failed' message for a failed assert was not
|
||||
only insufficient, it was nonstandard (when compared to JUnit) and didn't
|
||||
provide the user with an expected vs actual result. The code was revised
|
||||
somewhat to bring closer into alignment with JUnit (v4.3.1 specifically) so
|
||||
that it feels more "normal". (Credits to Richard Jensen)
|
||||
|
||||
As part of the JUnit realignment, it was noticed that fail*() functions in
|
||||
JUnit don't actually do any comparisons themselves. They only generate a
|
||||
failure message. Updated the code to match.
|
||||
|
||||
Added self-testing unit tests. Kinda horkey, but they did find bugs during the
|
||||
JUnit realignment.
|
||||
|
||||
Fixed the code for returning from asserts as the return was being called before
|
||||
the unsetting of variables occurred. (Credits to Mathias Goldau)
|
||||
|
||||
The assert(True|False)() functions now accept an integer value for a
|
||||
conditional test. A value of '0' is considered 'true', while any non-zero value
|
||||
is considered 'false'.
|
||||
|
||||
All public functions now fill use default values to work properly with the '-x'
|
||||
shell debugging flag.
|
||||
|
||||
Fixed the method of percent calculation for the report to get achieve better
|
||||
accuracy.
|
||||
|
||||
|
||||
Changes with 2.1.0 (since 2.0.1)
|
||||
--------------------------------
|
||||
|
||||
This release is a branch of the 2.0.1 release.
|
||||
|
||||
Moving to `reStructured Text <http://docutils.sourceforge.net/rst.html>`_ for
|
||||
the documentation.
|
||||
|
||||
Fixed problem with ``fail()``. The failure message was not properly printed.
|
||||
|
||||
Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be
|
||||
downloaded before parsing can continue.
|
||||
|
||||
Renamed the internal ``__SHUNIT_TRUE`` and ``__SHUNIT_FALSE`` variables to
|
||||
``SHUNIT_TRUE`` and ``SHUNIT_FALSE`` so that unit tests can "use" them.
|
||||
|
||||
Added support for test "skipping". If skipping is turned on with the
|
||||
``startSkip()`` function, ``assert`` and ``fail`` functions will return
|
||||
immediately, and the skip will be recorded.
|
||||
|
||||
The report output format was changed to include the percentage for each test
|
||||
result, rather than just those successful.
|
||||
|
||||
|
||||
.. $Revision: 326 $
|
||||
.. vim:fileencoding=latin1:ft=text:spell:tw=80
|
@ -1,504 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 2.1, February 1999
|
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the Lesser GPL. It also counts
|
||||
as the successor of the GNU Library Public License, version 2, hence
|
||||
the version number 2.1.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Lesser General Public License, applies to some
|
||||
specially designated software packages--typically libraries--of the
|
||||
Free Software Foundation and other authors who decide to use it. You
|
||||
can use it too, but we suggest you first think carefully about whether
|
||||
this license or the ordinary General Public License is the better
|
||||
strategy to use in any particular case, based on the explanations below.
|
||||
|
||||
When we speak of free software, we are referring to freedom of use,
|
||||
not price. Our General Public Licenses are designed to make sure that
|
||||
you have the freedom to distribute copies of free software (and charge
|
||||
for this service if you wish); that you receive source code or can get
|
||||
it if you want it; that you can change the software and use pieces of
|
||||
it in new free programs; and that you are informed that you can do
|
||||
these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
distributors to deny you these rights or to ask you to surrender these
|
||||
rights. These restrictions translate to certain responsibilities for
|
||||
you if you distribute copies of the library or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link other code with the library, you must provide
|
||||
complete object files to the recipients, so that they can relink them
|
||||
with the library after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the
|
||||
library, and (2) we offer you this license, which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
To protect each distributor, we want to make it very clear that
|
||||
there is no warranty for the free library. Also, if the library is
|
||||
modified by someone else and passed on, the recipients should know
|
||||
that what they have is not the original version, so that the original
|
||||
author's reputation will not be affected by problems that might be
|
||||
introduced by others.
|
||||
|
||||
Finally, software patents pose a constant threat to the existence of
|
||||
any free program. We wish to make sure that a company cannot
|
||||
effectively restrict the users of a free program by obtaining a
|
||||
restrictive license from a patent holder. Therefore, we insist that
|
||||
any patent license obtained for a version of the library must be
|
||||
consistent with the full freedom of use specified in this license.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the
|
||||
ordinary GNU General Public License. This license, the GNU Lesser
|
||||
General Public License, applies to certain designated libraries, and
|
||||
is quite different from the ordinary General Public License. We use
|
||||
this license for certain libraries in order to permit linking those
|
||||
libraries into non-free programs.
|
||||
|
||||
When a program is linked with a library, whether statically or using
|
||||
a shared library, the combination of the two is legally speaking a
|
||||
combined work, a derivative of the original library. The ordinary
|
||||
General Public License therefore permits such linking only if the
|
||||
entire combination fits its criteria of freedom. The Lesser General
|
||||
Public License permits more lax criteria for linking other code with
|
||||
the library.
|
||||
|
||||
We call this license the "Lesser" General Public License because it
|
||||
does Less to protect the user's freedom than the ordinary General
|
||||
Public License. It also provides other free software developers Less
|
||||
of an advantage over competing non-free programs. These disadvantages
|
||||
are the reason we use the ordinary General Public License for many
|
||||
libraries. However, the Lesser license provides advantages in certain
|
||||
special circumstances.
|
||||
|
||||
For example, on rare occasions, there may be a special need to
|
||||
encourage the widest possible use of a certain library, so that it becomes
|
||||
a de-facto standard. To achieve this, non-free programs must be
|
||||
allowed to use the library. A more frequent case is that a free
|
||||
library does the same job as widely used non-free libraries. In this
|
||||
case, there is little to gain by limiting the free library to free
|
||||
software only, so we use the Lesser General Public License.
|
||||
|
||||
In other cases, permission to use a particular library in non-free
|
||||
programs enables a greater number of people to use a large body of
|
||||
free software. For example, permission to use the GNU C Library in
|
||||
non-free programs enables many more people to use the whole GNU
|
||||
operating system, as well as its variant, the GNU/Linux operating
|
||||
system.
|
||||
|
||||
Although the Lesser General Public License is Less protective of the
|
||||
users' freedom, it does ensure that the user of a program that is
|
||||
linked with the Library has the freedom and the wherewithal to run
|
||||
that program using a modified version of the Library.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, whereas the latter must
|
||||
be combined with the library in order to run.
|
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library or other
|
||||
program which contains a notice placed by the copyright holder or
|
||||
other authorized party saying it may be distributed under the terms of
|
||||
this Lesser General Public License (also called "this License").
|
||||
Each licensee is addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also combine or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (1) uses at run time a
|
||||
copy of the library already present on the user's computer system,
|
||||
rather than copying library functions into the executable, and (2)
|
||||
will operate properly with a modified version of the library, if
|
||||
the user installs one, as long as the modified version is
|
||||
interface-compatible with the version that the work was made with.
|
||||
|
||||
c) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
d) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
e) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the materials to be distributed need not include anything that is
|
||||
normally distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties with
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Lesser General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
||||
|
||||
|
@ -1,540 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
|
||||
<title>shUnit2 2.1.x README</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger
|
||||
:Contact: goodger@users.sourceforge.net
|
||||
:Date: $Date: 2007-04-11 11:48:16 +0100 (Wed, 11 Apr 2007) $
|
||||
:Revision: $Revision: 2791 $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
:Modified by: Kate Ward <kate.ward@forestent.com>
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin-left: 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left {
|
||||
clear: left }
|
||||
|
||||
img.align-right {
|
||||
clear: right }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font-family: serif ;
|
||||
font-size: 100% }
|
||||
|
||||
pre.literal-block, pre.doctest-block {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em ;
|
||||
background-color: #eeeeee }
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
/*
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
*/
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px ;
|
||||
font-size: 80% }
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
/*
|
||||
tt.docutils {
|
||||
background-color: #eeeeee }
|
||||
*/
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
/* customizations by kward */
|
||||
|
||||
h1 { font-size: 133%; border-top:1px solid #CCCCFF; }
|
||||
h1.title { font-size: 150%; border-top:0px; padding-top: 1em; }
|
||||
/* div.document { font-size: 90% } */
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="shunit2-2-1-x-readme">
|
||||
<h1 class="title">shUnit2 2.1.x README</h1>
|
||||
|
||||
<div class="section" id="code-google-com">
|
||||
<h1>code.google.com</h1>
|
||||
<p>This project is stored on code.google.com as <a class="reference external" href="http://code.google.com/p/shunit2/">http://code.google.com/p/shunit2/</a>.
|
||||
All releases as of 2.1.4 and full source are available there. Documentation is
|
||||
included as part of the source and each release. Source code is stored in
|
||||
Subversion and can be accessed using the following information.</p>
|
||||
<p>Browse the code in a web browser:</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="http://code.google.com/p/shunit2/source/browse">http://code.google.com/p/shunit2/source/browse</a></li>
|
||||
<li>svn > trunk > source > 2.1</li>
|
||||
</ul>
|
||||
<p>Check out the code locally</p>
|
||||
<pre class="literal-block">
|
||||
$ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="sourceforge">
|
||||
<h1>SourceForge</h1>
|
||||
<p>DEPRECATED</p>
|
||||
<p>This project is stored on SourceForge as <a class="reference external" href="http://sf.net/projects/shunit2">http://sf.net/projects/shunit2</a>. The
|
||||
source code is stored in Subversion and can be accessed using the following
|
||||
information.</p>
|
||||
<p>Check out the code locally</p>
|
||||
<pre class="literal-block">
|
||||
$ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2
|
||||
</pre>
|
||||
<p>Browse the code in a web browser:</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="http://shunit2.svn.sourceforge.net/viewvc/shunit2/trunk/source/2.1/">http://shunit2.svn.sourceforge.net/viewvc/shunit2/trunk/source/2.1/</a></li>
|
||||
<li><a class="reference external" href="http://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1/">http://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1/</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section" id="making-a-release">
|
||||
<h1>Making a release</h1>
|
||||
<p>For these steps, it is assumed we are working with release 2.0.0.</p>
|
||||
<p>Steps:</p>
|
||||
<ul class="simple">
|
||||
<li>write release notes</li>
|
||||
<li>update version</li>
|
||||
<li>finish changelog</li>
|
||||
<li>check all the code in</li>
|
||||
<li>tag the release</li>
|
||||
<li>export the release</li>
|
||||
<li>create tarball</li>
|
||||
<li>md5sum the tarball and sign with gpg</li>
|
||||
<li>update website</li>
|
||||
<li>post to SourceForge and Freshmeat</li>
|
||||
</ul>
|
||||
<div class="section" id="write-release-notes">
|
||||
<h2>Write Release Notes</h2>
|
||||
<p>This should be pretty self explanatory. Use one of the release notes from a
|
||||
previous release as an example.</p>
|
||||
<p>The versions of the various platforms and shells are included when the
|
||||
master unit test script is run, or when <tt class="docutils literal">bin/gen_test_results.sh</tt> is
|
||||
used. To determine the versions of the installed shells by hand, use the
|
||||
<tt class="docutils literal">lib/versions</tt> script.</p>
|
||||
<p>Alternatively, do the following:</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="9%" />
|
||||
<col width="12%" />
|
||||
<col width="79%" />
|
||||
</colgroup>
|
||||
<thead valign="bottom">
|
||||
<tr><th class="head">Shell</th>
|
||||
<th class="head">OS</th>
|
||||
<th class="head">Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody valign="top">
|
||||
<tr><td>bash</td>
|
||||
<td> </td>
|
||||
<td><tt class="docutils literal">$ bash <span class="pre">--version</span></tt></td>
|
||||
</tr>
|
||||
<tr><td>dash</td>
|
||||
<td>Linux</td>
|
||||
<td><tt class="docutils literal">$ dpkg <span class="pre">-l</span> |grep dash</tt></td>
|
||||
</tr>
|
||||
<tr><td rowspan="3">ksh</td>
|
||||
<td> </td>
|
||||
<td><tt class="docutils literal">$ ksh <span class="pre">--version</span></tt>
|
||||
-or-
|
||||
<tt class="docutils literal">$ echo 'echo $KSH_VERSION' |ksh</tt></td>
|
||||
</tr>
|
||||
<tr><td>Cygwin</td>
|
||||
<td>see pdksh</td>
|
||||
</tr>
|
||||
<tr><td>Solaris</td>
|
||||
<td><tt class="docutils literal">$ strings /usr/bin/ksh |grep 'Version'</tt></td>
|
||||
</tr>
|
||||
<tr><td rowspan="2">pdksh</td>
|
||||
<td> </td>
|
||||
<td><tt class="docutils literal">$ strings /bin/pdksh |grep 'PD KSH'</tt></td>
|
||||
</tr>
|
||||
<tr><td>Cygwin</td>
|
||||
<td>look in the downloaded Cygwin directory</td>
|
||||
</tr>
|
||||
<tr><td>sh</td>
|
||||
<td>Solaris</td>
|
||||
<td>not possible</td>
|
||||
</tr>
|
||||
<tr><td>zsh</td>
|
||||
<td> </td>
|
||||
<td><tt class="docutils literal">$ zsh <span class="pre">--version</span></tt></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="update-version">
|
||||
<h2>Update Version</h2>
|
||||
<p>Edit <tt class="docutils literal">src/shell/shunit2</tt> and change the version number in the comment, as well
|
||||
as in the <tt class="docutils literal">SHUNIT_VERSION</tt> variable.</p>
|
||||
</div>
|
||||
<div class="section" id="finish-documentation">
|
||||
<h2>Finish Documentation</h2>
|
||||
<p>Make sure that any remaining changes get put into the <tt class="docutils literal"><span class="pre">CHANGES-X.X.txt</span></tt> file.</p>
|
||||
<p>Finish writing the <tt class="docutils literal"><span class="pre">RELEASE_NOTES-X.X.X.txt</span></tt>. If necessary, run it
|
||||
through the <strong>fmt</strong> command to make it pretty (hopefully it is already).</p>
|
||||
<pre class="literal-block">
|
||||
$ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new
|
||||
$ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt
|
||||
</pre>
|
||||
<p>We want to have an up-to-date version of the documentation in the release, so
|
||||
we'd better build it.</p>
|
||||
<pre class="literal-block">
|
||||
$ pwd
|
||||
.../shunit2/source/2.1
|
||||
$ cd doc
|
||||
$ RST2HTML_OPTS='--stylesheet-path=rst2html.css'
|
||||
$ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html
|
||||
$ rst2html ${RST2HTML_OPTS} README.txt >README.html
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="check-in-all-the-code">
|
||||
<h2>Check In All the Code</h2>
|
||||
<p>This step is pretty self-explanatory</p>
|
||||
<pre class="literal-block">
|
||||
$ pwd
|
||||
.../shunit2/source/2.0
|
||||
$ svn ci -m "finalizing release"
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="tag-the-release">
|
||||
<h2>Tag the Release</h2>
|
||||
<pre class="literal-block">
|
||||
$ pwd
|
||||
.../shunit2/source
|
||||
$ ls
|
||||
2.0 2.1
|
||||
$ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="export-the-release">
|
||||
<h2>Export the Release</h2>
|
||||
<pre class="literal-block">
|
||||
$ pwd
|
||||
.../shunit2/builds
|
||||
$ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="create-tarball">
|
||||
<h2>Create Tarball</h2>
|
||||
<pre class="literal-block">
|
||||
$ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="sign-the-tarball-with-gpg">
|
||||
<h2>Sign the Tarball with gpg</h2>
|
||||
<pre class="literal-block">
|
||||
$ cd ../releases
|
||||
$ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz
|
||||
</pre>
|
||||
</div>
|
||||
<div class="section" id="update-website">
|
||||
<h2>Update Website</h2>
|
||||
<p>Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once
|
||||
that is done, make sure to tag the website so we can go back in time if needed.</p>
|
||||
<pre class="literal-block">
|
||||
$ pwd
|
||||
.../shunit2
|
||||
$ ls
|
||||
source website
|
||||
$ svn cp -m "Release 2.0.0" \
|
||||
website https://shunit2.googlecode.com/svn/tags/website/20060916
|
||||
</pre>
|
||||
<p>Now, update the website. It too is held in Subversion, so <strong>ssh</strong> into the web
|
||||
server and use <tt class="docutils literal">svn up</tt> to grab the latest version.</p>
|
||||
</div>
|
||||
<div class="section" id="post-to-code-google-com-and-freshmeat">
|
||||
<h2>Post to code.google.com and Freshmeat</h2>
|
||||
<ul class="simple">
|
||||
<li><a class="reference external" href="http://code.google.com/p/shunit2/">http://code.google.com/p/shunit2/</a></li>
|
||||
<li><a class="reference external" href="http://freshmeat.net/">http://freshmeat.net/</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="related-documentation">
|
||||
<h1>Related Documentation</h1>
|
||||
<dl class="docutils">
|
||||
<dt>Docbook:</dt>
|
||||
<dd><a class="reference external" href="http://www.docbook.org/">http://www.docbook.org/</a></dd>
|
||||
<dt>Docbook XML</dt>
|
||||
<dd><dl class="first last docutils">
|
||||
<dt>docbook-xml-4.4.zip:</dt>
|
||||
<dd><a class="reference external" href="http://www.docbook.org/xml/4.4/docbook-xml-4.4.zip">http://www.docbook.org/xml/4.4/docbook-xml-4.4.zip</a>
|
||||
<a class="reference external" href="http://www.oasis-open.org/docbook/xml/4.4/docbook-xml-4.4.zip">http://www.oasis-open.org/docbook/xml/4.4/docbook-xml-4.4.zip</a></dd>
|
||||
<dt>docbook-xml-4.5.zip:</dt>
|
||||
<dd><a class="reference external" href="http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip">http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>Docbook XSL</dt>
|
||||
<dd><dl class="first last docutils">
|
||||
<dt>docbook-xsl-1.71.0.tar.bz2:</dt>
|
||||
<dd><a class="reference external" href="http://prdownloads.sourceforge.net/docbook/docbook-xsl-1.71.0.tar.bz2?download">http://prdownloads.sourceforge.net/docbook/docbook-xsl-1.71.0.tar.bz2?download</a></dd>
|
||||
<dt>docbook-xsl-1.71.1.tar.bz2:</dt>
|
||||
<dd><a class="reference external" href="http://downloads.sourceforge.net/docbook/docbook-xsl-1.71.1.tar.bz2?use_mirror=puzzle">http://downloads.sourceforge.net/docbook/docbook-xsl-1.71.1.tar.bz2?use_mirror=puzzle</a></dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt>JUnit:</dt>
|
||||
<dd><a class="reference external" href="http://www.junit.org/">http://www.junit.org/</a></dd>
|
||||
<dt>reStructuredText:</dt>
|
||||
<dd><a class="reference external" href="http://docutils.sourceforge.net/docs/user/rst/quickstart.html">http://docutils.sourceforge.net/docs/user/rst/quickstart.html</a></dd>
|
||||
</dl>
|
||||
<!-- generate HTML using rst2html from Docutils of -->
|
||||
<!-- http://docutils.sourceforge.net/ -->
|
||||
<!-- -->
|
||||
<!-- vim:fileencoding=latin1:ft=rst:spell:tw=80 -->
|
||||
<!-- $Revision: 286 $ -->
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,214 +0,0 @@
|
||||
====================
|
||||
shUnit2 2.1.x README
|
||||
====================
|
||||
|
||||
code.google.com
|
||||
===============
|
||||
|
||||
This project is stored on code.google.com as http://code.google.com/p/shunit2/.
|
||||
All releases as of 2.1.4 and full source are available there. Documentation is
|
||||
included as part of the source and each release. Source code is stored in
|
||||
Subversion and can be accessed using the following information.
|
||||
|
||||
Browse the code in a web browser:
|
||||
|
||||
- http://code.google.com/p/shunit2/source/browse
|
||||
- svn > trunk > source > 2.1
|
||||
|
||||
Check out the code locally ::
|
||||
|
||||
$ svn checkout http://shunit2.googlecode.com/svn/trunk/ shflags-read-only
|
||||
|
||||
|
||||
SourceForge
|
||||
===========
|
||||
|
||||
DEPRECATED
|
||||
|
||||
This project is stored on SourceForge as http://sf.net/projects/shunit2. The
|
||||
source code is stored in Subversion and can be accessed using the following
|
||||
information.
|
||||
|
||||
Check out the code locally ::
|
||||
|
||||
$ svn co https://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1 shunit2
|
||||
|
||||
Browse the code in a web browser:
|
||||
|
||||
- http://shunit2.svn.sourceforge.net/viewvc/shunit2/trunk/source/2.1/
|
||||
- http://shunit2.svn.sourceforge.net/svnroot/shunit2/trunk/source/2.1/
|
||||
|
||||
|
||||
Making a release
|
||||
================
|
||||
|
||||
For these steps, it is assumed we are working with release 2.0.0.
|
||||
|
||||
Steps:
|
||||
|
||||
- write release notes
|
||||
- update version
|
||||
- finish changelog
|
||||
- check all the code in
|
||||
- tag the release
|
||||
- export the release
|
||||
- create tarball
|
||||
- md5sum the tarball and sign with gpg
|
||||
- update website
|
||||
- post to SourceForge and Freshmeat
|
||||
|
||||
Write Release Notes
|
||||
-------------------
|
||||
|
||||
This should be pretty self explanatory. Use one of the release notes from a
|
||||
previous release as an example.
|
||||
|
||||
The versions of the various platforms and shells are included when the
|
||||
master unit test script is run, or when ``bin/gen_test_results.sh`` is
|
||||
used. To determine the versions of the installed shells by hand, use the
|
||||
``lib/versions`` script.
|
||||
|
||||
Alternatively, do the following:
|
||||
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| Shell | OS | Notes |
|
||||
+=======+=========+===========================================================+
|
||||
| bash | | ``$ bash --version`` |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| dash | Linux | ``$ dpkg -l |grep dash`` |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| ksh | | ``$ ksh --version`` |
|
||||
| | | -or- |
|
||||
| | | ``$ echo 'echo $KSH_VERSION' |ksh`` |
|
||||
| +---------+-----------------------------------------------------------+
|
||||
| | Cygwin | see pdksh |
|
||||
| +---------+-----------------------------------------------------------+
|
||||
| | Solaris | ``$ strings /usr/bin/ksh |grep 'Version'`` |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| pdksh | | ``$ strings /bin/pdksh |grep 'PD KSH'`` |
|
||||
| +---------+-----------------------------------------------------------+
|
||||
| | Cygwin | look in the downloaded Cygwin directory |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| sh | Solaris | not possible |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
| zsh | | ``$ zsh --version`` |
|
||||
+-------+---------+-----------------------------------------------------------+
|
||||
|
||||
Update Version
|
||||
--------------
|
||||
|
||||
Edit ``src/shell/shunit2`` and change the version number in the comment, as well
|
||||
as in the ``SHUNIT_VERSION`` variable.
|
||||
|
||||
Finish Documentation
|
||||
--------------------
|
||||
|
||||
Make sure that any remaining changes get put into the ``CHANGES-X.X.txt`` file.
|
||||
|
||||
Finish writing the ``RELEASE_NOTES-X.X.X.txt``. If necessary, run it
|
||||
through the **fmt** command to make it pretty (hopefully it is already). ::
|
||||
|
||||
$ fmt -w 80 RELEASE_NOTES-2.0.0.txt >RELEASE_NOTES-2.0.0.txt.new
|
||||
$ mv RELEASE_NOTES-2.0.0.txt.new RELEASE_NOTES-2.0.0.txt
|
||||
|
||||
We want to have an up-to-date version of the documentation in the release, so
|
||||
we'd better build it. ::
|
||||
|
||||
$ pwd
|
||||
.../shunit2/source/2.1
|
||||
$ cd doc
|
||||
$ RST2HTML_OPTS='--stylesheet-path=rst2html.css'
|
||||
$ rst2html ${RST2HTML_OPTS} shunit2.txt >shunit2.html
|
||||
$ rst2html ${RST2HTML_OPTS} README.txt >README.html
|
||||
|
||||
Check In All the Code
|
||||
---------------------
|
||||
|
||||
This step is pretty self-explanatory ::
|
||||
|
||||
$ pwd
|
||||
.../shunit2/source/2.0
|
||||
$ svn ci -m "finalizing release"
|
||||
|
||||
Tag the Release
|
||||
---------------
|
||||
::
|
||||
|
||||
$ pwd
|
||||
.../shunit2/source
|
||||
$ ls
|
||||
2.0 2.1
|
||||
$ svn cp -m "Release 2.0.0" 2.0 https://shunit2.googlecode.com/svn/tags/source/2.0.0
|
||||
|
||||
Export the Release
|
||||
------------------
|
||||
::
|
||||
|
||||
$ pwd
|
||||
.../shunit2/builds
|
||||
$ svn export https://shunit2.googlecode.com/svn/tags/source/2.0.0 shunit2-2.0.0
|
||||
|
||||
Create Tarball
|
||||
--------------
|
||||
::
|
||||
|
||||
$ tar cfz ../releases/shunit2-2.0.0.tgz shunit2-2.0.0
|
||||
|
||||
Sign the Tarball with gpg
|
||||
-------------------------
|
||||
::
|
||||
|
||||
$ cd ../releases
|
||||
$ gpg --default-key kate.ward@forestent.com --detach-sign shunit2-2.0.0.tgz
|
||||
|
||||
Update Website
|
||||
--------------
|
||||
|
||||
Again, pretty self-explanatory. Make sure to copy the GPG signature file. Once
|
||||
that is done, make sure to tag the website so we can go back in time if needed.
|
||||
::
|
||||
|
||||
$ pwd
|
||||
.../shunit2
|
||||
$ ls
|
||||
source website
|
||||
$ svn cp -m "Release 2.0.0" \
|
||||
website https://shunit2.googlecode.com/svn/tags/website/20060916
|
||||
|
||||
Now, update the website. It too is held in Subversion, so **ssh** into the web
|
||||
server and use ``svn up`` to grab the latest version.
|
||||
|
||||
Post to code.google.com and Freshmeat
|
||||
-------------------------------------
|
||||
|
||||
- http://code.google.com/p/shunit2/
|
||||
- http://freshmeat.net/
|
||||
|
||||
|
||||
Related Documentation
|
||||
=====================
|
||||
|
||||
Docbook:
|
||||
http://www.docbook.org/
|
||||
|
||||
Docbook XML
|
||||
docbook-xml-4.4.zip:
|
||||
http://www.docbook.org/xml/4.4/docbook-xml-4.4.zip
|
||||
http://www.oasis-open.org/docbook/xml/4.4/docbook-xml-4.4.zip
|
||||
docbook-xml-4.5.zip:
|
||||
http://www.docbook.org/xml/4.5/docbook-xml-4.5.zip
|
||||
Docbook XSL
|
||||
docbook-xsl-1.71.0.tar.bz2:
|
||||
http://prdownloads.sourceforge.net/docbook/docbook-xsl-1.71.0.tar.bz2?download
|
||||
docbook-xsl-1.71.1.tar.bz2:
|
||||
http://downloads.sourceforge.net/docbook/docbook-xsl-1.71.1.tar.bz2?use_mirror=puzzle
|
||||
JUnit:
|
||||
http://www.junit.org/
|
||||
reStructuredText:
|
||||
http://docutils.sourceforge.net/docs/user/rst/quickstart.html
|
||||
|
||||
.. generate HTML using rst2html from Docutils of
|
||||
.. http://docutils.sourceforge.net/
|
||||
..
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:tw=80
|
||||
.. $Revision: 310 $
|
@ -1,104 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.0
|
||||
===============================
|
||||
|
||||
This release was branched from shUnit2 2.0.1. It mostly adds new functionality,
|
||||
but there are couple of bugs fixed from the previous release.
|
||||
|
||||
See the ``CHANGES-2.1.rst`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
This list of platforms comes from the latest version of log4sh as shUnit2 is
|
||||
used in the testing of log4sh on each of these platforms.
|
||||
|
||||
Cygwin
|
||||
|
||||
- bash 3.2.9(10)
|
||||
- pdksh 5.2.14
|
||||
|
||||
Linux
|
||||
|
||||
- bash 3.1.17(1), 3.2.10(1)
|
||||
- dash 0.5.3
|
||||
- ksh 1993-12-28
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.2 (does not work)
|
||||
|
||||
Mac OS X 10.4.8 (Darwin 8.8)
|
||||
|
||||
- bash 2.05b.0(1)
|
||||
- ksh 1993-12-28
|
||||
|
||||
Solaris 8 U3 (x86)
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.03.0(1)
|
||||
- ksh M-11/16/88i
|
||||
|
||||
Solaris 10 U2 (sparc)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.00.16(1)
|
||||
- ksh M-11/16/88i
|
||||
|
||||
Solaris 10 U2 (x86)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.00.16(1)
|
||||
- ksh M-11/16/88i
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
Test skipping
|
||||
|
||||
Support added for test "skipping". A skip mode can be enabled so that
|
||||
subsequent ``assert`` and ``fail`` functions that are called will be recorded
|
||||
as "skipped" rather than as "passed" or "failed". This functionality can be
|
||||
used such that when a set of tests makes sense on one platform but not on
|
||||
another, they can be effectively disabled without altering the total number
|
||||
of tests.
|
||||
|
||||
One example might be when something is supported under ``bash``, but not
|
||||
under a standard Bourne shell.
|
||||
|
||||
New functions: ``startSkipping()``, ``endSkipping``, ``isSkipping``
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Moving to the use of `reStructured Text
|
||||
<http://docutils.sourceforge.net/rst.html>`_ for documentation. It is easy to
|
||||
read and edit in textual form, but converts nicely to HTML.
|
||||
|
||||
The report format has changed. Rather than including a simple "success"
|
||||
percentage at the end, a percentage is given for each type of test.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
The ``fail()`` function did not output the optional failure message.
|
||||
|
||||
Fixed the ``Makefile`` so that the DocBook XML and XSLT files would be
|
||||
downloaded before documentation parsing will continue.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
.. $Revision: 273 $
|
||||
.. vim:fileencoding=latin1:spell:syntax=rst:textwidth=80
|
@ -1,88 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.1
|
||||
===============================
|
||||
|
||||
This is mainly a bug fix release, but it also incorporates a realignment with
|
||||
the JUnit 4 code. Asserts now provide better failure messages, and the failure
|
||||
functions no longer perform tests.
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
This list of platforms comes from the latest version of log4sh as shUnit2 is
|
||||
used in the testing of log4sh on each of these platforms.
|
||||
|
||||
Cygwin
|
||||
|
||||
- bash 3.2.15(13)
|
||||
- pdksh 5.2.14
|
||||
|
||||
Linux
|
||||
|
||||
- bash 3.1.17(1), 3.2.10(1)
|
||||
- dash 0.5.3
|
||||
- ksh 1993-12-28
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.2 (does not work)
|
||||
|
||||
Mac OS X 10.4.9 (Darwin 8.9.1)
|
||||
|
||||
- bash 2.05b.0(1)
|
||||
- ksh 1993-12-28
|
||||
|
||||
Solaris 8 U3 (x86)
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.03.0(1)
|
||||
- ksh M-11/16/88i
|
||||
|
||||
Solaris 10 U2 (sparc, x86)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.00.16(1)
|
||||
- ksh M-11/16/88i
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
The internal test in ``assertFalse()`` now accepts any non-zero value as false.
|
||||
|
||||
The ``assertTrue()`` and ``assertFalse()`` functions now accept an integer value
|
||||
for a conditional test. A value of '0' is considered 'true', while any non-zero
|
||||
value is considered 'false'.
|
||||
|
||||
Self-testing unit tests were added.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
The ``fail()`` assert now honors skipping.
|
||||
|
||||
The ``docs-docbook-prep`` target now works properly.
|
||||
|
||||
All asserts now properly unset their variables.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
Functions do not properly test for an invalid number of arguments.
|
||||
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80
|
@ -1,83 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.2
|
||||
===============================
|
||||
|
||||
This release adds initial support for the zsh shell. Due to some differences
|
||||
with this shell as compared with others, some special checks have been added,
|
||||
and there are some extra requirements necessary when this shell is to be used.
|
||||
|
||||
To use zsh with shUnit2, the following two requirements must be met:
|
||||
* The ``shwordsplit`` option must be set.
|
||||
* The ``function_argzero`` option must be unset.
|
||||
|
||||
Please read the Shell Errata section of the documentation for guidance on how
|
||||
to meet these requirements.
|
||||
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
This list of platforms comes from the latest version of log4sh as shUnit2 is
|
||||
used in the testing of log4sh on each of these platforms.
|
||||
|
||||
Linux
|
||||
|
||||
- bash 3.1.17(1), 3.2.25(1)
|
||||
- dash 0.5.4
|
||||
- ksh 1993-12-28
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.2.5, 4.3.4
|
||||
|
||||
Mac OS X 10.4.11 (Darwin 8.11.1)
|
||||
|
||||
- bash 2.05b.0(1)
|
||||
- ksh 1993-12-28
|
||||
- zsh 4.2.3
|
||||
|
||||
Solaris 10 U3 (x86)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.00.16(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 4.2.1
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
Support for the zsh shell.
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Added some argument count checks.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
Functions do not properly test for an invalid number of arguments.
|
||||
|
||||
ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly,
|
||||
and as such checks do not work properly.
|
||||
|
||||
zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero``
|
||||
option to be unset for proper operation.
|
||||
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80
|
@ -1,84 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.3
|
||||
===============================
|
||||
|
||||
This release is minor feature release. It improves support for zsh (although it
|
||||
still isn't what it could be) and adds automated testing framework support by
|
||||
returning a non-zero exit when tests fail.
|
||||
|
||||
To use zsh with shUnit2, the following two requirements must be met:
|
||||
* The ``shwordsplit`` option must be set.
|
||||
* The ``function_argzero`` option must be unset.
|
||||
|
||||
Please read the Shell Errata section of the documentation for guidance on how
|
||||
to meet these requirements.
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
Cygwin
|
||||
|
||||
- bash 3.2.33(18)
|
||||
- pdksh 5.2.14
|
||||
|
||||
Linux
|
||||
|
||||
- bash 3.2.33(1)
|
||||
- dash 0.5.4
|
||||
- ksh 1993-12-28
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.4
|
||||
|
||||
Mac OS X 10.5.2 (Darwin 9.2.2)
|
||||
|
||||
- bash 3.2.17(1)
|
||||
- ksh 1993-12-28
|
||||
- zsh 4.3.4
|
||||
|
||||
Solaris 11 x86 (Nevada 77)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.2.25(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 4.3.4
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Support for automated testing frameworks.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
Fixed some issues with zsh support.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
Functions do not properly test for an invalid number of arguments.
|
||||
|
||||
ksh and pdksh do not pass null arguments (i.e. empty strings as '') properly,
|
||||
and as such checks do not work properly.
|
||||
|
||||
zsh requires the ``shwordsplit`` option to be set, and the ``function_argzero``
|
||||
option to be unset for proper operation.
|
||||
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:textwidth=80
|
@ -1,100 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.4
|
||||
===============================
|
||||
|
||||
This release contains lots of bug fixes and changes. Mostly, it fixes zsh
|
||||
support in zsh 3.0, and the handling of null values in ksh.
|
||||
|
||||
To use zsh with shUnit2, the following requirement must be met:
|
||||
|
||||
- The ``shwordsplit`` option must be set.
|
||||
|
||||
Please read the Shell Errata section of the documentation for guidance on how
|
||||
to meet these requirements.
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
Cygwin
|
||||
|
||||
- bash 3.2.39(19)
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.4
|
||||
|
||||
Linux (Ubuntu Dapper 6.06)
|
||||
|
||||
- bash 3.1.17(1)
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.2.5
|
||||
|
||||
Linux (Ubuntu Hardy 8.04)
|
||||
|
||||
- bash 3.2.39(1)
|
||||
- dash 0.5.4
|
||||
- ksh 1993-12-28
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.4
|
||||
|
||||
Mac OS X 10.5.4 (Darwin 9.4.0)
|
||||
|
||||
- bash 3.2.17(1)
|
||||
- ksh 1993-12-28
|
||||
- zsh 4.3.4
|
||||
|
||||
Solaris 9 U6 x86
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.05.0(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 3.0.8
|
||||
|
||||
Solaris 11 x86 (Nevada 77)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.2.25(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 4.3.4
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
Support added to output assert source line number as part of assert messages.
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Support for automated testing frameworks.
|
||||
|
||||
Added argument count error checking to all functions.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
Fixed some issues with ksh and zsh support.
|
||||
|
||||
Fixed off-by-one of exit value in trap handler.
|
||||
|
||||
Fixed handling of null values under ksh.
|
||||
|
||||
Fixed bug in last resort temporary directory creation.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
zsh requires the ``shwordsplit`` option to be set.
|
||||
|
||||
Line numbers in assert messages do not work properly with Bash 2.x.
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:tw=80
|
@ -1,128 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.5
|
||||
===============================
|
||||
|
||||
This release contains several bug fixes and changes. Additionally, it includes
|
||||
a rewrite of the test output to better match JUnit and PyUnit.
|
||||
|
||||
This version also includes a slightly expanded set of coding standards by which
|
||||
shUnit2 is coded. It should help anyone reading the code to better understand
|
||||
it.
|
||||
|
||||
|
||||
|
||||
Please read the Shell Errata section of the documentation for guidance on how
|
||||
to meet these requirements.
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
Cygwin
|
||||
|
||||
- bash 3.2.39(20)
|
||||
- ksh (sym-link to pdksh)
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.4
|
||||
|
||||
Linux (Ubuntu Dapper 6.06)
|
||||
|
||||
- bash 3.1.17(1)
|
||||
- ksh M-1993-12-28
|
||||
- pdksh 5.2.14-99/07/13.2
|
||||
- zsh 4.2.5
|
||||
|
||||
Linux (Ubuntu Hardy 8.04)
|
||||
|
||||
- bash 3.2.39(1)
|
||||
- dash 0.5.4
|
||||
- ksh M-1993-12-28
|
||||
- pdksh 5.2.14-99/07/13.2
|
||||
- zsh 4.3.4
|
||||
|
||||
Mac OS X 10.5.4 (Darwin 9.4.0)
|
||||
|
||||
- bash 3.2.17(1)
|
||||
- ksh M-1993-12-28
|
||||
- zsh 4.3.4
|
||||
|
||||
Solaris 9 U6 x86
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.05.0(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 3.0.8
|
||||
|
||||
Solaris 11 x86 (Nevada 77)
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.2.25(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 4.3.4
|
||||
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
Support added for output assert source line number as part of assert messages.
|
||||
|
||||
Issue #2: Added assertNotEquals() assert.
|
||||
|
||||
Provided a public ``shunit_tmpDir`` variable that can be used by unit test
|
||||
scripts that need automated and guaranteed cleanup.
|
||||
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Issue #3: Removed the check for unset variables as shUnit2 should not expect
|
||||
scripts being tested to be clean.
|
||||
|
||||
Issue #4: Rewrote the test summary. It is now greatly simplified and much more
|
||||
script friendly.
|
||||
|
||||
Issue #5: Fixed the documentation around the usage of failures.
|
||||
|
||||
Issue #9: Added unit tests and improved documentation around the use of macros.
|
||||
|
||||
Code updated to meet documented coding standards.
|
||||
|
||||
Improved code reuse of ``_shunit_exit()`` and ``_shunit_fatal()`` functions.
|
||||
|
||||
All output except shUnit2 error messages now goes to STDOUT.
|
||||
|
||||
Converted DocBook documentation to reStructuredText for easier maintenance.
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
Issue #1: Fixed bug in rap code where certain types of exit conditions did not
|
||||
generate the ending report.
|
||||
|
||||
Issue #7: Fixed duplicated printing of messages passed to asserts.
|
||||
|
||||
Fixed bugs in ``shlib_relToAbsPath()`` in ``shlib``.
|
||||
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
Zsh requires the ``shwordsplit`` option to be set. See the documentation for
|
||||
examples of how to do this.
|
||||
|
||||
Line numbers in assert messages do not work properly with BASH 2.x.
|
||||
|
||||
The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the
|
||||
SIGTERM signal. As such, shell interpreter failures due to such things as
|
||||
unbound variables cannot be caught. (See ``shunit_test_misc.sh``)
|
||||
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:tw=80
|
@ -1,112 +0,0 @@
|
||||
Release Notes for shUnit2 2.1.6
|
||||
===============================
|
||||
|
||||
This release contains bug fixes and changes. It is also the first release to
|
||||
support running shunit2 as a standalone program.
|
||||
|
||||
Please read the Shell Errata section of the documentation for guidance on how
|
||||
to meet these requirements.
|
||||
|
||||
See the ``CHANGES-2.1.txt`` file for a full list of changes.
|
||||
|
||||
New Features
|
||||
------------
|
||||
|
||||
Support for running shUnit2 as a standalone program. This makes it possible for
|
||||
users to execute their unit tests in a manner that is not dependent on the
|
||||
location an OS distribution maintainer chose to place shUnit2 in the file
|
||||
system.
|
||||
|
||||
Added support for functions defined like 'function someFunction()'.
|
||||
|
||||
Changes and Enhancements
|
||||
------------------------
|
||||
|
||||
Renamed the public ``shunit_tmpDir`` variable to ``SHUNIT_TMPDIR`` to be more
|
||||
consistent with the ``TMPDIR`` variable.
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
Fixed issue where shunit2 would fail on some distributions when creating a
|
||||
temporary directory because the **od** command was not present.
|
||||
|
||||
Deprecated Features
|
||||
-------------------
|
||||
|
||||
None.
|
||||
|
||||
Known Bugs and Issues
|
||||
---------------------
|
||||
|
||||
Zsh requires the ``shwordsplit`` option to be set. See the documentation for
|
||||
examples of how to do this.
|
||||
|
||||
Line numbers in assert messages do not work properly with BASH 2.x.
|
||||
|
||||
The Bourne shell of Solaris, BASH 2.x, and Zsh 3.0.x do not properly catch the
|
||||
SIGTERM signal. As such, shell interpreter failures due to such things as
|
||||
unbound variables cannot be caught. (See ``shunit_test_misc.sh``)
|
||||
|
||||
Tested Platforms
|
||||
----------------
|
||||
|
||||
Cygwin 1.7.9 (Windows XP SP2)
|
||||
|
||||
- bash 4.1.10(4)
|
||||
- dash 0.5.6.1
|
||||
- ksh (sym-link to pdksh)
|
||||
- pdksh 5.2.14
|
||||
- zsh 4.3.11
|
||||
|
||||
Linux (Ubuntu Dapper 6.06.2 LTS)
|
||||
|
||||
- bash 3.1.17(1)
|
||||
- dash 0.5.3
|
||||
- ksh (sym-link to pdksh)
|
||||
- pdksh 5.2.14-99/07/13.2
|
||||
- zsh 4.2.5
|
||||
|
||||
Linux (Ubuntu Hardy 8.04.4 LTS)
|
||||
|
||||
- bash 3.2.39(1)
|
||||
- dash 0.5.4
|
||||
- ksh M-1993-12-28
|
||||
- pdksh 5.2.14-99/07/13.2
|
||||
- zsh 4.3.4
|
||||
|
||||
Linux (Ubuntu Lucid 10.04.2 LTS)
|
||||
|
||||
- bash 4.1.5(1)
|
||||
- dash 0.5.5.1
|
||||
- ksh JM-93t+-2009-05-01
|
||||
- pdksh 5.2.14-99/07/13.2
|
||||
- zsh 4.3.10
|
||||
|
||||
Mac OS X 10.6.7
|
||||
|
||||
- bash 3.2.48(1)
|
||||
- ksh M-1993-12-28
|
||||
- zsh 4.3.9
|
||||
|
||||
Solaris 8 U7 x86
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.03.0(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 3.0.6
|
||||
|
||||
Solaris 9 U6 x86
|
||||
|
||||
- /bin/sh
|
||||
- bash 2.05.0(1)
|
||||
- ksh M-11/16/88i
|
||||
- zsh 3.0.8
|
||||
|
||||
OpenSolaris 2009.06(snv_111b) x86
|
||||
|
||||
- /bin/sh
|
||||
- bash 3.2.25(1)
|
||||
- ksh 2008-11-04
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:tw=80
|
@ -1,13 +0,0 @@
|
||||
Make it possible to execute a single test by passing the name of the test on
|
||||
the command line
|
||||
|
||||
Add support for '--randomize-order' so that the test order is randomized to
|
||||
check for dependencies (which shouldn't be there) between tests.
|
||||
|
||||
--debug option to display point in source code (line number and such) where the
|
||||
problem showed up.
|
||||
|
||||
assertTrue() just gives 'ASSERT:', nothing else :-(. others too?
|
||||
upd: assertNull() will give message passed, but nothing else useful :-(
|
||||
|
||||
$Revision: 228 $
|
@ -1,74 +0,0 @@
|
||||
Coding Standards
|
||||
================
|
||||
|
||||
Variable and Function Names
|
||||
---------------------------
|
||||
|
||||
All shUnit2 specific constants, variables, and functions will be prefixed
|
||||
appropriately with 'shunit'. This is to distinguish usage in the shUnit2 code
|
||||
from users own scripts so that the shell name space remains predictable to
|
||||
users. The exceptions here are the standard ``assertEquals``, etc. functions.
|
||||
|
||||
All non-builtin constants and variables will be surrouned with squiggle
|
||||
brackets, e.g. '${shunit_someVariable}' to improve code readability.
|
||||
|
||||
Due to some shells not supporting local variables in functions, care in the
|
||||
naming and use of variables, both public and private, is very important.
|
||||
Accidental overriding of the variables can occur easily if care is not taken as
|
||||
all variables are technically global variables in some shells.
|
||||
|
||||
+----------------------------------+---------------------------+
|
||||
| *type* | *sample* |
|
||||
+==================================+===========================+
|
||||
| global public constant | ``SHUNIT_TRUE`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| global private constant | ``__SHUNIT_SHELL_FLAGS`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| global public variable | not used |
|
||||
+----------------------------------+---------------------------+
|
||||
| global private variable | ``__shunit_someVariable`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| global macro | ``_SHUNIT_SOME_MACRO_`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| public function | ``assertEquals`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| public function, local variable | ``shunit_someVariable_`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| private function | ``_shunit_someFunction`` |
|
||||
+----------------------------------+---------------------------+
|
||||
| private function, local variable | ``_shunit_someVariable_`` |
|
||||
+----------------------------------+---------------------------+
|
||||
|
||||
Where it makes sense, variables can have the first letter of the second and
|
||||
later words capitalized. For example, the local variable name for the total
|
||||
number of test cases seen might be ``shunit_totalTestsSeen_``.
|
||||
|
||||
Local Variable Cleanup
|
||||
----------------------
|
||||
|
||||
As many shells do not support local variables, no support for cleanup of
|
||||
variables is present either. As such, all variables local to a function must be
|
||||
cleared up with the ``unset`` command at the end of each function.
|
||||
|
||||
Indentation
|
||||
-----------
|
||||
|
||||
Code block indentation is two (2) spaces, and tabs may not be used. ::
|
||||
|
||||
if [ -z 'some string' ]; then
|
||||
someFunction
|
||||
fi
|
||||
|
||||
Lines of code should be no longer than 80 characters unless absolutely
|
||||
necessary. When lines are wrapped using the backslash character '\', subsequent
|
||||
lines should be indented with four (4) spaces so as to differentiate from the
|
||||
standard spacing of two characters. Tabs may *not* be used. ::
|
||||
|
||||
for x in some set of very long set of arguments that make for a very long \
|
||||
that extends much too long for one line
|
||||
do
|
||||
echo ${x}
|
||||
done
|
||||
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:tw=80
|
||||
.. $Revision: 301 $
|
@ -1,14 +0,0 @@
|
||||
The original author of shunit2 is Kate Ward. The following people have
|
||||
contributed in some way or another to shunit2.
|
||||
|
||||
Bryan Larsen
|
||||
Kevin Van Horn
|
||||
Maciej Bliziński
|
||||
Mario Sparada
|
||||
Mathias Goldau
|
||||
Richard Jensen
|
||||
Rob Holland
|
||||
Rocky Bernstein
|
||||
wood4321 (of code.google.com)
|
||||
|
||||
$Revision: 313 $
|
@ -1,34 +0,0 @@
|
||||
Design Doc for shUnit
|
||||
|
||||
shUnit is based upon JUnit. The initial ideas for the script came from the book
|
||||
"Pragmatic Unit Testing - In Java with JUnit" by Andrew Hunt and David Thomas.
|
||||
|
||||
The script was written to perform unit testing for log4sh. log4sh had grown
|
||||
enough that it was becoming difficult to easily test and and verify that the
|
||||
tests passed for the many different operating systems on which it was being
|
||||
used.
|
||||
|
||||
The functions in shUnit are meant to match those in JUnit as much as possible
|
||||
where shell allows. In the initial version, there will be no concept of
|
||||
exceptions (as normal POSIX shell has no concept of them) but attempts to trap
|
||||
problems will be done.
|
||||
|
||||
Programatic Standards:
|
||||
|
||||
* SHUNIT_TRUE - public global constant
|
||||
* __SHUNIT_SHELL_FLAGS - private global constant
|
||||
* __shunit_oldShellFlags - private global variable
|
||||
|
||||
* assertEquals - public unit test function
|
||||
* shunit_publicFunc - public shUnit function; can be called from parent unit
|
||||
test script
|
||||
* _shunit_privateFunc - private shUnit function; should not be called from
|
||||
parent script. meant for internal use by shUnit
|
||||
|
||||
* _su_myVar - variable inside a public function. prefixing with '_su_' to
|
||||
reduce the chances that a variable outside of shUnit will be overridden.
|
||||
* _su__myVar - variable inside a private function. prefixing with '_su__' to
|
||||
reduce the chances that a variable in a shUnit public function, or a variable
|
||||
outside of shUnit will be overridden.
|
||||
|
||||
$Revision: 4 $
|
@ -1,292 +0,0 @@
|
||||
/*
|
||||
:Author: David Goodger
|
||||
:Contact: goodger@users.sourceforge.net
|
||||
:Date: $Date: 2007-04-11 11:48:16 +0100 (Wed, 11 Apr 2007) $
|
||||
:Revision: $Revision: 2791 $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
:Modified by: Kate Ward <kate.ward@forestent.com>
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin-left: 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left {
|
||||
clear: left }
|
||||
|
||||
img.align-right {
|
||||
clear: right }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font-family: serif ;
|
||||
font-size: 100% }
|
||||
|
||||
pre.literal-block, pre.doctest-block {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em ;
|
||||
background-color: #eeeeee }
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
/*
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
*/
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px ;
|
||||
font-size: 80% }
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
/*
|
||||
tt.docutils {
|
||||
background-color: #eeeeee }
|
||||
*/
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
/* customizations by kward */
|
||||
|
||||
h1 { font-size: 133%; border-top:1px solid #CCCCFF; }
|
||||
h1.title { font-size: 150%; border-top:0px; padding-top: 1em; }
|
||||
/* div.document { font-size: 90% } */
|
@ -1,880 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
|
||||
<title>shUnit2 2.1.x Documentation</title>
|
||||
<style type="text/css">
|
||||
|
||||
/*
|
||||
:Author: David Goodger
|
||||
:Contact: goodger@users.sourceforge.net
|
||||
:Date: $Date: 2007-04-11 11:48:16 +0100 (Wed, 11 Apr 2007) $
|
||||
:Revision: $Revision: 2791 $
|
||||
:Copyright: This stylesheet has been placed in the public domain.
|
||||
:Modified by: Kate Ward <kate.ward@forestent.com>
|
||||
|
||||
Default cascading style sheet for the HTML output of Docutils.
|
||||
|
||||
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
|
||||
customize this style sheet.
|
||||
*/
|
||||
|
||||
/* used to remove borders from tables and images */
|
||||
.borderless, table.borderless td, table.borderless th {
|
||||
border: 0 }
|
||||
|
||||
table.borderless td, table.borderless th {
|
||||
/* Override padding for "table.docutils td" with "! important".
|
||||
The right padding separates the table cells. */
|
||||
padding: 0 0.5em 0 0 ! important }
|
||||
|
||||
.first {
|
||||
/* Override more specific margin styles with "! important". */
|
||||
margin-top: 0 ! important }
|
||||
|
||||
.last, .with-subtitle {
|
||||
margin-bottom: 0 ! important }
|
||||
|
||||
.hidden {
|
||||
display: none }
|
||||
|
||||
a.toc-backref {
|
||||
text-decoration: none ;
|
||||
color: black }
|
||||
|
||||
blockquote.epigraph {
|
||||
margin: 2em 5em ; }
|
||||
|
||||
dl.docutils dd {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
/* Uncomment (and remove this text!) to get bold-faced definition list terms
|
||||
dl.docutils dt {
|
||||
font-weight: bold }
|
||||
*/
|
||||
|
||||
div.abstract {
|
||||
margin: 2em 5em }
|
||||
|
||||
div.abstract p.topic-title {
|
||||
font-weight: bold ;
|
||||
text-align: center }
|
||||
|
||||
div.admonition, div.attention, div.caution, div.danger, div.error,
|
||||
div.hint, div.important, div.note, div.tip, div.warning {
|
||||
margin: 2em ;
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.admonition p.admonition-title, div.hint p.admonition-title,
|
||||
div.important p.admonition-title, div.note p.admonition-title,
|
||||
div.tip p.admonition-title {
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
div.attention p.admonition-title, div.caution p.admonition-title,
|
||||
div.danger p.admonition-title, div.error p.admonition-title,
|
||||
div.warning p.admonition-title {
|
||||
color: red ;
|
||||
font-weight: bold ;
|
||||
font-family: sans-serif }
|
||||
|
||||
/* Uncomment (and remove this text!) to get reduced vertical space in
|
||||
compound paragraphs.
|
||||
div.compound .compound-first, div.compound .compound-middle {
|
||||
margin-bottom: 0.5em }
|
||||
|
||||
div.compound .compound-last, div.compound .compound-middle {
|
||||
margin-top: 0.5em }
|
||||
*/
|
||||
|
||||
div.dedication {
|
||||
margin: 2em 5em ;
|
||||
text-align: center ;
|
||||
font-style: italic }
|
||||
|
||||
div.dedication p.topic-title {
|
||||
font-weight: bold ;
|
||||
font-style: normal }
|
||||
|
||||
div.figure {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em }
|
||||
|
||||
div.footer, div.header {
|
||||
clear: both;
|
||||
font-size: smaller }
|
||||
|
||||
div.line-block {
|
||||
display: block ;
|
||||
margin-top: 1em ;
|
||||
margin-bottom: 1em }
|
||||
|
||||
div.line-block div.line-block {
|
||||
margin-top: 0 ;
|
||||
margin-bottom: 0 ;
|
||||
margin-left: 1.5em }
|
||||
|
||||
div.sidebar {
|
||||
margin-left: 1em ;
|
||||
border: medium outset ;
|
||||
padding: 1em ;
|
||||
background-color: #ffffee ;
|
||||
width: 40% ;
|
||||
float: right ;
|
||||
clear: right }
|
||||
|
||||
div.sidebar p.rubric {
|
||||
font-family: sans-serif ;
|
||||
font-size: medium }
|
||||
|
||||
div.system-messages {
|
||||
margin: 5em }
|
||||
|
||||
div.system-messages h1 {
|
||||
color: red }
|
||||
|
||||
div.system-message {
|
||||
border: medium outset ;
|
||||
padding: 1em }
|
||||
|
||||
div.system-message p.system-message-title {
|
||||
color: red ;
|
||||
font-weight: bold }
|
||||
|
||||
div.topic {
|
||||
margin: 2em }
|
||||
|
||||
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
|
||||
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
|
||||
margin-top: 0.4em }
|
||||
|
||||
h1.title {
|
||||
text-align: center }
|
||||
|
||||
h2.subtitle {
|
||||
text-align: center }
|
||||
|
||||
hr.docutils {
|
||||
width: 75% }
|
||||
|
||||
img.align-left {
|
||||
clear: left }
|
||||
|
||||
img.align-right {
|
||||
clear: right }
|
||||
|
||||
ol.simple, ul.simple {
|
||||
margin-bottom: 1em }
|
||||
|
||||
ol.arabic {
|
||||
list-style: decimal }
|
||||
|
||||
ol.loweralpha {
|
||||
list-style: lower-alpha }
|
||||
|
||||
ol.upperalpha {
|
||||
list-style: upper-alpha }
|
||||
|
||||
ol.lowerroman {
|
||||
list-style: lower-roman }
|
||||
|
||||
ol.upperroman {
|
||||
list-style: upper-roman }
|
||||
|
||||
p.attribution {
|
||||
text-align: right ;
|
||||
margin-left: 50% }
|
||||
|
||||
p.caption {
|
||||
font-style: italic }
|
||||
|
||||
p.credits {
|
||||
font-style: italic ;
|
||||
font-size: smaller }
|
||||
|
||||
p.label {
|
||||
white-space: nowrap }
|
||||
|
||||
p.rubric {
|
||||
font-weight: bold ;
|
||||
font-size: larger ;
|
||||
color: maroon ;
|
||||
text-align: center }
|
||||
|
||||
p.sidebar-title {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold ;
|
||||
font-size: larger }
|
||||
|
||||
p.sidebar-subtitle {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
p.topic-title {
|
||||
font-weight: bold }
|
||||
|
||||
pre.address {
|
||||
margin-bottom: 0 ;
|
||||
margin-top: 0 ;
|
||||
font-family: serif ;
|
||||
font-size: 100% }
|
||||
|
||||
pre.literal-block, pre.doctest-block {
|
||||
margin-left: 2em ;
|
||||
margin-right: 2em ;
|
||||
background-color: #eeeeee }
|
||||
|
||||
span.classifier {
|
||||
font-family: sans-serif ;
|
||||
font-style: oblique }
|
||||
|
||||
span.classifier-delimiter {
|
||||
font-family: sans-serif ;
|
||||
font-weight: bold }
|
||||
|
||||
span.interpreted {
|
||||
font-family: sans-serif }
|
||||
|
||||
span.option {
|
||||
white-space: nowrap }
|
||||
|
||||
span.pre {
|
||||
white-space: pre }
|
||||
|
||||
span.problematic {
|
||||
color: red }
|
||||
|
||||
span.section-subtitle {
|
||||
/* font-size relative to parent (h1..h6 element) */
|
||||
font-size: 80% }
|
||||
|
||||
table.citation {
|
||||
border-left: solid 1px gray;
|
||||
margin-left: 1px }
|
||||
|
||||
table.docinfo {
|
||||
margin: 2em 4em }
|
||||
|
||||
/*
|
||||
table.docutils {
|
||||
margin-top: 0.5em ;
|
||||
margin-bottom: 0.5em }
|
||||
*/
|
||||
|
||||
table.footnote {
|
||||
border-left: solid 1px black;
|
||||
margin-left: 1px ;
|
||||
font-size: 80% }
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th,
|
||||
table.docinfo td, table.docinfo th {
|
||||
padding-left: 0.5em ;
|
||||
padding-right: 0.5em ;
|
||||
vertical-align: top }
|
||||
|
||||
table.docutils th.field-name, table.docinfo th.docinfo-name {
|
||||
font-weight: bold ;
|
||||
text-align: left ;
|
||||
white-space: nowrap ;
|
||||
padding-left: 0 }
|
||||
|
||||
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
|
||||
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
|
||||
font-size: 100% }
|
||||
|
||||
/*
|
||||
tt.docutils {
|
||||
background-color: #eeeeee }
|
||||
*/
|
||||
|
||||
ul.auto-toc {
|
||||
list-style-type: none }
|
||||
|
||||
/* customizations by kward */
|
||||
|
||||
h1 { font-size: 133%; border-top:1px solid #CCCCFF; }
|
||||
h1.title { font-size: 150%; border-top:0px; padding-top: 1em; }
|
||||
/* div.document { font-size: 90% } */
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="document" id="shunit2-2-1-x-documentation">
|
||||
<h1 class="title">shUnit2 2.1.x Documentation</h1>
|
||||
|
||||
<div class="section" id="abstract">
|
||||
<h1><a class="toc-backref" href="#id1">Abstract</a></h1>
|
||||
<p><a class="reference external" href="http://shunit2.googlecode.com/">shUnit2</a> is a <a class="reference external" href="http://en.wikipedia.org/wiki/XUnit">xUnit</a> unit test framework for Bourne based shell scripts, and it
|
||||
is designed to work in a similar manner to <a class="reference external" href="http://www.junit.org/">JUnit</a>, <a class="reference external" href="http://pyunit.sourceforge.net/">PyUnit</a>, etc.. If you have
|
||||
ever had the desire to write a unit test for a shell script, shUnit2 can do the
|
||||
job.</p>
|
||||
<div class="contents topic" id="table-of-contents">
|
||||
<p class="topic-title first">Table of Contents</p>
|
||||
<ul class="simple">
|
||||
<li><a class="reference internal" href="#abstract" id="id1">Abstract</a></li>
|
||||
<li><a class="reference internal" href="#introduction" id="id2">Introduction</a><ul>
|
||||
<li><a class="reference internal" href="#credits-contributors" id="id3">Credits / Contributors</a></li>
|
||||
<li><a class="reference internal" href="#feedback" id="id4">Feedback</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#quickstart" id="id5">Quickstart</a></li>
|
||||
<li><a class="reference internal" href="#function-reference" id="id6">Function Reference</a><ul>
|
||||
<li><a class="reference internal" href="#general-info" id="id7">General Info</a></li>
|
||||
<li><a class="reference internal" href="#asserts" id="id8">Asserts</a></li>
|
||||
<li><a class="reference internal" href="#failures" id="id9">Failures</a></li>
|
||||
<li><a class="reference internal" href="#setup-teardown" id="id10">Setup/Teardown</a></li>
|
||||
<li><a class="reference internal" href="#skipping" id="id11">Skipping</a></li>
|
||||
<li><a class="reference internal" href="#suites" id="id12">Suites</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#advanced-usage" id="id13">Advanced Usage</a><ul>
|
||||
<li><a class="reference internal" href="#some-constants-you-can-use" id="id14">Some constants you can use</a></li>
|
||||
<li><a class="reference internal" href="#error-handling" id="id15">Error handling</a></li>
|
||||
<li><a class="reference internal" href="#including-line-numbers-in-asserts-macros" id="id16">Including Line Numbers in Asserts (Macros)</a></li>
|
||||
<li><a class="reference internal" href="#test-skipping" id="id17">Test Skipping</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#appendix" id="id18">Appendix</a><ul>
|
||||
<li><a class="reference internal" href="#getting-help" id="id19">Getting help</a></li>
|
||||
<li><a class="reference internal" href="#zsh" id="id20">Zsh</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="introduction">
|
||||
<h1><a class="toc-backref" href="#id2">Introduction</a></h1>
|
||||
<p>shUnit2 was originally developed to provide a consistent testing solution for
|
||||
<a class="reference external" href="http://log4sh.sourceforge.net/">log4sh</a>, a shell based logging framework similar to <a class="reference external" href="http://logging.apache.org/">log4j</a>. During the
|
||||
development of that product, a repeated problem of having things work just fine
|
||||
under one shell (<tt class="docutils literal">/bin/bash</tt> on Linux to be specific), and then not working
|
||||
under another shell (<tt class="docutils literal">/bin/sh</tt> on Solaris) kept coming up. Although several
|
||||
simple tests were run, they were not adequate and did not catch some corner
|
||||
cases. The decision was finally made to write a proper unit test framework after
|
||||
multiple brown-bag releases were made. <em>Research was done to look for an
|
||||
existing product that met the testing requirements, but no adequate product was
|
||||
found.</em></p>
|
||||
<p>Tested Operating Systems (varies over time)</p>
|
||||
<ul class="simple">
|
||||
<li>Cygwin</li>
|
||||
<li>FreeBSD (user supported)</li>
|
||||
<li>Linux (Gentoo, Ubuntu)</li>
|
||||
<li>Mac OS X</li>
|
||||
<li>Solaris 8, 9, 10 (inc. OpenSolaris)</li>
|
||||
</ul>
|
||||
<p>Tested Shells</p>
|
||||
<ul class="simple">
|
||||
<li>Bourne Shell (<strong>sh</strong>)</li>
|
||||
<li>BASH - GNU Bourne Again SHell (<strong>bash</strong>)</li>
|
||||
<li>DASH (<strong>dash</strong>)</li>
|
||||
<li>Korn Shell (<strong>ksh</strong>)</li>
|
||||
<li>pdksh - Public Domain Korn Shell (<strong>pdksh</strong>)</li>
|
||||
<li>zsh - Zsh (<strong>zsh</strong>) (since 2.1.2) <em>please see the Zsh shell errata for more
|
||||
information</em></li>
|
||||
</ul>
|
||||
<p>See the appropriate Release Notes for this release
|
||||
(<tt class="docutils literal"><span class="pre">doc/RELEASE_NOTES-X.X.X.txt</span></tt>) for the list of actual versions tested.</p>
|
||||
<div class="section" id="credits-contributors">
|
||||
<h2><a class="toc-backref" href="#id3">Credits / Contributors</a></h2>
|
||||
<p>A list of contributors to shUnit2 can be found in the source archive in
|
||||
<tt class="docutils literal">doc/contributors.txt</tt>. Many thanks go out to all those who have contributed
|
||||
to make this a better tool.</p>
|
||||
<p>shUnit2 is the original product of many hours of work by Kate Ward, the primary
|
||||
author of the code. For other products by her, look up <a class="reference external" href="http://log4sh.sourceforge.net/">log4sh</a> or <a class="reference external" href="http://shflags.googlecode.com/">shFlags</a>, or
|
||||
visit her website at <a class="reference external" href="http://forestent.com/">http://forestent.com/</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="feedback">
|
||||
<h2><a class="toc-backref" href="#id4">Feedback</a></h2>
|
||||
<p>Feedback is most certainly welcome for this document. Send your additions,
|
||||
comments and criticisms to the <a class="reference external" href="mailto:shunit2-users@google.com">shunit2-users@google.com</a> mailing list.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="quickstart">
|
||||
<h1><a class="toc-backref" href="#id5">Quickstart</a></h1>
|
||||
<p>This section will give a very quick start to running unit tests with shUnit2.
|
||||
More information is located in later sections.</p>
|
||||
<p>Here is a quick sample script to show how easy it is to write a unit test in
|
||||
shell. <em>Note: the script as it stands expects that you are running it from the
|
||||
``examples`` directory.</em></p>
|
||||
<pre class="literal-block">
|
||||
#! /bin/sh
|
||||
# file: examples/equality_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
</pre>
|
||||
<p>Running the unit test should give results similar to the following.</p>
|
||||
<pre class="literal-block">
|
||||
testEquality
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK
|
||||
</pre>
|
||||
<p>W00t! You've just run your first successful unit test. So, what just happened?
|
||||
Quite a bit really, and it all happened simply by sourcing the <tt class="docutils literal">shunit2</tt>
|
||||
library. The basic functionality for the script above goes like this:</p>
|
||||
<ul class="simple">
|
||||
<li>When shUnit2 is sourced, it will walk through any functions defined whose
|
||||
namestart with the string <tt class="docutils literal">test</tt> and add those to an internal list of tests
|
||||
to execute. Once a list of test functions to be run has been determined,
|
||||
shunit2 will go to work.</li>
|
||||
<li>Before any tests are executed, shUnit2 again looks for a function, this time
|
||||
one named <tt class="docutils literal">oneTimeSetUp()</tt>. If it exists, it will be run. This function is
|
||||
normally used to setup the environment for all tests to be run. Things like
|
||||
creating directories for output or setting environment variables are good to
|
||||
place here. Just so you know, you can also declare a corresponding function
|
||||
named <tt class="docutils literal">oneTimeTearDown()</tt> function that does the same thing, but once all
|
||||
the tests have been completed. It is good for removing temporary directories,
|
||||
etc.</li>
|
||||
<li>shUnit2 is now ready to run tests. Before doing so though, it again looks for
|
||||
another function that might be declared, one named <tt class="docutils literal">setUp()</tt>. If the
|
||||
function exists, it will be run before each test. It is good for resetting the
|
||||
environment so that each test starts with a clean slate. At this stage, the
|
||||
first test is finally run. The success of the test is recorded for a report
|
||||
that will be generated later. After the test is run, shUnit2 looks for a final
|
||||
function that might be declared, one named <tt class="docutils literal">tearDown()</tt>. If it exists, it
|
||||
will be run after each test. It is a good place for cleaning up after each
|
||||
test, maybe doing things like removing files that were created, or removing
|
||||
directories. This set of steps, <tt class="docutils literal">setUp()</tt> > <tt class="docutils literal">test()</tt> > <tt class="docutils literal">tearDown()</tt>, is
|
||||
repeated for all of the available tests.</li>
|
||||
<li>Once all the work is done, shUnit2 will generate the nice report you saw
|
||||
above. A summary of all the successes and failures will be given so that you
|
||||
know how well your code is doing.</li>
|
||||
</ul>
|
||||
<p>We should now try adding a test that fails. Change your unit test to look like
|
||||
this.</p>
|
||||
<pre class="literal-block">
|
||||
#! /bin/sh
|
||||
# file: examples/party_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
testPartyLikeItIs1999()
|
||||
{
|
||||
year=`date '+%Y'`
|
||||
assertEquals "It's not 1999 :-(" \
|
||||
'1999' "${year}"
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
</pre>
|
||||
<p>So, what did you get? I guess it told you that this isn't 1999. Bummer, eh?
|
||||
Hopefully, you noticed a couple of things that were different about the second
|
||||
test. First, we added an optional message that the user will see if the assert
|
||||
fails. Second, we did comparisons of strings instead of integers as in the first
|
||||
test. It doesn't matter whether you are testing for equality of strings or
|
||||
integers. Both work equally well with shUnit2.</p>
|
||||
<p>Hopefully, this is enough to get you started with unit testing. If you want a
|
||||
ton more examples, take a look at the tests provided with <a class="reference external" href="http://log4sh.sourceforge.net/">log4sh</a> or <a class="reference external" href="http://shflags.googlecode.com/">shFlags</a>.
|
||||
Both provide excellent examples of more advanced usage. shUnit2 was after all
|
||||
written to help with the unit testing problems that <a class="reference external" href="http://log4sh.sourceforge.net/">log4sh</a> had.</p>
|
||||
</div>
|
||||
<div class="section" id="function-reference">
|
||||
<h1><a class="toc-backref" href="#id6">Function Reference</a></h1>
|
||||
<div class="section" id="general-info">
|
||||
<h2><a class="toc-backref" href="#id7">General Info</a></h2>
|
||||
<p>Any string values passed should be properly quoted -- they should must be
|
||||
surrounded by single-quote (') or double-quote (") characters -- so that the
|
||||
shell will properly parse them.</p>
|
||||
</div>
|
||||
<div class="section" id="asserts">
|
||||
<h2><a class="toc-backref" href="#id8">Asserts</a></h2>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">assertEquals [message] expected actual</tt></dt>
|
||||
<dd>Asserts that <em>expected</em> and <em>actual</em> are equal to one another. The <em>expected</em>
|
||||
and <em>actual</em> values can be either strings or integer values as both will be
|
||||
treated as strings. The <em>message</em> is optional, and must be quoted.</dd>
|
||||
<dt><tt class="docutils literal">assertNotEquals [message] expected actual</tt></dt>
|
||||
<dd>Asserts that <em>unexpected</em> and <em>actual</em> are not equal to one another. The
|
||||
<em>unexpected</em> and <em>actual</em> values can be either strings or integer values as
|
||||
both will be treaded as strings. The <em>message</em> is optional, and must be
|
||||
quoted.</dd>
|
||||
<dt><tt class="docutils literal">assertSame [message] expected actual</tt></dt>
|
||||
<dd>This function is functionally equivalent to <tt class="docutils literal">assertEquals</tt>.</dd>
|
||||
<dt><tt class="docutils literal">assertNotSame [message] unexpected actual</tt></dt>
|
||||
<dd>This function is functionally equivalent to <tt class="docutils literal">assertNotEquals</tt>.</dd>
|
||||
<dt><tt class="docutils literal">assertNull [message] value</tt></dt>
|
||||
<dd>Asserts that <em>value</em> is <em>null</em>, or in shell terms, a zero-length string. The
|
||||
<em>value</em> must be a string as an integer value does not translate into a
|
||||
zero-length string. The <em>message</em> is optional, and must be quoted.</dd>
|
||||
<dt><tt class="docutils literal">assertNotNull [message] value</tt></dt>
|
||||
<dd>Asserts that <em>value</em> is <em>not null</em>, or in shell terms, a non-empty string. The
|
||||
<em>value</em> may be a string or an integer as the later will be parsed as a
|
||||
non-empty string value. The <em>message</em> is optional, and must be quoted.</dd>
|
||||
<dt><tt class="docutils literal">assertTrue [message] condition</tt></dt>
|
||||
<dd><p class="first">Asserts that a given shell test <em>condition</em> is <em>true</em>. The condition can be as
|
||||
simple as a shell <em>true</em> value (the value <tt class="docutils literal">0</tt> -- equivalent to
|
||||
<tt class="docutils literal">${SHUNIT_TRUE}</tt>), or a more sophisticated shell conditional expression. The
|
||||
<em>message</em> is optional, and must be quoted.</p>
|
||||
<p>A sophisticated shell conditional expression is equivalent to what the <strong>if</strong>
|
||||
or <strong>while</strong> shell built-ins would use (more specifically, what the <strong>test</strong>
|
||||
command would use). Testing for example whether some value is greater than
|
||||
another value can be done this way.</p>
|
||||
<pre class="literal-block">
|
||||
assertTrue "[ 34 -gt 23 ]"
|
||||
</pre>
|
||||
<p>Testing for the ability to read a file can also be done. This particular test
|
||||
will fail.</p>
|
||||
<pre class="literal-block">
|
||||
assertTrue 'test failed' "[ -r /some/non-existant/file' ]"
|
||||
</pre>
|
||||
<p>As the expressions are standard shell <strong>test</strong> expressions, it is possible to
|
||||
string multiple expressions together with <tt class="docutils literal"><span class="pre">-a</span></tt> and <tt class="docutils literal"><span class="pre">-o</span></tt> in the standard
|
||||
fashion. This test will succeed as the entire expression evaluates to <em>true</em>.</p>
|
||||
<pre class="literal-block">
|
||||
assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]'
|
||||
</pre>
|
||||
<p class="last"><em>One word of warning: be very careful with your quoting as shell is not the
|
||||
most forgiving of bad quoting, and things will fail in strange ways.</em></p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">assertFalse [message] condition</tt></dt>
|
||||
<dd><p class="first">Asserts that a given shell test <em>condition</em> is <em>false</em>. The condition can be
|
||||
as simple as a shell <em>false</em> value (the value <tt class="docutils literal">1</tt> -- equivalent to
|
||||
<tt class="docutils literal">${SHUNIT_FALSE}</tt>), or a more sophisticated shell conditional expression.
|
||||
The <em>message</em> is optional, and must be quoted.</p>
|
||||
<p class="last"><em>For examples of more sophisticated expressions, see ``assertTrue``.</em></p>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="failures">
|
||||
<h2><a class="toc-backref" href="#id9">Failures</a></h2>
|
||||
<p>Just to clarify, failures <strong>do not</strong> test the various arguments against one
|
||||
another. Failures simply fail, optionally with a message, and that is all they
|
||||
do. If you need to test arguments against one another, use asserts.</p>
|
||||
<p>If all failures do is fail, why might one use them? There are times when you may
|
||||
have some very complicated logic that you need to test, and the simple asserts
|
||||
provided are simply not adequate. You can do your own validation of the code,
|
||||
use an <tt class="docutils literal">assertTrue ${SHUNIT_TRUE}</tt> if your own tests succeeded, and use a
|
||||
failure to record a failure.</p>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">fail [message]</tt></dt>
|
||||
<dd>Fails the test immediately. The <em>message</em> is optional, and must be quoted.</dd>
|
||||
<dt><tt class="docutils literal">failNotEquals [message] unexpected actual</tt></dt>
|
||||
<dd><p class="first">Fails the test immediately, reporting that the <em>unexpected</em> and <em>actual</em>
|
||||
values are not equal to one another. The <em>message</em> is optional, and must be
|
||||
quoted.</p>
|
||||
<p class="last"><em>Note: no actual comparison of unexpected and actual is done.</em></p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">failSame [message] expected actual</tt></dt>
|
||||
<dd><p class="first">Fails the test immediately, reporting that the <em>expected</em> and <em>actual</em> values
|
||||
are the same. The <em>message</em> is optional, and must be quoted.</p>
|
||||
<p class="last"><em>Note: no actual comparison of expected and actual is done.</em></p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">failNotSame [message] expected actual</tt></dt>
|
||||
<dd><p class="first">Fails the test immediately, reporting that the <em>expected</em> and <em>actual</em> values
|
||||
are not the same. The <em>message</em> is optional, and must be quoted.</p>
|
||||
<p class="last"><em>Note: no actual comparison of expected and actual is done.</em></p>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="setup-teardown">
|
||||
<h2><a class="toc-backref" href="#id10">Setup/Teardown</a></h2>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">oneTimeSetUp</tt></dt>
|
||||
<dd><p class="first">This function can be be optionally overridden by the user in their test suite.</p>
|
||||
<p class="last">If this function exists, it will be called once before any tests are run. It
|
||||
is useful to prepare a common environment for all tests.</p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">oneTimeTearDown</tt></dt>
|
||||
<dd><p class="first">This function can be be optionally overridden by the user in their test suite.</p>
|
||||
<p class="last">If this function exists, it will be called once after all tests are completed.
|
||||
It is useful to clean up the environment after all tests.</p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">setUp</tt></dt>
|
||||
<dd><p class="first">This function can be be optionally overridden by the user in their test suite.</p>
|
||||
<p class="last">If this function exists, it will be called before each test is run. It is
|
||||
useful to reset the environment before each test.</p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">tearDown</tt></dt>
|
||||
<dd><p class="first">This function can be be optionally overridden by the user in their test suite.</p>
|
||||
<p class="last">If this function exists, it will be called after each test completes. It is
|
||||
useful to clean up the environment after each test.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="skipping">
|
||||
<h2><a class="toc-backref" href="#id11">Skipping</a></h2>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">startSkipping</tt></dt>
|
||||
<dd>This function forces the remaining <em>assert</em> and <em>fail</em> functions to be
|
||||
"skipped", i.e. they will have no effect. Each function skipped will be
|
||||
recorded so that the total of asserts and fails will not be altered.</dd>
|
||||
<dt><tt class="docutils literal">endSkipping</tt></dt>
|
||||
<dd>This function returns calls to the <em>assert</em> and <em>fail</em> functions to their
|
||||
default behavior, i.e. they will be called.</dd>
|
||||
<dt><tt class="docutils literal">isSkipping</tt></dt>
|
||||
<dd>This function returns the current state of skipping. It can be compared
|
||||
against <tt class="docutils literal">${SHUNIT_TRUE}</tt> or <tt class="docutils literal">${SHUNIT_FALSE}</tt> if desired.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="section" id="suites">
|
||||
<h2><a class="toc-backref" href="#id12">Suites</a></h2>
|
||||
<p>The default behavior of shUnit2 is that all tests will be found dynamically. If
|
||||
you have a specific set of tests you want to run, or you don't want to use the
|
||||
standard naming scheme of prefixing your tests with <tt class="docutils literal">test</tt>, these functions
|
||||
are for you. Most users will never use them though.</p>
|
||||
<dl class="docutils">
|
||||
<dt><tt class="docutils literal">suite</tt></dt>
|
||||
<dd><p class="first">This function can be optionally overridden by the user in their test suite.</p>
|
||||
<p class="last">If this function exists, it will be called when <tt class="docutils literal">shunit2</tt> is sourced. If it
|
||||
does not exist, shUnit2 will search the parent script for all functions
|
||||
beginning with the word <tt class="docutils literal">test</tt>, and they will be added dynamically to the
|
||||
test suite.</p>
|
||||
</dd>
|
||||
<dt><tt class="docutils literal">suite_addTest name</tt></dt>
|
||||
<dd>This function adds a function named <em>name</em> to the list of tests scheduled for
|
||||
execution as part of this test suite. This function should only be called from
|
||||
within the <tt class="docutils literal">suite()</tt> function.</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="advanced-usage">
|
||||
<h1><a class="toc-backref" href="#id13">Advanced Usage</a></h1>
|
||||
<p>This section covers several advanced usage topics.</p>
|
||||
<div class="section" id="some-constants-you-can-use">
|
||||
<h2><a class="toc-backref" href="#id14">Some constants you can use</a></h2>
|
||||
<p>There are several constants provided by shUnit2 as variables that might be of
|
||||
use to you.</p>
|
||||
<p>Predefined</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="23%" />
|
||||
<col width="77%" />
|
||||
</colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">SHUNIT_VERSION</tt></td>
|
||||
<td>The version of shUnit2 you are running.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">SHUNIT_TRUE</tt></td>
|
||||
<td>Standard shell <em>true</em> value (the integer value 0).</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">SHUNIT_FALSE</tt></td>
|
||||
<td>Standard shell <em>false</em> value (the integer value 1).</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">SHUNIT_ERROR</tt></td>
|
||||
<td>The integer value 2.</td>
|
||||
</tr>
|
||||
<tr><td><tt class="docutils literal">SHUNIT_TMPDIR</tt></td>
|
||||
<td>Path to temporary directory that will be automatically
|
||||
cleaned up upon exit of shUnit2.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>User defined</p>
|
||||
<table border="1" class="docutils">
|
||||
<colgroup>
|
||||
<col width="23%" />
|
||||
<col width="77%" />
|
||||
</colgroup>
|
||||
<tbody valign="top">
|
||||
<tr><td><tt class="docutils literal">SHUNIT_PARENT</tt></td>
|
||||
<td>The filename of the shell script containing the tests. This
|
||||
is needed specifically for Zsh support.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="section" id="error-handling">
|
||||
<h2><a class="toc-backref" href="#id15">Error handling</a></h2>
|
||||
<p>The constants values <tt class="docutils literal">SHUNIT_TRUE</tt>, <tt class="docutils literal">SHUNIT_FALSE</tt>, and <tt class="docutils literal">SHUNIT_ERROR</tt> are
|
||||
returned from nearly every function to indicate the success or failure of the
|
||||
function. Additionally the variable <tt class="docutils literal">flags_error</tt> is filled with a detailed
|
||||
error message if any function returns with a <tt class="docutils literal">SHUNIT_ERROR</tt> value.</p>
|
||||
</div>
|
||||
<div class="section" id="including-line-numbers-in-asserts-macros">
|
||||
<h2><a class="toc-backref" href="#id16">Including Line Numbers in Asserts (Macros)</a></h2>
|
||||
<p>If you include lots of assert statements in an individual test function, it can
|
||||
become difficult to determine exactly which assert was thrown unless your
|
||||
messages are unique. To help somewhat, line numbers can be included in the
|
||||
assert messages. To enable this, a special shell "macro" must be used rather
|
||||
than the standard assert calls. <em>Shell doesn't actually have macros; the name is
|
||||
used here as the operation is similar to a standard macro.</em></p>
|
||||
<p>For example, to include line numbers for a <tt class="docutils literal">assertEquals()</tt> function call,
|
||||
replace the <tt class="docutils literal">assertEquals()</tt> with <tt class="docutils literal">${_ASSERT_EQUALS_}</tt>.</p>
|
||||
<p>Example -- Asserts with and without line numbers</p>
|
||||
<pre class="literal-block">
|
||||
#! /bin/sh
|
||||
# file: examples/lineno_test.sh
|
||||
|
||||
testLineNo()
|
||||
{
|
||||
# this assert will have line numbers included (e.g. "ASSERT:[123] ...")
|
||||
echo "ae: ${_ASSERT_EQUALS_}"
|
||||
${_ASSERT_EQUALS_} 'not equal' 1 2
|
||||
|
||||
# this assert will not have line numbers included (e.g. "ASSERT: ...")
|
||||
assertEquals 'not equal' 1 2
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
</pre>
|
||||
<p>Notes:</p>
|
||||
<ol class="arabic">
|
||||
<li><p class="first">Due to how shell parses command-line arguments, all strings used with macros
|
||||
should be quoted twice. Namely, single-quotes must be converted to
|
||||
single-double-quotes, and vice-versa. If the string being passed is
|
||||
absolutely for sure not empty, the extra quoting is not necessary.</p>
|
||||
<p>Normal <tt class="docutils literal">assertEquals</tt> call.</p>
|
||||
<pre class="literal-block">
|
||||
assertEquals 'some message' 'x' ''
|
||||
</pre>
|
||||
<p>Macro <tt class="docutils literal">_ASSERT_EQUALS_</tt> call. Note the extra quoting around the <em>message</em>
|
||||
and the <em>null</em> value.</p>
|
||||
<pre class="literal-block">
|
||||
_ASSERT_EQUALS_ '"some message"' 'x' '""'
|
||||
</pre>
|
||||
</li>
|
||||
<li><p class="first">Line numbers are not supported in all shells. If a shell does not support
|
||||
them, no errors will be thrown. Supported shells include: <strong>bash</strong> (>=3.0),
|
||||
<strong>ksh</strong>, <strong>pdksh</strong>, and <strong>zsh</strong>.</p>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
<div class="section" id="test-skipping">
|
||||
<h2><a class="toc-backref" href="#id17">Test Skipping</a></h2>
|
||||
<p>There are times where the test code you have written is just not applicable to
|
||||
the system you are running on. This section describes how to skip these tests
|
||||
but maintain the total test count.</p>
|
||||
<p>Probably the easiest example would be shell code that is meant to run under the
|
||||
<strong>bash</strong> shell, but the unit test is running under the Bourne shell. There are
|
||||
things that just won't work. The following test code demonstrates two sample
|
||||
functions, one that will be run under any shell, and the another that will run
|
||||
only under the <strong>bash</strong> shell.</p>
|
||||
<p>Example -- math include</p>
|
||||
<pre class="literal-block">
|
||||
# available as examples/math.inc
|
||||
|
||||
add_generic()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
expr $1 + $2
|
||||
}
|
||||
|
||||
add_bash()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
echo $(($1 + $2))
|
||||
}
|
||||
</pre>
|
||||
<p>And here is a corresponding unit test that correctly skips the <tt class="docutils literal">add_bash()</tt>
|
||||
function when the unit test is not running under the <strong>bash</strong> shell.</p>
|
||||
<p>Example -- math unit test</p>
|
||||
<pre class="literal-block">
|
||||
#! /bin/sh
|
||||
# available as examples/math_test.sh
|
||||
|
||||
testAdding()
|
||||
{
|
||||
result=`add_generic 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
|
||||
# disable non-generic tests
|
||||
[ -z "${BASH_VERSION:-}" ] && startSkipping
|
||||
|
||||
result=`add_bash 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
}
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
# load include to test
|
||||
. ./math.inc
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
. ../src/shell/shunit2
|
||||
</pre>
|
||||
<p>Running the above test under the <strong>bash</strong> shell will result in the following
|
||||
output.</p>
|
||||
<pre class="literal-block">
|
||||
$ /bin/bash math_test.sh
|
||||
testAdding
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK
|
||||
</pre>
|
||||
<p>But, running the test under any other Unix shell will result in the following
|
||||
output.</p>
|
||||
<pre class="literal-block">
|
||||
$ /bin/ksh math_test.sh
|
||||
testAdding
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK (skipped=1)
|
||||
</pre>
|
||||
<p>As you can see, the total number of tests has not changed, but the report
|
||||
indicates that some tests were skipped.</p>
|
||||
<p>Skipping can be controlled with the following functions: <tt class="docutils literal">startSkipping()</tt>,
|
||||
<tt class="docutils literal">stopSkipping()</tt>, and <tt class="docutils literal">isSkipping()</tt>. Once skipping is enabled, it will
|
||||
remain enabled until the end of the current test function call, after which
|
||||
skipping is disabled.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="appendix">
|
||||
<h1><a class="toc-backref" href="#id18">Appendix</a></h1>
|
||||
<div class="section" id="getting-help">
|
||||
<h2><a class="toc-backref" href="#id19">Getting help</a></h2>
|
||||
<p>For help, please send requests to either the <a class="reference external" href="mailto:shunit2-users@googlegroups.com">shunit2-users@googlegroups.com</a>
|
||||
mailing list (archives available on the web at
|
||||
<a class="reference external" href="http://groups.google.com/group/shunit2-users">http://groups.google.com/group/shunit2-users</a>) or directly to
|
||||
Kate Ward <kate dot ward at forestent dot com>.</p>
|
||||
</div>
|
||||
<div class="section" id="zsh">
|
||||
<h2><a class="toc-backref" href="#id20">Zsh</a></h2>
|
||||
<p>For compatibility with Zsh, there is one requirement that must be met -- the
|
||||
<tt class="docutils literal">shwordsplit</tt> option must be set. There are three ways to accomplish this.</p>
|
||||
<ol class="arabic">
|
||||
<li><p class="first">In the unit-test script, add the following shell code snippet before sourcing
|
||||
the <tt class="docutils literal">shunit2</tt> library.</p>
|
||||
<pre class="literal-block">
|
||||
setopt shwordsplit
|
||||
</pre>
|
||||
</li>
|
||||
<li><p class="first">When invoking <strong>zsh</strong> from either the command-line or as a script with
|
||||
<tt class="docutils literal">#!</tt>, add the <tt class="docutils literal"><span class="pre">-y</span></tt> parameter.</p>
|
||||
<pre class="literal-block">
|
||||
#! /bin/zsh -y
|
||||
</pre>
|
||||
</li>
|
||||
<li><p class="first">When invoking <strong>zsh</strong> from the command-line, add <tt class="docutils literal"><span class="pre">-o</span> shwordsplit <span class="pre">--</span></tt> as
|
||||
parameters before the script name.</p>
|
||||
<pre class="literal-block">
|
||||
$ zsh -o shwordsplit -- some_script
|
||||
</pre>
|
||||
</li>
|
||||
</ol>
|
||||
<!-- generate HTML using rst2html from Docutils of -->
|
||||
<!-- http://docutils.sourceforge.net/ -->
|
||||
<!-- -->
|
||||
<!-- vim:fileencoding=latin1:ft=rst:spell:sts=2:sw=2:tw=80 -->
|
||||
<!-- $Revision: 233 $ -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,562 +0,0 @@
|
||||
===========================
|
||||
shUnit2 2.1.x Documentation
|
||||
===========================
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
shUnit2_ is a xUnit_ unit test framework for Bourne based shell scripts, and it
|
||||
is designed to work in a similar manner to JUnit_, PyUnit_, etc.. If you have
|
||||
ever had the desire to write a unit test for a shell script, shUnit2 can do the
|
||||
job.
|
||||
|
||||
.. contents:: Table of Contents
|
||||
:depth: 2
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
shUnit2 was originally developed to provide a consistent testing solution for
|
||||
log4sh_, a shell based logging framework similar to log4j_. During the
|
||||
development of that product, a repeated problem of having things work just fine
|
||||
under one shell (``/bin/bash`` on Linux to be specific), and then not working
|
||||
under another shell (``/bin/sh`` on Solaris) kept coming up. Although several
|
||||
simple tests were run, they were not adequate and did not catch some corner
|
||||
cases. The decision was finally made to write a proper unit test framework after
|
||||
multiple brown-bag releases were made. *Research was done to look for an
|
||||
existing product that met the testing requirements, but no adequate product was
|
||||
found.*
|
||||
|
||||
Tested Operating Systems (varies over time)
|
||||
|
||||
- Cygwin
|
||||
- FreeBSD (user supported)
|
||||
- Linux (Gentoo, Ubuntu)
|
||||
- Mac OS X
|
||||
- Solaris 8, 9, 10 (inc. OpenSolaris)
|
||||
|
||||
Tested Shells
|
||||
|
||||
- Bourne Shell (**sh**)
|
||||
- BASH - GNU Bourne Again SHell (**bash**)
|
||||
- DASH (**dash**)
|
||||
- Korn Shell (**ksh**)
|
||||
- pdksh - Public Domain Korn Shell (**pdksh**)
|
||||
- zsh - Zsh (**zsh**) (since 2.1.2) *please see the Zsh shell errata for more
|
||||
information*
|
||||
|
||||
See the appropriate Release Notes for this release
|
||||
(``doc/RELEASE_NOTES-X.X.X.txt``) for the list of actual versions tested.
|
||||
|
||||
Credits / Contributors
|
||||
----------------------
|
||||
|
||||
A list of contributors to shUnit2 can be found in the source archive in
|
||||
``doc/contributors.txt``. Many thanks go out to all those who have contributed
|
||||
to make this a better tool.
|
||||
|
||||
shUnit2 is the original product of many hours of work by Kate Ward, the primary
|
||||
author of the code. For other products by her, look up log4sh_ or shFlags_, or
|
||||
visit her website at http://forestent.com/.
|
||||
|
||||
Feedback
|
||||
--------
|
||||
|
||||
Feedback is most certainly welcome for this document. Send your additions,
|
||||
comments and criticisms to the shunit2-users@google.com mailing list.
|
||||
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
This section will give a very quick start to running unit tests with shUnit2.
|
||||
More information is located in later sections.
|
||||
|
||||
Here is a quick sample script to show how easy it is to write a unit test in
|
||||
shell. *Note: the script as it stands expects that you are running it from the
|
||||
``examples`` directory.* ::
|
||||
|
||||
#! /bin/sh
|
||||
# file: examples/equality_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
|
||||
Running the unit test should give results similar to the following. ::
|
||||
|
||||
testEquality
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK
|
||||
|
||||
W00t! You've just run your first successful unit test. So, what just happened?
|
||||
Quite a bit really, and it all happened simply by sourcing the ``shunit2``
|
||||
library. The basic functionality for the script above goes like this:
|
||||
|
||||
- When shUnit2 is sourced, it will walk through any functions defined whose
|
||||
namestart with the string ``test`` and add those to an internal list of tests
|
||||
to execute. Once a list of test functions to be run has been determined,
|
||||
shunit2 will go to work.
|
||||
- Before any tests are executed, shUnit2 again looks for a function, this time
|
||||
one named ``oneTimeSetUp()``. If it exists, it will be run. This function is
|
||||
normally used to setup the environment for all tests to be run. Things like
|
||||
creating directories for output or setting environment variables are good to
|
||||
place here. Just so you know, you can also declare a corresponding function
|
||||
named ``oneTimeTearDown()`` function that does the same thing, but once all
|
||||
the tests have been completed. It is good for removing temporary directories,
|
||||
etc.
|
||||
- shUnit2 is now ready to run tests. Before doing so though, it again looks for
|
||||
another function that might be declared, one named ``setUp()``. If the
|
||||
function exists, it will be run before each test. It is good for resetting the
|
||||
environment so that each test starts with a clean slate. At this stage, the
|
||||
first test is finally run. The success of the test is recorded for a report
|
||||
that will be generated later. After the test is run, shUnit2 looks for a final
|
||||
function that might be declared, one named ``tearDown()``. If it exists, it
|
||||
will be run after each test. It is a good place for cleaning up after each
|
||||
test, maybe doing things like removing files that were created, or removing
|
||||
directories. This set of steps, ``setUp()`` > ``test()`` > ``tearDown()``, is
|
||||
repeated for all of the available tests.
|
||||
- Once all the work is done, shUnit2 will generate the nice report you saw
|
||||
above. A summary of all the successes and failures will be given so that you
|
||||
know how well your code is doing.
|
||||
|
||||
We should now try adding a test that fails. Change your unit test to look like
|
||||
this. ::
|
||||
|
||||
#! /bin/sh
|
||||
# file: examples/party_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
testPartyLikeItIs1999()
|
||||
{
|
||||
year=`date '+%Y'`
|
||||
assertEquals "It's not 1999 :-(" \
|
||||
'1999' "${year}"
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
|
||||
So, what did you get? I guess it told you that this isn't 1999. Bummer, eh?
|
||||
Hopefully, you noticed a couple of things that were different about the second
|
||||
test. First, we added an optional message that the user will see if the assert
|
||||
fails. Second, we did comparisons of strings instead of integers as in the first
|
||||
test. It doesn't matter whether you are testing for equality of strings or
|
||||
integers. Both work equally well with shUnit2.
|
||||
|
||||
Hopefully, this is enough to get you started with unit testing. If you want a
|
||||
ton more examples, take a look at the tests provided with log4sh_ or shFlags_.
|
||||
Both provide excellent examples of more advanced usage. shUnit2 was after all
|
||||
written to help with the unit testing problems that log4sh_ had.
|
||||
|
||||
Function Reference
|
||||
==================
|
||||
|
||||
General Info
|
||||
------------
|
||||
|
||||
Any string values passed should be properly quoted -- they should must be
|
||||
surrounded by single-quote (') or double-quote (") characters -- so that the
|
||||
shell will properly parse them.
|
||||
|
||||
Asserts
|
||||
-------
|
||||
|
||||
``assertEquals [message] expected actual``
|
||||
Asserts that *expected* and *actual* are equal to one another. The *expected*
|
||||
and *actual* values can be either strings or integer values as both will be
|
||||
treated as strings. The *message* is optional, and must be quoted.
|
||||
|
||||
``assertNotEquals [message] expected actual``
|
||||
Asserts that *unexpected* and *actual* are not equal to one another. The
|
||||
*unexpected* and *actual* values can be either strings or integer values as
|
||||
both will be treaded as strings. The *message* is optional, and must be
|
||||
quoted.
|
||||
|
||||
``assertSame [message] expected actual``
|
||||
This function is functionally equivalent to ``assertEquals``.
|
||||
|
||||
``assertNotSame [message] unexpected actual``
|
||||
This function is functionally equivalent to ``assertNotEquals``.
|
||||
|
||||
``assertNull [message] value``
|
||||
Asserts that *value* is *null*, or in shell terms, a zero-length string. The
|
||||
*value* must be a string as an integer value does not translate into a
|
||||
zero-length string. The *message* is optional, and must be quoted.
|
||||
|
||||
``assertNotNull [message] value``
|
||||
Asserts that *value* is *not null*, or in shell terms, a non-empty string. The
|
||||
*value* may be a string or an integer as the later will be parsed as a
|
||||
non-empty string value. The *message* is optional, and must be quoted.
|
||||
|
||||
``assertTrue [message] condition``
|
||||
Asserts that a given shell test *condition* is *true*. The condition can be as
|
||||
simple as a shell *true* value (the value ``0`` -- equivalent to
|
||||
``${SHUNIT_TRUE}``), or a more sophisticated shell conditional expression. The
|
||||
*message* is optional, and must be quoted.
|
||||
|
||||
A sophisticated shell conditional expression is equivalent to what the **if**
|
||||
or **while** shell built-ins would use (more specifically, what the **test**
|
||||
command would use). Testing for example whether some value is greater than
|
||||
another value can be done this way. ::
|
||||
|
||||
assertTrue "[ 34 -gt 23 ]"
|
||||
|
||||
Testing for the ability to read a file can also be done. This particular test
|
||||
will fail. ::
|
||||
|
||||
assertTrue 'test failed' "[ -r /some/non-existant/file' ]"
|
||||
|
||||
As the expressions are standard shell **test** expressions, it is possible to
|
||||
string multiple expressions together with ``-a`` and ``-o`` in the standard
|
||||
fashion. This test will succeed as the entire expression evaluates to *true*.
|
||||
::
|
||||
|
||||
assertTrue 'test failed' '[ 1 -eq 1 -a 2 -eq 2 ]'
|
||||
|
||||
*One word of warning: be very careful with your quoting as shell is not the
|
||||
most forgiving of bad quoting, and things will fail in strange ways.*
|
||||
|
||||
``assertFalse [message] condition``
|
||||
Asserts that a given shell test *condition* is *false*. The condition can be
|
||||
as simple as a shell *false* value (the value ``1`` -- equivalent to
|
||||
``${SHUNIT_FALSE}``), or a more sophisticated shell conditional expression.
|
||||
The *message* is optional, and must be quoted.
|
||||
|
||||
*For examples of more sophisticated expressions, see ``assertTrue``.*
|
||||
|
||||
Failures
|
||||
--------
|
||||
|
||||
Just to clarify, failures **do not** test the various arguments against one
|
||||
another. Failures simply fail, optionally with a message, and that is all they
|
||||
do. If you need to test arguments against one another, use asserts.
|
||||
|
||||
If all failures do is fail, why might one use them? There are times when you may
|
||||
have some very complicated logic that you need to test, and the simple asserts
|
||||
provided are simply not adequate. You can do your own validation of the code,
|
||||
use an ``assertTrue ${SHUNIT_TRUE}`` if your own tests succeeded, and use a
|
||||
failure to record a failure.
|
||||
|
||||
``fail [message]``
|
||||
Fails the test immediately. The *message* is optional, and must be quoted.
|
||||
|
||||
``failNotEquals [message] unexpected actual``
|
||||
Fails the test immediately, reporting that the *unexpected* and *actual*
|
||||
values are not equal to one another. The *message* is optional, and must be
|
||||
quoted.
|
||||
|
||||
*Note: no actual comparison of unexpected and actual is done.*
|
||||
|
||||
``failSame [message] expected actual``
|
||||
Fails the test immediately, reporting that the *expected* and *actual* values
|
||||
are the same. The *message* is optional, and must be quoted.
|
||||
|
||||
*Note: no actual comparison of expected and actual is done.*
|
||||
|
||||
``failNotSame [message] expected actual``
|
||||
Fails the test immediately, reporting that the *expected* and *actual* values
|
||||
are not the same. The *message* is optional, and must be quoted.
|
||||
|
||||
*Note: no actual comparison of expected and actual is done.*
|
||||
|
||||
Setup/Teardown
|
||||
--------------
|
||||
|
||||
``oneTimeSetUp``
|
||||
This function can be be optionally overridden by the user in their test suite.
|
||||
|
||||
If this function exists, it will be called once before any tests are run. It
|
||||
is useful to prepare a common environment for all tests.
|
||||
|
||||
``oneTimeTearDown``
|
||||
This function can be be optionally overridden by the user in their test suite.
|
||||
|
||||
If this function exists, it will be called once after all tests are completed.
|
||||
It is useful to clean up the environment after all tests.
|
||||
|
||||
``setUp``
|
||||
This function can be be optionally overridden by the user in their test suite.
|
||||
|
||||
If this function exists, it will be called before each test is run. It is
|
||||
useful to reset the environment before each test.
|
||||
|
||||
``tearDown``
|
||||
This function can be be optionally overridden by the user in their test suite.
|
||||
|
||||
If this function exists, it will be called after each test completes. It is
|
||||
useful to clean up the environment after each test.
|
||||
|
||||
Skipping
|
||||
--------
|
||||
|
||||
``startSkipping``
|
||||
This function forces the remaining *assert* and *fail* functions to be
|
||||
"skipped", i.e. they will have no effect. Each function skipped will be
|
||||
recorded so that the total of asserts and fails will not be altered.
|
||||
|
||||
``endSkipping``
|
||||
This function returns calls to the *assert* and *fail* functions to their
|
||||
default behavior, i.e. they will be called.
|
||||
|
||||
``isSkipping``
|
||||
This function returns the current state of skipping. It can be compared
|
||||
against ``${SHUNIT_TRUE}`` or ``${SHUNIT_FALSE}`` if desired.
|
||||
|
||||
Suites
|
||||
------
|
||||
|
||||
The default behavior of shUnit2 is that all tests will be found dynamically. If
|
||||
you have a specific set of tests you want to run, or you don't want to use the
|
||||
standard naming scheme of prefixing your tests with ``test``, these functions
|
||||
are for you. Most users will never use them though.
|
||||
|
||||
``suite``
|
||||
This function can be optionally overridden by the user in their test suite.
|
||||
|
||||
If this function exists, it will be called when ``shunit2`` is sourced. If it
|
||||
does not exist, shUnit2 will search the parent script for all functions
|
||||
beginning with the word ``test``, and they will be added dynamically to the
|
||||
test suite.
|
||||
|
||||
``suite_addTest name``
|
||||
This function adds a function named *name* to the list of tests scheduled for
|
||||
execution as part of this test suite. This function should only be called from
|
||||
within the ``suite()`` function.
|
||||
|
||||
Advanced Usage
|
||||
==============
|
||||
|
||||
This section covers several advanced usage topics.
|
||||
|
||||
Some constants you can use
|
||||
--------------------------
|
||||
|
||||
There are several constants provided by shUnit2 as variables that might be of
|
||||
use to you.
|
||||
|
||||
Predefined
|
||||
|
||||
================== ===========================================================
|
||||
``SHUNIT_VERSION`` The version of shUnit2 you are running.
|
||||
``SHUNIT_TRUE`` Standard shell *true* value (the integer value 0).
|
||||
``SHUNIT_FALSE`` Standard shell *false* value (the integer value 1).
|
||||
``SHUNIT_ERROR`` The integer value 2.
|
||||
``SHUNIT_TMPDIR`` Path to temporary directory that will be automatically
|
||||
cleaned up upon exit of shUnit2.
|
||||
================== ===========================================================
|
||||
|
||||
User defined
|
||||
|
||||
================== ===========================================================
|
||||
``SHUNIT_PARENT`` The filename of the shell script containing the tests. This
|
||||
is needed specifically for Zsh support.
|
||||
================== ===========================================================
|
||||
|
||||
Error handling
|
||||
--------------
|
||||
|
||||
The constants values ``SHUNIT_TRUE``, ``SHUNIT_FALSE``, and ``SHUNIT_ERROR`` are
|
||||
returned from nearly every function to indicate the success or failure of the
|
||||
function. Additionally the variable ``flags_error`` is filled with a detailed
|
||||
error message if any function returns with a ``SHUNIT_ERROR`` value.
|
||||
|
||||
Including Line Numbers in Asserts (Macros)
|
||||
------------------------------------------
|
||||
|
||||
If you include lots of assert statements in an individual test function, it can
|
||||
become difficult to determine exactly which assert was thrown unless your
|
||||
messages are unique. To help somewhat, line numbers can be included in the
|
||||
assert messages. To enable this, a special shell "macro" must be used rather
|
||||
than the standard assert calls. *Shell doesn't actually have macros; the name is
|
||||
used here as the operation is similar to a standard macro.*
|
||||
|
||||
For example, to include line numbers for a ``assertEquals()`` function call,
|
||||
replace the ``assertEquals()`` with ``${_ASSERT_EQUALS_}``.
|
||||
|
||||
Example -- Asserts with and without line numbers ::
|
||||
|
||||
#! /bin/sh
|
||||
# file: examples/lineno_test.sh
|
||||
|
||||
testLineNo()
|
||||
{
|
||||
# this assert will have line numbers included (e.g. "ASSERT:[123] ...")
|
||||
echo "ae: ${_ASSERT_EQUALS_}"
|
||||
${_ASSERT_EQUALS_} 'not equal' 1 2
|
||||
|
||||
# this assert will not have line numbers included (e.g. "ASSERT: ...")
|
||||
assertEquals 'not equal' 1 2
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shell/shunit2
|
||||
|
||||
Notes:
|
||||
|
||||
#. Due to how shell parses command-line arguments, all strings used with macros
|
||||
should be quoted twice. Namely, single-quotes must be converted to
|
||||
single-double-quotes, and vice-versa. If the string being passed is
|
||||
absolutely for sure not empty, the extra quoting is not necessary.
|
||||
|
||||
Normal ``assertEquals`` call. ::
|
||||
|
||||
assertEquals 'some message' 'x' ''
|
||||
|
||||
Macro ``_ASSERT_EQUALS_`` call. Note the extra quoting around the *message*
|
||||
and the *null* value. ::
|
||||
|
||||
_ASSERT_EQUALS_ '"some message"' 'x' '""'
|
||||
|
||||
#. Line numbers are not supported in all shells. If a shell does not support
|
||||
them, no errors will be thrown. Supported shells include: **bash** (>=3.0),
|
||||
**ksh**, **pdksh**, and **zsh**.
|
||||
|
||||
Test Skipping
|
||||
-------------
|
||||
|
||||
There are times where the test code you have written is just not applicable to
|
||||
the system you are running on. This section describes how to skip these tests
|
||||
but maintain the total test count.
|
||||
|
||||
Probably the easiest example would be shell code that is meant to run under the
|
||||
**bash** shell, but the unit test is running under the Bourne shell. There are
|
||||
things that just won't work. The following test code demonstrates two sample
|
||||
functions, one that will be run under any shell, and the another that will run
|
||||
only under the **bash** shell.
|
||||
|
||||
Example -- math include ::
|
||||
|
||||
# available as examples/math.inc
|
||||
|
||||
add_generic()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
expr $1 + $2
|
||||
}
|
||||
|
||||
add_bash()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
echo $(($1 + $2))
|
||||
}
|
||||
|
||||
And here is a corresponding unit test that correctly skips the ``add_bash()``
|
||||
function when the unit test is not running under the **bash** shell.
|
||||
|
||||
Example -- math unit test ::
|
||||
|
||||
#! /bin/sh
|
||||
# available as examples/math_test.sh
|
||||
|
||||
testAdding()
|
||||
{
|
||||
result=`add_generic 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
|
||||
# disable non-generic tests
|
||||
[ -z "${BASH_VERSION:-}" ] && startSkipping
|
||||
|
||||
result=`add_bash 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
}
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
# load include to test
|
||||
. ./math.inc
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
. ../src/shell/shunit2
|
||||
|
||||
Running the above test under the **bash** shell will result in the following
|
||||
output. ::
|
||||
|
||||
$ /bin/bash math_test.sh
|
||||
testAdding
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK
|
||||
|
||||
But, running the test under any other Unix shell will result in the following
|
||||
output. ::
|
||||
|
||||
$ /bin/ksh math_test.sh
|
||||
testAdding
|
||||
|
||||
Ran 1 test.
|
||||
|
||||
OK (skipped=1)
|
||||
|
||||
As you can see, the total number of tests has not changed, but the report
|
||||
indicates that some tests were skipped.
|
||||
|
||||
Skipping can be controlled with the following functions: ``startSkipping()``,
|
||||
``stopSkipping()``, and ``isSkipping()``. Once skipping is enabled, it will
|
||||
remain enabled until the end of the current test function call, after which
|
||||
skipping is disabled.
|
||||
|
||||
Appendix
|
||||
========
|
||||
|
||||
Getting help
|
||||
------------
|
||||
|
||||
For help, please send requests to either the shunit2-users@googlegroups.com
|
||||
mailing list (archives available on the web at
|
||||
http://groups.google.com/group/shunit2-users) or directly to
|
||||
Kate Ward <kate dot ward at forestent dot com>.
|
||||
|
||||
Zsh
|
||||
---
|
||||
|
||||
For compatibility with Zsh, there is one requirement that must be met -- the
|
||||
``shwordsplit`` option must be set. There are three ways to accomplish this.
|
||||
|
||||
#. In the unit-test script, add the following shell code snippet before sourcing
|
||||
the ``shunit2`` library. ::
|
||||
|
||||
setopt shwordsplit
|
||||
|
||||
#. When invoking **zsh** from either the command-line or as a script with
|
||||
``#!``, add the ``-y`` parameter. ::
|
||||
|
||||
#! /bin/zsh -y
|
||||
|
||||
#. When invoking **zsh** from the command-line, add ``-o shwordsplit --`` as
|
||||
parameters before the script name. ::
|
||||
|
||||
$ zsh -o shwordsplit -- some_script
|
||||
|
||||
.. _log4sh: http://log4sh.sourceforge.net/
|
||||
.. _log4j: http://logging.apache.org/
|
||||
.. _JUnit: http://www.junit.org/
|
||||
.. _PyUnit: http://pyunit.sourceforge.net/
|
||||
.. _shFlags: http://shflags.googlecode.com/
|
||||
.. _shUnit2: http://shunit2.googlecode.com/
|
||||
.. _xUnit: http://en.wikipedia.org/wiki/XUnit
|
||||
|
||||
.. generate HTML using rst2html from Docutils of
|
||||
.. http://docutils.sourceforge.net/
|
||||
..
|
||||
.. vim:fileencoding=latin1:ft=rst:spell:sts=2:sw=2:tw=80
|
||||
.. $Revision: 233 $
|
@ -1,10 +0,0 @@
|
||||
#! /bin/sh
|
||||
# file: examples/equality_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shunit2
|
@ -1,16 +0,0 @@
|
||||
#! /bin/sh
|
||||
# file: examples/lineno_test.sh
|
||||
|
||||
testLineNo()
|
||||
{
|
||||
# this assert will have line numbers included (e.g. "ASSERT:[123] ...") if
|
||||
# they are supported.
|
||||
echo "_ASSERT_EQUALS_ macro value: ${_ASSERT_EQUALS_}"
|
||||
${_ASSERT_EQUALS_} 'not equal' 1 2
|
||||
|
||||
# this assert will not have line numbers included (e.g. "ASSERT: ...")
|
||||
assertEquals 'not equal' 1 2
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shunit2
|
@ -1,17 +0,0 @@
|
||||
# available as examples/math.inc
|
||||
|
||||
add_generic()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
expr $1 + $2
|
||||
}
|
||||
|
||||
add_bash()
|
||||
{
|
||||
num_a=$1
|
||||
num_b=$2
|
||||
|
||||
echo $(($1 + $2))
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
#! /bin/sh
|
||||
# available as examples/math_test.sh
|
||||
|
||||
testAdding()
|
||||
{
|
||||
result=`add_generic 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
|
||||
# disable non-generic tests
|
||||
[ -z "${BASH_VERSION:-}" ] && startSkipping
|
||||
|
||||
result=`add_bash 1 2`
|
||||
assertEquals \
|
||||
"the result of '${result}' was wrong" \
|
||||
3 "${result}"
|
||||
}
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
# load include to test
|
||||
. ./math.inc
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
. ../src/shunit2
|
@ -1,89 +0,0 @@
|
||||
#!/bin/sh
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# Example unit test for the mkdir command.
|
||||
#
|
||||
# There are times when an existing shell script needs to be tested. In this
|
||||
# example, we will test several aspects of the the mkdir command, but the
|
||||
# techniques could be used for any existing shell script.
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
testMissingDirectoryCreation()
|
||||
{
|
||||
${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF}
|
||||
rtrn=$?
|
||||
th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}"
|
||||
|
||||
assertTrue 'directory missing' "[ -d '${testDir}' ]"
|
||||
}
|
||||
|
||||
testExistingDirectoryCreationFails()
|
||||
{
|
||||
# create a directory to test against
|
||||
${mkdirCmd} "${testDir}"
|
||||
|
||||
# test for expected failure while trying to create directory that exists
|
||||
${mkdirCmd} "${testDir}" >${stdoutF} 2>${stderrF}
|
||||
rtrn=$?
|
||||
assertFalse 'expecting return code of 1 (false)' ${rtrn}
|
||||
assertNull 'unexpected output to stdout' "`cat ${stdoutF}`"
|
||||
assertNotNull 'expected error message to stderr' "`cat ${stderrF}`"
|
||||
|
||||
assertTrue 'directory missing' "[ -d '${testDir}' ]"
|
||||
}
|
||||
|
||||
testRecursiveDirectoryCreation()
|
||||
{
|
||||
testDir2="${testDir}/test2"
|
||||
|
||||
${mkdirCmd} -p "${testDir2}" >${stdoutF} 2>${stderrF}
|
||||
rtrn=$?
|
||||
th_assertTrueWithNoOutput ${rtrn} "${stdoutF}" "${stderrF}"
|
||||
|
||||
assertTrue 'first directory missing' "[ -d '${testDir}' ]"
|
||||
assertTrue 'second directory missing' "[ -d '${testDir2}' ]"
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# suite functions
|
||||
#
|
||||
|
||||
th_assertTrueWithNoOutput()
|
||||
{
|
||||
th_return_=$1
|
||||
th_stdout_=$2
|
||||
th_stderr_=$3
|
||||
|
||||
assertFalse 'unexpected output to STDOUT' "[ -s '${th_stdout_}' ]"
|
||||
assertFalse 'unexpected output to STDERR' "[ -s '${th_stderr_}' ]"
|
||||
|
||||
unset th_return_ th_stdout_ th_stderr_
|
||||
}
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
outputDir="${SHUNIT_TMPDIR}/output"
|
||||
mkdir "${outputDir}"
|
||||
stdoutF="${outputDir}/stdout"
|
||||
stderrF="${outputDir}/stderr"
|
||||
|
||||
mkdirCmd='mkdir' # save command name in variable to make future changes easy
|
||||
testDir="${SHUNIT_TMPDIR}/some_test_dir"
|
||||
}
|
||||
|
||||
tearDown()
|
||||
{
|
||||
rm -fr "${testDir}"
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
|
||||
. ../src/shunit2
|
@ -1,17 +0,0 @@
|
||||
#! /bin/sh
|
||||
# file: examples/party_test.sh
|
||||
|
||||
testEquality()
|
||||
{
|
||||
assertEquals 1 1
|
||||
}
|
||||
|
||||
testPartyLikeItIs1999()
|
||||
{
|
||||
year=`date '+%Y'`
|
||||
assertEquals "It's not 1999 :-(" \
|
||||
'1999' "${year}"
|
||||
}
|
||||
|
||||
# load shunit2
|
||||
. ../src/shunit2
|
File diff suppressed because it is too large
Load Diff
@ -1,39 +0,0 @@
|
||||
# $Id: shlib 14 2007-02-18 19:43:41Z sfsetse $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License).
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# Library of shell functions.
|
||||
|
||||
# Convert a relative path into it's absolute equivalent.
|
||||
#
|
||||
# This function will automatically prepend the current working directory if the
|
||||
# path is not already absolute. It then removes all parent references (../) to
|
||||
# reconstruct the proper absolute path.
|
||||
#
|
||||
# Args:
|
||||
# shlib_path_: string: relative path
|
||||
# Outputs:
|
||||
# string: absolute path
|
||||
shlib_relToAbsPath()
|
||||
{
|
||||
shlib_path_=$1
|
||||
|
||||
# prepend current directory to relative paths
|
||||
echo "${shlib_path_}" |grep '^/' >/dev/null 2>&1 \
|
||||
|| shlib_path_="`pwd`/${shlib_path_}"
|
||||
|
||||
# clean up the path. if all seds supported true regular expressions, then
|
||||
# this is what it would be:
|
||||
shlib_old_=${shlib_path_}
|
||||
while true; do
|
||||
shlib_new_=`echo "${shlib_old_}" |sed 's/[^/]*\/\.\.\/*//g;s/\/\.\//\//'`
|
||||
[ "${shlib_old_}" = "${shlib_new_}" ] && break
|
||||
shlib_old_=${shlib_new_}
|
||||
done
|
||||
echo "${shlib_new_}"
|
||||
|
||||
unset shlib_path_ shlib_old_ shlib_new_
|
||||
}
|
@ -1,227 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: versions 100 2008-11-15 20:24:03Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# This library provides reusable functions that determine actual names and
|
||||
# versions of installed shells and the OS. The library can also be run as a
|
||||
# script if set execuatable.
|
||||
|
||||
ARGV0=`basename "$0"`
|
||||
LSB_RELEASE='/etc/lsb-release'
|
||||
VERSIONS_SHELLS="/bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/sh /bin/zsh"
|
||||
|
||||
TRUE=0
|
||||
FALSE=1
|
||||
ERROR=2
|
||||
|
||||
__versions_haveStrings=${ERROR}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# functions
|
||||
#
|
||||
|
||||
versions_osName()
|
||||
{
|
||||
os_name_='unrecognized'
|
||||
os_system_=`uname -s`
|
||||
case ${os_system_} in
|
||||
CYGWIN_NT-*) os_name_='Cygwin' ;;
|
||||
Darwin) os_name_='Mac OS X' ;;
|
||||
FreeBSD) os_name_='FreeBSD' ;;
|
||||
Linux) os_name_='Linux' ;;
|
||||
SunOS)
|
||||
if grep 'OpenSolaris' /etc/release >/dev/null; then
|
||||
os_name_='OpenSolaris'
|
||||
else
|
||||
os_name_='Solaris'
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
echo ${os_name_}
|
||||
unset os_name_ os_system_
|
||||
}
|
||||
|
||||
versions_osVersion()
|
||||
{
|
||||
os_version_='unrecognized'
|
||||
os_system_=`uname -s`
|
||||
os_release_=`uname -r`
|
||||
case ${os_system_} in
|
||||
CYGWIN_NT-*)
|
||||
os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]\.[0-9]*\).*'`
|
||||
;;
|
||||
Darwin)
|
||||
major_='10'
|
||||
sub_=`echo ${os_release_} |sed 's/^[0-9]*\.\([0-9]*\)\.[0-9]*$/\1/'`
|
||||
case ${os_release_} in
|
||||
8.*) minor_='4' ;;
|
||||
9.*) minor_='5' ;;
|
||||
10.*) minor_='6' ;;
|
||||
*) minor_='X'; sub_='X' ;;
|
||||
esac
|
||||
os_version_="${major_}.${minor_}.${sub_}"
|
||||
;;
|
||||
FreeBSD)
|
||||
os_version_=`expr "${os_release_}" : '\([0-9]*\.[0-9]*\)-.*'`
|
||||
;;
|
||||
Linux)
|
||||
if [ -r "${LSB_RELEASE}" ]; then
|
||||
if grep -q 'DISTRIB_ID=Ubuntu' "${LSB_RELEASE}"; then
|
||||
os_version_=`cat "${LSB_RELEASE}" \
|
||||
|awk -F= '$1~/DISTRIB_DESCRIPTION/{print $2}' \
|
||||
|sed 's/"//g;s/ /-/g'`
|
||||
fi
|
||||
elif [ -r '/etc/redhat-release' ]; then
|
||||
os_version_=`cat /etc/redhat-release`
|
||||
fi
|
||||
;;
|
||||
SunOS)
|
||||
if grep 'OpenSolaris' /etc/release >/dev/null; then
|
||||
os_version_=`grep 'OpenSolaris' /etc/release |awk '{print $2"("$3")"}'`
|
||||
else
|
||||
major_=`echo ${os_release_} |sed 's/[0-9]*\.\([0-9]*\)/\1/'`
|
||||
minor_=`grep Solaris /etc/release |sed 's/[^u]*\(u[0-9]*\).*/\1/'`
|
||||
os_version_="${major_}${minor_}"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
echo ${os_version_}
|
||||
unset os_name_ os_release_ os_version_ major_ minor_ sub_
|
||||
}
|
||||
|
||||
versions_shellVersion()
|
||||
{
|
||||
shell_=$1
|
||||
|
||||
if [ ! -x "${shell_}" ]; then
|
||||
echo 'not installed'
|
||||
return
|
||||
fi
|
||||
|
||||
version_=''
|
||||
case ${shell_} in
|
||||
*/sh)
|
||||
# TODO(kward): fix this
|
||||
## this could be one of any number of shells. try until one fits.
|
||||
#version_=`versions_shell_bash ${shell_}`
|
||||
## dash cannot be self determined yet
|
||||
#[ -z "${version_}" ] && version_=`versions_shell_ksh ${shell_}`
|
||||
## pdksh is covered in versions_shell_ksh()
|
||||
#[ -z "${version_}" ] && version_=`versions_shell_zsh ${shell_}`
|
||||
;;
|
||||
*/bash) version_=`versions_shell_bash ${shell_}` ;;
|
||||
*/dash)
|
||||
# simply assuming Ubuntu Linux until somebody comes up with a better
|
||||
# test. the following test will return an empty string if dash is not
|
||||
# installed.
|
||||
version_=`versions_shell_dash`
|
||||
;;
|
||||
*/ksh) version_=`versions_shell_ksh ${shell_}` ;;
|
||||
*/pdksh) version_=`versions_shell_pdksh ${shell_}` ;;
|
||||
*/zsh) version_=`versions_shell_zsh ${shell_}` ;;
|
||||
*) version_='invalid'
|
||||
esac
|
||||
|
||||
echo ${version_:-unknown}
|
||||
unset shell_ version_
|
||||
}
|
||||
|
||||
versions_shell_bash()
|
||||
{
|
||||
$1 --version 2>&1 |grep 'GNU bash' |sed 's/.*version \([^ ]*\).*/\1/'
|
||||
}
|
||||
|
||||
versions_shell_dash()
|
||||
{
|
||||
eval dpkg >/dev/null 2>&1
|
||||
[ $? -eq 127 ] && return # return if dpkg not found
|
||||
|
||||
dpkg -l |grep ' dash ' |awk '{print $3}'
|
||||
}
|
||||
|
||||
versions_shell_ksh()
|
||||
{
|
||||
versions_shell_=$1
|
||||
|
||||
# see if --version gives a result
|
||||
versions_version_=`${versions_shell_} --version 2>&1 \
|
||||
|sed 's/.*\([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]\).*/\1/'`
|
||||
|
||||
# --version didn't work... look into the binary
|
||||
if [ $? -ne ${TRUE} ]; then
|
||||
_versions_have_strings
|
||||
versions_version_=`strings ${versions_shell_} 2>&1 \
|
||||
|grep Version \
|
||||
|sed 's/^.*Version \(.*\)$/\1/;s/ s+ \$$//;s/ /-/g'`
|
||||
[ -z "${versions_version_}" ] \
|
||||
&& versions_version_=`versions_shell_pdksh ${versions_shell_}`
|
||||
fi
|
||||
|
||||
echo ${versions_version_}
|
||||
|
||||
unset versions_shell_ versions_version_
|
||||
}
|
||||
|
||||
versions_shell_pdksh()
|
||||
{
|
||||
_versions_have_strings
|
||||
strings $1 2>&1 \
|
||||
|grep 'PD KSH' \
|
||||
|sed -e 's/.*PD KSH \(.*\)/\1/;s/ /-/g'
|
||||
}
|
||||
|
||||
versions_shell_zsh()
|
||||
{
|
||||
versions_shell_=$1
|
||||
|
||||
versions_version_=`${versions_shell_} --version 2>&1 |awk '{print $2}'`
|
||||
|
||||
if [ $? -ne ${TRUE} ]; then
|
||||
versions_version_=`echo 'echo ${ZSH_VERSION}' |${versions_shell_}`
|
||||
fi
|
||||
|
||||
echo ${versions_version_}
|
||||
|
||||
unset versions_shell_ versions_version_
|
||||
}
|
||||
|
||||
# Determine if the 'strings' binary installed.
|
||||
_versions_have_strings()
|
||||
{
|
||||
[ ${__versions_haveStrings} -ne ${ERROR} ] && return
|
||||
eval strings /dev/null >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
__versions_haveStrings=${TRUE}
|
||||
else
|
||||
echo 'WARN: strings not installed. try installing binutils?' >&2
|
||||
__versions_haveStrings=${FALSE}
|
||||
fi
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# main
|
||||
#
|
||||
|
||||
versions_main()
|
||||
{
|
||||
# treat unset variables as an error
|
||||
set -u
|
||||
|
||||
os_name=`versions_osName`
|
||||
os_version=`versions_osVersion`
|
||||
echo "os: ${os_name} version: ${os_version}"
|
||||
|
||||
for shell in ${VERSIONS_SHELLS}; do
|
||||
shell_version=`versions_shellVersion ${shell}`
|
||||
echo "shell: ${shell} version: ${shell_version}"
|
||||
done
|
||||
}
|
||||
|
||||
if [ "${ARGV0}" = 'versions' ]; then
|
||||
versions_main "$@"
|
||||
fi
|
File diff suppressed because it is too large
Load Diff
@ -1,124 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test suite runner.
|
||||
#
|
||||
# This script runs all the unit tests that can be found, and generates a nice
|
||||
# report of the tests.
|
||||
|
||||
MY_NAME=`basename $0`
|
||||
MY_PATH=`dirname $0`
|
||||
|
||||
PREFIX='shunit2_test_'
|
||||
SHELLS='/bin/sh /bin/bash /bin/dash /bin/ksh /bin/pdksh /bin/zsh'
|
||||
TESTS=''
|
||||
for test in ${PREFIX}[a-z]*.sh; do
|
||||
TESTS="${TESTS} ${test}"
|
||||
done
|
||||
|
||||
# load common unit test functions
|
||||
. ../lib/versions
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
usage()
|
||||
{
|
||||
echo "usage: ${MY_NAME} [-e key=val ...] [-s shell(s)] [-t test(s)]"
|
||||
}
|
||||
|
||||
env=''
|
||||
|
||||
# process command line flags
|
||||
while getopts 'e:hs:t:' opt; do
|
||||
case ${opt} in
|
||||
e) # set an environment variable
|
||||
key=`expr "${OPTARG}" : '\([^=]*\)='`
|
||||
val=`expr "${OPTARG}" : '[^=]*=\(.*\)'`
|
||||
if [ -z "${key}" -o -z "${val}" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
eval "${key}='${val}'"
|
||||
export ${key}
|
||||
env="${env:+${env} }${key}"
|
||||
;;
|
||||
h) usage; exit 0 ;; # output help
|
||||
s) shells=${OPTARG} ;; # list of shells to run
|
||||
t) tests=${OPTARG} ;; # list of tests to run
|
||||
*) usage; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
shift `expr ${OPTIND} - 1`
|
||||
|
||||
# fill shells and/or tests
|
||||
shells=${shells:-${SHELLS}}
|
||||
tests=${tests:-${TESTS}}
|
||||
|
||||
# error checking
|
||||
if [ -z "${tests}" ]; then
|
||||
th_error 'no tests found to run; exiting'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
#------------------------------------------------------------------------------
|
||||
# System data
|
||||
#
|
||||
|
||||
# test run info
|
||||
shells: ${shells}
|
||||
tests: ${tests}
|
||||
EOF
|
||||
for key in ${env}; do
|
||||
eval "echo \"${key}=\$${key}\""
|
||||
done
|
||||
echo
|
||||
|
||||
# output system data
|
||||
echo "# system info"
|
||||
echo "$ date"
|
||||
date
|
||||
echo
|
||||
|
||||
echo "$ uname -mprsv"
|
||||
uname -mprsv
|
||||
|
||||
#
|
||||
# run tests
|
||||
#
|
||||
|
||||
for shell in ${shells}; do
|
||||
echo
|
||||
|
||||
# check for existance of shell
|
||||
if [ ! -x ${shell} ]; then
|
||||
th_warn "unable to run tests with the ${shell} shell"
|
||||
continue
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# Running the test suite with ${shell}
|
||||
#
|
||||
EOF
|
||||
|
||||
SHUNIT_SHELL=${shell} # pass shell onto tests
|
||||
shell_name=`basename ${shell}`
|
||||
shell_version=`versions_shellVersion "${shell}"`
|
||||
|
||||
echo "shell name: ${shell_name}"
|
||||
echo "shell version: ${shell_version}"
|
||||
|
||||
# execute the tests
|
||||
for suite in ${tests}; do
|
||||
suiteName=`expr "${suite}" : "${PREFIX}\(.*\).sh"`
|
||||
echo
|
||||
echo "--- Executing the '${suiteName}' test suite ---"
|
||||
( exec ${shell} ./${suite} 2>&1; )
|
||||
done
|
||||
done
|
@ -1,209 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test_asserts.sh 312 2011-03-14 22:41:29Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test for assert functions
|
||||
|
||||
# load test helpers
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
commonEqualsSame()
|
||||
{
|
||||
fn=$1
|
||||
|
||||
( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'equal' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'equal; with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} 'abc def' 'abc def' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'equal with spaces' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'not equal' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'null values' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
commonNotEqualsSame()
|
||||
{
|
||||
fn=$1
|
||||
|
||||
( ${fn} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} "${MSG}" 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not same, with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} '' '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} arg1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( ${fn} arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testAssertEquals()
|
||||
{
|
||||
commonEqualsSame 'assertEquals'
|
||||
}
|
||||
|
||||
testAssertNotEquals()
|
||||
{
|
||||
commonNotEqualsSame 'assertNotEquals'
|
||||
}
|
||||
|
||||
testAssertSame()
|
||||
{
|
||||
commonEqualsSame 'assertSame'
|
||||
}
|
||||
|
||||
testAssertNotSame()
|
||||
{
|
||||
commonNotEqualsSame 'assertNotSame'
|
||||
}
|
||||
|
||||
testAssertNull()
|
||||
{
|
||||
( assertNull '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'null' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNull "${MSG}" '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'null, with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNull 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'not null' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNull >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testAssertNotNull()
|
||||
{
|
||||
( assertNotNull 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull "${MSG}" 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null, with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull 'x"b' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null, with double-quote' $? \
|
||||
"${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull "x'b" >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null, with single-quote' $? \
|
||||
"${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull 'x$b' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null, with dollar' $? \
|
||||
"${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull 'x`b' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'not null, with backtick' $? \
|
||||
"${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertNotNull '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
# there is no test for too few arguments as $1 might actually be null
|
||||
|
||||
( assertNotNull arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testAssertTrue()
|
||||
{
|
||||
( assertTrue 0 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'true' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue "${MSG}" 0 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'true, with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'true condition' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue 1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'false' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'false condition' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'null' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertTrue arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testAssertFalse()
|
||||
{
|
||||
( assertFalse 1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'false' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse "${MSG}" 1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'false, with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse '[ 0 -eq 1 ]' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertTrueWithNoOutput 'false condition' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse 0 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'true' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse '[ 0 -eq 0 ]' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'true condition' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( assertFalse arg1 arg2 arg3 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite functions
|
||||
#
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
tmpDir="${__shunit_tmpDir}/output"
|
||||
mkdir "${tmpDir}"
|
||||
stdoutF="${tmpDir}/stdout"
|
||||
stderrF="${tmpDir}/stderr"
|
||||
|
||||
MSG='This is a test message'
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
|
||||
. ${TH_SHUNIT}
|
@ -1,89 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test_failures.sh 286 2008-11-24 21:42:34Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test for failure functions
|
||||
|
||||
# load common unit-test functions
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
testFail()
|
||||
{
|
||||
( fail >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'fail' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( fail "${MSG}" >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'fail with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( fail arg1 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testFailNotEquals()
|
||||
{
|
||||
( failNotEquals 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failNotEquals "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failNotEquals 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failNotEquals '' '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failNotEquals >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failNotEquals arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
testFailSame()
|
||||
{
|
||||
( failSame 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failSame "${MSG}" 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'same with msg' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failSame 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'not same' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failSame '' '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithOutput 'null values' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failSame >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too few arguments' $? "${stdoutF}" "${stderrF}"
|
||||
|
||||
( failSame arg1 arg2 arg3 arg4 >"${stdoutF}" 2>"${stderrF}" )
|
||||
th_assertFalseWithError 'too many arguments' $? "${stdoutF}" "${stderrF}"
|
||||
}
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# suite functions
|
||||
#
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
tmpDir="${__shunit_tmpDir}/output"
|
||||
mkdir "${tmpDir}"
|
||||
stdoutF="${tmpDir}/stdout"
|
||||
stderrF="${tmpDir}/stderr"
|
||||
|
||||
MSG='This is a test message'
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
|
||||
. ${TH_SHUNIT}
|
@ -1,177 +0,0 @@
|
||||
# $Id: shunit2_test_helpers 286 2008-11-24 21:42:34Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test common functions
|
||||
|
||||
# treat unset variables as an error when performing parameter expansion
|
||||
set -u
|
||||
|
||||
# set shwordsplit for zsh
|
||||
[ -n "${ZSH_VERSION:-}" ] && setopt shwordsplit
|
||||
|
||||
#
|
||||
# constants
|
||||
#
|
||||
|
||||
# path to shUnit2 library. can be overridden by setting SHUNIT_INC
|
||||
TH_SHUNIT=${SHUNIT_INC:-./shunit2}
|
||||
|
||||
# configure debugging. set the DEBUG environment variable to any
|
||||
# non-empty value to enable debug output, or TRACE to enable trace
|
||||
# output.
|
||||
TRACE=${TRACE:+'th_trace '}
|
||||
[ -n "${TRACE}" ] && DEBUG=1
|
||||
[ -z "${TRACE}" ] && TRACE=':'
|
||||
|
||||
DEBUG=${DEBUG:+'th_debug '}
|
||||
[ -z "${DEBUG}" ] && DEBUG=':'
|
||||
|
||||
#
|
||||
# variables
|
||||
#
|
||||
|
||||
th_RANDOM=0
|
||||
|
||||
#
|
||||
# functions
|
||||
#
|
||||
|
||||
# message functions
|
||||
th_trace() { echo "${MY_NAME}:TRACE $@" >&2; }
|
||||
th_debug() { echo "${MY_NAME}:DEBUG $@" >&2; }
|
||||
th_info() { echo "${MY_NAME}:INFO $@" >&2; }
|
||||
th_warn() { echo "${MY_NAME}:WARN $@" >&2; }
|
||||
th_error() { echo "${MY_NAME}:ERROR $@" >&2; }
|
||||
th_fatal() { echo "${MY_NAME}:FATAL $@" >&2; }
|
||||
|
||||
# output subtest name
|
||||
th_subtest() { echo " $@" >&2; }
|
||||
|
||||
# generate a random number
|
||||
th_generateRandom()
|
||||
{
|
||||
tfgr_random=${th_RANDOM}
|
||||
|
||||
while [ "${tfgr_random}" = "${th_RANDOM}" ]; do
|
||||
if [ -n "${RANDOM:-}" ]; then
|
||||
# $RANDOM works
|
||||
tfgr_random=${RANDOM}${RANDOM}${RANDOM}$$
|
||||
elif [ -r '/dev/urandom' ]; then
|
||||
tfgr_random=`od -vAn -N4 -tu4 </dev/urandom |sed 's/^[^0-9]*//'`
|
||||
else
|
||||
tfgr_date=`date '+%H%M%S'`
|
||||
tfgr_random=`expr ${tfgr_date} \* $$`
|
||||
unset tfgr_date
|
||||
fi
|
||||
[ "${tfgr_random}" = "${th_RANDOM}" ] && sleep 1
|
||||
done
|
||||
|
||||
th_RANDOM=${tfgr_random}
|
||||
unset tfgr_random
|
||||
}
|
||||
|
||||
# this section returns the data section from the specified section of a file. a
|
||||
# datasection is defined by a [header], one or more lines of data, and then a
|
||||
# blank line.
|
||||
th_getDataSect()
|
||||
{
|
||||
th_sgrep "\\[$1\\]" "$2" |sed '1d'
|
||||
}
|
||||
|
||||
# this function greps a section from a file. a section is defined as a group of
|
||||
# lines preceeded and followed by blank lines.
|
||||
th_sgrep()
|
||||
{
|
||||
th_pattern_=$1
|
||||
shift
|
||||
|
||||
sed -e '/./{H;$!d;}' -e "x;/${th_pattern_}/"'!d;' $@ |sed '1d'
|
||||
|
||||
unset th_pattern_
|
||||
}
|
||||
|
||||
# Custom assert that checks for true return value (0), and no output to STDOUT
|
||||
# or STDERR. If a non-zero return value is encountered, the output of STDERR
|
||||
# will be output.
|
||||
#
|
||||
# Args:
|
||||
# th_test_: string: name of the subtest
|
||||
# th_rtrn_: integer: the return value of the subtest performed
|
||||
# th_stdout_: string: filename where stdout was redirected to
|
||||
# th_stderr_: string: filename where stderr was redirected to
|
||||
th_assertTrueWithNoOutput()
|
||||
{
|
||||
th_test_=$1
|
||||
th_rtrn_=$2
|
||||
th_stdout_=$3
|
||||
th_stderr_=$4
|
||||
|
||||
assertTrue "${th_test_}; expected return value of zero" ${th_rtrn_}
|
||||
[ ${th_rtrn_} -ne ${SHUNIT_TRUE} ] && cat "${th_stderr_}"
|
||||
assertFalse "${th_test_}; expected no output to STDOUT" \
|
||||
"[ -s '${th_stdout_}' ]"
|
||||
assertFalse "${th_test_}; expected no output to STDERR" \
|
||||
"[ -s '${th_stderr_}' ]"
|
||||
|
||||
unset th_test_ th_rtrn_ th_stdout_ th_stderr_
|
||||
}
|
||||
|
||||
# Custom assert that checks for non-zero return value, output to STDOUT, but no
|
||||
# output to STDERR.
|
||||
#
|
||||
# Args:
|
||||
# th_test_: string: name of the subtest
|
||||
# th_rtrn_: integer: the return value of the subtest performed
|
||||
# th_stdout_: string: filename where stdout was redirected to
|
||||
# th_stderr_: string: filename where stderr was redirected to
|
||||
th_assertFalseWithOutput()
|
||||
{
|
||||
th_test_=$1
|
||||
th_rtrn_=$2
|
||||
th_stdout_=$3
|
||||
th_stderr_=$4
|
||||
|
||||
assertFalse "${th_test_}; expected non-zero return value" ${th_rtrn_}
|
||||
assertTrue "${th_test_}; expected output to STDOUT" \
|
||||
"[ -s '${th_stdout_}' ]"
|
||||
assertFalse "${th_test_}; expected no output to STDERR" \
|
||||
"[ -s '${th_stderr_}' ]"
|
||||
|
||||
unset th_test_ th_rtrn_ th_stdout_ th_stderr_
|
||||
}
|
||||
|
||||
# Custom assert that checks for non-zero return value, no output to STDOUT, but
|
||||
# output to STDERR.
|
||||
#
|
||||
# Args:
|
||||
# th_test_: string: name of the subtest
|
||||
# th_rtrn_: integer: the return value of the subtest performed
|
||||
# th_stdout_: string: filename where stdout was redirected to
|
||||
# th_stderr_: string: filename where stderr was redirected to
|
||||
th_assertFalseWithError()
|
||||
{
|
||||
th_test_=$1
|
||||
th_rtrn_=$2
|
||||
th_stdout_=$3
|
||||
th_stderr_=$4
|
||||
|
||||
assertFalse "${th_test_}; expected non-zero return value" ${th_rtrn_}
|
||||
assertFalse "${th_test_}; expected no output to STDOUT" \
|
||||
"[ -s '${th_stdout_}' ]"
|
||||
assertTrue "${th_test_}; expected output to STDERR" \
|
||||
"[ -s '${th_stderr_}' ]"
|
||||
|
||||
unset th_test_ th_rtrn_ th_stdout_ th_stderr_
|
||||
}
|
||||
|
||||
#
|
||||
# main
|
||||
#
|
||||
|
||||
${TRACE} 'trace output enabled'
|
||||
${DEBUG} 'debug output enabled'
|
@ -1,249 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test_macros.sh 299 2010-05-03 12:44:20Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test for macros.
|
||||
|
||||
# load test helpers
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
testAssertEquals()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_EQUALS_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_EQUALS_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testAssertNotEquals()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_NOT_EQUALS_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_EQUALS_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_NOT_EQUALS_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_EQUALS_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testSame()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_SAME_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_SAME_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testNotSame()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_NOT_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_SAME_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_NOT_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_SAME_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testNull()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_NULL_} 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NULL_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_NULL_} '"some msg"' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NULL_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testNotNull()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_NOT_NULL_} '' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_NULL_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_NOT_NULL_} '"some msg"' '""' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_NOT_NULL_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stdoutF}" "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testAssertTrue()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_TRUE_} ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_TRUE_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
|
||||
( ${_ASSERT_TRUE_} '"some msg"' ${SHUNIT_FALSE} >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_TRUE_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testAssertFalse()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_ASSERT_FALSE_} ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_FALSE_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_ASSERT_FALSE_} '"some msg"' ${SHUNIT_TRUE} >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_ASSERT_FALSE_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testFail()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_FAIL_} >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_FAIL_} '"some msg"' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testFailNotEquals()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_FAIL_NOT_EQUALS_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_NOT_EQUALS_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_FAIL_NOT_EQUALS_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_NOT_EQUALS_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testFailSame()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_FAIL_SAME_} 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_SAME_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_FAIL_SAME_} '"some msg"' 'x' 'x' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_SAME_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testFailNotSame()
|
||||
{
|
||||
# start skipping if LINENO not available
|
||||
[ -z "${LINENO:-}" ] && startSkipping
|
||||
|
||||
( ${_FAIL_NOT_SAME_} 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_NOT_SAME_ failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
|
||||
( ${_FAIL_NOT_SAME_} '"some msg"' 'x' 'y' >"${stdoutF}" 2>"${stderrF}" )
|
||||
grep '^ASSERT:\[[0-9]*\] *' "${stdoutF}" >/dev/null
|
||||
rtrn=$?
|
||||
assertTrue '_FAIL_NOT_SAME_ w/ msg failure' ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite functions
|
||||
#
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
tmpDir="${__shunit_tmpDir}/output"
|
||||
mkdir "${tmpDir}"
|
||||
stdoutF="${tmpDir}/stdout"
|
||||
stderrF="${tmpDir}/stderr"
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
|
||||
. ${TH_SHUNIT}
|
@ -1,165 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test_misc.sh 322 2011-04-24 00:09:45Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2008 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
#
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit tests of miscellaneous things
|
||||
|
||||
# load test helpers
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
# Note: the test script is prefixed with '#' chars so that shUnit2 does not
|
||||
# incorrectly interpret the embedded functions as real functions.
|
||||
testUnboundVariable()
|
||||
{
|
||||
sed 's/^#//' >"${unittestF}" <<EOF
|
||||
## treat unset variables as an error when performing parameter expansion
|
||||
#set -u
|
||||
#
|
||||
#boom() { x=\$1; } # this function goes boom if no parameters are passed!
|
||||
#test_boom()
|
||||
#{
|
||||
# assertEquals 1 1
|
||||
# boom # No parameter given
|
||||
# assertEquals 0 \$?
|
||||
#}
|
||||
#. ${TH_SHUNIT}
|
||||
EOF
|
||||
( exec ${SHUNIT_SHELL:-sh} "${unittestF}" >"${stdoutF}" 2>"${stderrF}" )
|
||||
assertFalse 'expected a non-zero exit value' $?
|
||||
grep '^ASSERT:Unknown failure' "${stdoutF}" >/dev/null
|
||||
assertTrue 'assert message was not generated' $?
|
||||
grep '^Ran [0-9]* test' "${stdoutF}" >/dev/null
|
||||
assertTrue 'test count message was not generated' $?
|
||||
grep '^FAILED' "${stdoutF}" >/dev/null
|
||||
assertTrue 'failure message was not generated' $?
|
||||
}
|
||||
|
||||
testIssue7()
|
||||
{
|
||||
( assertEquals 'Some message.' 1 2 >"${stdoutF}" 2>"${stderrF}" )
|
||||
diff "${stdoutF}" - >/dev/null <<EOF
|
||||
ASSERT:Some message. expected:<1> but was:<2>
|
||||
EOF
|
||||
rtrn=$?
|
||||
assertEquals ${SHUNIT_TRUE} ${rtrn}
|
||||
[ ${rtrn} -ne ${SHUNIT_TRUE} ] && cat "${stderrF}" >&2
|
||||
}
|
||||
|
||||
testPrepForSourcing()
|
||||
{
|
||||
assertEquals '/abc' `_shunit_prepForSourcing '/abc'`
|
||||
assertEquals './abc' `_shunit_prepForSourcing './abc'`
|
||||
assertEquals './abc' `_shunit_prepForSourcing 'abc'`
|
||||
}
|
||||
|
||||
testEscapeCharInStr()
|
||||
{
|
||||
actual=`_shunit_escapeCharInStr '\' ''`
|
||||
assertEquals '' "${actual}"
|
||||
assertEquals 'abc\\' `_shunit_escapeCharInStr '\' 'abc\'`
|
||||
assertEquals 'abc\\def' `_shunit_escapeCharInStr '\' 'abc\def'`
|
||||
assertEquals '\\def' `_shunit_escapeCharInStr '\' '\def'`
|
||||
|
||||
actual=`_shunit_escapeCharInStr '"' ''`
|
||||
assertEquals '' "${actual}"
|
||||
assertEquals 'abc\"' `_shunit_escapeCharInStr '"' 'abc"'`
|
||||
assertEquals 'abc\"def' `_shunit_escapeCharInStr '"' 'abc"def'`
|
||||
assertEquals '\"def' `_shunit_escapeCharInStr '"' '"def'`
|
||||
|
||||
actual=`_shunit_escapeCharInStr '$' ''`
|
||||
assertEquals '' "${actual}"
|
||||
assertEquals 'abc\$' `_shunit_escapeCharInStr '$' 'abc$'`
|
||||
assertEquals 'abc\$def' `_shunit_escapeCharInStr '$' 'abc$def'`
|
||||
assertEquals '\$def' `_shunit_escapeCharInStr '$' '$def'`
|
||||
|
||||
# actual=`_shunit_escapeCharInStr "'" ''`
|
||||
# assertEquals '' "${actual}"
|
||||
# assertEquals "abc\\'" `_shunit_escapeCharInStr "'" "abc'"`
|
||||
# assertEquals "abc\\'def" `_shunit_escapeCharInStr "'" "abc'def"`
|
||||
# assertEquals "\\'def" `_shunit_escapeCharInStr "'" "'def"`
|
||||
|
||||
# # must put the backtick in a variable so the shell doesn't misinterpret it
|
||||
# # while inside a backticked sequence (e.g. `echo '`'` would fail).
|
||||
# backtick='`'
|
||||
# actual=`_shunit_escapeCharInStr ${backtick} ''`
|
||||
# assertEquals '' "${actual}"
|
||||
# assertEquals '\`abc' \
|
||||
# `_shunit_escapeCharInStr "${backtick}" ${backtick}'abc'`
|
||||
# assertEquals 'abc\`' \
|
||||
# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}`
|
||||
# assertEquals 'abc\`def' \
|
||||
# `_shunit_escapeCharInStr "${backtick}" 'abc'${backtick}'def'`
|
||||
}
|
||||
|
||||
testEscapeCharInStr_specialChars()
|
||||
{
|
||||
# make sure our forward slash doesn't upset sed
|
||||
assertEquals '/' `_shunit_escapeCharInStr '\' '/'`
|
||||
|
||||
# some shells escape these differently
|
||||
#assertEquals '\\a' `_shunit_escapeCharInStr '\' '\a'`
|
||||
#assertEquals '\\b' `_shunit_escapeCharInStr '\' '\b'`
|
||||
}
|
||||
|
||||
# Test the various ways of declaring functions.
|
||||
#
|
||||
# Prefixing (then stripping) with comment symbol so these functions aren't
|
||||
# treated as real functions by shUnit2.
|
||||
testExtractTestFunctions()
|
||||
{
|
||||
f="${tmpD}/extract_test_functions"
|
||||
sed 's/^#//' <<EOF >"${f}"
|
||||
#testABC() { echo 'ABC'; }
|
||||
#test_def() {
|
||||
# echo 'def'
|
||||
#}
|
||||
#testG3 ()
|
||||
#{
|
||||
# echo 'G3'
|
||||
#}
|
||||
#function test4() { echo '4'; }
|
||||
# test5() { echo '5'; }
|
||||
#some_test_function() { echo 'some func'; }
|
||||
#func_with_test_vars() {
|
||||
# testVariable=1234
|
||||
#}
|
||||
EOF
|
||||
|
||||
actual=`_shunit_extractTestFunctions "${f}"`
|
||||
assertEquals 'testABC test_def testG3 test4 test5' "${actual}"
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite functions
|
||||
#
|
||||
|
||||
setUp()
|
||||
{
|
||||
for f in ${expectedF} ${stdoutF} ${stderrF}; do
|
||||
cp /dev/null ${f}
|
||||
done
|
||||
rm -fr "${tmpD}"
|
||||
mkdir "${tmpD}"
|
||||
}
|
||||
|
||||
oneTimeSetUp()
|
||||
{
|
||||
tmpD="${SHUNIT_TMPDIR}/tmp"
|
||||
expectedF="${SHUNIT_TMPDIR}/expected"
|
||||
stdoutF="${SHUNIT_TMPDIR}/stdout"
|
||||
stderrF="${SHUNIT_TMPDIR}/stderr"
|
||||
unittestF="${SHUNIT_TMPDIR}/unittest"
|
||||
}
|
||||
|
||||
# load and run shUnit2
|
||||
[ -n "${ZSH_VERSION:-}" ] && SHUNIT_PARENT=$0
|
||||
. ${TH_SHUNIT}
|
@ -1,41 +0,0 @@
|
||||
#! /bin/sh
|
||||
# $Id: shunit2_test_standalone.sh 303 2010-05-03 13:11:27Z kate.ward@forestent.com $
|
||||
# vim:et:ft=sh:sts=2:sw=2
|
||||
#
|
||||
# Copyright 2010 Kate Ward. All Rights Reserved.
|
||||
# Released under the LGPL (GNU Lesser General Public License)
|
||||
# Author: kate.ward@forestent.com (Kate Ward)
|
||||
#
|
||||
# shUnit2 unit test for standalone operation.
|
||||
#
|
||||
# This unit test is purely to test that calling shunit2 directly, while passing
|
||||
# the name of a unit test script, works. When run, this script determines if it
|
||||
# is running as a standalone program, and calls main() if it is.
|
||||
|
||||
ARGV0=`basename "$0"`
|
||||
|
||||
# load test helpers
|
||||
. ./shunit2_test_helpers
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# suite tests
|
||||
#
|
||||
|
||||
testStandalone()
|
||||
{
|
||||
assertTrue ${SHUNIT_TRUE}
|
||||
}
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
# main
|
||||
#
|
||||
|
||||
main()
|
||||
{
|
||||
${TH_SHUNIT} "${ARGV0}"
|
||||
}
|
||||
|
||||
# are we running as a standalone?
|
||||
if [ "${ARGV0}" = 'shunit2_test_standalone.sh' ]; then
|
||||
if [ $# -gt 0 ]; then main "$@"; else main; fi
|
||||
fi
|
@ -1,419 +0,0 @@
|
||||
# !/usr/bin/env bash
|
||||
#
|
||||
# stub.sh 1.0.2 - stubbing helpers for simplifying bash script tests.
|
||||
# https://github.com/jimeh/stub.sh
|
||||
#
|
||||
# (The MIT License)
|
||||
#
|
||||
# Copyright (c) 2014 Jim Myhrberg.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to
|
||||
# deal in the Software without restriction, including without limitation the
|
||||
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
# sell copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
# IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
# Public: Stub given command.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: (optional) When set to "STDOUT", echo a default message to STDOUT.
|
||||
# When set to "STDERR", echo default message to STDERR.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns nothing.
|
||||
stub() {
|
||||
local redirect="null"
|
||||
if [ "$2" = "stdout" ] || [ "$2" = "STDOUT" ]; then redirect=""; fi
|
||||
if [ "$2" = "stderr" ] || [ "$2" = "STDERR" ]; then redirect="stderr"; fi
|
||||
|
||||
stub_and_echo "$1" "$1 stub: \$@" "$redirect"
|
||||
}
|
||||
|
||||
|
||||
# Public: Stub given command, and echo given string.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: String to echo when stub is called.
|
||||
# - $3: (optional) When set to "STDERR", echo to STDERR instead of STDOUT.
|
||||
# When set to "null", all output is redirected to /dev/null.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns nothing.
|
||||
stub_and_echo() {
|
||||
local redirect=""
|
||||
if [ "$3" = "stderr" ] || [ "$3" = "STDERR" ]; then redirect=" 1>&2"; fi
|
||||
if [ "$3" = "null" ]; then redirect=" &>/dev/null"; fi
|
||||
|
||||
stub_and_eval "$1" "echo \"$2\"$redirect"
|
||||
}
|
||||
|
||||
|
||||
# Public: Stub given command, and execute given string with eval.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to stub.
|
||||
# - $2: String to eval when stub is called.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns nothing.
|
||||
stub_and_eval() {
|
||||
local cmd="$1"
|
||||
|
||||
# Setup empty list of active stubs.
|
||||
if [ -z "$STUB_ACTIVE_STUBS" ]; then STUB_ACTIVE_STUBS=(); fi
|
||||
|
||||
# If stubbing a function, store non-stubbed copy of it required for restore.
|
||||
if [ -n "$(command -v "$cmd")" ]; then
|
||||
if [ -z "$(command -v "non_stubbed_${cmd}")" ]; then
|
||||
if [[ "$(type "$cmd" | head -1)" == *"is a function" ]]; then
|
||||
local source="$(type "$cmd" | tail -n +2)"
|
||||
source="${source/$cmd/non_stubbed_${cmd}}"
|
||||
eval "$source"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Prepare stub index and call list for this stub.
|
||||
__stub_register "$cmd"
|
||||
|
||||
# Keep track of what is currently stubbed to ensure restore only acts on
|
||||
# actual stubs.
|
||||
if [[ " ${STUB_ACTIVE_STUBS[@]} " != *" $cmd "* ]]; then
|
||||
STUB_ACTIVE_STUBS+=("$cmd")
|
||||
fi
|
||||
|
||||
# Create the stub.
|
||||
eval "$( printf "%s" "${cmd}() { __stub_call \"${cmd}\" \$@; $2;}")"
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called. Returns 0 if yes, 1 if no.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) is stub has been called, 1 (error) otherwise.
|
||||
stub_called() {
|
||||
if [ "$(stub_called_times "$1")" -lt 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called with specific arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $@: Any/all additional arguments are used to specify what stub was
|
||||
# called with.
|
||||
#
|
||||
# Examples:
|
||||
# stub uname
|
||||
# uname
|
||||
# uname -r -a
|
||||
# stub_called_with uname # Returns 0 (success).
|
||||
# stub_called_with uname -r # Returns 1 (error).
|
||||
# stub_called_with uname -r -a # Returns 0 (success).
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if specified stub has been called with given arguments,
|
||||
# otherwise returns 1 (error).
|
||||
stub_called_with() {
|
||||
local cmd="$1"
|
||||
shift 1
|
||||
|
||||
if [ "$(stub_called_with_times "$cmd" $@)" -lt 1 ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out how many times a stub has been called.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
#
|
||||
# Echoes number of times stub has been called if $2 is not given, otherwise
|
||||
# echoes nothing.
|
||||
# Returns 0 (success) if $2 is not given, or if it is given and it matches the
|
||||
# number of times the stub has been called. Otherwise 1 (error) is returned if
|
||||
# it doesn't match..
|
||||
stub_called_times() {
|
||||
local cmd="$1"
|
||||
|
||||
local index="$(__stub_index "$1")"
|
||||
local count=0
|
||||
|
||||
if [ -n "$index" ]; then
|
||||
eval "count=\"\${#STUB_${index}_CALLS[@]}\""
|
||||
fi
|
||||
|
||||
echo $count
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called exactly the given number of times
|
||||
# with specified arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Exact number of times stub has been called.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called at least the given number of
|
||||
# times with specified arguments, otherwise 1 (error) is returned.
|
||||
stub_called_exactly_times() {
|
||||
if [ "$(stub_called_times "$1")" != "$2" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called at least the given number of times.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Minimum required number of times stub has been called.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called at least the given number of
|
||||
# times, otherwise 1 (error) is returned.
|
||||
stub_called_at_least_times() {
|
||||
if [ "$(stub_called_times "$1")" -lt "$2" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called no more than the given number of
|
||||
# times.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Maximum allowed number of times stub has been called.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called no more than the given number of
|
||||
# times, otherwise 1 (error) is returned.
|
||||
stub_called_at_most_times() {
|
||||
if [ "$(stub_called_times "$1")" -gt "$2" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out how many times a stub has been called with specific
|
||||
# arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $@: Any/all additional arguments are used to specify what stub was
|
||||
# called with.
|
||||
#
|
||||
# Echoes number of times stub has been called with given arguments.
|
||||
# Return 0 (success).
|
||||
stub_called_with_times() {
|
||||
local cmd="$1"
|
||||
|
||||
shift 1
|
||||
local args="$@"
|
||||
if [ "$args" = "" ]; then args="<none>"; fi
|
||||
|
||||
local count=0
|
||||
local index="$(__stub_index "$cmd")"
|
||||
if [ -n "$index" ]; then
|
||||
eval "local calls=(\"\${STUB_${index}_CALLS[@]}\")"
|
||||
for call in "${calls[@]}"; do
|
||||
if [ "$call" = "$args" ]; then ((count++)); fi
|
||||
done
|
||||
fi
|
||||
|
||||
echo $count
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called exactly the given number of times
|
||||
# with specified arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Exact number of times stub has been called.
|
||||
# - $@: Any/all additional arguments are used to specify what stub was
|
||||
# called with.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called at least the given number of
|
||||
# times with specified arguments, otherwise 1 (error) is returned.
|
||||
stub_called_with_exactly_times() {
|
||||
local cmd="$1"
|
||||
local count="$2"
|
||||
shift 2
|
||||
|
||||
if [ "$(stub_called_with_times "$cmd" $@)" != "$count" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called at least the given number of times
|
||||
# with specified arguments.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Minimum required number of times stub has been called.
|
||||
# - $@: Any/all additional arguments are used to specify what stub was
|
||||
# called with.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called at least the given number of
|
||||
# times with specified arguments, otherwise 1 (error) is returned.
|
||||
stub_called_with_at_least_times() {
|
||||
local cmd="$1"
|
||||
local count="$2"
|
||||
shift 2
|
||||
|
||||
if [ "$(stub_called_with_times "$cmd" $@)" -lt "$count" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Find out if stub has been called no more than the given number of
|
||||
# times.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of stubbed command.
|
||||
# - $2: Maximum allowed number of times stub has been called.
|
||||
# - $@: Any/all additional arguments are used to specify what stub was
|
||||
# called with.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns 0 (success) if stub has been called no more than the given number of
|
||||
# times with specified arguments, otherwise 1 (error) is returned.
|
||||
stub_called_with_at_most_times() {
|
||||
local cmd="$1"
|
||||
local count="$2"
|
||||
shift 2
|
||||
|
||||
if [ "$(stub_called_with_times "$cmd" $@)" -gt "$count" ]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Public: Restore the original command/function that was stubbed.
|
||||
#
|
||||
# Arguments:
|
||||
# - $1: Name of command to restore.
|
||||
#
|
||||
# Echoes nothing.
|
||||
# Returns nothing.
|
||||
restore() {
|
||||
local cmd="$1"
|
||||
|
||||
# Don't do anything if the command isn't currently stubbed.
|
||||
if [[ " ${STUB_ACTIVE_STUBS[@]} " != *" $1 "* ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove stub functions.
|
||||
unset -f "$cmd"
|
||||
|
||||
# Remove stub from list of active stubs.
|
||||
STUB_ACTIVE_STUBS=(${STUB_ACTIVE_STUBS[@]/$cmd/})
|
||||
|
||||
# If stub was for a function, restore the original function.
|
||||
if type "non_stubbed_${cmd}" &>/dev/null; then
|
||||
local original_type="$(type "non_stubbed_${cmd}" | head -1)"
|
||||
if [[ "$original_type" == *"is a function" ]]; then
|
||||
local source="$(type "non_stubbed_$cmd" | tail -n +2)"
|
||||
source="${source/non_stubbed_${cmd}/$cmd}"
|
||||
eval "$source"
|
||||
unset -f "non_stubbed_${cmd}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# Internal functions
|
||||
#
|
||||
|
||||
# Private: Used to keep track of which stubs have been called and how many
|
||||
# times.
|
||||
__stub_call() {
|
||||
local cmd="$1"
|
||||
shift 1
|
||||
local args="$@"
|
||||
if [ "$args" = "" ]; then args="<none>"; fi
|
||||
|
||||
local index="$(__stub_index "$cmd")"
|
||||
if [ -n "$index" ]; then
|
||||
eval "STUB_${index}_CALLS+=(\"\$args\")"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
# Private: Get index value of stub. Required to access list of stub calls.
|
||||
__stub_index() {
|
||||
local cmd="$1"
|
||||
|
||||
for item in ${STUB_INDEX[@]}; do
|
||||
if [[ "$item" = "${cmd}="* ]]; then
|
||||
local index="$item"
|
||||
index="${index/${cmd}=/}"
|
||||
echo "$index"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
# Private: Prepare for the creation of a new stub. Adds stub to index and
|
||||
# sets up an empty call list.
|
||||
__stub_register() {
|
||||
local cmd="$1"
|
||||
|
||||
if [ -z "$STUB_NEXT_INDEX" ]; then STUB_NEXT_INDEX=0; fi
|
||||
if [ -z "$STUB_INDEX" ]; then STUB_INDEX=(); fi
|
||||
|
||||
# Clean up after any previous stub for the same command.
|
||||
__stub_clean "$cmd"
|
||||
|
||||
# Add stub to index.
|
||||
STUB_INDEX+=("${cmd}=${STUB_NEXT_INDEX}")
|
||||
eval "STUB_${STUB_NEXT_INDEX}_CALLS=()"
|
||||
|
||||
# Increment stub count.
|
||||
((STUB_NEXT_INDEX++))
|
||||
}
|
||||
|
||||
# Private: Cleans out and removes a stub's call list, and removes stub from
|
||||
# index.
|
||||
__stub_clean() {
|
||||
local cmd="$1"
|
||||
local index="$(__stub_index "$cmd")"
|
||||
|
||||
# Remove all relevant details from any previously existing stub for the same
|
||||
# command.
|
||||
if [ -n "$index" ]; then
|
||||
eval "unset STUB_${index}_CALLS"
|
||||
STUB_INDEX=(${STUB_INDEX[@]/${cmd}=*/})
|
||||
fi
|
||||
}
|
@ -1 +0,0 @@
|
||||
zsh-autosuggestions.zsh
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user