Skip to content

Completes coverage of all .R files#3761

Merged
mattdowle merged 8 commits intomasterfrom
dt_covr
Aug 12, 2019
Merged

Completes coverage of all .R files#3761
mattdowle merged 8 commits intomasterfrom
dt_covr

Conversation

@MichaelChirico
Copy link
Copy Markdown
Member

@MichaelChirico MichaelChirico commented Aug 11, 2019

Closes #3758 too.

Please see also inline notes

Comment thread R/bmerge.R Outdated
}
if (xclass == iclass) {
if (verbose) cat("i.",names(i)[ic],"has same type (",xclass,") as x.",names(x)[xc],". No coercion needed.\n", sep="")
if (verbose) cat("i.", names(i)[ic], " has same type (", xclass, ") as x.", names(x)[xc], ". No coercion needed.\n", sep="")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

mainly missing a space, noticed in the verbose output for 2074.18

Comment thread R/data.table.R
tt = grep("^eval|^[^[:alpha:]. ]",byvars,invert=TRUE,value=TRUE)
if (length(tt)) tt = tt[1L] else all.vars(bysubl[[jj+1L]])[1L]
# take the first variable that is (1) not eval (#3758) and (2) starts with a character that can't start a variable name
tt = grep("^eval$|^[^[:alpha:]. ]", byvars, invert=TRUE, value=TRUE)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

simple fix for #3758 -- add ending anchor $ to the regex for eval

Comment thread R/data.table.R
# take the first variable that is (1) not eval (#3758) and (2) starts with a character that can't start a variable name
tt = grep("^eval$|^[^[:alpha:]. ]", byvars, invert=TRUE, value=TRUE)
# byvars but exclude functions or `0`+`1` becomes `+`
tt = if (length(tt)) tt[1L] else all.vars(bysubl[[jj+1L]])[1L]
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

previous code I believe was doing nothing in the else case, so I'm not 100% sure of the intended behavior but I believe this is it.

Comment thread R/data.table.R
origj = j = if (name[[1L]] == "$") as.character(name[[3L]]) else eval(name[[3L]], parent.frame(), parent.frame())
if (is.character(j)) {
if (length(j)!=1L) stop("L[[i]][,:=] syntax only valid when i is length 1, but it's length %d",length(j))
if (length(j)!=1L) stop("Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but it's length ", length(j))
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Quite the obscure error. Especially because the first code works while the second produces this error:

opt = options(datatable.alloccol=1L)
l = list(foo = list(bar = data.table(a = 1:3, b = 4:6)))
l$foo$bar[ , (letters) := 16:18]
l = list(foo = list(bar = data.table(a = 1:3, b = 4:6)))
l[[c('foo', 'bar')]][ , (letters) := 16:18]
options(opt)

Comment thread R/data.table.R
if (length(j)!=1L) stop("Cannot assign to an under-allocated recursively indexed list -- L[[i]][,:=] syntax is only valid when i is length 1, but it's length ", length(j))
j = match(j, names(k))
if (is.na(j)) stop("Item '",origj,"' not found in names of list")
if (is.na(j)) stop("Internal error -- item '", origj, "' not found in names of list") # nocov
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I can't see a way for this to be triggered, so marking it as internal

Comment thread R/data.table.R
icols = icolsAns = integer()
} else {
if (!length(leftcols)) stop("column(s) not found: ", paste(ansvars[wna],collapse=", "))
if (!length(leftcols)) stop("Internal error -- column(s) not found: ", paste(ansvars[wna],collapse=", ")) # nocov
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Ditto above. AFAICT things that might trigger this are caught much earlier than here.

@codecov
Copy link
Copy Markdown

codecov bot commented Aug 11, 2019

Codecov Report

Merging #3761 into master will increase coverage by 0.58%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3761      +/-   ##
==========================================
+ Coverage   98.83%   99.41%   +0.58%     
==========================================
  Files          70       70              
  Lines       13228    13204      -24     
==========================================
+ Hits        13074    13127      +53     
+ Misses        154       77      -77
Impacted Files Coverage Δ
R/setops.R 100% <ø> (+0.52%) ⬆️
R/IDateTime.R 100% <ø> (+1.24%) ⬆️
src/fread.c 99.44% <ø> (+0.94%) ⬆️
R/print.data.table.R 100% <100%> (+4.95%) ⬆️
R/transpose.R 100% <100%> (ø) ⬆️
R/data.table.R 100% <100%> (+2.16%) ⬆️
src/bmerge.c 100% <100%> (+1.74%) ⬆️
R/groupingsets.R 100% <100%> (+3.57%) ⬆️
R/bmerge.R 100% <100%> (ø) ⬆️
... and 11 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 30a4fcd...8c1fe1b. Read the comment docs.

Comment thread R/data.table.R
length(irows) && !anyNA(irows) && all(irows==0L) ## anyNA() because all() returns NA (not FALSE) when irows is all-NA. TODO: any way to not check all 'irows' values?
))
if (is.atomic(jval)) jval = jval[0L] else jval = lapply(jval, `[`, 0L)
jval = lapply(jval, `[`, 0L)
Copy link
Copy Markdown
Member Author

@MichaelChirico MichaelChirico Aug 11, 2019

Choose a reason for hiding this comment

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

I don't believe is.atomic(jval) is possible here.

Just above you can see this branch enters with either is.list(jval) or !missingby:

https://github.com/Rdatatable/data.table/pull/3761/files#diff-650e4a11ed4384f8e560a6ebfff4ff53L1287

if ((is.call(jsub) && is.list(jval) && jsub[[1L]] != "get" && !is.object(jval)) || !missingby)

Obviously is.atomic(jval) is impossible in the first case. You have to scroll a bit further up but I think the second case is also impossible:

