Skip to content

Conversation

@kislayykumar
Copy link

@kislayykumar kislayykumar commented Sep 13, 2025

Fix for #748 (comment)

Summary by CodeRabbit

  • New Features

    • Added a lint that warns when test objects contain comments and recommends concise, self‑explanatory test names.
  • Tests

    • Added unit tests validating the lint’s behavior, name, and guidance.
    • Increased a test timeout to 6 minutes to accommodate longer validation runs.

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
@coderabbitai
Copy link

coderabbitai bot commented Sep 13, 2025

Walkthrough

Adds a package-private lint LtTestComment that detects XMIR test objects (names starting with '+') containing meta comments and reports a WARNING defect test-has-comment; adds unit tests for the lint and adjusts a test timeout annotation in an existing test.

Changes

Cohort / File(s) Summary
New lint implementation
src/main/java/org/eolang/lints/LtTestComment.java
Adds final class LtTestComment implements Lint<XML>: scans XMIR with //o[@name and starts-with(@name,'+')], checks for .//meta[@key='comment'], emits defect test-has-comment (severity WARNING) with line parsed from @line; implements defects, motive, and name.
Unit tests for lint
src/test/java/org/eolang/lints/LtTestCommentTest.java
Adds JUnit 5 tests using JCabi XMLDocument and Hamcrest: verifies no defects when a +test has no comment and when no test object exists; asserts motive() contains guidance and name() equals test-has-comment.
Test timeout tweak
src/test/java/org/eolang/lints/LtByXslTest.java
Changes @Timeout(180L) to @Timeout(value = 6, unit = TimeUnit.MINUTES) on validatesEoPacksForErrors; no logic change.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant LintRunner
    participant LtTestComment
    participant XMIR as "XMIR Document"

    LintRunner->>LtTestComment: defects(XML)
    LtTestComment->>XMIR: select //o[@name and starts-with(@name,'+')]
    XMIR-->>LtTestComment: matching <o> nodes
    loop each +test node
        LtTestComment->>XMIR: search .//meta[@key='comment']
        alt comment present
            LtTestComment-->>LintRunner: report defect id="test-has-comment" severity=WARNING line=@line
        else
            LtTestComment-->>LintRunner: no defect
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

core

Suggested reviewers

  • h1alexbel
  • yegor256

Poem

I hop through XMIR with twitchy whiskers bright,
Finding plus-sign tests in morning light.
"Let names speak," I nibble, gentle and clear,
A tiny warning carrot nudges near.
Tidy tests, happy bunnies — hop on, delight! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title identifies that a lint was added for comments in test code, which matches the new LtTestComment rule that flags comments in XML test objects; however the phrase "duplicate test names" is misleading and the overall phrasing is awkward and not fully concise. The title is therefore partially related to the changeset but could confuse a reviewer about the primary intent. It should be tightened to more clearly reflect the actual lint behavior.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/test/java/org/eolang/lints/LtTestCommentTest.java (1)

3-3: Remove unused import.

Xnav isn’t used in this test class.

-import com.github.lombrozo.xnav.Xnav;
src/main/java/org/eolang/lints/LtTestComment.java (1)

23-23: Avoid zero-capacity allocation.

Use default constructor; capacity hint of 0 is misleading.

-        final Collection<Defect> defects = new ArrayList<>(0);
+        final Collection<Defect> defects = new ArrayList<>();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b1af474 and 41d151e.

📒 Files selected for processing (2)
  • src/main/java/org/eolang/lints/LtTestComment.java (1 hunks)
  • src/test/java/org/eolang/lints/LtTestCommentTest.java (1 hunks)
🧰 Additional context used
🪛 GitHub Actions: copyrights
src/test/java/org/eolang/lints/LtTestCommentTest.java

[warning] 1-1: Missed copyright header.

src/main/java/org/eolang/lints/LtTestComment.java

[warning] 1-1: Missed copyright header.

🪛 GitHub Actions: qulice
src/test/java/org/eolang/lints/LtTestCommentTest.java

[error] 1-1: Test name 'motiveReturnsExpectedString' doesn't follow naming rules, because the test name has to be written using present tense.


[error] 1-1: Method 'motiveReturnsExpectedString' has assertion without message: 'MatcherAssert.assertThat(lint.motive(), Matchers.containsString("Comments in test objects are discouraged"))'. Please add the explanation message to make the test more readable.


