File: test-function-args.R

package info (click to toggle)
r-cran-ggplot2 4.0.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 11,084 kB
  • sloc: sh: 15; makefile: 5
file content (142 lines) | stat: -rw-r--r-- 5,017 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
filter_args <- function(x) {
  all_names <- names(x)
  all_names <- setdiff(all_names, c("self", "data", "scales", "coordinates", "..."))
  x[all_names]
}

find_partial_match_pairs <- function(args) {
  if (length(args) < 2) {
    return(NULL)
  }
  combinations <- combn(args, 2L)
  contains <- startsWith(combinations[1, ], combinations[2, ]) |
    startsWith(combinations[2, ], combinations[1, ])

  if (!any(contains)) {
    return(NULL)
  }

  problem <- combinations[, contains, drop = FALSE]
  paste0("`", problem[1, ], "` with `", problem[2, ], "`")
}


test_that("geom_xxx and GeomXxx$draw arg defaults match", {
  ggplot2_ns <- asNamespace("ggplot2")
  objs <- ls(ggplot2_ns)
  geom_fun_names <- objs[grepl("^(geom|annotation)_", objs)]
  # These aren't actually geoms, or need special parameters and can't be tested this way.
  geom_fun_names <- setdiff(
    geom_fun_names,
    c("geom_map", "geom_sf", "geom_smooth", "geom_column", "geom_area",
      "geom_density", "annotation_custom", "annotation_map", "annotation_raster",
      "annotation_id", "geom_errorbarh")
  )

  # For each geom_xxx function and the corresponding GeomXxx$draw and
  # GeomXxx$draw_groups functions, make sure that if they have same args, that
  # the args have the same default values.
  lapply(geom_fun_names, function(geom_fun_name) {
    geom_fun    <- ggplot2_ns[[geom_fun_name]]
    geom <- geom_fun()$geom
    if (!is_geom(geom)) # for geoms that return more than one thing
      return()

    fun_args <- formals(geom_fun)
    draw_args <- c(
      ggproto_formals(geom$draw_layer),
      ggproto_formals(geom$draw_group)
    )
    draw_args <- filter_args(draw_args)

    common_names <- intersect(names(fun_args), names(draw_args))

    expect_identical(fun_args[common_names], draw_args[common_names],
      info = paste0("Mismatch between arg defaults for ", geom_fun_name,
        " and ", class(geom_fun()$geom)[1], "'s $draw and/or $draw_group functions.")
    )
  })
})

test_that("stat_xxx and StatXxx$compute_panel arg defaults match", {
  ggplot2_ns <- asNamespace("ggplot2")
  objs <- ls(ggplot2_ns)
  stat_fun_names <- objs[grepl("^stat_", objs)]
  # These aren't actually stats, or need special parameters and can't be tested this way.
  stat_fun_names <- setdiff(
    stat_fun_names,
    c("stat_function", "stat_sf")
  )
  # Remove deprecated stats
  stat_fun_names <- setdiff(stat_fun_names, c("stat_spoke", "stat_summary2d"))

  # For each stat_xxx function and the corresponding StatXxx$compute_panel and
  # StatXxx$compute_group functions, make sure that if they have same args, that
  # the args have the same default values.
  lapply(stat_fun_names, function(stat_fun_name) {
    stat_fun         <- ggplot2_ns[[stat_fun_name]]
    calculate        <- stat_fun()$stat$compute_panel
    calculate_groups <- stat_fun()$stat$compute_group

    fun_args <- formals(stat_fun)
    calc_args <- c(ggproto_formals(calculate), ggproto_formals(calculate_groups))
    calc_args <- filter_args(calc_args)

    common_names <- intersect(names(fun_args), names(calc_args))

    expect_identical(fun_args[common_names], calc_args[common_names],
      info = paste0("Mismatch between arg defaults for ", stat_fun_name,
        " and ", class(stat_fun()$stat)[1], "'s $compute_panel and/or $compute_group functions.")
    )
  })
})

# If the following tests fail, you may have introduced a potential partial match
# in argument names. The code should be double checked that is doesn't
# accidentally use `list$arg` when `list$arg_name` also exists. If that doesn't
# occur, the snapshot can be updated.

test_that("GeomXxx$parameters() does not contain partial matches", {
  ggplot2_ns <- asNamespace("ggplot2")
  objs <- ls(ggplot2_ns)
  geom_class_names <- grep("^Geom", objs, value = TRUE)
  geom_class_names <- setdiff(geom_class_names, c("Geom"))

  problems <- list()

  for (geom_class_name in geom_class_names) {
    geom_obj <- ggplot2_ns[[geom_class_name]]
    params <- geom_obj$parameters()
    issues <- find_partial_match_pairs(params)
    if (length(issues) == 0) {
      next
    }
    problems[[geom_class_name]] <- issues
  }

  problems <- vapply(problems, paste0, character(1), collapse = ", ")
  problems <- paste0(format(names(problems)), ": ", problems)
  expect_snapshot(problems)
})

test_that("StatXxx$parameters() does not contain partial matches", {
  ggplot2_ns <- asNamespace("ggplot2")
  objs <- ls(ggplot2_ns)
  stat_class_names <- grep("^Stat", objs, value = TRUE)
  stat_class_names <- setdiff(stat_class_names, c("Stat"))

  problems <- list()

  for (stat_class_name in stat_class_names) {
    stat_obj <- ggplot2_ns[[stat_class_name]]
    params <- stat_obj$parameters()
    issues <- find_partial_match_pairs(params)
    if (length(issues) == 0) {
      next
    }
    problems[[stat_class_name]] <- issues
  }
  problems <- vapply(problems, paste0, character(1), collapse = ", ")
  problems <- paste0(format(names(problems)), ": ", problems)
  expect_snapshot(problems)
})