library(testit) # Factors and strings are searched differently. # Older versions of R don't have this set. op = options(stringsAsFactors = FALSE) assert('searching integer values works', { x = seq(-2, 2) (setequal(doColumnSearch(x, '0 ... 2'), 3:5)) (setequal(doColumnSearch(x, '-2 ... 0'), 1:3)) }) assert('searching numeric values works', { x = seq(-2, 2) / 10 (setequal(doColumnSearch(x, '0 ... 0.15'), 3:4)) (setequal(doColumnSearch(x, '-0.2 ... 0'), 1:3)) }) assert('searching dates works', { x = as.Date('2022-03-17') + seq(-1, 1) (setequal(doColumnSearch(x, '2022-03-16 ... 2022-03-17'), 1:2)) }) assert('searching factors works', { (setequal(doColumnSearch(factor(c('A', 'B')), '["A"]'), 1L)) (setequal(doColumnSearch(factor(c('A', 'B')), '["B"]'), 2L)) (setequal(doColumnSearch(factor(c('A', 'B')), '["A", "B"]'), 1:2)) }) assert('searching booleans works', { (setequal(doColumnSearch(c(TRUE, FALSE), '["true"]'), 1L)) (setequal(doColumnSearch(c(TRUE, FALSE), '["false"]'), 2L)) (setequal(doColumnSearch(c(TRUE, FALSE), '["true", "false"]'), 1:2)) }) assert('searching characters works', { (setequal(doColumnSearch(c('foo', 'food'), 'oo'), 1:2)) (setequal(doColumnSearch(c('foo', 'food'), 'ood'), 2L)) }) assert('character search options work', { (setequal(doColumnSearch(c('foo', 'food'), 'foo.?', options = list(regex = TRUE)), 1:2)) (setequal(doColumnSearch(c('foo', 'food'), 'foo.?', options = list(regex = FALSE)), integer(0))) (setequal(doColumnSearch(c('foo', 'Foo'), 'F', options = list(caseInsensitive = TRUE)), 1:2)) (setequal(doColumnSearch(c('foo', 'Foo'), 'F', options = list(caseInsensitive = FALSE)), 2L)) }) assert('global search works', { tbl = data.frame( foo = c('foo', 'bar', 'baz'), bar = c('bar', 'baz', 'foo') ) (setequal(doGlobalSearch(tbl, 'ba'), 1:3)) (setequal(doGlobalSearch(tbl, 'bar'), 1:2)) (setequal(doGlobalSearch(tbl, 'baz'), 2:3)) (setequal(doGlobalSearch(tbl, 'f'), c(1L, 3L))) }) assert('smart searching works', { tbl = data.frame(foo = c('foo bar baz', 'bar baz foo')) (setequal(doGlobalSearch(tbl, 'foo bar', options = list(smart = TRUE)), 1:2)) (setequal(doGlobalSearch(tbl, 'foo bar', options = list(smart = FALSE)), 1L)) }) assert('empty search returns everything', { tbl = data.frame(foo = c('foo bar baz', 'bar baz foo')) (setequal(doGlobalSearch(tbl, ''), 1:2)) (setequal(doGlobalSearch(tbl, NULL), 1:2)) (setequal(doColumnSearch(tbl$foo, ''), 1:2)) (setequal(doColumnSearch(tbl$foo, NULL), 1:2)) }) assert('global search works for tibbles', { if (requireNamespace("tibble", quietly = TRUE)) { tbl = tibble::tibble( foo = c('foo', 'bar', 'baz'), bar = c('bar', 'baz', 'foo') ) (setequal(doGlobalSearch(tbl, 'ba'), 1:3)) } }) # We know from tests above that individual search components work. # Here we make sure they are combined correctly for client queries. # Helpers to create client queries that run without errors clientQuery = function(data, global = globalQuery(), columns = list(columnQuery())) { columns = rep_len(columns, ncol(data)) names(columns) = seq_len(ncol(data)) - 1 list( draw = '0', start = '0', length = '10', escape = 'true', search = global, columns = columns ) } globalQuery = function(value = '', regex = FALSE, caseInsensitive = TRUE, smart = TRUE) { list( value = value, regex = tolower(regex), caseInsensitive = tolower(caseInsensitive), smart = tolower(smart) ) } columnQuery = function(value = '', searchable = TRUE, regex = FALSE) { list( searchable = tolower(searchable), search = list(value = value, regex = tolower(regex)) ) } assert('server-side search handler works', { tbl = data.frame( foo = c('foo', 'bar', 'baz'), bar = c('bar', 'baz', 'foo') ) query = clientQuery(tbl) out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1:3)) query = clientQuery(tbl, globalQuery('bar')) out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1:2)) query = clientQuery(tbl, globalQuery('foo')) query$columns[[1]] = columnQuery('ba') out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 3L)) query = clientQuery(tbl) query$columns[[1]] = columnQuery('b') query$columns[[2]] = columnQuery('a') out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 2L)) }) assert('server-side search handler skips unsearchable columns', { tbl = data.frame( foo = c('foo', 'bar', 'baz'), bar = c('bar', 'baz', 'foo') ) query = clientQuery(tbl, globalQuery('bar')) query$columns[[1]] = columnQuery(searchable = FALSE) out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1L)) query = clientQuery(tbl) query$columns[[1]] = columnQuery('bar', searchable = FALSE) out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1:3)) query = clientQuery(tbl) query$columns[[1]] = columnQuery(searchable = FALSE) query$columns[[2]] = columnQuery('bar') out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1L)) }) assert('server-side search handler ignores NULL search', { tbl = data.frame( foo = c('foo', 'bar', 'baz'), bar = c('bar', 'baz', 'foo') ) query = clientQuery(tbl, NULL) out = dataTablesFilter(tbl, query) (setequal(out$DT_rows_all, 1:3)) }) # Restore stringsAsFactors options(op)