Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Identify incorrect subcommand after a correct one #2024

Merged
merged 1 commit into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 36 additions & 9 deletions tests/core/docs/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,51 @@ rlJournalStart
rlPhaseEnd

rlPhaseStartTest "version"
rlRun "tmt --version | tee output" 0 "Check version"
rlAssertGrep "tmt version:" "output"
rlRun -s "tmt --version" 0 "Check version"
rlAssertGrep "tmt version:" "$rlRun_LOG"
rlPhaseEnd

rlPhaseStartTest "help"
rlRun "tmt --help | tee help" 0 "Run help"
rlAssertGrep "Test Management Tool" "help"
# Note tmt has different levels of '--help', and L1 > L2 > L3 > L4
#
# ---- ------ ------ ------ ------
# #ID# #L1 #L2 #L3 #L4
# ---- ------ ------ ------ ------
# 1) tmt --help run --help discover --help --how fmf --help
# 2) tmt run --help discover --help --how fmf --help
# 3) tmt run discover --help --how fmf --help
# 4) tmt run discover --how fmf --help
#
# where
# 1) is the same as tmt --help
# 2) is the same as tmt run --help
# 3) is the same as tmt run discover --help
rlRun -s "tmt --help" 0 "Check tmt --help"
rlAssertGrep "Test Management Tool" "$rlRun_LOG"
rlRun -s 'tmt run --help' 0 "Check tmt run --help"
rlAssertGrep 'Run test steps' "$rlRun_LOG"
rlRun -s 'tmt run discover --help' 0 "Check tmt run discover --help"
rlAssertGrep 'Gather information about test cases to be executed' "$rlRun_LOG"

rlRun -s "tmt --help run --help discover --help --how fmf --help" 0 "Check tmt --help"
rlAssertGrep "Test Management Tool" "$rlRun_LOG"
rlRun -s 'tmt run --help discover --help --how fmf --help' 0 "Check tmt run --help"
rlAssertGrep 'Run test steps' "$rlRun_LOG"
rlRun -s 'tmt run discover --help --how fmf --help' 0 "Check tmt run discover --help"
rlAssertGrep 'Gather information about test cases to be executed' "$rlRun_LOG"
rlRun -s 'tmt run discover --how fmf --help' 0 "Check tmt run discover --how fmf --help"
rlAssertGrep 'Discover available tests from fmf metadata' "$rlRun_LOG"
rlPhaseEnd

rlPhaseStartTest "man"
rlRun "man tmt | tee man" 0 "Check man page"
rlAssertGrep "usage is straightforward" "man"
rlAssertNotGrep "WARNING" "man"
rlRun -s "man tmt" 0 "Check man page"
rlAssertGrep "usage is straightforward" "$rlRun_LOG"
rlAssertNotGrep "WARNING" "$rlRun_LOG"
rlPhaseEnd

rlPhaseStartTest "examples"
rlRun "ls $EXAMPLES | tee examples" 0 "Check examples"
rlAssertGrep "mini" "examples"
rlRun -s "ls $EXAMPLES" 0 "Check examples"
rlAssertGrep "mini" "$rlRun_LOG"
rlPhaseEnd

rlPhaseStartCleanup
Expand Down
9 changes: 4 additions & 5 deletions tests/discover/options.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@ rlJournalStart
rlRun 'set -o pipefail'
rlPhaseEnd

rlPhaseStartTest 'fmf help'
rlRun 'tmt run discover --help --how fmf | tee output'
rlAssertGrep 'Discover available tests from fmf metadata' 'output'
rlPhaseStartTest 'tmt run discover --how=fmf --help'
rlRun -s 'tmt run discover --how fmf --help'
rlAssertGrep 'Discover available tests from fmf metadata' $rlRun_LOG
for option in url ref path test filter fmf-id; do
rlAssertGrep "--$option" output
rlAssertGrep "--$option" "$rlRun_LOG"
done
rlPhaseEnd

rlPhaseStartCleanup
rlRun 'rm -f output' 0 'Removing tmp file'
rlRun 'popd'
rlPhaseEnd
rlJournalEnd
18 changes: 18 additions & 0 deletions tests/usability/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,30 @@ rlJournalStart
rlRun -s "tmt run --rm pl disc provi -h local"
rlRun "grep -A1 discover $rlRun_LOG | grep 'how: fmf'"
rlRun "grep -A1 provision $rlRun_LOG | grep 'how: local'"
rlRun -s "tmt run --rm pl disc provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s "tmt run --rm pl disc --log-topic key-normalization provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s "tmt run --rm pl disc --log-topic=key-normalization provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG

rlRun -s "tmt run --rm pl disc -vvvddd -h local 2>&1" "1-255"
rlAssertGrep "Unsupported discover method 'local'" $rlRun_LOG
rlRun -s "tmt run --rm pl disc -vvvddd provi -h local"
rlRun "grep -A1 discover $rlRun_LOG | grep 'how: fmf'"
rlRun "grep -A1 provision $rlRun_LOG | grep 'how: local'"
rlRun -s "tmt run --rm pl disc -v provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s "tmt run --rm pl disc --verbose provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s "tmt run --rm pl disc -vvvddd provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s \
"tmt run --rm pl disc -vvvddd --log-topic key-normalization provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlRun -s \
"tmt run --rm pl disc -v -d --log-topic=key-normalization provN -h local 2>&1" "1-255"
rlAssertGrep "Invalid subcommand of 'run'" $rlRun_LOG
rlPhaseEnd

rlPhaseStartCleanup
Expand Down
103 changes: 84 additions & 19 deletions tmt/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,25 +298,90 @@ def _check_method(self, context: 'tmt.cli.Context', args: List[str]) -> None:
subcommands = (
tmt.steps.STEPS + tmt.steps.ACTIONS + ['tests', 'plans'])

for index, arg in enumerate(args):
# Handle '--how method' or '-h method'
if arg in ['--how', '-h']:
try:
how = args[index + 1]
except IndexError:
pass
break
# Handle '--how=method'
elif arg.startswith('--how='):
how = re.sub('^--how=', '', arg)
break
# Handle '-hmethod'
elif arg.startswith('-h'):
how = re.sub('^-h ?', '', arg)
break
# Stop search at the first argument looking like a subcommand
elif is_likely_subcommand(arg, subcommands):
break
def _find_option_by_arg(arg: str) -> Optional[click.Parameter]:
for option in self.params:
if arg in option.opts or arg in option.secondary_opts:
return option
return None

def _find_how(args: List[str]) -> Optional[str]:
while args:
arg = args.pop(0)

# Handle '--how method' or '-h method'
if arg in ['--how', '-h']:
# Found `-h/--how foo`, next argument is how'
return args.pop(0)

# Handle '--how=method'
if arg.startswith('--how='):
return re.sub('^--how=', '', arg)

# Handle '-hmethod'
if arg.startswith('-h'):
return re.sub('^-h ?', '', arg)

# Handle anything that looks like an option
if arg.startswith('-'):
# Is it a --foo or --foo=bar?
match = re.match(r'(--[a-z\-]+)(=.*)?', arg)
if match:
if match.group(2):
# Found option like '--foo=bar'
continue
else:
# Or is it a -f?
match = re.match(r'(-[a-z])', arg)
if match is None:
# Found unexpected option format
return None
option_name: str = match.group(1)
option = _find_option_by_arg(option_name)
if option is None:
# Unknown option? Probably remain silent, Click should report it in.
return None

# Options, unlike arguments, may not consume any additional arguments
if isinstance(option, click.core.Option):
if option.is_flag:
# Found a flag
continue
if option.count:
# Found options like '-ddddd'
continue

# Consume all remaining arguments. Think `ls /foo /bar ...`, it's not
# possible to tell which of these is an actual argument or misspelled
# subcommand name.
if option.nargs == -1:
# Found option consuming all arguments
return None
if option.nargs == 0:
# Found option with no arguments
continue

# Consume the given number of arguments
for _ in range(option.nargs):
args.pop(0)

continue

if is_likely_subcommand(arg, subcommands):
# Found a subcommand
return None

# We're left with a string that does not start with `-`, and which has not
# been claimed by an option. It is highly likely this is a misspelled
# subcommand name.
raise tmt.utils.SpecificationError(
f"Invalid subcommand of 'run' found: '{arg}'.")

return None

try:
how = _find_how(args[:])
except IndexError:
pass

# Find method with the first matching prefix
if how is not None:
Expand Down
Loading