https://github.com/Rdatatable/data.table/pull/3761/files#diff-650e4a11ed4384f8e560a6ebfff4ff53L1168

if (missingby || bynull || (!byjoin && !length(byval)))

So we've either got bynull or (!byjoin && !length(byval)). But I'm not sure how length(byval) can be 0 but bynull is FALSE -- e.g. by = integer() would have byval = list(integer = integer()), so it's already en-listed.

Comment thread R/data.table.R
all.logical = TRUE
for (j in seq_len(p)) {
if (is.ff(X[[j]])) X[[j]] = X[[j]][] # to bring the ff into memory, since we need to create a matrix in memory
if (is.ff(X[[j]])) X[[j]] = X[[j]][] # nocov to bring the ff into memory, since we need to create a matrix in memory
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

we don't have ff in Suggests, so nocov. We have is.ff as a simple wrapper, so technically we could construct some object and force ff class to it & test but that's not really a test of what this branch is supposed to do. So nocov unless we want to add ff to Suggests, or if you think we should add ff to the test packages.

Comment thread R/data.table.R
stub = call("==", as.symbol(col), TRUE)
}
if (length(stub[[1L]]) != 1) return(NULL) ## Whatever it is, definitely not one of the valid operators
if (length(stub[[1L]]) != 1) return(NULL) # nocov Whatever it is, definitely not one of the valid operators
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I can't see a way to reach this branch and the comment suggests it's there as an internal default, could you confirm @MarkusBonsch?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You are completely right.

Comment thread R/data.table.R
# the mode() checks also deals with NULL since mode(NULL)=="NULL" and causes this return, as one CRAN package (eplusr 0.9.1) relies on
return(NULL)
}
if(is.character(x[[col]]) && !operator %chin% c("==", "%in%", "%chin%")) return(NULL) ## base R allows for non-equi operators on character columns, but these can't be optimized.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Redundant to here in current logic:

https://github.com/Rdatatable/data.table/pull/3761/files#diff-650e4a11ed4384f8e560a6ebfff4ff53L2885

if (!operator %chin% validOps$op)

Comment thread R/data.table.R
pat = paste0("(", ops, ")", collapse="|")
if (is.call(onsub) && onsub[[1L]] == "eval") {
onsub = eval(onsub[[2L]], parent.frame(2L), parent.frame(2L))
if (is.call(onsub) && onsub[[1L]] == "eval") { onsub = onsub[[2L]] }
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The eval will eliminate any level of nested eval/quote already, so I don't think this branch is possible; see:

DT <- data.table(id = 1:3, `counts(a>=0)` = 1:3, sameName = 1:3)
i <- data.table(idi = 1:3, `  weirdName>=` = 1:3, sameName = 1:3)
DT[i, on = eval(eval(quote(eval("id<=idi"))))]

After eval onsub becomes id<=idi

@MichaelChirico
Copy link
Copy Markdown
Member Author

Once merged we'll be over 99% coverage! Mission accomplished 😎

Comment thread R/data.table.R Outdated
@MichaelChirico MichaelChirico changed the title Closes #3758 and completes coverage of data.table.R Closes #3758 and completes coverage of all files in R/ Aug 11, 2019
Comment thread R/IDateTime.R
`+.IDate` = function (e1, e2) {
if (nargs() == 1L)
return(e1)
# TODO: investigate Ops.IDate method a la Ops.difftime
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

As noted in ?Ops

The classes of both arguments are considered in dispatching any member of this group. For each argument its vector of classes is examined to see if there is a matching specific (preferred) or Ops method. If a method is found for just one argument or the same method is found for both, it is used. If different methods are found, there is a warning about ‘incompatible methods’: in that case or if no method is found for either argument the internal method is used.

Hence we can't really reach this branch since the incompatible methods barrier is hit first.

Comment thread R/last.R Outdated
if (!length(x)) return(x) else return(x[[length(x)]]) # for vectors, [[ works like [
} else if (is.data.frame(x)) return(x[NROW(x),])
}
# nocov start
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I saw the if branches covered in first but not last (despite apparently neither actually being hit in tests), so just throw the whole sections in nocov to be sure. maybe surface to Jim as well...

Comment thread R/transpose.R Outdated
make.names=chmatch(make.names, names(l))
if (is.na(make.names))
stop("make.names='",make.names,"' not found in names of input")
stop("make.names not found in names of input")
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

make.names original value is overwritten already. Rather than complicate the logic (i.e. by one or two extra lines), just axed here, but easy to change.

Comment thread inst/tests/tests.Rraw
test(1613.563, all(
all.equal(rbind(x,y), rbind(y,y), ignore.row.order=FALSE),
all.equal(rbind(x,y), rbind(y,y), ignore.row.order=TRUE),
all.equal(rbind(y,y), rbind(x,y), ignore.row.order=TRUE)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

New test switches the order to hit the first-but-not-second-has-dups branch whose second-but-not-first counterpart is hit by the 2nd test already

@mattdowle mattdowle changed the title Closes #3758 and completes coverage of all files in R/ Completes coverage of all .R files Aug 12, 2019
@mattdowle mattdowle added this to the 1.12.4 milestone Aug 12, 2019
…between arguments so we can see where the real spaces inside quotes are. In this instance the diff now shows where the real space was added.
@mattdowle
Copy link
Copy Markdown
Member

Fantastic! I went through it and all looks good. Great comments. I added comment in the tests.Rraw for the new tests 2074.* file pointing back to this PR so we can get back to the comments if we ever need to.

@mattdowle mattdowle merged commit f7e82a5 into master Aug 12, 2019
@mattdowle mattdowle deleted the dt_covr branch August 12, 2019 22:49
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.

by auto-naming is too greedy on eval-like columns

4 participants