Repository: MarketSquare/robotframework-robocop
Pull request #1273 (2025-03-02 16:07:15)

Add tests for extended view for naming rules


Patch:
diff --git a/src/robocop/linter/reports/print_issues.py b/src/robocop/linter/reports/print_issues.py
index d283aef..edd04ae 100644
--- a/src/robocop/linter/reports/print_issues.py
+++ b/src/robocop/linter/reports/print_issues.py
@@ -136,7 +136,8 @@ class PrintIssuesReport(robocop.linter.reports.Report):
         start_line, end_line = diagnostic.range.start.line, diagnostic.range.end.line
         start_col, end_col = diagnostic.range.start.character, diagnostic.range.end.character
         self.console.print(
-            f"{source_rel_path}:{start_line}:{start_col} [red]{diagnostic.rule.rule_id}[/red] {diagnostic.message}"
+            f"{source_rel_path}:{start_line}:{start_col} "
+            f"[red]{diagnostic.rule.rule_id}[/red] {escape(diagnostic.message)}"
         )
         if diagnostic.rule.file_wide_rule or start_line > len(lines):
             return
diff --git a/src/robocop/linter/rules/naming.py b/src/robocop/linter/rules/naming.py
index 694bb97..c6d0958 100644
--- a/src/robocop/linter/rules/naming.py
+++ b/src/robocop/linter/rules/naming.py
@@ -642,7 +642,9 @@ class KeywordNamingChecker(VisitorChecker):
 
     def visit_KeywordCall(self, node) -> None:  # noqa: N802
         if self.inside_if_block and node.keyword and node.keyword.lower() in self.else_statements:
-            self.report(self.else_not_upper_case, node=node, col=keyword_col(node))
+            col = keyword_col(node)
+            end_col = col + len(node.keyword)
+            self.report(self.else_not_upper_case, node=node, col=col, end_col=end_col)
         self.check_keyword_naming_with_subkeywords(node, Token.KEYWORD)
         self.check_bdd_keywords(node.keyword, node)
 
@@ -688,7 +690,15 @@ class KeywordNamingChecker(VisitorChecker):
         arg = node.get_token(Token.ARGUMENT)
         suffix = f". Use one space between: '{keyword_name.title()} {arg.value}'" if arg else ""
         col = token_col(node, Token.NAME, Token.KEYWORD)
-        self.report(self.bdd_without_keyword_call, keyword_name=keyword_name, error_msg=suffix, node=node, col=col)
+        end_col = col + len(keyword_name)
+        self.report(
+            self.bdd_without_keyword_call,
+            keyword_name=keyword_name,
+            error_msg=suffix,
+            node=node,
+            col=col,
+            end_col=end_col,
+        )
 
     def check_if_keyword_is_reserved(self, keyword_name, node) -> bool:
         # if there is typo in syntax, it is interpreted as keyword
@@ -795,7 +805,10 @@ class SettingsNamingChecker(VisitorChecker):
         if not with_name:
             for arg in node.get_tokens(Token.ARGUMENT):
                 if arg.value and arg.value in self.ALIAS_TOKENS_VALUES:
