Skip to content

Commit 7ea2245

Browse files
authored
Improve expect_setequal() feedback (#1745)
Fixes #1657
1 parent d65933d commit 7ea2245

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# testthat (development version)
22

3+
* `expect_setequal()` gives more actionable feedback (#1657).
4+
35
* `expect_snapshot()` no longer elides new lines when run interactively (#1726).
46

57
* Experimental new `with_mocked_bindings()` and `local_mocked_bindings()`

R/expect-setequal.R

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,41 +32,40 @@ expect_setequal <- function(object, expected) {
3232
}
3333

3434
act_miss <- !act$val %in% exp$val
35-
if (any(act_miss)) {
36-
fail(
37-
paste0(act$lab, "[", locations(act_miss), "] absent from ", exp$lab)
38-
)
39-
}
40-
4135
exp_miss <- !exp$val %in% act$val
42-
if (any(exp_miss)) {
43-
fail(
44-
paste0(exp$lab, "[", locations(exp_miss), "] absent from ", act$lab)
45-
)
46-
}
4736

48-
if (!any(exp_miss) && !any(act_miss)) {
37+
if (any(exp_miss) || any(act_miss)) {
38+
fail(paste0(
39+
act$lab, " (`actual`) and ", exp$lab, " (`expected`) don't have the same values.\n",
40+
if (any(exp_miss))
41+
paste0("* Only in `actual`: ", values(act$val[act_miss]), "\n"),
42+
if (any(act_miss))
43+
paste0("* Only in `expected`: ", values(exp$val[exp_miss]), "\n")
44+
))
45+
} else {
4946
succeed()
5047
}
5148

5249
invisible(act$val)
5350
}
5451

55-
is_vector <- function(x) is.list(x) || (is.atomic(x) && !is.null(x))
56-
57-
locations <- function(i) {
58-
loc <- which(i)
59-
if (length(loc) == 1) {
60-
return(loc)
52+
values <- function(x) {
53+
has_extra <- length(x) > 10
54+
if (has_extra) {
55+
x <- x[1:9]
6156
}
62-
63-
if (length(loc) > 10) {
64-
loc <- c(loc[1:9], "...")
57+
if (is.character(x)) {
58+
x <- encodeString(x, quote = '"')
6559
}
6660

67-
paste0("c(", paste0(loc, collapse = ", "), ")")
61+
out <- paste0(x, collapse = ", ")
62+
if (has_extra) {
63+
out <- paste0(out, ", ...")
64+
}
65+
out
6866
}
6967

68+
is_vector <- function(x) is.list(x) || (is.atomic(x) && !is.null(x))
7069

7170
#' @export
7271
#' @rdname expect_setequal
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# useful message on faillure
2+
3+
`x1` (`actual`) and `x2` (`expected`) don't have the same values.
4+
* Only in `actual`: "a"
5+
* Only in `expected`: "c"
6+
7+
8+
---
9+
10+
`y1` (`actual`) and `y2` (`expected`) don't have the same values.
11+
* Only in `actual`: 1
12+
* Only in `expected`: 4, 5, 6, 7, 8, 9, 10, 11, 12, ...
13+
14+

tests/testthat/test-expect-setequal.R

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ test_that("error for non-vectors", {
2323
expect_error(expect_setequal(sum, sum), "be vectors")
2424
})
2525

26+
test_that("useful message on faillure", {
27+
x1 <- c("a", "b")
28+
x2 <- c("b", "c")
29+
y1 <- 1:3
30+
y2 <- 2:50
31+
32+
expect_snapshot_failure(expect_setequal(x1, x2))
33+
expect_snapshot_failure(expect_setequal(y1, y2))
34+
})
35+
2636
# mapequal ----------------------------------------------------------------
2737

2838
test_that("ignores order", {

0 commit comments

Comments
 (0)