Repository: MarketSquare/robotframework-robocop
Pull request #1276 (2025-03-02 17:32:17)

Add tests for extended view for tags rules


Patch:
diff --git a/src/robocop/linter/rules/tags.py b/src/robocop/linter/rules/tags.py
index 8a1124a..b21107c 100644
--- a/src/robocop/linter/rules/tags.py
+++ b/src/robocop/linter/rules/tags.py
@@ -117,6 +117,7 @@ class CouldBeTestTagsRule(Rule):
     name = "could-be-test-tags"
     rule_id = "TAG05"
     message = "All tests in suite share these tags: '{tags}'"
+    file_wide_rule = True
     severity = RuleSeverity.INFO
     added_in_version = "1.0.0"
 
@@ -238,6 +239,7 @@ class CouldBeKeywordTagsRule(Rule):
     name = "could-be-keyword-tags"
     rule_id = "TAG10"
     message = "All keywords in suite share these tags: '{tags}'"
+    file_wide_rule = True
     severity = RuleSeverity.INFO
     version = ">=6"
     added_in_version = "3.3.0"
@@ -379,7 +381,7 @@ class TagNameChecker(VisitorChecker):
                 node=node,
                 lineno=tag_token.lineno,
                 col=tag_token.col_offset + 1,
-                end_col=tag_token.end_col_offset,
+                end_col=tag_token.end_col_offset + 1,
             )
 
     def check_tag_substring(self, substring: str, tag: Token, node: type[Node]) -> bool:
@@ -395,7 +397,14 @@ class TagNameChecker(VisitorChecker):
             )
             res = True
         if "OR" in substring or "AND" in substring:
-            self.report(self.tag_with_or_and, tag=tag.value, node=node, lineno=tag.lineno, col=tag.col_offset + 1)
+            self.report(
+                self.tag_with_or_and,
+                tag=tag.value,
+                node=node,
+                lineno=tag.lineno,
+                col=tag.col_offset + 1,
+                end_col=tag.end_col_offset + 1,
+            )
             res = True
         return res
 
@@ -489,6 +498,7 @@ class TagScopeChecker(VisitorChecker):
                 node=node,
                 lineno=tag.lineno,
                 col=tag.col_offset + 1,
+                end_col=tag.end_col_offset + 1,
             )
 
 
@@ -555,4 +565,5 @@ class KeywordTagsChecker(VisitorChecker):
                 node=node,
                 lineno=tag.lineno,
                 col=tag.col_offset + 1,
+                end_col=tag.end_col_offset + 1,
             )