[error] 1-1: Test name 'nameReturnsExpectedValue' doesn't follow naming rules, because the test name has to be written using present tense.


[error] 1-1: Method 'nameReturnsExpectedValue' has assertion without message: 'MatcherAssert.assertThat(lint.name(), Matchers.equalTo("test-has-comment"))'. Please add the explanation message to make the test more readable.


[error] 1-1: Test name 'returnsNoDefectWhenTestObjectHasNoComment' doesn't follow naming rules, because the test name has to be written using present tense.


[error] 1-1: Method 'returnsNoDefectWhenTestObjectHasNoComment' has assertion without message: 'MatcherAssert.assertThat(defects, Matchers.empty())'. Please add the explanation message to make the test more readable.


[error] 1-1: Test name 'returnsNoDefectWhenNoTestObjectPresent' doesn't follow naming rules, because test name doesn't have to contain the word 'test'.


[error] 1-1: Method 'returnsNoDefectWhenNoTestObjectPresent' has assertion without message: 'MatcherAssert.assertThat(defects, Matchers.empty())'. Please add the explanation message to make the test more readable.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: ort
  • GitHub Check: mvn (windows-2022, 11)
  • GitHub Check: mvn (ubuntu-24.04, 21)
  • GitHub Check: mvn (macos-15, 11)
  • GitHub Check: mvn (windows-2022, 21)
  • GitHub Check: mvn (macos-15, 21)
  • GitHub Check: deep
  • GitHub Check: mvn (ubuntu-24.04, 11)
🔇 Additional comments (1)
src/main/java/org/eolang/lints/LtTestComment.java (1)

1-4: Align license header with repo expectations.

CI warns about a missing/mismatched header. Ensure this header exactly matches what Qulice expects in this repository (copy from an existing passing file).

Would you like me to scan the repo for the canonical header and propose an exact replacement?

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/java/org/eolang/lints/LtTestComment.java (2)

25-33: Single-pass XPath to avoid extra allocations

You can filter objects with comments directly in XPath and drop the per-object comments traversal.

