Skip to content

Commit

Permalink
Use "normal" match over embedded matches in case of conflicts.
Browse files Browse the repository at this point in the history
Matches not containing embedded args are considered exact and thus
they win over matches with embedded args. Searching for keywords from
a single file has always worked like that. This change makes the
behavior consistent if matches are from different files.

This is part of #4454.
  • Loading branch information
pekkaklarck committed Sep 15, 2022
1 parent 7288cdd commit 48aea61
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 15 deletions.
5 changes: 4 additions & 1 deletion atest/robot/keywords/embedded_arguments_conflicts.robot
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,8 @@ Public match wins over better private match in different resource
Match in same resource wins over better match elsewhere
Check Test Case ${TESTNAME}

Keyword without embedded arguments wins over keyword with them
Keyword without embedded arguments wins over keyword with them in same file
Check Test Case ${TESTNAME}

Keyword without embedded arguments wins over keyword with them in different file
Check Test Case ${TESTNAME}
29 changes: 25 additions & 4 deletions atest/testdata/keywords/embedded_arguments_conflicts.robot
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ Resource embedded_arguments_conflicts/resource.resource
Resource embedded_arguments_conflicts/resource2.resource
Library embedded_arguments_conflicts/library.py
Library embedded_arguments_conflicts/library2.py
Suite Setup Set library search order resource2 library2

*** Variables ***
${INDENT} ${SPACE * 4}
Expand Down Expand Up @@ -88,30 +87,42 @@ Conflict in library with explicit usage
library.y in library

Search order resolves conflict with resources
[Setup] Enable search order
Match in both resources
[Teardown] Disable search order

Best match in resource wins over search order
[Setup] Enable search order
Best match in one of resources
[Teardown] Disable search order

Search order resolves conflict with libraries
[Setup] Enable search order
Match in both libraries
[Teardown] Disable search order

Best match in library wins over search order
[Setup] Enable search order
Best match in one of libraries
[Teardown] Disable search order

Search order cannot resolve conflict within resource
[Documentation] FAIL
... Multiple keywords matching name 'Unresolvable conflict in resource' found:
... ${INDENT}resource2.\${possible} conflict in resource
... ${INDENT}resource2.Unresolvable \${conflict} in resource
[Setup] Enable search order
Unresolvable conflict in resource
[Teardown] Disable search order

Search order cannot resolve conflict within library
[Documentation] FAIL
... Multiple keywords matching name 'Unresolvable conflict in library' found:
... ${INDENT}library2.\${possible} conflict in library
... ${INDENT}library2.Unresolvable \${conflict} in library
[Setup] Enable search order
Unresolvable conflict in library
[Teardown] Disable search order

Public match wins over better private match in different resource
[Documentation] and better match wins when both are in same file
Expand All @@ -121,10 +132,14 @@ Match in same resource wins over better match elsewhere
[Documentation] even if match in same file would be private
Match in same resource wins over better match elsewhere

Keyword without embedded arguments wins over keyword with them
Keyword without embedded arguments wins over keyword with them in same file
Match with and without embedded arguments
Match with embedded arguments

Keyword without embedded arguments wins over keyword with them in different file
Match with and without embedded arguments in different files
Match with embedded arguments in different files

*** Keywords ***
Execute "${command}"
Should be equal ${command} robot
Expand All @@ -145,5 +160,11 @@ Robot ${x}
Match with and without embedded arguments
No Operation

Match ${with} embedded arguments
Should be equal ${with} with
Match ${with and without} embedded arguments
Should be equal ${with and without} with

Enable search order
Set library search order resource2 library2

Disable search order
Set library search order
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ Match in same resource wins over better match elsewhere
Another match ${in both resource files}
[Tags] robot:private
Should be equal ${in both resource files} in both resource files

Match with and without embedded arguments in different files
No operation
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ Better ${private} match

Another ${match} in both resource files
Fail Better match but should not be run due to being in different file

Match ${with and without} embedded arguments in different files
Should be equal ${with and without} with
23 changes: 13 additions & 10 deletions src/robot/running/namespace.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ def _get_runner_from_suite_file(self, name):
return None
handlers = self.user_keywords.handlers.get_handlers(name)
if len(handlers) > 1:
handlers = self._select_best_embedded_match(handlers)
handlers = self._select_best_match(handlers)
if len(handlers) > 1:
self._raise_multiple_keywords_found(handlers, name)
runner = handlers[0].create_runner(name, self.languages)
Expand All @@ -336,15 +336,18 @@ def _get_runner_from_suite_file(self, name):
runner.pre_run_messages += Message(message, level='WARN'),
return runner

def _select_best_embedded_match(self, handlers):
if all(hand.supports_embedded_args for hand in handlers):
for hand in handlers:
if self._is_best_embedded_match(hand, handlers):
return [hand]
def _select_best_match(self, handlers):
# "Normal" match is considered exact and wins over embedded matches.
normal = [hand for hand in handlers if not hand.supports_embedded_args]
if normal:
return normal if len(normal) == 1 else handlers
for hand in handlers:
if self._is_best_embedded_match(hand, handlers):
return [hand]
return handlers

def _is_best_embedded_match(self, candidate, alternatives):
# Match is considered better than another match if it doesn't match
# Embedded match is considered better than another if it doesn't match
# the other but the other matches it.
for other in alternatives:
if candidate is other:
Expand All @@ -367,7 +370,7 @@ def _get_runner_from_resource_files(self, name):
if len(handlers) > 1:
handlers = self._prioritize_same_file_or_public(handlers)
if len(handlers) > 1:
handlers = self._select_best_embedded_match(handlers)
handlers = self._select_best_match(handlers)
if len(handlers) > 1:
handlers = self._filter_based_on_search_order(handlers)
if len(handlers) != 1:
Expand All @@ -381,7 +384,7 @@ def _get_runner_from_libraries(self, name):
return None
pre_run_message = None
if len(handlers) > 1:
handlers = self._select_best_embedded_match(handlers)
handlers = self._select_best_match(handlers)
if len(handlers) > 1:
handlers, pre_run_message = self._filter_stdlib_handler(handlers)
if len(handlers) > 1:
Expand Down Expand Up @@ -451,7 +454,7 @@ def _get_explicit_runner(self, name):
handler, kw_name = handlers_and_names[0]
else:
handlers = [h for h, n in handlers_and_names]
matches = self._select_best_embedded_match(handlers)
matches = self._select_best_match(handlers)
if len(matches) > 1:
self._raise_multiple_keywords_found(handlers, name, implicit=False)
handler, kw_name = handlers_and_names[handlers.index(matches[0])]
Expand Down

0 comments on commit 48aea61

Please sign in to comment.