Skip to content

feat: Add expect_no_match rule (testthat)#368

Merged
etiennebacher merged 5 commits intoetiennebacher:mainfrom
bjyberg:feat/expect_no_match
Feb 28, 2026
Merged

feat: Add expect_no_match rule (testthat)#368
etiennebacher merged 5 commits intoetiennebacher:mainfrom
bjyberg:feat/expect_no_match

Conversation

@bjyberg
Copy link
Contributor

@bjyberg bjyberg commented Feb 27, 2026

Largely a copy paste job from the expect_match linter. It is not doing any handling of ! at the moment as these cases are covered by the expect_not linter.

I did however discover a bug with the fix for the expect_match linter while working on this. In cases where grepl has extra args (i.e. perl, fixed, etc.) that are unnamed, the fix cannot be applied due to differences in the args and orders between grepl and expect_match.

This has been addressed for this linter by reporting the lint but no fix where unnamed additional args exist. I'll open up a separate pr to fix the expect_match linter.

Part of #214

Pretty much a copy paste job from the expect_match linter, but I noticed
a bit (impacting expect_match as well) where unnamed/positional args in
grepl would be incorrectly carried over in a fix due to ignore.case
being the 3rd grepl arg but not a positional arg in
expect_match/no_match at all.

docs: add in changelog and rules.
@etiennebacher etiennebacher added the title needs formatting PR title doesn't follow conventional commits message format label Feb 27, 2026
@bjyberg bjyberg changed the title feat: add expect_no_match linter feat: Add expect_no_match linter (testthat) Feb 27, 2026
@etiennebacher etiennebacher removed the title needs formatting PR title doesn't follow conventional commits message format label Feb 27, 2026
@github-actions
Copy link

Ecosystem checks

easystats/datawizard: +4 -0 violations
New violations (first 100):
tests/testthat/test-data_tabulate.R[711:2]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-data_tabulate.R[712:2]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-data_tabulate.R[715:2]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-data_tabulate.R[716:2]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.  
nlmixr2/nlmixr2est: +8 -0 violations
New violations (first 100):
tests/testthat/test-issue-281.R[48:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-issue-281.R[51:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-issue-281.R[55:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-issue-281.R[57:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-issue-281.R[59:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-nlm.R[47:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-nlme.R[28:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.
tests/testthat/test-nls.R[21:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.  
ropensci/targets: +1 -0 violations
New violations (first 100):
tests/testthat/test-utils_data.R[6:2]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.  
rstudio/shiny: +1 -0 violations
New violations (first 100):
tests/testthat/test-built-files.R[9:4]: expect_no_match -- `expect_false(grepl(...))` is not as clear as `expect_no_match(...)`.  

@github-actions
Copy link

github-actions bot commented Feb 27, 2026

Benchmark on real-projects

Repository Avg. duration (main, seconds) Avg. duration (PR, seconds) PR - main PR - main (%) Number of iterations
easystats/datawizard 0.1889740 0.1927065 0.0037325469 1.9751644 50
lrberge/stringmagic 0.1876611 0.1871629 -0.0004981652 -0.2654601 50
pola-rs/r-polars 0.2387702 0.2447377 0.0059675161 2.4992716 50
Rdatatable/data.table 0.2296779 0.2338465 0.0041686072 1.8149800 50
ropensci/targets 0.3843597 0.3935271 0.0091674504 2.3851227 50
rstudio/shiny 0.2012968 0.2046825 0.0033857246 1.6819567 50
tidyverse/dplyr 0.2340755 0.2396800 0.0056044300 2.3942826 50
tidyverse/ggplot2 0.3530317 0.3595609 0.0065292075 1.8494678 50
vincentarelbundock/marginaleffects 0.1984439 0.2023827 0.0039387678 1.9848270 50
wch/r-source 1.8552783 1.8953064 0.0400281700 2.1575292 50

@etiennebacher etiennebacher changed the title feat: Add expect_no_match linter (testthat) feat: Add expect_no_match rule (testthat) Feb 27, 2026
Copy link
Owner

@etiennebacher etiennebacher left a comment

Choose a reason for hiding this comment

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

Thanks, just a couple of nitpicks

Comment on lines +66 to +68
if checker.is_rule_enabled(Rule::ExpectNoMatch) {
checker.report_diagnostic(expect_no_match(r_expr)?);
}
Copy link
Owner

Choose a reason for hiding this comment

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

Can you put this in alphabetical order?

Comment on lines +356 to +362
ExpectNoMatch => {
name: "expect_no_match",
categories: [Testthat],
default: Disabled,
fix: Safe,
min_r_version: None,
},
Copy link
Owner

Choose a reason for hiding this comment

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

Same here

@etiennebacher etiennebacher merged commit 727cc25 into etiennebacher:main Feb 28, 2026
15 checks passed
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.

2 participants