Test patch:
diff --git a/tests/linter/rules/tags/could_be_keyword_tags/expected_extended.txt b/tests/linter/rules/tags/could_be_keyword_tags/expected_extended.txt
new file mode 100644
index 0000000..c95547c
--- /dev/null
+++ b/tests/linter/rules/tags/could_be_keyword_tags/expected_extended.txt
@@ -0,0 +1,2 @@
+keywords_with_tests.robot:1:1 TAG10 All keywords in suite share these tags: 'tag'
+only_keywords.robot:1:1 TAG10 All keywords in suite share these tags: 'tag'
\ No newline at end of file
diff --git a/tests/linter/rules/tags/could_be_keyword_tags/test_rule.py b/tests/linter/rules/tags/could_be_keyword_tags/test_rule.py
index 97c6dc1..82d3f09 100644
--- a/tests/linter/rules/tags/could_be_keyword_tags/test_rule.py
+++ b/tests/linter/rules/tags/could_be_keyword_tags/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(expected_file="expected_output.txt", test_on_version=">=6")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended", test_on_version=">=6")
diff --git a/tests/linter/rules/tags/could_be_test_tags/expected_extended.txt b/tests/linter/rules/tags/could_be_test_tags/expected_extended.txt
new file mode 100644
index 0000000..6d9d0cc
--- /dev/null
+++ b/tests/linter/rules/tags/could_be_test_tags/expected_extended.txt
@@ -0,0 +1,2 @@
+test.robot:1:1 TAG05 All tests in suite share these tags: 'sometag'
+tests_with_keywords.robot:1:1 TAG05 All tests in suite share these tags: 'sometag'
\ No newline at end of file
diff --git a/tests/linter/rules/tags/could_be_test_tags/test_rule.py b/tests/linter/rules/tags/could_be_test_tags/test_rule.py
index 97c6dc1..c0e5433 100644
--- a/tests/linter/rules/tags/could_be_test_tags/test_rule.py
+++ b/tests/linter/rules/tags/could_be_test_tags/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(expected_file="expected_output.txt", test_on_version=">=6")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/tags/duplicated_tags/expected_extended.txt b/tests/linter/rules/tags/duplicated_tags/expected_extended.txt
new file mode 100644
index 0000000..7109ac2
--- /dev/null
+++ b/tests/linter/rules/tags/duplicated_tags/expected_extended.txt
@@ -0,0 +1,50 @@
+test.robot:3:30 TAG09 Multiple tags with name 'Tag' (first occurrence at line 3 column 15)
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Default Tags  tag  othertag  Tag
+   |                              ^^^ TAG09
+ 4 | Force Tags  t ag  tag  sometag
+   |
+
+test.robot:4:19 TAG09 Multiple tags with name 'tag' (first occurrence at line 4 column 13)
+   |
+ 2 | Documentation  doc
+ 3 | Default Tags  tag  othertag  Tag
+ 4 | Force Tags  t ag  tag  sometag
+   |                   ^^^ TAG09
+   |
+
+test.robot:8:27 TAG09 Multiple tags with name 'TAG' (first occurrence at line 8 column 22)
+   |
+ 6 | *** Test Cases ***
+ 7 | Test With Tags
+ 8 |     [Tags]    dummy  tag  TAG
+   |                           ^^^ TAG09
+ 9 |     Log    2
+   |
+
+test.robot:21:31 TAG09 Multiple tags with name 'taG' (first occurrence at line 21 column 15)
+    |
+ 19 |
+ 20 | Keyword With Tags
+ 21 |     [Tags]    tag  sometag    taG   t-ag
+    |                               ^^^ TAG09
+    |
+
+test.robot:24:45 TAG09 Multiple tags with name 'tag' (first occurrence at line 24 column 29)
+    |
+ 22 |
+ 23 | Keyword With Tags In Documentation
+ 24 |     [Documentation]  Tags:  tag,  sometag,  tag,  t ag
+    |                                             ^^^ TAG09
+    |
+
+test.robot:24:51 TAG09 Multiple tags with name 't ag' (first occurrence at line 24 column 29)
+    |
+ 22 |
+ 23 | Keyword With Tags In Documentation
+ 24 |     [Documentation]  Tags:  tag,  sometag,  tag,  t ag
+    |                                                   ^^^^ TAG09
+    |
+
diff --git a/tests/linter/rules/tags/duplicated_tags/test_rule.py b/tests/linter/rules/tags/duplicated_tags/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/tags/duplicated_tags/test_rule.py
+++ b/tests/linter/rules/tags/duplicated_tags/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output.txt")
+
+    def test_extended(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/tags/empty_tags/expected_extended.txt b/tests/linter/rules/tags/empty_tags/expected_extended.txt
new file mode 100644
index 0000000..a722af6
--- /dev/null
+++ b/tests/linter/rules/tags/empty_tags/expected_extended.txt
@@ -0,0 +1,19 @@
+default_and_empty_tags.robot:8:5 TAG08 [Tags] setting without values. Consider using NONE if you want to overwrite the Default Tags
+   |
+ 6 | Test
+ 7 |     [Documentation]  doc
+ 8 |     [Tags]
+   |     ^^^^^^ TAG08
+ 9 |     Pass
+10 |     Keyword
+   |
+
+default_and_empty_tags.robot:31:5 TAG08 [Tags] setting without values
+    |
+ 29 |
+ 30 | Keyword With Empty Tags
+ 31 |     [Tags]
+    |     ^^^^^^ TAG08
+ 32 |     No Operation
+    |
+
diff --git a/tests/linter/rules/tags/empty_tags/test_rule.py b/tests/linter/rules/tags/empty_tags/test_rule.py
index d3f86ca..34939e7 100644
--- a/tests/linter/rules/tags/empty_tags/test_rule.py
+++ b/tests/linter/rules/tags/empty_tags/test_rule.py
@@ -4,3 +4,8 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(src_files=["default_and_empty_tags.robot"], expected_file="expected_output.txt")
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=["default_and_empty_tags.robot"], expected_file="expected_extended.txt", output_format="extended"
+        )
diff --git a/tests/linter/rules/tags/tag_already_set_in_keyword_tags/expected_extended.txt b/tests/linter/rules/tags/tag_already_set_in_keyword_tags/expected_extended.txt
new file mode 100644
index 0000000..c03e7c6
--- /dev/null
+++ b/tests/linter/rules/tags/tag_already_set_in_keyword_tags/expected_extended.txt
@@ -0,0 +1,18 @@
+keyword_tags.robot:8:13 TAG11 Tag 'tag' is already set by Keyword Tags in suite settings
+   |
+ 6 | *** Keywords ***
+ 7 | Keyword
+ 8 |     [Tags]  tag
+   |             ^^^ TAG11
+ 9 |     No Operation
+   |
+
+keyword_tags.robot:12:13 TAG11 Tag 'tag' is already set by Keyword Tags in suite settings
+    |
+ 10 |
+ 11 | Keyword 2
+ 12 |     [Tags]  tag   tag2
+    |             ^^^ TAG11
+ 13 |     No Operation
+    |
+
diff --git a/tests/linter/rules/tags/tag_already_set_in_keyword_tags/test_rule.py b/tests/linter/rules/tags/tag_already_set_in_keyword_tags/test_rule.py
index 97c6dc1..82d3f09 100644
--- a/tests/linter/rules/tags/tag_already_set_in_keyword_tags/test_rule.py
+++ b/tests/linter/rules/tags/tag_already_set_in_keyword_tags/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(expected_file="expected_output.txt", test_on_version=">=6")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended", test_on_version=">=6")
diff --git a/tests/linter/rules/tags/tag_already_set_in_test_tags/expected_extended.txt b/tests/linter/rules/tags/tag_already_set_in_test_tags/expected_extended.txt
new file mode 100644
index 0000000..4b5ab4f
--- /dev/null
+++ b/tests/linter/rules/tags/tag_already_set_in_test_tags/expected_extended.txt
@@ -0,0 +1,10 @@
+test.robot:9:13 TAG06 Tag 'sometag' is already set by Force Tags in suite settings
+   |
+ 7 | Test
+ 8 |     [Documentation]  doc
+ 9 |     [Tags]  sometag  anothertag
+   |             ^^^^^^^ TAG06
+10 |     Pass
+11 |     Keyword
+   |
+
diff --git a/tests/linter/rules/tags/tag_already_set_in_test_tags/test_rule.py b/tests/linter/rules/tags/tag_already_set_in_test_tags/test_rule.py
index 5ef0f33..492aaea 100644
--- a/tests/linter/rules/tags/tag_already_set_in_test_tags/test_rule.py
+++ b/tests/linter/rules/tags/tag_already_set_in_test_tags/test_rule.py
@@ -9,3 +9,11 @@ class TestRuleAcceptance(RuleAcceptance):
         self.check_rule(
             src_files=["test_tags.robot"], expected_file="expected_output_test_tags.txt", test_on_version=">=6"
         )
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=6",
+        )
diff --git a/tests/linter/rules/tags/tag_with_or_and/expected_extended.txt b/tests/linter/rules/tags/tag_with_or_and/expected_extended.txt
new file mode 100644
index 0000000..8a64594
--- /dev/null
+++ b/tests/linter/rules/tags/tag_with_or_and/expected_extended.txt
@@ -0,0 +1,47 @@
+test.robot:3:13 TAG02 Tag 'tagORtag2' with reserved word OR/AND
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Force Tags  tagORtag2  tagor
+   |             ^^^^^^^^^ TAG02
+ 4 | Default Tags  tagORtag2  tagor  tag${AND}
+   |
+
+test.robot:4:15 TAG02 Tag 'tagORtag2' with reserved word OR/AND
+   |
+ 2 | Documentation  doc
+ 3 | Force Tags  tagORtag2  tagor
+ 4 | Default Tags  tagORtag2  tagor  tag${AND}
+   |               ^^^^^^^^^ TAG02
+   |
+
+test.robot:10:13 TAG02 Tag 'tagORtag2' with reserved word OR/AND
+    |
+  8 | Test
+  9 |     [Documentation]  doc
+ 10 |     [Tags]  tagORtag2  tagor  tag${OR}  tagOR${var}
+    |             ^^^^^^^^^ TAG02
+ 11 |     Pass
+ 12 |     Keyword
+    |
+
+test.robot:10:41 TAG02 Tag 'tagOR${var}' with reserved word OR/AND
+    |
+  8 | Test
+  9 |     [Documentation]  doc
+ 10 |     [Tags]  tagORtag2  tagor  tag${OR}  tagOR${var}
+    |                                         ^^^^^^^^^^^ TAG02
+ 11 |     Pass
+ 12 |     Keyword
+    |
+
+test.robot:19:29 TAG02 Tag 'tagORtag2' with reserved word OR/AND
+    |
+ 17 | Keyword
+ 18 |     [Documentation]  this is doc
+ 19 |     ...              Tags:  tagORtag2,  tagor, tag${OR}
+    |                             ^^^^^^^^^ TAG02
+ 20 |     No Operation
+ 21 |     Pass
+    |
+
diff --git a/tests/linter/rules/tags/tag_with_or_and/test_rule.py b/tests/linter/rules/tags/tag_with_or_and/test_rule.py
index 363f0cd..cdac1f9 100644
--- a/tests/linter/rules/tags/tag_with_or_and/test_rule.py
+++ b/tests/linter/rules/tags/tag_with_or_and/test_rule.py
@@ -9,3 +9,6 @@ class TestRuleAcceptance(RuleAcceptance):
         self.check_rule(
             src_files=["keyword_tags.robot"], expected_file="expected_output_keyword_tags.txt", test_on_version=">=6"
         )
