@@ -63,7 +63,7 @@ class WrongCaseInKeywordNameRule(Rule):
6363 Keyword name does not follow case convention.
6464
6565 Keyword names need to follow a specific case convention.
66- The convention can be set using `` convention`` parameter and accepts
66+ The convention can be set using the `` convention `` parameter and accepts
6767 one of the 2 values: ``each_word_capitalized`` or ``first_word_capitalized``.
6868
6969 By default, it's configured to ``each_word_capitalized``, which requires each keyword to follow such
@@ -76,7 +76,7 @@ class WrongCaseInKeywordNameRule(Rule):
7676 Click 'Next' Button
7777 [Teardown] Log Form Data
7878
79- You can also set it to ``first_word_capitalized`` which requires first word to have first letter capital :
79+ You can also set it to ``first_word_capitalized`` which requires capitalising the first word of the keyword :
8080
8181 *** Keywords ***
8282 Fill out the form
@@ -89,10 +89,12 @@ class WrongCaseInKeywordNameRule(Rule):
8989 that are accepted in the keyword name, even though they violate the case convention.
9090
9191 ``pattern`` parameter accepts a regex pattern. For example, configuring it to ``robocop\.readthedocs\.io``
92- would make such keyword legal:
92+ would make the following keyword legal:
9393
9494 Go To robocop.readthedocs.io Page
9595
96+ See the sibling rule [wrong-case-in-keyword-call](#wrong-case-in-keyword-call) that checks keyword call
97+ naming convention.
9698 """
9799
98100 name = "wrong-case-in-keyword-name"
@@ -563,6 +565,70 @@ class MixedTaskTestSettingsRule(Rule):
563565 deprecated_names = ("0326" ,)
564566
565567
568+ class WrongCaseInKeywordCallRule (Rule ):
569+ r"""
570+ Keyword call name does not follow case convention.
571+
572+ Keyword names need to follow a specific case convention.
573+ The convention can be set using the `` convention `` parameter and accepts
574+ one of the 2 values: ``each_word_capitalized`` or ``first_word_capitalized``.
575+
576+ By default, it's configured to ``each_word_capitalized``, which requires each keyword to follow such
577+ convention:
578+
579+ *** Keywords ***
580+ Fill out the form
581+ Provide Shipping Address
582+ Provide Payment Method
583+ Click 'Next' Button
584+ [Teardown] Log Form Data
585+
586+ You can also set it to ``first_word_capitalized`` which requires capitalising the first word of the keyword:
587+
588+ *** Keywords ***
589+ Fill out the form
590+ Provide shipping address
591+ Provide payment method
592+ Click 'Next' button
593+ [Teardown] Log form data
594+
595+ The rule also accepts another parameter ``pattern`` which can be used to configure words
596+ that are accepted in the keyword name, even though they violate the case convention.
597+
598+ ``pattern`` parameter accepts a regex pattern. For example, configuring it to ``robocop\.readthedocs\.io``
599+ would make the following keyword legal:
600+
601+ Go To robocop.readthedocs.io Page
602+
603+ See the sibling rule [wrong-case-in-keyword-name](#wrong-case-in-keyword-name) that checks keyword definition
604+ naming convention.
605+ """
606+
607+ name = "wrong-case-in-keyword-call"
608+ rule_id = "NAME18"
609+ message = "Keyword name '{keyword_name}' does not follow case convention"
610+ severity = RuleSeverity .WARNING
611+ parameters = [
612+ RuleParam (
613+ name = "convention" ,
614+ default = "each_word_capitalized" ,
615+ converter = str ,
616+ desc = "possible values: 'each_word_capitalized' (default) or 'first_word_capitalized'" ,
617+ ),
618+ RuleParam (
619+ name = "pattern" ,
620+ default = re .compile (r"" ),
621+ converter = utils .pattern_type ,
622+ show_type = "regex" ,
623+ desc = "pattern for accepted words in keyword" ,
624+ ),
625+ ]
626+ added_in_version = "7.0.0"
627+ sonar_qube_attrs = sonar_qube .SonarQubeAttributes (
628+ clean_code = sonar_qube .CleanCodeAttribute .IDENTIFIABLE , issue_type = sonar_qube .SonarQubeIssueType .CODE_SMELL
629+ )
630+
631+
566632SET_VARIABLE_VARIANTS = {
567633 "settaskvariable" ,
568634 "settestvariable" ,
@@ -647,6 +713,7 @@ class KeywordNamingChecker(VisitorChecker):
647713 """Checker for keyword naming violations."""
648714
649715 wrong_case_in_keyword_name : WrongCaseInKeywordNameRule
716+ wrong_case_in_keyword_call : WrongCaseInKeywordCallRule
650717 keyword_name_is_reserved_word : KeywordNameIsReservedWordRule
651718 underscore_in_keyword_name : UnderscoreInKeywordNameRule
652719 else_not_upper_case : ElseNotUpperCaseRule
@@ -697,7 +764,7 @@ def visit_Keyword(self, node) -> None: # noqa: N802
697764 if not node .name :
698765 self .report (self .keyword_name_is_empty , node = node )
699766 else :
700- self .check_keyword_naming (node .name , node )
767+ self .check_keyword_naming (node .name , node , is_keyword_definition = True )
701768 self .generic_visit (node )
702769
703770 def visit_KeywordCall (self , node ) -> None : # noqa: N802
@@ -713,15 +780,19 @@ def visit_If(self, node) -> None: # noqa: N802
713780 self .generic_visit (node )
714781 self .inside_if_block = False
715782
716- def check_keyword_naming (self , keyword_name , node ) -> None :
783+ def check_keyword_naming (self , keyword_name , node , is_keyword_definition : bool = False ) -> None :
717784 if not keyword_name or keyword_name .lstrip ().startswith ("#" ):
718785 return
719786 if keyword_name == r"/" : # old for loop, / are interpreted as keywords
720787 return
721788 if self .check_if_keyword_is_reserved (keyword_name , node ):
722789 return
790+ if is_keyword_definition :
791+ case_naming_rule = self .wrong_case_in_keyword_name
792+ else :
793+ case_naming_rule = self .wrong_case_in_keyword_call
723794 normalized = utils .remove_robot_vars (keyword_name )
724- normalized = self . wrong_case_in_keyword_name .pattern .sub ("" , normalized )
795+ normalized = case_naming_rule .pattern .sub ("" , normalized )
725796 normalized = normalized .split ("." )[- 1 ] # remove any imports ie ExternalLib.SubLib.Log -> Log
726797 normalized = normalized .replace ("'" , "" ) # replace ' apostrophes
727798 if "_" in normalized :
@@ -733,11 +804,11 @@ def check_keyword_naming(self, keyword_name, node) -> None:
733804 end_col = node .col_offset + len (keyword_name .rstrip ()) + 1 ,
734805 )
735806 words = self .letter_pattern .sub (" " , normalized ).split (" " )
736- if self . wrong_case_in_keyword_name .convention == "first_word_capitalized" :
807+ if case_naming_rule .convention == "first_word_capitalized" :
737808 words = words [:1 ]
738809 if any (word [0 ].islower () for word in words if word ):
739810 self .report (
740- self . wrong_case_in_keyword_name ,
811+ case_naming_rule ,
741812 keyword_name = keyword_name ,
742813 node = node ,
743814 col = node .col_offset + 1 ,
0 commit comments