Bash补全脚本的单元测试
我想为一个比较复杂的Bash自动补全脚本写一个单元测试,最好是用Python来实现。我的目标是通过编程的方式获取Bash自动补全的值。
这个测试应该像这样:
def test_completion():
# trigger_completion should return what a user should get on triggering
# Bash completion like this: 'pbt createkvm<TAB>'
assert trigger_completion('pbt createkvm') == "module1 module2 module3"
我该如何通过编程模拟Bash的自动补全,以便在我的工具的测试套件中检查补全的值呢?
2 个回答
1
bonsaiviking的解决方案对我来说差不多可行。我需要修改一下bash脚本字符串。我在执行的bash脚本中添加了一个额外的';'分隔符,否则在Mac OS X上执行就不行了。具体原因我也不太清楚。
我还稍微调整了一下各种COMP_参数的初始化,以便处理我遇到的不同情况。
最终的解决方案是一个辅助类,用来从python测试bash补全功能,这样上面的测试就可以写成:
from completion import BashCompletionTest
class AdsfTestCase(BashCompletionTest):
def test_orig(self):
self.run_complete("other arguments f", "four five")
def run_complete(self, command, expected):
completion_file="adsf-completion"
program="asdf"
super(AdsfTestCase, self).run_complete(completion_file, program, command, expected)
if (__name__=='__main__'):
unittest.main()
补全库位于 https://github.com/lacostej/unity3d-bash-completion/blob/master/lib/completion.py
9
假设你有一个叫做 asdf-completion
的文件,这个文件里有一个 bash 自动补全的脚本,内容如下:
_asdf() {
COMPREPLY=()
local cur prev
cur=$(_get_cword)
COMPREPLY=( $( compgen -W "one two three four five six" -- "$cur") )
return 0
}
complete -F _asdf asdf
这个脚本使用了一个叫 _asdf
的函数,来为一个虚构的 asdf
命令提供自动补全的功能。如果我们设置好正确的环境变量(可以参考 bash 手册),那么就能得到相同的效果,也就是把可能的补全结果放到 COMPREPLY
这个变量里。下面是一个在单元测试中实现这个功能的例子:
import subprocess
import unittest
class BashTestCase(unittest.TestCase):
def test_complete(self):
completion_file="asdf-completion"
partial_word="f"
cmd=["asdf", "other", "arguments", partial_word]
cmdline = ' '.join(cmd)
out = subprocess.Popen(['bash', '-i', '-c',
r'source {compfile}; COMP_LINE="{cmdline}" COMP_WORDS=({cmdline}) COMP_CWORD={cword} COMP_POINT={cmdlen} $(complete -p {cmd} | sed "s/.*-F \\([^ ]*\\) .*/\\1/") && echo ${{COMPREPLY[*]}}'.format(
compfile=completion_file, cmdline=cmdline, cmdlen=len(cmdline), cmd=cmd[0], cword=cmd.index(partial_word)
)],
stdout=subprocess.PIPE)
stdout, stderr = out.communicate()
self.assertEqual(stdout, "four five\n")
if (__name__=='__main__'):
unittest.main()
这个方法应该适用于任何使用 -F
的补全,但也可能适用于其他类型的补全。
je4d 提到的使用 expect
的建议是个不错的主意,可以让测试更加全面。