+
+    def test_extended(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/tags/tag_with_reserved_word/expected_extended.txt b/tests/linter/rules/tags/tag_with_reserved_word/expected_extended.txt
new file mode 100644
index 0000000..f0f06bd
--- /dev/null
+++ b/tests/linter/rules/tags/tag_with_reserved_word/expected_extended.txt
@@ -0,0 +1,18 @@
+test.robot:3:17 TAG03 Tag 'roBot:TEST' prefixed with reserved word `robot:`
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Default Tags    roBot:TEST
+   |                 ^^^^^^^^^^ TAG03
+   |
+
+test.robot:24:84 TAG03 Tag 'robot:my_tag' prefixed with reserved word `robot:`
+    |
+ 22 |
+ 23 | Keyword With Reserved Tags
+ 24 |     [Tags]  tagORtag  tagorand  andsmth  with space or reserved  robot:no-dry-run  robot:my_tag
+    |                                                                                    ^^^^^^^^^^^^ TAG03
+ 25 |     ...     robot:continue-on-failure    robot:recursive-continue-on-failure
+ 26 |     Keyword
+    |
+
diff --git a/tests/linter/rules/tags/tag_with_reserved_word/test_rule.py b/tests/linter/rules/tags/tag_with_reserved_word/test_rule.py
index eb61fad..37afd0b 100644
--- a/tests/linter/rules/tags/tag_with_reserved_word/test_rule.py
+++ b/tests/linter/rules/tags/tag_with_reserved_word/test_rule.py
@@ -7,3 +7,6 @@ class TestRuleAcceptance(RuleAcceptance):
 
     def test_keyword_doc(self):
         self.check_rule(src_files=["keyword_doc.robot"], expected_file="expected_output_keyword_doc.txt")
+
+    def test_extended(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/tags/tag_with_space/expected_extended.txt b/tests/linter/rules/tags/tag_with_space/expected_extended.txt
new file mode 100644
index 0000000..cf907d8
--- /dev/null
+++ b/tests/linter/rules/tags/tag_with_space/expected_extended.txt
@@ -0,0 +1,65 @@
+test.robot:3:15 TAG01 Tag 'with space' contains spaces
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Force Tags    with space
+   |               ^^^^^^^^^^ TAG01
+ 4 | Default Tags  with space    ${var with space}    ${var} space
+   |
+
+test.robot:4:15 TAG01 Tag 'with space' contains spaces
+   |
+ 2 | Documentation  doc
+ 3 | Force Tags    with space
+ 4 | Default Tags  with space    ${var with space}    ${var} space
+   |               ^^^^^^^^^^ TAG01
+   |
+
+test.robot:4:50 TAG01 Tag '${var} space' contains spaces
+   |
+ 2 | Documentation  doc
+ 3 | Force Tags    with space
+ 4 | Default Tags  with space    ${var with space}    ${var} space
+   |                                                  ^^^^^^^^^^^^ TAG01
+   |
+
+test.robot:10:13 TAG01 Tag 'some tag' contains spaces
+    |
+  8 | Test
+  9 |     [Documentation]  doc
+ 10 |     [Tags]  some tag    ${var with space}    ${var} space
+    |             ^^^^^^^^ TAG01
+ 11 |     Pass
+ 12 |     Keyword
+    |
+
+test.robot:10:46 TAG01 Tag '${var} space' contains spaces
+    |
+  8 | Test
+  9 |     [Documentation]  doc
+ 10 |     [Tags]  some tag    ${var with space}    ${var} space
+    |                                              ^^^^^^^^^^^^ TAG01
+ 11 |     Pass
+ 12 |     Keyword
+    |
+
+test.robot:19:27 TAG01 Tag 'space tag' contains spaces
+    |
+ 17 | Keyword
+ 18 |     [Documentation]  this is doc
+ 19 |     ...              Tags: space tag,${var with space}tag, ${var} space
+    |                           ^^^^^^^^^ TAG01
+ 20 |     No Operation
+ 21 |     Pass
+    |
+
+test.robot:19:59 TAG01 Tag '${var} space' contains spaces
+    |
+ 17 | Keyword
+ 18 |     [Documentation]  this is doc
+ 19 |     ...              Tags: space tag,${var with space}tag, ${var} space
+    |                                                           ^^^^^^^^^^^^ TAG01
+ 20 |     No Operation
+ 21 |     Pass
+    |
+
diff --git a/tests/linter/rules/tags/tag_with_space/test_rule.py b/tests/linter/rules/tags/tag_with_space/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/tags/tag_with_space/test_rule.py
+++ b/tests/linter/rules/tags/tag_with_space/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output.txt")
+
+    def test_extended(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/tags/unnecessary_default_tags/expected_extended.txt b/tests/linter/rules/tags/unnecessary_default_tags/expected_extended.txt
new file mode 100644
index 0000000..e2a5e44
--- /dev/null
+++ b/tests/linter/rules/tags/unnecessary_default_tags/expected_extended.txt
@@ -0,0 +1,8 @@
+test.robot:3:1 TAG07 Tags defined in Default Tags are always overwritten
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Default Tags  tag  othertag
+   | ^^^^^^^^^^^^ TAG07
+   |
+
diff --git a/tests/linter/rules/tags/unnecessary_default_tags/test_rule.py b/tests/linter/rules/tags/unnecessary_default_tags/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/tags/unnecessary_default_tags/test_rule.py
+++ b/tests/linter/rules/tags/unnecessary_default_tags/test_rule.py
@@ -4,3 +4,6 @@ from tests.linter.utils import RuleAcceptance
 class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output.txt")
+
+    def test_extended(self):
+        self.check_rule(src_files=["test.robot"], expected_file="expected_extended.txt", output_format="extended")