Open alex-gable opened 4 years ago
thanks for the issue @alex-gable and for the thorough dive into the problem.
I admit the solution in check_cassette_names()
isn't great. Partly we're limited because R doesn't have a great way to parse/manipulate/inspect ASTs.
I'll have a look and see if there's a solution that will be more general
it gets more complex too:
name <- "foo_bar"
use_cassette(name, {
...
})
I started working on this, but its complicated. we need to account for:
vcr::use_cassette("foo"
vcr::use_cassette(name = "foo"
use_cassette("foo"
use_cassette(name = "foo"
x = "foo"; vcr::use_cassette(x
x = "foo"; vcr::use_cassette(name = x
x
defined somewhere else in the test fileuse_cassette
calls per test_that blocktried breaking up each test file by test_that
blocks first, but that's still complicated, and not sure if that would lead to problems as well
my local branch cassette-names
it occurred to me that this functionality might be implemented in a package like r-lib/styler
apologize for not giving a more thorough inspection of how exactly that package could help. but something like a syntax highlighter or language server that returns a more rich syntax tokenization of R code.
Good idea to look at styler. I should look to see if there's anything in there that may help
Sorry for delay on this, getting a new version out soon, then can look at this again
I've created a repo to reproduce the below scenario.
Session Info
```r r$> devtools::session_info() ─ Session info ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── setting value version R version 4.0.0 (2020-04-24) os macOS Catalina 10.15.4 system x86_64, darwin17.0 ui vscode language (EN) collate en_US.UTF-8 ctype en_US.UTF-8 tz America/Los_Angeles date 2020-05-26 ─ Packages ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── ! package * version date lib source assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.0.0) backports 1.1.7 2020-05-13 [1] CRAN (R 4.0.0) base64enc 0.1-3 2015-07-28 [1] CRAN (R 4.0.0) callr 3.4.3 2020-03-28 [1] CRAN (R 4.0.0) R catfact * 0.1.1check_cassette_names
fails when thename = {cassette name}
form is used to call the function. debugging shows that the issue is in thecassette_names
function.Debugging the internals led me to discover that the "magic number"
"2"
being added to the"use_cassette"
row number is dependent on allowing strictly a"("
between the function call and the name of the cassette. Looking atdf
as it gets subsetted and assigned toz
, you'd need to add"4"
in the named-argument instance. This situation becomes even more dire if the function arguments are out of order in addition to being named.Inspecting the
df
created by callinggetParseData
on my erroring file, I found that theSYMBOL_FUNCTION_CALL
foruse_cassettes
gives us a scope ofline1 == 5
orline1 == 18
to find our"name"
argument. I believe you'll find promising results by selecting thetoken == "STR_CONST
in those subsets.Looking at the
lobstr::ast()
for various ways to tell vcr which cassette to use, it's hard to see how all cases can be accommodated and parsed easily.Example Abstract Syntax Trees
```r r$> lobstr::ast(expression(testthat::test_that("cat_fact works", { vcr::use_cassette(name = "cat_fact", { aa <- cat_fact() expect_is(aa, "list") expect_named(aa, c('fact', 'length')) expect_is(aa$fact, 'character') expect_type(aa$length, 'integer') }) })) ) █─expression └─█─█─`::` │ ├─testthat │ └─test_that ├─"cat_fact works" └─█─`{` └─█─█─`::` │ ├─vcr │ └─use_cassette ├─name = "cat_fact" └─█─`{` ├─█─`<-` │ ├─aa │ └─█─cat_fact ├─█─expect_is │ ├─aa │ └─"list" ├─█─expect_named │ ├─aa │ └─█─c │ ├─"fact" │ └─"length" ├─█─expect_is │ ├─█─`$` │ │ ├─aa │ │ └─fact │ └─"character" └─█─expect_type ├─█─`$` │ ├─aa │ └─length └─"integer" r$> lobstr::ast(expression(testthat::test_that("cat_fact works", { vcr::use_cassette("cat_fact", { aa <- cat_fact() expect_is(aa, "list") expect_named(aa, c('fact', 'length')) expect_is(aa$fact, 'character') expect_type(aa$length, 'integer') }) })) ) █─expression └─█─█─`::` │ ├─testthat │ └─test_that ├─"cat_fact works" └─█─`{` └─█─█─`::` │ ├─vcr │ └─use_cassette ├─"cat_fact" └─█─`{` ├─█─`<-` │ ├─aa │ └─█─cat_fact ├─█─expect_is │ ├─aa │ └─"list" ├─█─expect_named │ ├─aa │ └─█─c │ ├─"fact" │ └─"length" ├─█─expect_is │ ├─█─`$` │ │ ├─aa │ │ └─fact │ └─"character" └─█─expect_type ├─█─`$` │ ├─aa │ └─length └─"integer" r$> lobstr::ast(expression(testthat::test_that("cat_fact works", { use_cassette("cat_fact", { aa <- cat_fact() expect_is(aa, "list") expect_named(aa, c('fact', 'length')) expect_is(aa$fact, 'character') expect_type(aa$length, 'integer') }) })) ) █─expression └─█─█─`::` │ ├─testthat │ └─test_that ├─"cat_fact works" └─█─`{` └─█─use_cassette ├─"cat_fact" └─█─`{` ├─█─`<-` │ ├─aa │ └─█─cat_fact ├─█─expect_is │ ├─aa │ └─"list" ├─█─expect_named │ ├─aa │ └─█─c │ ├─"fact" │ └─"length" ├─█─expect_is │ ├─█─`$` │ │ ├─aa │ │ └─fact │ └─"character" └─█─expect_type ├─█─`$` │ ├─aa │ └─length └─"integer" r$> lobstr::ast(expression(testthat::test_that("cat_fact works", { use_cassette(name = "cat_fact", { aa <- cat_fact() expect_is(aa, "list") expect_named(aa, c('fact', 'length')) expect_is(aa$fact, 'character') expect_type(aa$length, 'integer') }) })) ) █─expression └─█─█─`::` │ ├─testthat │ └─test_that ├─"cat_fact works" └─█─`{` └─█─use_cassette ├─name = "cat_fact" └─█─`{` ├─█─`<-` │ ├─aa │ └─█─cat_fact ├─█─expect_is │ ├─aa │ └─"list" ├─█─expect_named │ ├─aa │ └─█─c │ ├─"fact" │ └─"length" ├─█─expect_is │ ├─█─`$` │ │ ├─aa │ │ └─fact │ └─"character" └─█─expect_type ├─█─`$` │ ├─aa │ └─length └─"integer" ```