Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle comparison to negative non-integer in expect_identical_linter #2411

Merged
merged 14 commits into from
Jun 8, 2024

Conversation

Bisaloo
Copy link
Contributor

@Bisaloo Bisaloo commented Dec 10, 2023

Fix #2410

@codecov-commenter
Copy link

codecov-commenter commented Dec 10, 2023

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.

R/expect_identical_linter.R Outdated Show resolved Hide resolved
NEWS.md Outdated Show resolved Hide resolved
or following-sibling::expr[
OP-MINUS
and count(expr) = 1
and expr[NUM_CONST[contains(text(), '.')]]
Copy link
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
Contributor 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
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.

@@ -69,6 +69,11 @@ expect_identical_linter <- function() {
and expr[NUM_CONST[contains(text(), '.')]]
Copy link
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
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
Contributor 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
Copy link
Contributor Author

Bisaloo commented Jun 7, 2024

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
Copy link
Contributor Author

Bisaloo commented Jun 7, 2024

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

@@ -30,6 +30,10 @@ test_that("expect_identical_linter skips cases likely testing numeric equality",
lint_msg <- rex::rex("Use expect_identical(x, y) by default; resort to expect_equal() only when needed")

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
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
Contributor 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.

R/expect_identical_linter.R Show resolved Hide resolved
@IndrajeetPatil IndrajeetPatil merged commit ee951ab into r-lib:main Jun 8, 2024
20 checks passed
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