-                    self.report(self.empty_library_alias, node=arg, col=arg.col_offset + 1)
+                    col = arg.col_offset + 1
+                    self.report(
+                        self.empty_library_alias, node=arg, col=arg.col_offset + 1, end_col=col + len(arg.value)
+                    )
         elif node.alias.replace(" ", "") == node.name.replace(" ", ""):  # New Name == NewName
             name_token = node.get_tokens(Token.NAME)[-1]
             self.report(
@@ -822,20 +835,24 @@ class SettingsNamingChecker(VisitorChecker):
         if self.task_section is None and ("test" in name_normalized or "task" in name_normalized):
             self.task_section = "task" in name_normalized
         if "test" in name_normalized and self.task_section:
+            end_col = node.col_offset + 1 + len(name)
             self.report(
                 self.mixed_task_test_settings,
                 setting="Task " + name.split()[1],
                 task_or_test="task",
                 tasks_or_tests="Tasks",
                 node=node,
+                end_col=end_col,
             )
         elif "task" in name_normalized and not self.task_section:
+            end_col = node.col_offset + 1 + len(name)
             self.report(
                 self.mixed_task_test_settings,
                 setting="Test " + name.split()[1],
                 task_or_test="test",
                 tasks_or_tests="Test Cases",
                 node=node,
+                end_col=end_col,
             )
 
 


Test patch:
diff --git a/tests/linter/rules/naming/bdd_without_keyword_call/expected_extended.txt b/tests/linter/rules/naming/bdd_without_keyword_call/expected_extended.txt
new file mode 100644
index 0000000..2091a6a
--- /dev/null
+++ b/tests/linter/rules/naming/bdd_without_keyword_call/expected_extended.txt
@@ -0,0 +1,232 @@
+test.robot:3:19 NAME14 BDD reserved keyword 'Given' not followed by any keyword
+   |
+ 1 | *** Settings ***
+ 2 | Suite Setup    Given Keyword
+ 3 | Suite Teardown    Given
+   |                   ^^^^^ NAME14
+   |
+
+test.robot:5:15 NAME14 BDD reserved keyword 'Given' not followed by any keyword
+   |
+ 5 | Test Setup    Given
+   |               ^^^^^ NAME14
+ 6 | Test Teardown    Then  Keyword With  ${args}
+   |
+
+test.robot:6:18 NAME14 BDD reserved keyword 'Then' not followed by any keyword. Use one space between: 'Then Keyword With'
+   |
+ 4 |
+ 5 | Test Setup    Given
+ 6 | Test Teardown    Then  Keyword With  ${args}
+   |                  ^^^^ NAME14
+   |
+
+test.robot:17:14 NAME14 BDD reserved keyword 'Given' not followed by any keyword
+    |
+ 15 |
+ 16 | Invalid Empty
+ 17 |     [Setup]  Given
+    |              ^^^^^ NAME14
+ 18 |     Given
+ 19 |     When
+    |
+
+test.robot:18:5 NAME14 BDD reserved keyword 'Given' not followed by any keyword
+    |
+ 16 | Invalid Empty
+ 17 |     [Setup]  Given
+ 18 |     Given
+    |     ^^^^^ NAME14
+ 19 |     When
+ 20 |     But
+    |
+
+test.robot:19:5 NAME14 BDD reserved keyword 'When' not followed by any keyword
+    |
+ 17 |     [Setup]  Given
+ 18 |     Given
+ 19 |     When
+    |     ^^^^ NAME14
+ 20 |     But
+ 21 |     IF  ${condtion}
+    |
+
+test.robot:20:5 NAME14 BDD reserved keyword 'But' not followed by any keyword
+    |
+ 18 |     Given
+ 19 |     When
+ 20 |     But
+    |     ^^^ NAME14
+ 21 |     IF  ${condtion}
+ 22 |         and
+    |
+
+test.robot:22:9 NAME14 BDD reserved keyword 'and' not followed by any keyword
+    |
+ 20 |     But
+ 21 |     IF  ${condtion}
+ 22 |         and
+    |         ^^^ NAME14
+ 23 |     END
+ 24 |     FOR  ${var}  IN RANGE  10
+    |
+
+test.robot:25:9 NAME14 BDD reserved keyword 'Then' not followed by any keyword
+    |
+ 23 |     END
+ 24 |     FOR  ${var}  IN RANGE  10
+ 25 |         Then
+    |         ^^^^ NAME14
+ 26 |     END
+ 27 |     [Teardown]  Then
+    |
+
+test.robot:27:17 NAME14 BDD reserved keyword 'Then' not followed by any keyword
+    |
+ 25 |         Then
+ 26 |     END
+ 27 |     [Teardown]  Then
+    |                 ^^^^ NAME14
+    |
+
+test.robot:30:5 NAME14 BDD reserved keyword 'Given' not followed by any keyword. Use one space between: 'Given login page is open'
+    |
+ 28 |
+ 29 | Invalid Separator
+ 30 |     Given  login page is open
+    |     ^^^^^ NAME14
+ 31 |     When  valid username and password are inserted
+ 32 |     and  credentials are submitted
+    |
+
+test.robot:31:5 NAME14 BDD reserved keyword 'When' not followed by any keyword. Use one space between: 'When valid username and password are inserted'
+    |
+ 29 | Invalid Separator
+ 30 |     Given  login page is open
+ 31 |     When  valid username and password are inserted
+    |     ^^^^ NAME14
+ 32 |     and  credentials are submitted
+ 33 |     But  still Authorized
+    |
+
+test.robot:32:5 NAME14 BDD reserved keyword 'and' not followed by any keyword. Use one space between: 'And credentials are submitted'
+    |
+ 30 |     Given  login page is open
+ 31 |     When  valid username and password are inserted
+ 32 |     and  credentials are submitted
+    |     ^^^ NAME14
+ 33 |     But  still Authorized
+ 34 |     Then  welcome page should be open
+    |
+
+test.robot:33:5 NAME14 BDD reserved keyword 'But' not followed by any keyword. Use one space between: 'But still Authorized'
+    |
+ 31 |     When  valid username and password are inserted
+ 32 |     and  credentials are submitted
+ 33 |     But  still Authorized
+    |     ^^^ NAME14
+ 34 |     Then  welcome page should be open
+    |
+
+test.robot:34:5 NAME14 BDD reserved keyword 'Then' not followed by any keyword. Use one space between: 'Then welcome page should be open'
+    |
+ 32 |     and  credentials are submitted
+ 33 |     But  still Authorized
+ 34 |     Then  welcome page should be open
+    |     ^^^^ NAME14
+    |
+
+test.robot:45:5 NAME14 BDD reserved keyword 'Given' not followed by any keyword
+    |
+ 43 |
+ 44 | Invalid Empty Keyword
+ 45 |     Given
+    |     ^^^^^ NAME14
+ 46 |     When
+ 47 |     and
+    |
+
+test.robot:46:5 NAME14 BDD reserved keyword 'When' not followed by any keyword
+    |
+ 44 | Invalid Empty Keyword
+ 45 |     Given
+ 46 |     When
+    |     ^^^^ NAME14
+ 47 |     and
+ 48 |     BuT
+    |
+
+test.robot:47:5 NAME14 BDD reserved keyword 'and' not followed by any keyword
+    |
+ 45 |     Given
+ 46 |     When
+ 47 |     and
+    |     ^^^ NAME14
+ 48 |     BuT
+ 49 |     Then
+    |
+
+test.robot:48:5 NAME14 BDD reserved keyword 'BuT' not followed by any keyword
+    |
+ 46 |     When
+ 47 |     and
+ 48 |     BuT
+    |     ^^^ NAME14
+ 49 |     Then
+    |
+
+test.robot:49:5 NAME14 BDD reserved keyword 'Then' not followed by any keyword
+    |
+ 47 |     and
+ 48 |     BuT
+ 49 |     Then
+    |     ^^^^ NAME14
+    |
+
+test.robot:52:5 NAME14 BDD reserved keyword 'Given' not followed by any keyword. Use one space between: 'Given ${variable}'
+    |
+ 50 |
+ 51 | Invalid Separator Keyword
+ 52 |     Given  ${variable}
+    |     ^^^^^ NAME14
+ 53 |     When  %valid username and password are inserted
+ 54 |     and  credentials are submitted
+    |
+
+test.robot:53:5 NAME14 BDD reserved keyword 'When' not followed by any keyword. Use one space between: 'When %valid username and password are inserted'
+    |
+ 51 | Invalid Separator Keyword
+ 52 |     Given  ${variable}
+ 53 |     When  %valid username and password are inserted
+    |     ^^^^ NAME14
+ 54 |     and  credentials are submitted
+ 55 |     But  still authorized
+    |
+
+test.robot:54:5 NAME14 BDD reserved keyword 'and' not followed by any keyword. Use one space between: 'And credentials are submitted'
+    |
+ 52 |     Given  ${variable}
+ 53 |     When  %valid username and password are inserted
+ 54 |     and  credentials are submitted
+    |     ^^^ NAME14
+ 55 |     But  still authorized
+ 56 |     Then  welcome page should be open
+    |
+
+test.robot:55:5 NAME14 BDD reserved keyword 'But' not followed by any keyword. Use one space between: 'But still authorized'
+    |
+ 53 |     When  %valid username and password are inserted
+ 54 |     and  credentials are submitted
+ 55 |     But  still authorized
+    |     ^^^ NAME14
+ 56 |     Then  welcome page should be open
+    |
+
+test.robot:56:5 NAME14 BDD reserved keyword 'Then' not followed by any keyword. Use one space between: 'Then welcome page should be open'
+    |
+ 54 |     and  credentials are submitted
+ 55 |     But  still authorized
+ 56 |     Then  welcome page should be open
+    |     ^^^^ NAME14
+    |
+
diff --git a/tests/linter/rules/naming/bdd_without_keyword_call/test_rule.py b/tests/linter/rules/naming/bdd_without_keyword_call/test_rule.py
index e0553eb..931c17e 100644
--- a/tests/linter/rules/naming/bdd_without_keyword_call/test_rule.py
+++ b/tests/linter/rules/naming/bdd_without_keyword_call/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")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/naming/duplicated_library_alias/expected_extended.txt b/tests/linter/rules/naming/duplicated_library_alias/expected_extended.txt
new file mode 100644
index 0000000..e48d5ea
--- /dev/null
+++ b/tests/linter/rules/naming/duplicated_library_alias/expected_extended.txt
@@ -0,0 +1,37 @@
+test.robot:3:40 NAME13 Library alias is the same as original name
+   |
+ 1 | *** Settings ***
+ 2 | Resource     library.py
+ 3 | Library      Collections    WITH NAME  Collections
+   |                                        ^^^^^^^^^^^ NAME13
+ 4 | Library      Collections    AS  Collections
+ 5 | Library      other_library.py    WITH NAME  PrettyName
+   |
+
+test.robot:4:33 NAME13 Library alias is the same as original name
+   |
+ 2 | Resource     library.py
+ 3 | Library      Collections    WITH NAME  Collections
+ 4 | Library      Collections    AS  Collections
+   |                                 ^^^^^^^^^^^ NAME13
+ 5 | Library      other_library.py    WITH NAME  PrettyName
+ 6 | Library      WITH NAME
+   |
+
+test.robot:7:42 NAME13 Library alias is the same as original name
+   |
+ 5 | Library      other_library.py    WITH NAME  PrettyName
+ 6 | Library      WITH NAME
+ 7 | Library      Collections    WITH NAME    Coll ections
+   |                                          ^^^^^^^^^^^^ NAME13
+ 8 | Library      Collections    AS    Coll ections
+   |
+
+test.robot:8:35 NAME13 Library alias is the same as original name
+   |
+ 6 | Library      WITH NAME
+ 7 | Library      Collections    WITH NAME    Coll ections
+ 8 | Library      Collections    AS    Coll ections
+   |                                   ^^^^^^^^^^^^ NAME13
+   |
+
diff --git a/tests/linter/rules/naming/duplicated_library_alias/test_rule.py b/tests/linter/rules/naming/duplicated_library_alias/test_rule.py
index ea0586b..2223c6c 100644
--- a/tests/linter/rules/naming/duplicated_library_alias/test_rule.py
+++ b/tests/linter/rules/naming/duplicated_library_alias/test_rule.py
@@ -7,3 +7,11 @@ class TestRuleAcceptance(RuleAcceptance):
 
     def test_pre_rf6(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output_pre_rf6_0.txt", test_on_version="<6.0")
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=6.0",
+        )
diff --git a/tests/linter/rules/naming/else_not_upper_case/expected_extended.txt b/tests/linter/rules/naming/else_not_upper_case/expected_extended.txt
new file mode 100644
index 0000000..a036a79
--- /dev/null
+++ b/tests/linter/rules/naming/else_not_upper_case/expected_extended.txt
@@ -0,0 +1,20 @@
+test.robot:11:5 NAME09 ELSE and ELSE IF is not uppercase
+    |
+  9 |     IF    ${condition}
+ 10 |         Keyword
+ 11 |     ELse IF   ${condition}
+    |     ^^^^^^^ NAME09
+ 12 |         Keyword
+ 13 |     END
+    |
+
+test.robot:18:5 NAME09 ELSE and ELSE IF is not uppercase
+    |
+ 16 |     ELSE IF   ${condition}
+ 17 |         Keyword
+ 18 |     ElSE
+    |     ^^^^ NAME09
+ 19 |         Keyword
+ 20 |     END
+    |
+
diff --git a/tests/linter/rules/naming/else_not_upper_case/test_rule.py b/tests/linter/rules/naming/else_not_upper_case/test_rule.py
index 51374e7..7849086 100644
--- a/tests/linter/rules/naming/else_not_upper_case/test_rule.py
+++ b/tests/linter/rules/naming/else_not_upper_case/test_rule.py
@@ -10,3 +10,11 @@ class TestRuleAcceptance(RuleAcceptance):
 
     def test_rf_3(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output_rf3.txt", test_on_version="==3.*")
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=5",
+        )
diff --git a/tests/linter/rules/naming/empty_library_alias/expected_extended.txt b/tests/linter/rules/naming/empty_library_alias/expected_extended.txt
new file mode 100644
index 0000000..a1176a8
--- /dev/null
+++ b/tests/linter/rules/naming/empty_library_alias/expected_extended.txt
@@ -0,0 +1,38 @@
+test.robot:3:29 NAME12 Library alias is empty
+   |
+ 1 | *** Settings ***
+ 2 | Resources    library.py
+ 3 | Library      Collections    WITH NAME
+   |                             ^^^^^^^^^ NAME12
+ 4 | Library      other_library.py    WITH NAME  # comment
+ 5 | Library      other_library.py    WITH NAME  PrettyName  # comment
+   |
+
+test.robot:4:34 NAME12 Library alias is empty
+   |
+ 2 | Resources    library.py
+ 3 | Library      Collections    WITH NAME
+ 4 | Library      other_library.py    WITH NAME  # comment
+   |                                  ^^^^^^^^^ NAME12
+ 5 | Library      other_library.py    WITH NAME  PrettyName  # comment
+ 6 | Library      other_library.py    AS
+   |
+
+test.robot:6:34 NAME12 Library alias is empty
+   |
+ 4 | Library      other_library.py    WITH NAME  # comment
+ 5 | Library      other_library.py    WITH NAME  PrettyName  # comment
+ 6 | Library      other_library.py    AS
+   |                                  ^^ NAME12
+ 7 | Library      other_library.py    AS    SomeName
+ 8 | Library      WITH NAME
+   |
+
+test.robot:10:44 NAME12 Library alias is empty
+    |
+  8 | Library      WITH NAME
+  9 | Library      other_library.py     arg=1    AS     MyName
+ 10 | Library      other_library.py     arg=1    AS
+    |                                            ^^ NAME12
+    |
+
diff --git a/tests/linter/rules/naming/empty_library_alias/test_rule.py b/tests/linter/rules/naming/empty_library_alias/test_rule.py
index 1ac5f64..78300ba 100644
--- a/tests/linter/rules/naming/empty_library_alias/test_rule.py
+++ b/tests/linter/rules/naming/empty_library_alias/test_rule.py
@@ -7,3 +7,11 @@ class TestRuleAcceptance(RuleAcceptance):
 
     def test_pre_rf6(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output_pre_rf6.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/naming/invalid_section/expected_extended.txt b/tests/linter/rules/naming/invalid_section/expected_extended.txt
new file mode 100644
index 0000000..ca6bf60
--- /dev/null
+++ b/tests/linter/rules/naming/invalid_section/expected_extended.txt
@@ -0,0 +1,21 @@
+test.robot:1:1 NAME16 Invalid section '*** Kommentit ***'
+   |
+ 1 | *** Kommentit ***
+   | ^^^^^^^^^^^^^^^^^^ NAME16
+ 2 | Some general comments
+   |
+
+test.robot:9:1 NAME16 Invalid section '*** Testit ***'
+   |
+ 9 | *** Testit ***
+   | ^^^^^^^^^^^^^^^ NAME16
+10 | Test
+11 |     [Documentation]    doc.
+   |
+
+test.robot:14:1 NAME16 Invalid section '*** Bad ***'
+    |
+ 14 | *** Bad ***
+    | ^^^^^^^^^^^^ NAME16
+    |
+
diff --git a/tests/linter/rules/naming/invalid_section/test_rule.py b/tests/linter/rules/naming/invalid_section/test_rule.py
index 468a362..92bedac 100644
--- a/tests/linter/rules/naming/invalid_section/test_rule.py
+++ b/tests/linter/rules/naming/invalid_section/test_rule.py
@@ -6,3 +6,11 @@ class TestRuleAcceptance(RuleAcceptance):
         self.check_rule(
             src_files=["test.robot", "test_lang.resource"], expected_file="expected_output.txt", test_on_version=">=6.1"
         )
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot", "test_lang.resource"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=6.1",
+        )
diff --git a/tests/linter/rules/naming/keyword_name_is_empty/expected_extended.txt b/tests/linter/rules/naming/keyword_name_is_empty/expected_extended.txt
new file mode 100644
index 0000000..e2622f1
--- /dev/null
+++ b/tests/linter/rules/naming/keyword_name_is_empty/expected_extended.txt
@@ -0,0 +1,8 @@
+test.robot:8:1 NAME10 Keyword name is empty
+   |
+ 6 | *** Keywords ***
+ 7 | # no keyword name here!!!
+ 8 |     Log To Console  hi
+   | ^ NAME10
+   |
+
diff --git a/tests/linter/rules/naming/keyword_name_is_empty/test_rule.py b/tests/linter/rules/naming/keyword_name_is_empty/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/naming/keyword_name_is_empty/test_rule.py
+++ b/tests/linter/rules/naming/keyword_name_is_empty/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/naming/keyword_name_is_reserved_word/expected_extended.txt b/tests/linter/rules/naming/keyword_name_is_reserved_word/expected_extended.txt
new file mode 100644
index 0000000..8969831
--- /dev/null
+++ b/tests/linter/rules/naming/keyword_name_is_reserved_word/expected_extended.txt
@@ -0,0 +1,149 @@
+if_blocks.robot:4:5 NAME03 'If' is a reserved keyword. It must be in uppercase (IF) when used as a statement
+   |
+ 2 | Test
+ 3 |     No Operation
+ 4 |     If  ${condition}    Keyword     END
+   |     ^^ NAME03
+ 5 |     IF    ${condition}    Keyword
+ 6 |     ELSE if    Keyword2
+   |
+
+if_blocks.robot:6:5 NAME03 'ELSE if' is a reserved keyword. It must be in uppercase (ELSE IF) when used as a statement
+   |
+ 4 |     If  ${condition}    Keyword     END
+ 5 |     IF    ${condition}    Keyword
+ 6 |     ELSE if    Keyword2
+   |     ^^^^^^^ NAME03
+ 7 |     ELse    Keyword3
+ 8 |     End
+   |
+
+if_blocks.robot:7:5 NAME03 'ELse' is a reserved keyword. It must be in uppercase (ELSE) when used as a statement
+   |
+ 5 |     IF    ${condition}    Keyword
+ 6 |     ELSE if    Keyword2
+ 7 |     ELse    Keyword3
+   |     ^^^^ NAME03
+ 8 |     End
+ 9 |     IF    ${condition}
+   |
+
+if_blocks.robot:8:5 NAME03 'End' is a reserved keyword. It must be in uppercase (END) when used as a statement
+   |
+ 6 |     ELSE if    Keyword2
+ 7 |     ELse    Keyword3
+ 8 |     End
+   |     ^^^ NAME03
+ 9 |     IF    ${condition}
+10 |         Keyword
+   |
+
+if_blocks.robot:24:9 NAME03 'End' is a reserved keyword. It must be in uppercase (END) when used as a statement
+    |
+ 22 |         FOR  ${i}  IN  @{list}
+ 23 |             Keyword
+ 24 |         End
+    |         ^^^ NAME03
+ 25 |     END
+    |
+
+templated_suite.robot:2:18 NAME03 'End' is a reserved keyword. It must be in uppercase (END) when used as a statement
+   |
+ 1 | *** Settings ***
+ 2 | Test Template    End
+   |                  ^^^ NAME03
+   |
+
+test.robot:15:19 NAME03 'End' is a reserved keyword. It must be in uppercase (END) when used as a statement
+    |
+ 13 |
+ 14 | Templated test
+ 15 |     [Template]    End
+    |                   ^^^ NAME03
+    |
+
+test.robot:24:5 NAME03 'For' is a reserved keyword. It must be in uppercase (FOR) when used as a statement
+    |
+ 22 |     Pass
+ 23 |     No Operation
+ 24 |     For
+    |     ^^^ NAME03
+ 25 |     End
+ 26 |     Fail
+    |
+
+test.robot:25:5 NAME03 'End' is a reserved keyword. It must be in uppercase (END) when used as a statement
+    |
+ 23 |     No Operation
+ 24 |     For
+ 25 |     End
+    |     ^^^ NAME03
+ 26 |     Fail
+ 27 |     Run Keyword If  ${True}  Keyword
+    |
+
+test.robot:30:9 NAME03 'Return' is a reserved keyword. It must be in uppercase (RETURN) when used as a statement
+    |
+ 28 |     ...  else  Keyword2
+ 29 |     IF    $condition
+ 30 |         Return
+    |         ^^^^^^ NAME03
+ 31 |     END
+ 32 |     RETURN
+    |
+
+test.robot:34:1 NAME03 'While' is a reserved keyword. It must be in uppercase (WHILE) when used as a statement
+    |
+ 34 | While
+    | ^ NAME03
+ 35 |     While
+ 36 |     Continue
+    |
+
+test.robot:35:5 NAME03 'While' is a reserved keyword. It must be in uppercase (WHILE) when used as a statement
+    |
+ 33 |
+ 34 | While
+ 35 |     While
+    |     ^^^^^ NAME03
+ 36 |     Continue
+ 37 |     Try
+    |
+
+test.robot:36:5 NAME03 'Continue' is a reserved keyword. It must be in uppercase (CONTINUE) when used as a statement
+    |
+ 34 | While
+ 35 |     While
+ 36 |     Continue
+    |     ^^^^^^^^ NAME03
+ 37 |     Try
+ 38 |     Except
+    |
+
+test.robot:37:5 NAME03 'Try' is a reserved keyword. It must be in uppercase (TRY) when used as a statement
+    |
+ 35 |     While
+ 36 |     Continue
+ 37 |     Try
+    |     ^^^ NAME03
+ 38 |     Except
+ 39 |     finally
+    |
+
+test.robot:38:5 NAME03 'Except' is a reserved keyword. It must be in uppercase (EXCEPT) when used as a statement
+    |
+ 36 |     Continue
+ 37 |     Try
+ 38 |     Except
+    |     ^^^^^^ NAME03
+ 39 |     finally
+    |
+
+test.robot:39:5 NAME03 'finally' is a reserved keyword. It must be in uppercase (FINALLY) when used as a statement
+    |
+ 37 |     Try
+ 38 |     Except
+ 39 |     finally
+    |     ^^^^^^^ NAME03
+    |
+
diff --git a/tests/linter/rules/naming/keyword_name_is_reserved_word/test_rule.py b/tests/linter/rules/naming/keyword_name_is_reserved_word/test_rule.py
index c897cc0..1517922 100644
--- a/tests/linter/rules/naming/keyword_name_is_reserved_word/test_rule.py
+++ b/tests/linter/rules/naming/keyword_name_is_reserved_word/test_rule.py
@@ -10,3 +10,6 @@ class TestRuleAcceptance(RuleAcceptance):
 
     def test_rf3(self):
         self.check_rule(expected_file="expected_output_rf3.txt", test_on_version="==3.*")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended", test_on_version=">=5")
diff --git a/tests/linter/rules/naming/mixed_task_test_settings/expected_extended.txt b/tests/linter/rules/naming/mixed_task_test_settings/expected_extended.txt
new file mode 100644
index 0000000..8026a8d
--- /dev/null
+++ b/tests/linter/rules/naming/mixed_task_test_settings/expected_extended.txt
@@ -0,0 +1,144 @@
+tasks_with_test_settings.robot:2:1 NAME17 Use task-related setting 'Task Setup' if Tasks section is used
+   |
+ 1 | *** Settings ***
+ 2 | Test Setup      Some Keyword
+   | ^^^^^^^^^^ NAME17
+ 3 | Test Teardown   Some Keyword
+ 4 | Test Template   Some Keyword
+   |
+
+tasks_with_test_settings.robot:3:1 NAME17 Use task-related setting 'Task Teardown' if Tasks section is used
+   |
+ 1 | *** Settings ***
+ 2 | Test Setup      Some Keyword
+ 3 | Test Teardown   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 4 | Test Template   Some Keyword
+ 5 | Test Timeout    100
+   |
+
+tasks_with_test_settings.robot:4:1 NAME17 Use task-related setting 'Task Template' if Tasks section is used
+   |
+ 2 | Test Setup      Some Keyword
+ 3 | Test Teardown   Some Keyword
+ 4 | Test Template   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 5 | Test Timeout    100
+ 6 | Test Tags       tag
+   |
+
+tasks_with_test_settings.robot:5:1 NAME17 Use task-related setting 'Task Timeout' if Tasks section is used
+   |
+ 3 | Test Teardown   Some Keyword
+ 4 | Test Template   Some Keyword
+ 5 | Test Timeout    100
+   | ^^^^^^^^^^^^ NAME17
+ 6 | Test Tags       tag
+ 7 | Documentation   some docs
+   |
+
+tasks_with_test_settings.robot:6:1 NAME17 Use task-related setting 'Task Tags' if Tasks section is used
+   |
+ 4 | Test Template   Some Keyword
+ 5 | Test Timeout    100
+ 6 | Test Tags       tag
+   | ^^^^^^^^^ NAME17
+ 7 | Documentation   some docs
+   |
+
+tests_with_task_settings.robot:2:1 NAME17 Use test-related setting 'Test Setup' if Test Cases section is used
+   |
+ 1 | *** Settings ***
+ 2 | Task Setup      Some Keyword
+   | ^^^^^^^^^^ NAME17
+ 3 | Task Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+   |
+
+tests_with_task_settings.robot:3:1 NAME17 Use test-related setting 'Test Teardown' if Test Cases section is used
+   |
+ 1 | *** Settings ***
+ 2 | Task Setup      Some Keyword
+ 3 | Task Teardown   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 4 | Task Template   Some Keyword
+ 5 | Task Timeout    100
+   |
+
+tests_with_task_settings.robot:4:1 NAME17 Use test-related setting 'Test Template' if Test Cases section is used
+   |
+ 2 | Task Setup      Some Keyword
+ 3 | Task Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 5 | Task Timeout    100
+ 6 | Task Tags       tag
+   |
+
+tests_with_task_settings.robot:5:1 NAME17 Use test-related setting 'Test Timeout' if Test Cases section is used
+   |
+ 3 | Task Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+ 5 | Task Timeout    100
+   | ^^^^^^^^^^^^ NAME17
+ 6 | Task Tags       tag
+ 7 | Documentation   some docs
+   |
+
+tests_with_task_settings.robot:6:1 NAME17 Use test-related setting 'Test Tags' if Test Cases section is used
+   |
+ 4 | Task Template   Some Keyword
+ 5 | Task Timeout    100
+ 6 | Task Tags       tag
+   | ^^^^^^^^^ NAME17
+ 7 | Documentation   some docs
+   |
+
+mixed_tasks.robot:3:1 NAME17 Use task-related setting 'Task Teardown' if Tasks section is used
+   |
+ 1 | *** Settings ***
+ 2 | Task Setup      Some Keyword
+ 3 | Test Teardown   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 4 | Task Template   Some Keyword
+ 5 | Test Timeout    100
+   |
+
+mixed_tasks.robot:5:1 NAME17 Use task-related setting 'Task Timeout' if Tasks section is used
+   |
+ 3 | Test Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+ 5 | Test Timeout    100
+   | ^^^^^^^^^^^^ NAME17
+ 6 | Task Tags       tag
+ 7 | Documentation   some docs
+   |
+
+mixed_tests.robot:2:1 NAME17 Use test-related setting 'Test Setup' if Test Cases section is used
+   |
+ 1 | *** Settings ***
+ 2 | Task Setup      Some Keyword
+   | ^^^^^^^^^^ NAME17
+ 3 | Test Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+   |
+
+mixed_tests.robot:4:1 NAME17 Use test-related setting 'Test Template' if Test Cases section is used
+   |
+ 2 | Task Setup      Some Keyword
+ 3 | Test Teardown   Some Keyword
+ 4 | Task Template   Some Keyword
+   | ^^^^^^^^^^^^^ NAME17
+ 5 | Test Timeout    100
+ 6 | Task Tags       tag
+   |
+
+mixed_tests.robot:6:1 NAME17 Use test-related setting 'Test Tags' if Test Cases section is used
+   |
+ 4 | Task Template   Some Keyword
+ 5 | Test Timeout    100
+ 6 | Task Tags       tag
+   | ^^^^^^^^^ NAME17
+ 7 | Documentation   some docs
+   |
+
diff --git a/tests/linter/rules/naming/mixed_task_test_settings/test_rule.py b/tests/linter/rules/naming/mixed_task_test_settings/test_rule.py
index 5b01d27..841dccf 100644
--- a/tests/linter/rules/naming/mixed_task_test_settings/test_rule.py
+++ b/tests/linter/rules/naming/mixed_task_test_settings/test_rule.py
@@ -31,3 +31,19 @@ class TestRuleAcceptance(RuleAcceptance):
             expected_file="expected_output_pre_rf6.txt",
             test_on_version="<6",
         )
+
+    def test_extended(self):
+        self.check_rule(
+            src_files=[
+                "tasks_with_test_settings.robot",
+                "tests_with_task_settings.robot",
+                "mixed_tasks.robot",
+                "mixed_tests.robot",
+                "golden_task.robot",
+                "golden_test.robot",
+                "__init__.robot",
+            ],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=6",
+        )
diff --git a/tests/linter/rules/naming/not_allowed_char_in_filename/expected_extended.txt b/tests/linter/rules/naming/not_allowed_char_in_filename/expected_extended.txt
new file mode 100644
index 0000000..5876dad
--- /dev/null
+++ b/tests/linter/rules/naming/not_allowed_char_in_filename/expected_extended.txt
@@ -0,0 +1,2 @@
+not_allowed_suite_foo.bar.robot:1:21 NAME15 Not allowed character '.' found in suite name
+suite.withdot${/}__init__.robot:1:5 NAME15 Not allowed character '.' found in suite name
\ No newline at end of file
diff --git a/tests/linter/rules/naming/not_allowed_char_in_filename/test_rule.py b/tests/linter/rules/naming/not_allowed_char_in_filename/test_rule.py
index 8a5a6ab..66db57b 100644
--- a/tests/linter/rules/naming/not_allowed_char_in_filename/test_rule.py
+++ b/tests/linter/rules/naming/not_allowed_char_in_filename/test_rule.py
@@ -7,6 +7,13 @@ class TestRuleAcceptance(RuleAcceptance):
             src_files=["not_allowed_suite_foo.bar.robot", "suite.withdot"], expected_file="expected_output.txt"
         )
 
