Testing Bash completions

If you've ever wondered why SDKMAN! rarely breaks, the answer is simple: Loads and loads of tests!

Almost every single line of https://sdkman.io/ is covered by tests, often with varying inputs to account for some edge case.

But there has always been a stain on SDKMAN!'s shiny, test-plated armor: Its Bash completions. Because they are only tested manually, they regularly break, much to the regret of our users and of course us, the maintainers.

So after another breakage I've decided to roll up my sleeves and started writing some automated tests.

But how to test Bash completions?

To help you in creating those completions, Bash provides some predefined variables, namely COMP_WORDS, an array which contains the words on the command line, and COMP_CWORD, which gives you the index of the current word.

These variables are normally filled by Bash's completion facility but can also be set manually before calling the completion function.

So in order to test the completions for the sdk command, you can do something like this

COMP_WORDS=(sdk); COMP_CWORD=1; _sdk

where COMP_WORDS contains sdk (the words on the command line) and COMP_CWORD the index of the current word (here 1 because we are completing the word after sdk). _sdk is the shell function for generating the completions and looks similar to this

_sdk() {
    local -r current_word="${COMP_WORDS[$COMP_CWORD]}"

    # the logic for generating the list of completion candidates

    COMPREPLY=($(compgen -W "${candidates[*]}" -- "$current_word"))
}

After running the _sdk function, COMPREPLY will contain the list of all possible completions, which you can assert on

[[ ${COMPREPLY[*]} == 'install uninstall list use config default home env current upgrade version broadcast help offline selfupdate update flush' ]]

And that's it! To test other completions just modify COMP_WORDS and COMP_CWORD accordingly

COMP_WORDS=(sdk install); COMP_CWORD=2; _sdk

TLDR;

COMP_WORDS=(sdk); COMP_CWORD=1; _sdk
[[ ${COMPREPLY[*]} == 'install uninstall list use config default home env current upgrade version broadcast help offline selfupdate update flush' ]]