diff options
author | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2019-01-11 16:09:33 -0500 |
---|---|---|
committer | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2019-01-16 18:35:21 -0500 |
commit | 5ea2f59d64ed0b5bf521c925247ffc90175be711 (patch) | |
tree | 948f0767a9c54b71583df3364b42cd8bc07d1c66 /tests/frontend/completions.py | |
parent | 5e9598c51e2bf6bc0a5448ad69ea4757e9459c5e (diff) | |
download | buildstream-5ea2f59d64ed0b5bf521c925247ffc90175be711.tar.gz |
tests: Migrate completions test to tests/frontend
Diffstat (limited to 'tests/frontend/completions.py')
-rw-r--r-- | tests/frontend/completions.py | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/tests/frontend/completions.py b/tests/frontend/completions.py new file mode 100644 index 000000000..0e4c6ad7e --- /dev/null +++ b/tests/frontend/completions.py @@ -0,0 +1,327 @@ +import os +import pytest +from tests.testutils import cli + +# Project directory +DATA_DIR = os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'completions' +) + +MAIN_COMMANDS = [ + 'artifact ', + 'build ', + 'checkout ', + 'help ', + 'init ', + 'pull ', + 'push ', + 'shell ', + 'show ', + 'source ', + 'workspace ' +] + +MAIN_OPTIONS = [ + "--builders ", + "-c ", + "-C ", + "--colors ", + "--config ", + "--debug ", + "--default-mirror ", + "--directory ", + "--error-lines ", + "--fetchers ", + "--log-file ", + "--message-lines ", + "--network-retries ", + "--no-colors ", + "--no-debug ", + "--no-interactive ", + "--no-strict ", + "--no-verbose ", + "-o ", + "--option ", + "--on-error ", + "--pull-buildtrees ", + "--pushers ", + "--strict ", + "--verbose ", + "--version ", +] + +SOURCE_COMMANDS = [ + 'checkout ', + 'fetch ', + 'track ', +] + +WORKSPACE_COMMANDS = [ + 'close ', + 'list ', + 'open ', + 'reset ' +] + +PROJECT_ELEMENTS = [ + "compose-all.bst", + "compose-exclude-dev.bst", + "compose-include-bin.bst", + "import-bin.bst", + "import-dev.bst", + "target.bst" +] + +INVALID_ELEMENTS = [ + "target.foo" + "target.bst.bar" +] + +MIXED_ELEMENTS = PROJECT_ELEMENTS + INVALID_ELEMENTS + + +def assert_completion(cli, cmd, word_idx, expected, cwd=None): + result = cli.run(cwd=cwd, env={ + '_BST_COMPLETION': 'complete', + 'COMP_WORDS': cmd, + 'COMP_CWORD': str(word_idx) + }) + words = [] + if result.output: + words = result.output.splitlines() + + # The order is meaningless, bash will + # take the results and order it by its + # own little heuristics + words = sorted(words) + expected = sorted(expected) + assert words == expected + + +def assert_completion_failed(cli, cmd, word_idx, expected, cwd=None): + result = cli.run(cwd=cwd, env={ + '_BST_COMPLETION': 'complete', + 'COMP_WORDS': cmd, + 'COMP_CWORD': str(word_idx) + }) + words = [] + if result.output: + words = result.output.splitlines() + + # The order is meaningless, bash will + # take the results and order it by its + # own little heuristics + words = sorted(words) + expected = sorted(expected) + assert words != expected + + +@pytest.mark.parametrize("cmd,word_idx,expected", [ + ('bst', 0, []), + ('bst ', 1, MAIN_COMMANDS), + ('bst pu', 1, ['pull ', 'push ']), + ('bst pul', 1, ['pull ']), + ('bst source ', 2, SOURCE_COMMANDS), + ('bst w ', 1, ['workspace ']), + ('bst workspace ', 2, WORKSPACE_COMMANDS), +]) +def test_commands(cli, cmd, word_idx, expected): + assert_completion(cli, cmd, word_idx, expected) + + +@pytest.mark.parametrize("cmd,word_idx,expected", [ + ('bst -', 1, MAIN_OPTIONS), + ('bst --l', 1, ['--log-file ']), + + # Test that options of subcommands also complete + ('bst --no-colors build -', 3, ['--all ', '--track ', '--track-all ', + '--track-except ', + '--track-cross-junctions ', '-J ', + '--track-save ']), + + # Test the behavior of completing after an option that has a + # parameter that cannot be completed, vs an option that has + # no parameter + ('bst --fetchers ', 2, []), + ('bst --no-colors ', 2, MAIN_COMMANDS), +]) +def test_options(cli, cmd, word_idx, expected): + assert_completion(cli, cmd, word_idx, expected) + + +@pytest.mark.parametrize("cmd,word_idx,expected", [ + ('bst --on-error ', 2, ['continue ', 'quit ', 'terminate ']), + ('bst show --deps ', 3, ['all ', 'build ', 'none ', 'plan ', 'run ']), + ('bst show --deps=', 2, ['all ', 'build ', 'none ', 'plan ', 'run ']), + ('bst show --deps b', 3, ['build ']), + ('bst show --deps=b', 2, ['build ']), + ('bst show --deps r', 3, ['run ']), + ('bst track --deps ', 3, ['all ', 'none ']), +]) +def test_option_choice(cli, cmd, word_idx, expected): + assert_completion(cli, cmd, word_idx, expected) + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, 'project')) +@pytest.mark.parametrize("cmd,word_idx,expected,subdir", [ + # Note that elements/ and files/ are partial completions and + # as such do not come with trailing whitespace + ('bst --config ', 2, ['cache/', 'elements/', 'files/', 'project.conf '], None), + ('bst --log-file ', 2, ['cache/', 'elements/', 'files/', 'project.conf '], None), + ('bst --config f', 2, ['files/'], None), + ('bst --log-file f', 2, ['files/'], None), + ('bst --config files', 2, ['files/bin-files/', 'files/dev-files/'], None), + ('bst --log-file files', 2, ['files/bin-files/', 'files/dev-files/'], None), + ('bst --config files/', 2, ['files/bin-files/', 'files/dev-files/'], None), + ('bst --log-file elements/', 2, [os.path.join('elements', e) + ' ' for e in PROJECT_ELEMENTS], None), + ('bst --config ../', 2, ['../cache/', '../elements/', '../files/', '../project.conf '], 'files'), + ('bst --config ../elements/', 2, [os.path.join('..', 'elements', e) + ' ' for e in PROJECT_ELEMENTS], 'files'), + ('bst --config ../nofile', 2, [], 'files'), + ('bst --config /pony/rainbow/nobodyhas/this/file', 2, [], 'files'), +]) +def test_option_file(datafiles, cli, cmd, word_idx, expected, subdir): + cwd = str(datafiles) + if subdir: + cwd = os.path.join(cwd, subdir) + assert_completion(cli, cmd, word_idx, expected, cwd=cwd) + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, 'project')) +@pytest.mark.parametrize("cmd,word_idx,expected,subdir", [ + # Note that regular files like project.conf are not returned when + # completing for a directory + ('bst --directory ', 2, ['cache/', 'elements/', 'files/'], None), + ('bst --directory elements/', 2, [], None), + ('bst --directory ', 2, ['dev-files/', 'bin-files/'], 'files'), + ('bst --directory ../', 2, ['../cache/', '../elements/', '../files/'], 'files'), +]) +def test_option_directory(datafiles, cli, cmd, word_idx, expected, subdir): + cwd = str(datafiles) + if subdir: + cwd = os.path.join(cwd, subdir) + assert_completion(cli, cmd, word_idx, expected, cwd=cwd) + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("project,cmd,word_idx,expected,subdir", [ + # When running in the project directory + ('project', 'bst show ', 2, [e + ' ' for e in PROJECT_ELEMENTS], None), + ('project', 'bst build com', 2, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], None), + + # When running from the files subdir + ('project', 'bst show ', 2, [e + ' ' for e in PROJECT_ELEMENTS], 'files'), + ('project', 'bst build com', 2, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], 'files'), + + # When passing the project directory + ('project', 'bst --directory ../ show ', 4, [e + ' ' for e in PROJECT_ELEMENTS], 'files'), + ('project', 'bst --directory ../ build com', 4, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], 'files'), + + # Also try multi arguments together + ('project', 'bst --directory ../ checkout t ', 4, ['target.bst '], 'files'), + ('project', 'bst --directory ../ checkout target.bst ', 5, ['bin-files/', 'dev-files/'], 'files'), + + # When running in the project directory + ('no-element-path', 'bst show ', 2, + [e + ' ' for e in PROJECT_ELEMENTS] + ['files/'], None), + ('no-element-path', 'bst build com', 2, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], None), + + # When running from the files subdir + ('no-element-path', 'bst show ', 2, + [e + ' ' for e in PROJECT_ELEMENTS] + ['files/'], 'files'), + ('no-element-path', 'bst build com', 2, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], 'files'), + + # When passing the project directory + ('no-element-path', 'bst --directory ../ show ', 4, + [e + ' ' for e in PROJECT_ELEMENTS] + ['files/'], 'files'), + ('no-element-path', 'bst --directory ../ show f', 4, ['files/'], 'files'), + ('no-element-path', 'bst --directory ../ show files/', 4, ['files/bin-files/', 'files/dev-files/'], 'files'), + ('no-element-path', 'bst --directory ../ build com', 4, + ['compose-all.bst ', 'compose-include-bin.bst ', 'compose-exclude-dev.bst '], 'files'), + + # Also try multi arguments together + ('no-element-path', 'bst --directory ../ checkout t ', 4, ['target.bst '], 'files'), + ('no-element-path', 'bst --directory ../ checkout target.bst ', 5, ['bin-files/', 'dev-files/'], 'files'), + + # When element-path have sub-folders + ('sub-folders', 'bst show base', 2, ['base/wanted.bst '], None), + ('sub-folders', 'bst show base/', 2, ['base/wanted.bst '], None), +]) +def test_argument_element(datafiles, cli, project, cmd, word_idx, expected, subdir): + cwd = os.path.join(str(datafiles), project) + if subdir: + cwd = os.path.join(cwd, subdir) + assert_completion(cli, cmd, word_idx, expected, cwd=cwd) + + +@pytest.mark.datafiles(DATA_DIR) +@pytest.mark.parametrize("project,cmd,word_idx,expected,subdir", [ + + # When element has invalid suffix + ('project', 'bst --directory ../ show ', 4, [e + ' ' for e in MIXED_ELEMENTS], 'files') +]) +def test_argument_element_invalid(datafiles, cli, project, cmd, word_idx, expected, subdir): + cwd = os.path.join(str(datafiles), project) + if subdir: + cwd = os.path.join(cwd, subdir) + assert_completion_failed(cli, cmd, word_idx, expected, cwd=cwd) + + +@pytest.mark.parametrize("cmd,word_idx,expected", [ + ('bst he', 1, ['help ']), + ('bst help ', 2, MAIN_COMMANDS), + ('bst help in', 2, ['init ']), + ('bst help p', 2, ['pull ', 'push ']), + ('bst help p', 2, ['pull ', 'push ']), + ('bst help source ', 3, SOURCE_COMMANDS), + ('bst help w', 2, ['workspace ']), + ('bst help workspace ', 3, WORKSPACE_COMMANDS), +]) +def test_help_commands(cli, cmd, word_idx, expected): + assert_completion(cli, cmd, word_idx, expected) + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, 'project')) +def test_argument_artifact(cli, tmpdir, datafiles): + project = os.path.join(datafiles.dirname, datafiles.basename) + + # Build an import element with no dependencies (as there will only be ONE cache key) + result = cli.run(project=project, args=['build', 'import-bin.bst']) # Has no dependencies + result.assert_success() + + # Get the key and the artifact ref ($project/$element_name/$key) + key = cli.get_element_key(project, 'import-bin.bst') + artifact = os.path.join('test', 'import-bin', key) + + # Test autocompletion of the artifact + cmds = [ + 'bst artifact log ', + 'bst artifact log t', + 'bst artifact log test/' + ] + + for i, cmd in enumerate(cmds): + word_idx = 3 + result = cli.run(project=project, cwd=project, env={ + '_BST_COMPLETION': 'complete', + 'COMP_WORDS': cmd, + 'COMP_CWORD': str(word_idx) + }) + words = [] + if result.output: + words = result.output.splitlines() # This leaves an extra space on each e.g. ['foo.bst '] + words = [word.strip() for word in words] + + if i == 0: + expected = PROJECT_ELEMENTS + [artifact] # We should now be able to see the artifact + elif i == 1: + expected = ['target.bst', artifact] + elif i == 2: + expected = [artifact] + + assert expected == words |