Unit Test для Bash завершения script

Я хотел бы написать Unit Test для (довольно сложного) Bash завершения script, желательно с 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 программно, чтобы проверить значения завершения внутри testuite для моего инструмента?

Ответ 1

Предположим, что у вас есть bash -комплекс script в файле с именем asdf-completion, содержащий:

_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 man page), тогда мы получим тот же результат, который представляет собой размещение потенциальных разложений в переменную COMPREPLY. Вот пример этого в unittest:

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 является хорошим для более полного теста.

Ответ 2

решение для бонсайдинга почти сработало для меня. Мне пришлось изменить строку bash script. Я добавил дополнительный ';' разделитель к выполненному bash script, иначе выполнение не будет работать в Mac OS X. Не совсем уверен, почему.

Я также обобщил инициализацию различных аргументов COMP_, чтобы обработать различные случаи, в которых я закончил.

Окончательное решение является вспомогательным классом для проверки завершения bash с python, чтобы вышеупомянутый тест был записан как:

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()

Завершение lib находится под https://github.com/lacostej/unity3d-bash-completion/blob/master/lib/completion.py