Skip to content

Handle comparison to negative non-integer in expect_identical_linter#2411

Merged
IndrajeetPatil merged 14 commits into
r-lib:mainfrom
Bisaloo:negative-expect-equal
Jun 8, 2024
Merged

Handle comparison to negative non-integer in expect_identical_linter#2411
IndrajeetPatil merged 14 commits into
r-lib:mainfrom
Bisaloo:negative-expect-equal

Conversation

@Bisaloo

@Bisaloo Bisaloo commented Dec 10, 2023

Copy link
Copy Markdown
Collaborator

Fix #2410

@codecov-commenter

codecov-commenter commented Dec 10, 2023

Copy link
Copy Markdown

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 98.65%. Comparing base (fc2268f) to head (1b4b058).
Report is 7 commits behind head on main.

Current head 1b4b058 differs from pull request most recent head 79334a8

Please upload reports for the commit 79334a8 to get more accurate results.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2411      +/-   ##
==========================================
+ Coverage   98.15%   98.65%   +0.49%     
==========================================
  Files         125      125              
  Lines        5738     5631     -107     
==========================================
- Hits         5632     5555      -77     
+ Misses        106       76      -30     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Comment thread R/expect_identical_linter.R Outdated
Comment thread R/expect_identical_linter.R Outdated
Comment thread NEWS.md Outdated
Comment thread R/expect_identical_linter.R Outdated
or following-sibling::expr[
OP-MINUS
and count(expr) = 1
and expr[NUM_CONST[contains(text(), '.')]]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
and expr[NUM_CONST[contains(text(), '.')]]
and expr/NUM_CONST[contains(text(), '.')]

nit: I've gravitated to this style to save a few characters (and also to avoid counting+matching nested ] visually)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Where is the cut-off?

From what I understand, I could also write

expr[1][SYMBOL_FUNCTION_CALL[text() = 'c']]

as

expr[1]/SYMBOL_FUNCTION_CALL/text() = 'c'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think the last condition belongs in [] -- otherwise it can get hard to visually parse operator presence of = vs. nearby logical operators like and/or. IINM occasionally we have to let /text() "out" e.g. to compare to the text() of another node, but it's best avoided.

We don't really have an XPath style guide, so these are just my thoughts from writing many of these, you or other lintr authors may disagree.

Comment thread R/expect_identical_linter.R Outdated
@@ -69,6 +69,11 @@ expect_identical_linter <- function() {
and expr[NUM_CONST[contains(text(), '.')]]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Hmm I saw this too -- so we haven't fully restored parity yet in this PR.

expect_equal(x, 1.02)     # no lint
expect_equal(x, c(1.02))  # no lint
expect_equal(x, -1.02)    # no lint
expect_equal(x, c(-1.02)) # lint!

Let's at least get parity in this PR. I would put all of the conditions on following-sibling::expr[] together btw, like:

following-sibling::expr[
  (
    expr[1]/SYMBOL_FUNCTION_CALL[text() = 'c']
    and expr/NUM_CONST[contains(text(), '.')]
  ) or (
    NUM_CONST[contains(text(), '.')]
  ) or (
    OP-MINUS ...
  )
]

Since NUM_CONST[contains(text(), '.')] is getting repeated so much let's extract it to a variable too to save space.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

BTW, could you also test if the following lints?

expect_equal(x, c(1.02, y))

I think it's something to possible address in follow-up. I'm wondering if maybe it was intentional not to lint c(1.02, y) because there's some part of the expectation that uses an "exact" number so we "should" skip linting on the same principle as just 1.02? In which case we shouldn't lint 1.01-y either 🤔

@AshesITR any thoughts? This cut-out does feel a bit arbitrary, probably by necessity at some level. Wondering how to close the loop here for this PR, and what can be deferred to a more holistic follow-up.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

lintr::lint(
  text = "expect_equal(x, c(1.02, y))", 
  linters = lintr::expect_identical_linter()
)

Created on 2023-12-11 with reprex v2.0.2

It doesn't lint.

@Bisaloo Bisaloo force-pushed the negative-expect-equal branch from ebcebc8 to df79a10 Compare June 7, 2024 09:24
@Bisaloo

Bisaloo commented Jun 7, 2024

Copy link
Copy Markdown
Collaborator Author

All tests are now passing. I'm not super happy about the complexity of this xpath but I can't think of something simpler at the moment. Please let me know if you have a better way in mind.

@IndrajeetPatil IndrajeetPatil added the feature a feature request or enhancement label Jun 7, 2024
@Bisaloo

Bisaloo commented Jun 7, 2024

Copy link
Copy Markdown
Collaborator Author

#963 may be a good way to simplify the code eventually.

expect_lint("expect_equal(x, 1.034)", NULL, linter)
expect_lint("expect_equal(x, -1.034)", NULL, linter)
expect_lint("expect_equal(x, c(-1.034))", NULL, linter)
expect_lint("expect_equal(x, -c(1.034))", NULL, linter)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Is this case relevant in practice?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I'm on the fence.

On the one hand, it should be caught be unnecessary_concatenation_linter() and converted to the standard case. On the other hand, it's not just a false negative; not treating this case would lead us to produce incorrect advice.

Comment thread R/expect_identical_linter.R
@IndrajeetPatil IndrajeetPatil merged commit ee951ab into r-lib:main Jun 8, 2024
@Bisaloo Bisaloo deleted the negative-expect-equal branch July 19, 2025 09:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature a feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

expect_identical_linter() doesn't skip cases with negative numeric constant

5 participants