+    def test_extended(self):
+        self.check_rule(
+            src_files=["not_allowed_suite_foo.bar.robot", "suite.withdot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+        )
+
     def test_configure_pattern(self):
         self.check_rule(
             configure=[r"not-allowed-char-in-filename.pattern=\.(?!bar)"],
diff --git a/tests/linter/rules/naming/not_allowed_char_in_name/expected_extended.txt b/tests/linter/rules/naming/not_allowed_char_in_name/expected_extended.txt
new file mode 100644
index 0000000..0d7e455
--- /dev/null
+++ b/tests/linter/rules/naming/not_allowed_char_in_name/expected_extended.txt
@@ -0,0 +1,28 @@
+test.robot:6:5 NAME01 Not allowed character '.' found in 'Test.' test case name
+   |
+ 4 |
+ 5 | *** Test Cases ***
+ 6 | Test.
+   |     ^ NAME01
+ 7 |     [Documentation]  doc
+ 8 |     [Tags]  sometag
+   |
+
+test.robot:15:10 NAME01 Not allowed character '?' found in 'Keyword${?' keyword name
+    |
+ 13 |
+ 14 | *** Keywords ***
+ 15 | Keyword${?
+    |          ^ NAME01
+ 16 |     [Documentation]  this is doc
+ 17 |     No Operation
+    |
+
+test.robot:31:20 NAME01 Not allowed character '?' found in 'Keyword Escaped \${?} Should Warn' keyword name
+    |
+ 31 | Keyword Escaped \${?} Should Warn
+    |                    ^ NAME01
+ 32 |     [Documentation]  this is doc
+ 33 |     No Operation
+    |
+
diff --git a/tests/linter/rules/naming/not_allowed_char_in_name/test_rule.py b/tests/linter/rules/naming/not_allowed_char_in_name/test_rule.py
index 93763ed..7bf01ba 100644
--- a/tests/linter/rules/naming/not_allowed_char_in_name/test_rule.py
+++ b/tests/linter/rules/naming/not_allowed_char_in_name/test_rule.py
@@ -7,6 +7,9 @@ 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")
+
     @pytest.mark.parametrize(
         ("test_id", "pattern"),
         [
diff --git a/tests/linter/rules/naming/not_capitalized_test_case_title/expected_extended.txt b/tests/linter/rules/naming/not_capitalized_test_case_title/expected_extended.txt
new file mode 100644
index 0000000..b447a42
--- /dev/null
+++ b/tests/linter/rules/naming/not_capitalized_test_case_title/expected_extended.txt
@@ -0,0 +1,7 @@
+test.robot:5:1 NAME07 Test case 'test not capitalized' title does not start with capital letter
+   |
+ 5 | test not capitalized
+   | ^^^^^^^^^^^^^^^^^^^^ NAME07
+ 6 |     Pass Execution
+   |
+
diff --git a/tests/linter/rules/naming/not_capitalized_test_case_title/test_rule.py b/tests/linter/rules/naming/not_capitalized_test_case_title/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/naming/not_capitalized_test_case_title/test_rule.py
+++ b/tests/linter/rules/naming/not_capitalized_test_case_title/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/naming/section_name_invalid/expected_extended.txt b/tests/linter/rules/naming/section_name_invalid/expected_extended.txt
new file mode 100644
index 0000000..1e07cec
--- /dev/null
+++ b/tests/linter/rules/naming/section_name_invalid/expected_extended.txt
@@ -0,0 +1,23 @@
+test.robot:5:1 NAME06 Section name should be in format '*** Variables ***' or '*** VARIABLES ***'
+   |
+ 5 | * Variables *
+   | ^^^^^^^^^^^^^ NAME06
+ 6 | ${var}  1
+   |
+
+test.robot:9:1 NAME06 Section name should be in format '*** Test Cases ***' or '*** TEST CASES ***'
+   |
+ 9 | *test cases*
+   | ^^^^^^^^^^^^ NAME06
+10 | Test
+11 |     [Documentation]  doc
+   |
+
+test.robot:18:1 NAME06 Section name should be in format '*** Keywords ***' or '*** KEYWORDS ***'
+    |
+ 18 | *** keywords ***
+    | ^^^^^^^^^^^^^^^^ NAME06
+ 19 | Keyword
+ 20 |     [Documentation]  this is doc
+    |
+
diff --git a/tests/linter/rules/naming/section_name_invalid/test_rule.py b/tests/linter/rules/naming/section_name_invalid/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/naming/section_name_invalid/test_rule.py
+++ b/tests/linter/rules/naming/section_name_invalid/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/naming/section_variable_not_uppercase/expected_extended.txt b/tests/linter/rules/naming/section_variable_not_uppercase/expected_extended.txt
new file mode 100644
index 0000000..e58dcbb
--- /dev/null
+++ b/tests/linter/rules/naming/section_variable_not_uppercase/expected_extended.txt
@@ -0,0 +1,195 @@
+test.robot:5:1 NAME08 Section variable '${my_var}' name is not uppercase
+   |
+ 3 | ${MY VAR}  2
+ 4 | ${MYVAR}   3
+ 5 | ${my_var}  4
+   | ^^^^^^^^^ NAME08
+ 6 | ${My Var}  5
+ 7 | ${my var}  6
+   |
+
+test.robot:6:1 NAME08 Section variable '${My Var}' name is not uppercase
+   |
+ 4 | ${MYVAR}   3
+ 5 | ${my_var}  4
+ 6 | ${My Var}  5
+   | ^^^^^^^^^ NAME08
+ 7 | ${my var}  6
+ 8 | ${MyVar}   7
+   |
+
+test.robot:7:1 NAME08 Section variable '${my var}' name is not uppercase
+   |
+ 5 | ${my_var}  4
+ 6 | ${My Var}  5
+ 7 | ${my var}  6
+   | ^^^^^^^^^ NAME08
+ 8 | ${MyVar}   7
+ 9 | ${My_Var}  8
+   |
+
+test.robot:8:1 NAME08 Section variable '${MyVar}' name is not uppercase
+   |
+ 6 | ${My Var}  5
+ 7 | ${my var}  6
+ 8 | ${MyVar}   7
+   | ^^^^^^^^ NAME08
+ 9 | ${My_Var}  8
+10 | ${myVar}   9
+   |
+
+test.robot:9:1 NAME08 Section variable '${My_Var}' name is not uppercase
+   |
+ 7 | ${my var}  6
+ 8 | ${MyVar}   7
+ 9 | ${My_Var}  8
+   | ^^^^^^^^^ NAME08
+10 | ${myVar}   9
+11 | ${MY_var}  10
+   |
+
+test.robot:10:1 NAME08 Section variable '${myVar}' name is not uppercase
+    |
+  8 | ${MyVar}   7
+  9 | ${My_Var}  8
+ 10 | ${myVar}   9
+    | ^^^^^^^^ NAME08
+ 11 | ${MY_var}  10
+ 12 | ${MY_VAR}
+    |
+
+test.robot:11:1 NAME08 Section variable '${MY_var}' name is not uppercase
+    |
+  9 | ${My_Var}  8
+ 10 | ${myVar}   9
+ 11 | ${MY_var}  10
+    | ^^^^^^^^^ NAME08
+ 12 | ${MY_VAR}
+ 13 | ...         11
+    |
+
+test.robot:14:1 NAME08 Section variable '${my_var}' name is not uppercase
+    |
+ 12 | ${MY_VAR}
+ 13 | ...         11
+ 14 | ${my_var}
+    | ^^^^^^^^^ NAME08
+ 15 | ...         12
+ 16 |  ${var}  1
+    |
+
+test.robot:16:1 NAME08 Section variable '${var}' name is not uppercase
+    |
+ 14 | ${my_var}
+ 15 | ...         12
+ 16 |  ${var}  1
+    | ^^^^^^^ NAME08
+ 17 |  @{var3}  a
+ 18 |  ...      b
+    |
+
+test.robot:17:1 NAME08 Section variable '@{var3}' name is not uppercase
+    |
+ 15 | ...         12
+ 16 |  ${var}  1
+ 17 |  @{var3}  a
+    | ^^^^^^^^ NAME08
+ 18 |  ...      b
+ 19 |  ...      c
+    |
+
+test.robot:21:1 NAME08 Section variable '@{var4}' name is not uppercase
+    |
+ 19 |  ...      c
+ 20 | ...      d
+ 21 | @{var4}  a
+    | ^^^^^^^ NAME08
+ 22 | ...      1
+ 23 |  ...     2
+    |
+
+test.robot:25:1 NAME08 Section variable '${MY_VAR${var}}' name is not uppercase
+    |
+ 25 | ${MY_VAR${var}}  11
+    | ^^^^^^^^^^^^^^^ NAME08
+ 26 | ${MY VAR${VAR}}  11
+ 27 | ${${var}MY VAR${VAR}}  11
+    |
+
+test.robot:27:1 NAME08 Section variable '${${var}MY VAR${VAR}}' name is not uppercase
+    |
+ 25 | ${MY_VAR${var}}  11
+ 26 | ${MY VAR${VAR}}  11
+ 27 | ${${var}MY VAR${VAR}}  11
+    | ^^^^^^^^^^^^^^^^^^^^^ NAME08
+ 28 | ${${var${VAR}}MY VAR${VAR}}  11
+ 29 | ${@{VAR}[1]MY_VAR&{var.param}}  11
+    |
+
+test.robot:28:1 NAME08 Section variable '${${var${VAR}}MY VAR${VAR}}' name is not uppercase
+    |
+ 26 | ${MY VAR${VAR}}  11
+ 27 | ${${var}MY VAR${VAR}}  11
+ 28 | ${${var${VAR}}MY VAR${VAR}}  11
+    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ NAME08
+ 29 | ${@{VAR}[1]MY_VAR&{var.param}}  11
+ 30 | ${${var${VAR}}my_var}  11
+    |
+
+test.robot:29:1 NAME08 Section variable '${@{VAR}[1]MY_VAR&{var.param}}' name is not uppercase
+    |
+ 27 | ${${var}MY VAR${VAR}}  11
+ 28 | ${${var${VAR}}MY VAR${VAR}}  11
+ 29 | ${@{VAR}[1]MY_VAR&{var.param}}  11
+    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NAME08
+ 30 | ${${var${VAR}}my_var}  11
+ 31 | ${${VAR}my_var}  11
+    |
+
+test.robot:30:1 NAME08 Section variable '${${var${VAR}}my_var}' name is not uppercase
+    |
+ 28 | ${${var${VAR}}MY VAR${VAR}}  11
+ 29 | ${@{VAR}[1]MY_VAR&{var.param}}  11
+ 30 | ${${var${VAR}}my_var}  11
+    | ^^^^^^^^^^^^^^^^^^^^^ NAME08
+ 31 | ${${VAR}my_var}  11
+ 32 | ${${VAR}my_var${var}}  11
+    |
+
+test.robot:31:1 NAME08 Section variable '${${VAR}my_var}' name is not uppercase
+    |
+ 29 | ${@{VAR}[1]MY_VAR&{var.param}}  11
+ 30 | ${${var${VAR}}my_var}  11
+ 31 | ${${VAR}my_var}  11
+    | ^^^^^^^^^^^^^^^ NAME08
+ 32 | ${${VAR}my_var${var}}  11
+ 33 | ${@{VAR}[1]my_var}  11
+    |
+
+test.robot:32:1 NAME08 Section variable '${${VAR}my_var${var}}' name is not uppercase
+    |
+ 30 | ${${var${VAR}}my_var}  11
+ 31 | ${${VAR}my_var}  11
+ 32 | ${${VAR}my_var${var}}  11
+    | ^^^^^^^^^^^^^^^^^^^^^ NAME08
+ 33 | ${@{VAR}[1]my_var}  11
+ 34 | ${@{VAR}[1]my_var&{var.param}}  11
+    |
+
+test.robot:33:1 NAME08 Section variable '${@{VAR}[1]my_var}' name is not uppercase
+    |
+ 31 | ${${VAR}my_var}  11
+ 32 | ${${VAR}my_var${var}}  11
+ 33 | ${@{VAR}[1]my_var}  11
+    | ^^^^^^^^^^^^^^^^^^ NAME08
+ 34 | ${@{VAR}[1]my_var&{var.param}}  11
+    |
+
+test.robot:34:1 NAME08 Section variable '${@{VAR}[1]my_var&{var.param}}' name is not uppercase
+    |
+ 32 | ${${VAR}my_var${var}}  11
+ 33 | ${@{VAR}[1]my_var}  11
+ 34 | ${@{VAR}[1]my_var&{var.param}}  11
+    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NAME08
+    |
+
diff --git a/tests/linter/rules/naming/section_variable_not_uppercase/test_rule.py b/tests/linter/rules/naming/section_variable_not_uppercase/test_rule.py
index 43e8bf6..ecefde9 100644
--- a/tests/linter/rules/naming/section_variable_not_uppercase/test_rule.py
+++ b/tests/linter/rules/naming/section_variable_not_uppercase/test_rule.py
@@ -5,6 +5,14 @@ class TestRuleAcceptance(RuleAcceptance):
     def test_rule(self):
         self.check_rule(src_files=["test.robot"], expected_file="expected_output.txt", test_on_version=">=4")
 
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+            test_on_version=">=4",
+        )
+
     def test_rule_rf3(self):
         # RF3 doesn't recognize nested variables in Variables section
         self.check_rule(src_files=["test.robot"], expected_file="expected_output_rf3.txt", test_on_version="==3.*")
diff --git a/tests/linter/rules/naming/setting_name_not_in_title_case/expected_extended.txt b/tests/linter/rules/naming/setting_name_not_in_title_case/expected_extended.txt
new file mode 100644
index 0000000..f3faa6f
--- /dev/null
+++ b/tests/linter/rules/naming/setting_name_not_in_title_case/expected_extended.txt
@@ -0,0 +1,202 @@
+test.robot:3:1 NAME05 Setting name 'library' not in title or uppercase
+   |
+ 1 | *** Settings ***
+ 2 | Documentation   doc
+ 3 | library         Library
+   | ^^^^^^^ NAME05
+ 4 | resource        resource.robot
+ 5 | variablES       variables.py
+   |
+
+test.robot:4:1 NAME05 Setting name 'resource' not in title or uppercase
+   |
+ 2 | Documentation   doc
+ 3 | library         Library
+ 4 | resource        resource.robot
+   | ^^^^^^^^ NAME05
+ 5 | variablES       variables.py
+ 6 | suite setup     Keyword
+   |
+
+test.robot:5:1 NAME05 Setting name 'variablES' not in title or uppercase
+   |
+ 3 | library         Library
+ 4 | resource        resource.robot
+ 5 | variablES       variables.py
+   | ^^^^^^^^^ NAME05
+ 6 | suite setup     Keyword
+ 7 | suite Teardown  Keyword
+   |
+
+test.robot:6:1 NAME05 Setting name 'suite setup' not in title or uppercase
+   |
+ 4 | resource        resource.robot
+ 5 | variablES       variables.py
+ 6 | suite setup     Keyword
+   | ^^^^^^^^^^^ NAME05
+ 7 | suite Teardown  Keyword
+ 8 | test seTup      Keyword
+   |
+
+test.robot:7:1 NAME05 Setting name 'suite Teardown' not in title or uppercase
+   |
+ 5 | variablES       variables.py
+ 6 | suite setup     Keyword
+ 7 | suite Teardown  Keyword
+   | ^^^^^^^^^^^^^^ NAME05
+ 8 | test seTup      Keyword
+ 9 | Test teardown   Keyword
+   |
+
+test.robot:8:1 NAME05 Setting name 'test seTup' not in title or uppercase
+   |
+ 6 | suite setup     Keyword
+ 7 | suite Teardown  Keyword
+ 8 | test seTup      Keyword
+   | ^^^^^^^^^^ NAME05
+ 9 | Test teardown   Keyword
+10 | force tags      tag
+   |
+
+test.robot:9:1 NAME05 Setting name 'Test teardown' not in title or uppercase
+   |
+ 7 | suite Teardown  Keyword
+ 8 | test seTup      Keyword
+ 9 | Test teardown   Keyword
+   | ^^^^^^^^^^^^^ NAME05
+10 | force tags      tag
+11 | default tags    defaulttag
+   |
+
+test.robot:10:1 NAME05 Setting name 'force tags' not in title or uppercase
+    |
+  8 | test seTup      Keyword
+  9 | Test teardown   Keyword
+ 10 | force tags      tag
+    | ^^^^^^^^^^ NAME05
+ 11 | default tags    defaulttag
+    |
+
+test.robot:11:1 NAME05 Setting name 'default tags' not in title or uppercase
+    |
+  9 | Test teardown   Keyword
+ 10 | force tags      tag
+ 11 | default tags    defaulttag
+    | ^^^^^^^^^^^^ NAME05
+    |
+
+test.robot:16:5 NAME05 Setting name '[documentation]' not in title or uppercase
+    |
+ 14 | *** Test Cases ***
+ 15 | Test Lowercase Settings
+ 16 |     [documentation]  doc
+    |     ^^^^^^^^^^^^^^^ NAME05
+ 17 |     [tags]  sometag
+ 18 |     [setup]  Keyword
+    |
+
+test.robot:17:5 NAME05 Setting name '[tags]' not in title or uppercase
+    |
+ 15 | Test Lowercase Settings
+ 16 |     [documentation]  doc
+ 17 |     [tags]  sometag
+    |     ^^^^^^ NAME05
+ 18 |     [setup]  Keyword
+ 19 |     [template]  template
+    |
+
+test.robot:18:5 NAME05 Setting name '[setup]' not in title or uppercase
+    |
+ 16 |     [documentation]  doc
+ 17 |     [tags]  sometag
+ 18 |     [setup]  Keyword
+    |     ^^^^^^^ NAME05
+ 19 |     [template]  template
+ 20 |     [timeout]  timeout
+    |
+
+test.robot:19:5 NAME05 Setting name '[template]' not in title or uppercase
+    |
+ 17 |     [tags]  sometag
+ 18 |     [setup]  Keyword
+ 19 |     [template]  template
+    |     ^^^^^^^^^^ NAME05
+ 20 |     [timeout]  timeout
+ 21 |     Pass
+    |
+
+test.robot:20:5 NAME05 Setting name '[timeout]' not in title or uppercase
+    |
+ 18 |     [setup]  Keyword
+ 19 |     [template]  template
+ 20 |     [timeout]  timeout
+    |     ^^^^^^^^^ NAME05
+ 21 |     Pass
+ 22 |     Keyword
+    |
+
+test.robot:24:5 NAME05 Setting name '[teardown]' not in title or uppercase
+    |
+ 22 |     Keyword
+ 23 |     One More
+ 24 |     [teardown]  Keyword
+    |     ^^^^^^^^^^ NAME05
+    |
+
+test.robot:51:5 NAME05 Setting name '[documentation]' not in title or uppercase
+    |
+ 49 | *** Keywords ***
+ 50 | Keyword Lowercase Settings
+ 51 |     [documentation]  this is doc
+    |     ^^^^^^^^^^^^^^^ NAME05
+ 52 |     [tags]  sometag
+ 53 |     [arguments]  arg1  arg2
+    |
+
+test.robot:52:5 NAME05 Setting name '[tags]' not in title or uppercase
+    |
+ 50 | Keyword Lowercase Settings
+ 51 |     [documentation]  this is doc
+ 52 |     [tags]  sometag
+    |     ^^^^^^ NAME05
+ 53 |     [arguments]  arg1  arg2
+ 54 |     [timeout]  timeout
+    |
+
+test.robot:53:5 NAME05 Setting name '[arguments]' not in title or uppercase
+    |
+ 51 |     [documentation]  this is doc
+ 52 |     [tags]  sometag
+ 53 |     [arguments]  arg1  arg2
+    |     ^^^^^^^^^^^ NAME05
+ 54 |     [timeout]  timeout
+ 55 |     No Operation
+    |
+
+test.robot:54:5 NAME05 Setting name '[timeout]' not in title or uppercase
+    |
+ 52 |     [tags]  sometag
+ 53 |     [arguments]  arg1  arg2
+ 54 |     [timeout]  timeout
+    |     ^^^^^^^^^ NAME05
+ 55 |     No Operation
+ 56 |     Pass
+    |
+
+test.robot:59:5 NAME05 Setting name '[teardown]' not in title or uppercase
+    |
+ 57 |     No Operation
+ 58 |     Fail
+ 59 |     [teardown]  Teardown
+    |     ^^^^^^^^^^ NAME05
+ 60 |     [return]  value
+    |
+
+test.robot:60:5 NAME05 Setting name '[return]' not in title or uppercase
+    |
+ 58 |     Fail
+ 59 |     [teardown]  Teardown
+ 60 |     [return]  value
+    |     ^^^^^^^^ NAME05
+    |
+
diff --git a/tests/linter/rules/naming/setting_name_not_in_title_case/test_rule.py b/tests/linter/rules/naming/setting_name_not_in_title_case/test_rule.py
index cba6753..4a48afe 100644
--- a/tests/linter/rules/naming/setting_name_not_in_title_case/test_rule.py
+++ b/tests/linter/rules/naming/setting_name_not_in_title_case/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/naming/test_case_name_is_empty/expected_extended.txt b/tests/linter/rules/naming/test_case_name_is_empty/expected_extended.txt
new file mode 100644
index 0000000..5c40191
--- /dev/null
+++ b/tests/linter/rules/naming/test_case_name_is_empty/expected_extended.txt
@@ -0,0 +1,8 @@
+test.robot:4:1 NAME11 Test case name is empty
+   |
+ 2 |
+ 3 | #  no test case name!!!
+ 4 |     Log To Console  hello
+   | ^ NAME11
+   |
+
diff --git a/tests/linter/rules/naming/test_case_name_is_empty/test_rule.py b/tests/linter/rules/naming/test_case_name_is_empty/test_rule.py
index e0553eb..931c17e 100644
--- a/tests/linter/rules/naming/test_case_name_is_empty/test_rule.py
+++ b/tests/linter/rules/naming/test_case_name_is_empty/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")
+
+    def test_extended(self):
+        self.check_rule(expected_file="expected_extended.txt", output_format="extended")
diff --git a/tests/linter/rules/naming/underscore_in_keyword_name/expected_extended.txt b/tests/linter/rules/naming/underscore_in_keyword_name/expected_extended.txt
new file mode 100644
index 0000000..3d2bfc8
--- /dev/null
+++ b/tests/linter/rules/naming/underscore_in_keyword_name/expected_extended.txt
@@ -0,0 +1,43 @@
+test.robot:11:5 NAME04 Underscores in keyword name 'No_Operation'
+    |
+  9 |     Pass
+ 10 |     Keyword
+ 11 |     No_Operation
+    |     ^^^^^^^^^^^^ NAME04
+    |
+
+test.robot:17:19 NAME04 Underscores in keyword name 'With_Underscore'
+    |
+ 15 |
+ 16 | Templated test
+ 17 |     [Template]    With_Underscore
+    |                   ^^^^^^^^^^^^^^^ NAME04
+    |
+
+test.robot:33:12 NAME04 Underscores in keyword name 'Run_keywords'
+    |
+ 31 | Run Keywords
+ 32 |     Run Keyword If    ${condition}
+ 33 |     ...    Run_keywords
+    |            ^^^^^^^^^^^^ NAME04
+ 34 |     ...        Name    ${arg}    AND
+ 35 |     ...        _Underscore    1    AND
+    |
+
+test.robot:35:16 NAME04 Underscores in keyword name '_Underscore'
+    |
+ 33 |     ...    Run_keywords
+ 34 |     ...        Name    ${arg}    AND
+ 35 |     ...        _Underscore    1    AND
+    |                ^^^^^^^^^^^ NAME04
+ 36 |     ...        Under_sc ore
+    |
+
+test.robot:36:16 NAME04 Underscores in keyword name 'Under_sc ore'
+    |
+ 34 |     ...        Name    ${arg}    AND
+ 35 |     ...        _Underscore    1    AND
+ 36 |     ...        Under_sc ore
+    |                ^^^^^^^^^^^^ NAME04
+    |
+
diff --git a/tests/linter/rules/naming/underscore_in_keyword_name/test_rule.py b/tests/linter/rules/naming/underscore_in_keyword_name/test_rule.py
index f65d654..cf88834 100644
--- a/tests/linter/rules/naming/underscore_in_keyword_name/test_rule.py
+++ b/tests/linter/rules/naming/underscore_in_keyword_name/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", "templated_suite.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/naming/wrong_case_in_keyword_name/expected_extended.txt b/tests/linter/rules/naming/wrong_case_in_keyword_name/expected_extended.txt
new file mode 100644
index 0000000..a128728
--- /dev/null
+++ b/tests/linter/rules/naming/wrong_case_in_keyword_name/expected_extended.txt
@@ -0,0 +1,215 @@
+test.robot:3:14 NAME02 Keyword name 'keyword' does not follow case convention
+   |
+ 1 | *** Settings ***
+ 2 | Documentation  doc
+ 3 | Suite Setup  keyword
+   |              ^^^^^^^ NAME02
+ 4 | Suite Teardown  keyword
+ 5 | Test Setup  keyword
+   |
+
+test.robot:4:17 NAME02 Keyword name 'keyword' does not follow case convention
+   |
+ 2 | Documentation  doc
+ 3 | Suite Setup  keyword
+ 4 | Suite Teardown  keyword
+   |                 ^^^^^^^ NAME02
+ 5 | Test Setup  keyword
+ 6 | Test Teardown  keyword
+   |
+
+test.robot:5:13 NAME02 Keyword name 'keyword' does not follow case convention
+   |
+ 3 | Suite Setup  keyword
+ 4 | Suite Teardown  keyword
+ 5 | Test Setup  keyword
+   |             ^^^^^^^ NAME02
+ 6 | Test Teardown  keyword
+   |
+
+test.robot:6:16 NAME02 Keyword name 'keyword' does not follow case convention
+   |
+ 4 | Suite Teardown  keyword
+ 5 | Test Setup  keyword
+ 6 | Test Teardown  keyword
+   |                ^^^^^^^ NAME02
+   |
+
+test.robot:14:14 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 12 |     [Documentation]  doc
+ 13 |     [Tags]  sometag
+ 14 |     [Setup]  keyword
+    |              ^^^^^^^ NAME02
+ 15 |     pass
+ 16 |     Keyword
+    |
+
+test.robot:15:5 NAME02 Keyword name 'pass' does not follow case convention
+    |
+ 13 |     [Tags]  sometag
+ 14 |     [Setup]  keyword
+ 15 |     pass
+    |     ^^^^ NAME02
+ 16 |     Keyword
+ 17 |     One More
+    |
+
+test.robot:18:17 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 16 |     Keyword
+ 17 |     One More
+ 18 |     [Teardown]  keyword
+    |                 ^^^^^^^ NAME02
+    |
+
+test.robot:36:19 NAME02 Keyword name 'lowercase' does not follow case convention
+    |
+ 34 |
+ 35 | Templated test
+ 36 |     [Template]    lowercase
+    |                   ^^^^^^^^^ NAME02
+ 37 |     Pass
+    |
+
+test.robot:41:1 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 39 |
+ 40 | *** Keywords ***
+ 41 | keyword
+    | ^^^^^^^ NAME02
+ 42 |     [Documentation]  this is doc
+ 43 |     No Operation
+    |
+
+test.robot:66:5 NAME02 Keyword name 'Keyword_With_underscores' does not follow case convention
+    |
+ 64 |     Take2 Is Capitalized
+ 65 |     Quoted "Strings" Are Fine Too
+ 66 |     Keyword_With_underscores
+    |     ^^^^^^^^^^^^^^^^^^^^^^^^ NAME02
+    |
+
+test.robot:112:1 NAME02 Keyword name 'Dot in name foo.bar' does not follow case convention
+     |
+ 112 | Dot in name foo.bar
+     | ^^^^^^^^^^^^^^^^^^^ NAME02
+ 113 |     No Operation
+     |
+
+templated_suite.robot:2:18 NAME02 Keyword name 'lowercase' does not follow case convention
+   |
+ 1 | *** Settings ***
+ 2 | Test Template    lowercase
+   |                  ^^^^^^^^^ NAME02
+   |
+
+run_keywords.robot:2:32 NAME02 Keyword name 'some keyword' does not follow case convention
+   |
+ 1 | *** Settings ***
+ 2 | Suite Setup    Run Keywords    some keyword  AND  SOME_Keyword
+   |                                ^^^^^^^^^^^^ NAME02
+   |
+
+run_keywords.robot:8:12 NAME02 Keyword name 'Run Keyword if' does not follow case convention
+   |
+ 6 | Test with run keywords
+ 7 |     Run Keyword And Continue On Failure
+ 8 |     ...    Run Keyword if    ${True}
+   |            ^^^^^^^^^^^^^^ NAME02
+ 9 |     ...      Run keywords
+10 |     ...        log    foo    AND
+   |
+
+run_keywords.robot:9:14 NAME02 Keyword name 'Run keywords' does not follow case convention
+   |
+ 7 |     Run Keyword And Continue On Failure
+ 8 |     ...    Run Keyword if    ${True}
+ 9 |     ...      Run keywords
+   |              ^^^^^^^^^^^^ NAME02
+10 |     ...        log    foo    AND
+11 |     ...        Log    bar
+   |
+
+run_keywords.robot:10:16 NAME02 Keyword name 'log' does not follow case convention
+    |
+  8 |     ...    Run Keyword if    ${True}
+  9 |     ...      Run keywords
+ 10 |     ...        log    foo    AND
+    |                ^^^ NAME02
+ 11 |     ...        Log    bar
+ 12 |     ...    ELSE
+    |
+
+run_keywords.robot:13:14 NAME02 Keyword name 'log' does not follow case convention
+    |
+ 11 |     ...        Log    bar
+ 12 |     ...    ELSE
+ 13 |     ...      log    baz
+    |              ^^^ NAME02
+    |
+
+run_keywords.robot:17:35 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 15 | Settings
+ 16 |     [Setup]    Keyword
+ 17 |     [Teardown]    Run Keywords    keyword    Keyword
+    |                                   ^^^^^^^ NAME02
+    |
+
+run_keywords.robot:21:47 NAME02 Keyword name 'run Keywords' does not follow case convention
+    |
+ 19 | *** Keywords ***
+ 20 | Keyword With Run Keywords
+ 21 |     Builtin.Run Keyword_If    ${condition}    run Keywords    keyword    Keyword
+    |                                               ^^^^^^^^^^^^ NAME02
+ 22 |     Run Keywords
+ 23 |     ...    Log    a
+    |
+
+run_keywords.robot:21:63 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 19 | *** Keywords ***
+ 20 | Keyword With Run Keywords
+ 21 |     Builtin.Run Keyword_If    ${condition}    run Keywords    keyword    Keyword
+    |                                                               ^^^^^^^ NAME02
+ 22 |     Run Keywords
+ 23 |     ...    Log    a
+    |
+
+run_keywords.robot:25:12 NAME02 Keyword name 'log' does not follow case convention
+    |
+ 23 |     ...    Log    a
+ 24 |     ...    AND
+ 25 |     ...    log    b
+    |            ^^^ NAME02
+ 26 |     ...    AND
+ 27 |     ...    Log    c
+    |
+
+run_keywords.robot:31:17 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 29 | More Branches
+ 30 |     Run Keyword If    ${condition
+ 31 |     ...         keyword
+    |                 ^^^^^^^ NAME02
+ 32 |     ...    ELSE IF    ${other_cond}
+ 33 |     ...        other_keyword
+    |
+
+run_keywords.robot:33:16 NAME02 Keyword name 'other_keyword' does not follow case convention
+    |
+ 31 |     ...         keyword
+ 32 |     ...    ELSE IF    ${other_cond}
+ 33 |     ...        other_keyword
+    |                ^^^^^^^^^^^^^ NAME02
+    |
+
+run_keywords.robot:36:35 NAME02 Keyword name 'keyword' does not follow case convention
+    |
+ 34 |
+ 35 | Settings
+ 36 |     [Teardown]    Run Keywords    keyword    Keyword
+    |                                   ^^^^^^^ NAME02
+    |
+
diff --git a/tests/linter/rules/naming/wrong_case_in_keyword_name/test_rule.py b/tests/linter/rules/naming/wrong_case_in_keyword_name/test_rule.py
index 7153d81..a1d2d22 100644
--- a/tests/linter/rules/naming/wrong_case_in_keyword_name/test_rule.py
+++ b/tests/linter/rules/naming/wrong_case_in_keyword_name/test_rule.py
@@ -7,6 +7,13 @@ class TestRuleAcceptance(RuleAcceptance):
             src_files=["test.robot", "templated_suite.robot", "run_keywords.robot"], expected_file="expected_output.txt"
         )
 
+    def test_extended(self):
+        self.check_rule(
+            src_files=["test.robot", "templated_suite.robot", "run_keywords.robot"],
+            expected_file="expected_extended.txt",
+            output_format="extended",
+        )
+
     def test_rule_pabot(self):
         self.check_rule(src_files=["pabot_run_keywords.robot"], expected_file="expected_output_pabot.txt")