-        final List<Xnav> objects = xml
-            .path("//o[@name and starts-with(@name, '+')]")
-            .collect(Collectors.toList());
-        for (final Xnav object : objects) {
-            final List<Xnav> comments = object
-                .path(".//meta[@key='comment']")
-                .collect(Collectors.toList());
-            if (!comments.isEmpty()) {
-                defects.add(
+        final List<Xnav> objects = xml
+            .path("//o[@name and starts-with(@name, '+')][.//meta[@key='comment']]")
+            .collect(Collectors.toList());
+        for (final Xnav object : objects) {
+            defects.add(
                 new Defect.Default(
                     "test-has-comment",
                     Severity.WARNING,
-                    new OnDefault(xmir).get(),
-                    Integer.parseInt(object.attribute("line").text().orElse("0")),
+                    new OnDefault(xmir).get(),
+                    Integer.parseInt(object.attribute("line").text().orElse("0")),
                     "Test object contains a comment. Prefer short, self-explanatory test names instead of documenting them."
                 )
             );
-            }
-        }
+        }

24-24: Avoid re-instantiating OnDefault inside the loop

Minor allocation nit: create it once and reuse origin.get().

-        final Xnav xml = new Xnav(xmir.inner());
+        final Xnav xml = new Xnav(xmir.inner());
+        final OnDefault origin = new OnDefault(xmir);
...
-                        new OnDefault(xmir).get(),
+                        origin.get(),

Also applies to: 37-37

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f27bdef and 894f58a.

📒 Files selected for processing (2)
  • src/main/java/org/eolang/lints/LtTestComment.java (1 hunks)
  • src/test/java/org/eolang/lints/LtTestCommentTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/org/eolang/lints/LtTestCommentTest.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: mvn (ubuntu-24.04, 21)
  • GitHub Check: mvn (ubuntu-24.04, 11)
  • GitHub Check: mvn (windows-2022, 21)
  • GitHub Check: mvn (macos-15, 21)
  • GitHub Check: mvn (macos-15, 11)
  • GitHub Check: mvn (windows-2022, 11)
  • GitHub Check: deep
  • GitHub Check: ort
🔇 Additional comments (3)
src/main/java/org/eolang/lints/LtTestComment.java (3)

25-27: Root-agnostic XPath fix LGTM

Using //o[@name and starts-with(@name, '+')] correctly finds test objects regardless of the document root.


29-31: Descendant search for comment meta is correct

.path(".//meta[@key='comment']") will catch comments not only as direct children; aligns with the intent of the lint.


29-32: Confirm scope: should comments in nested helper objects trigger this lint?

Current descendant search flags any meta[@key='comment'] under a test object, including nested helper objects’ comments. If the rule intends to only forbid comments attached to the test object itself, restrict to direct child metas. Otherwise keep as-is. Consider adding a unit test with a nested object comment to lock the intended behavior.

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
@yegor256
Copy link
Member

@kislayykumar Thanks for your contribution, we appreciate it! Before we can merge this pull request, we need to see all CI workflows pass without errors. We can't merge the pull request into the master branch unless all workflows are green. Try to fix them, also paying attention to code style issues.

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/test/java/org/eolang/lints/LtByXslTest.java (1)

362-362: 7-minute timeout is excessive; prefer expressing as minutes and revisit root cause

Bumping to 420s can hide regressions. Since this test is tagged "deep", consider keeping a tighter budget or splitting work; if long runtime is unavoidable, make the timeout self-explanatory.

Apply for readability:

-    @Timeout(420L)
+    @Timeout(value = 7, unit = TimeUnit.MINUTES)

Add import:

import java.util.concurrent.TimeUnit;

Please confirm typical runtime locally and on CI, and whether "deep" tests are excluded from regular PR runs (kept for nightly).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3240018 and 0b983e9.

📒 Files selected for processing (1)
  • src/test/java/org/eolang/lints/LtByXslTest.java (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: mvn (macos-15, 11)
  • GitHub Check: deep
  • GitHub Check: mvn (windows-2022, 21)
  • GitHub Check: mvn (macos-15, 21)
  • GitHub Check: mvn (ubuntu-24.04, 21)
  • GitHub Check: mvn (windows-2022, 11)
  • GitHub Check: mvn (ubuntu-24.04, 11)
  • GitHub Check: ort

Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
Signed-off-by: KISLAY KUMAR <135631873+kislayykumar@users.noreply.github.com>
@kislayykumar
Copy link
Author

Hi @yegor256

Kindly review the PR and merge it. All workflows and checks have passed.

Thank you!

@yegor256
Copy link
Member

@h1alexbel please, review this one

@yegor256 yegor256 requested a review from h1alexbel September 14, 2025 15:21
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
src/test/java/org/eolang/lints/LtTestCommentTest.java (1)

1-4: Header fixed — matches repo SPDX style.

This resolves the copyrights check.

🧹 Nitpick comments (4)
src/test/java/org/eolang/lints/LtTestCommentTest.java (4)

22-34: Drop unnecessary throws in test signature.

No IO occurs; remove throws IOException for cleanliness.

-    void reportsNoDefectsWhenNoCommentPresent() throws IOException {
+    void reportsNoDefectsWhenNoCommentPresent() {

36-48: Same: remove redundant throws.

-    void reportsNoDefectsWhenNoObjectPresent() throws IOException {
+    void reportsNoDefectsWhenNoObjectPresent() {

50-58: And here: no IO — remove throws.

-    void containsGuidanceInMotive() throws IOException {
+    void containsGuidanceInMotive() {

Also remove the now‑unused import:

-import java.io.IOException;

68-70: Add a positive test (comment present → defect reported).

Covers the core path and prevents regressions.

 }
+
+    @Test
+    void reportsDefectWhenTestObjectHasComment() {
+        final XML xml = new XMLDocument(
+            "<program>" +
+                "<object name='foo' line='10'>" +
+                    "<o name='+test' line='12'>" +
+                        "<meta key='comment' line='13'/>" +
+                    "</o>" +
+                "</object>" +
+            "</program>"
+        );
+        final LtTestComment lint = new LtTestComment();
+        final Collection<Defect> defects = lint.defects(xml);
+        MatcherAssert.assertThat(
+            "Should report exactly one defect when a test object has a comment",
+            defects,
+            Matchers.hasSize(1)
+        );
+    }
+
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 306eb56 and 0cf41ff.

📒 Files selected for processing (2)
  • src/test/java/org/eolang/lints/LtByXslTest.java (2 hunks)
  • src/test/java/org/eolang/lints/LtTestCommentTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/test/java/org/eolang/lints/LtByXslTest.java
🔇 Additional comments (1)
src/test/java/org/eolang/lints/LtTestCommentTest.java (1)

60-68: LGTM: stable id and assertion message.

Copy link
Member

@h1alexbel h1alexbel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar take a look, please

* Lint that warns if a comment is present at a test object.
* @since 0.0.59
*/
final class LtTestComment implements Lint<XML> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar looks like we can have this lint in XSL, there are no restrictions to implement it in Java, I believe. WDYT?

public Collection<Defect> defects(final XML xmir) throws IOException {
final Collection<Defect> defects = new ArrayList<>(0);
final Xnav xml = new Xnav(xmir.inner());
final List<Xnav> objects = xml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar this variable seems to be redundant, we can inlline it in the forEach loop

.path("//o[@name and starts-with(@name, '+')]")
.collect(Collectors.toList());
for (final Xnav object : objects) {
final List<Xnav> comments = object
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar redundant variable, we should inline it in the if. Also, read this, please: https://www.yegor256.com/2015/09/01/redundant-variables-are-evil.html


@Override
public String motive() throws IOException {
return "Avoid comments in test objects; use clear test names.";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar let's write more descriptive motive for lint. Please check src/main/resources/org/eolang/motives as reference for convention

final XML xml = new XMLDocument(
"<program><object name='foo' line='10'><o name='+test' line='12'></o></object></program>"
);
final LtTestComment lint = new LtTestComment();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar lint variable can be inlined


@Test
void containsGuidanceInMotive() throws IOException {
final LtTestComment lint = new LtTestComment();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar lint variable can be inlined


@Test
void returnsStableId() {
final LtTestComment lint = new LtTestComment();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar lint variable can be inlined


@Test
void reportsNoDefectsWhenNoCommentPresent() throws IOException {
final XML xml = new XMLDocument(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar let's use org.eolang.parser.EoSyntax for constructing EO program

*
* @since 0.0.1
*/
final class LtTestCommentTest {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar as @coderabbitai outlined, let's introduce test that would check how lint works for tests that have comments above:

[] > foo
  # This test checks how my object works:
  [] +> calculates-critical-path

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@h1alexbel I'll add a test case that verifies the lint correctly detects comments in test objects. Let me generate the test method that uses your EO example:

@Test
void detectsCommentInTestObject() throws IOException {
    final XML xml = new XMLDocument(
        String.join(
            "",
            "<?xml version='1.0' encoding='UTF-8'?>",
            "<program>",
            "<objects>",
            "<o abstract='true' line='1' name='foo'>",
            "<o line='3' name='+calculates-critical-path'>",
            "<meta key='comment' value='This test checks how my object works:'/>",
            "</o>",
            "</o>",
            "</objects>",
            "</program>"
        )
    );
    final Collection<Defect> defects = new LtTestComment().defects(xml);
    MatcherAssert.assertThat(
        "Should detect comment in test object",
        defects,
        Matchers.hasSize(1)
    );
    final Defect defect = defects.iterator().next();
    MatcherAssert.assertThat(
        "Defect should have correct ID",
        defect.name(),
        Matchers.equalTo("test-has-comment")
    );
    MatcherAssert.assertThat(
        "Defect should have correct message",
        defect.message(),
        Matchers.equalTo("Test object contains a comment. Prefer self-explanatory test names.")
    );
}

This test case:

  1. Creates XML representing your EO code example with a test object +calculates-critical-path that has a comment
  2. Verifies that LtTestComment.defects() finds exactly one defect
  3. Checks that the defect has the correct ID and message as expected from the lint implementation

The XML structure follows the XMIR format where the comment from EO code gets converted to a <meta key='comment' value='...'/> element, which is what the LtTestComment lint searches for.

.collect(Collectors.toList());
for (final Xnav object : objects) {
final List<Xnav> comments = object
.path(".//meta[@key='comment']")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kislayykumar In EO we have this:

[] > foo
  # Comment is here.
  [] +> my-test

After parsing, we have the following XMIR:

<object >
   <comments>
      <comment line="3">Comment is here</comment>
   </comments>
   <o line="1" name="foo" pos="0">
      <o base="ξ" line="1" name="xi🌵" pos="0"/>
      <o line="3" name="+my-test" pos="2">
         <o base="ξ" line="3" name="xi🌵" pos="2"/>
      </o>
   </o>
</object>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants