Running 'test-gadget_areafile.R' [150s]
  Running 'test-gadget_directory.R' [175s]
  Running 'test-gadget_file.R' [1s]
  Running 'test-gadget_fleetfile.R' [1s]
  Running 'test-gadget_likelihood_component.R' [2s]
  Running 'test-gadget_mainfile.R' [1s]
  Running 'test-mfdb.R' [1s]
  Running 'test-mfdb_aggregate.R' [1s]
  Running 'test-mfdb_aggregate_group.R' [156s]
  Running 'test-mfdb_aggregate_interval.R' [158s]
  Running 'test-mfdb_aggregate_step_interval.R' [1s]
  Running 'test-mfdb_aggregate_unaggregated.R' [155s]
  Running 'test-mfdb_helpers.R' [1s]
  Running 'test-mfdb_import.R' [163s]
  Running 'test-mfdb_queries.R' [157s]
  Running 'test-mfdb_sql.R' [1s]
Running the tests in 'tests/test-gadget_areafile.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > ok_group("Can write area files", {
  +     gd <- gadget_directory(tempfile())
  +     gadget_dir_write(gd, gadget_areafile(data.frame(
  +         area = c("divA", "divB", "divC"),
  +         size = c(15, 25, 10),
  +         stringsAsFactors = FALSE
  +     ), data.frame(
  +         year = rep(c(1998), each = 12),
  +         step = rep(c("q1", "q2", "q3", "q4"), each = 3),
  +         area = rep(c("divA", "divB", "divC"), times = 4),
  +         mean = 1:12,
  +         stringsAsFactors = FALSE
  +     ), area = list(divA = 14, divX = 99, divB = 30, divC = 44, divD = 88)))
  +     ok(cmp_file(gd, 'main',
  +         ver_string,
  +         "timefile\t",
  +         "areafile\tModelfiles/area",
  +         "printfiles\t; Required comment",
  +         "[stock]","[tagging]","[otherfood]","[fleet]","[likelihood]"
  +     ))
  +     ok(cmp_file(gd, 'Modelfiles/area',
  +         ver_string,
  +         "; divA\tdivX\tdivB\tdivC\tdivD",
  +         "areas\t1\t2\t3\t4\t5",
  +         "size\t15\t0\t25\t10\t0",
  +         "temperature",
  +         "; -- data --",
  +         "; year\tstep\tarea\tmean",
  +         "1998\tq1\t1\t1",
  +         "1998\tq1\t3\t2",
  +         "1998\tq1\t4\t3",
  +         "1998\tq2\t1\t4",
  +         "1998\tq2\t3\t5",
  +         "1998\tq2\t4\t6",
  +         "1998\tq3\t1\t7",
  +         "1998\tq3\t3\t8",
  +         "1998\tq3\t4\t9",
  +         "1998\tq4\t1\t10",
  +         "1998\tq4\t3\t11",
  +         "1998\tq4\t4\t12"
  +     ))
  + })
  # Can write area files
  ok - cmp_file(gd, "main", ver_string, "timefile\t", "areafile\tMo
  ok - cmp_file(gd, "Modelfiles/area", ver_string, "; divA\tdivX\td
  > 
  > proc.time()
     user  system elapsed 
      0.4     0.1     0.5 
Running the tests in 'tests/test-gadget_directory.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > ok_group("Will create a directory when creating gadget_directories", {
  +     dir <- tempfile()
  +     ok(!file.exists(dir))
  +     gd <- gadget_directory(dir)
  +     ok(file.exists(dir) && file_test("-d", dir))
  + })
  # Will create a directory when creating gadget_directories
  ok - !file.exists(dir)
  ok - file.exists(dir) && file_test("-d", dir)
  > 
  > ok_group("Can write files", {
  +     # Create a temporary directory, starts off empty
  +     dir <- tempfile()
  +     gd <- gadget_directory(dir)
  +     expect_equal(list.files(dir), character(0))
  + 
  +     # Write out files, come back the same
  +     gf_animals <- gadget_file("animals", components = list(list(cow = "Daisy", pig = "George")))
  +     gadget_dir_write(gd, gf_animals)
  +     expect_equal(gadget_dir_read(gd, "animals"), gf_animals)
  +     expect_equal(list.files(dir), c("animals"))
  + 
  +     gf_plants <- gadget_file("plants", components = list(list(tree = "The larch", tree = "The pine")))
  +     gadget_dir_write(gd, gf_plants)
  +     expect_equal(gadget_dir_read(gd, "plants"), gf_plants)
  +     expect_equal(list.files(dir), c("animals", "plants"))
  + })
  # Can write files
  ok - list.files(dir) == character(0)
  ok - gadget_dir_read(gd, "animals") == gf_animals
  ok - list.files(dir) == c("animals")
  ok - gadget_dir_read(gd, "plants") == gf_plants
  ok - list.files(dir) == c("animals", "plants")
  > 
  > ok_group("Can write files into model subdirectories", {
  +     dir <- tempfile()
  +     gd <- gadget_directory(dir)
  +     ok(cmp(list.files(dir, recursive = TRUE), character(0)), "Directory currently empty")
  + 
  +     gf <- gadget_file("field/animals", components = list(
  +         list(),
  +         cows = list("daisy" = 4, "freda" = 2),
  +         pigs = list("george" = 3, "arnold" = 8)))
  +     gadget_dir_write(gd, gf)
  +     ok(cmp(list.files(dir, recursive = TRUE), c(
  +         "field/animals",
  +         NULL)), "Wrote our animals file into the field directory")
  + 
  +     gf2 <- gadget_dir_read(gd, "field/animals")
  +     ok(cmp(gf, gf2), "File read back is identical")
  + 
  +     gf2$components$pigs$george = 99
  +     gadget_dir_write(gd, gf2)
  +     ok(cmp(list.files(dir, recursive = TRUE), c(
  +         "field/animals",
  +         NULL)), "Altered animals, wrote back in right place")
  + 
  +     gf3 <- gadget_dir_read(gd, "field/animals")
  +     ok(cmp(gf2, gf3), "Content is correct")
  + })
  # Can write files into model subdirectories
  ok - Directory currently empty
  ok - Wrote our animals file into the field directory
  ok - File read back is identical
  ok - Altered animals, wrote back in right place
  ok - Content is correct
  > 
  > ok_group("Can create files in model subdirectories", {
  +     dir <- tempfile()
  +     gd <- gadget_directory(dir)
  +     ok(cmp(list.files(dir, recursive = TRUE), character(0)), "Directory currently empty")
  + 
  +     ok(cmp_error(gadget_dir_read(gd, "farmhouse/kitchen", missing_okay = FALSE), "farmhouse"),
  +         "Can complain about missing files if we want to")
  +     gf <- gadget_dir_read(gd, "farmhouse/kitchen")
  +     ok(cmp(gf$components, list()), "No components yet")
  + 
  +     ok(cmp(list.files(dir, recursive = TRUE), character(0)), "Directory still empty")
  +     gadget_dir_write(gd, gf)
  +     ok(cmp(list.files(dir, recursive = TRUE), c("farmhouse/kitchen")), "Wrote file, created directory")
  + })
  # Can create files in model subdirectories
  ok - Directory currently empty
  ok - Can complain about missing files if we want to
  ok - No components yet
  ok - Directory still empty
  ok - Wrote file, created directory
  > 
  > proc.time()
     user  system elapsed 
     0.57    0.09    0.65 
Running the tests in 'tests/test-mfdb_aggregate_group.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > cmp_group <- function (a, b) {
  +     cmp(a[names(a)], b[names(b)])
  + }
  > 
  > ok_group("Can generate groupobjects", {
  +     expect_equal(
  +         class(mfdb_group()),
  +         c("mfdb_group", "mfdb_aggregate"))
  + 
  +     expect_equal(
  +         class(mfdb_group(cows = c("daisy", "freda"))),
  +         c("mfdb_group", "mfdb_aggregate"))
  + })
  # Can generate groupobjects
  ok - class(mfdb_group()) == c("mfdb_group", "mfdb_aggregat
  ok - class(mfdb_group(cows = c("dai == c("mfdb_group", "mfdb_aggregat
  > 
  > ok_group("Can generate a numbered group", {
  +     ok(cmp_group(
  +         mfdb_group_numbered("age", c(4), c(5)),
  +         mfdb_group(age1 = c(4), age2 = c(5))
  +         ), "groups match")
  + })
  # Can generate a numbered group
  ok - groups match
  > 
  > ok_group("Can get a bootstrap group", {
  +     expect_error(
  +         mfdb_bootstrap_group(2, "camel"),
  +         "Second argument should be a mfdb_group")
  +     expect_error(
  +         mfdb_bootstrap_group(0, mfdb_group()),
  +         "Count should be equal or greater than 1")
  + })
  # Can get a bootstrap group
  ok - Error contained 'Second argument should be a mfdb_group'
  ok - Error contained 'Count should be equal or greater than 1'
  > 
  > ok_group("Predefined timestep groups", {
  +     ok(cmp(mfdb_timestep_yearly[[1]], 1:12), "mfdb_timestep_yearly")
  +     ok(cmp(mfdb_timestep_biannually[[1]], 1:6), "mfdb_timestep_biannually")
  +     ok(cmp(mfdb_timestep_biannually[[2]], 7:12), "mfdb_timestep_biannually")
  +     ok(cmp(mfdb_timestep_quarterly[[1]], 1:3), "mfdb_timestep_quarterly")
  +     ok(cmp(mfdb_timestep_quarterly[[2]], 4:6), "mfdb_timestep_quarterly")
  +     ok(cmp(mfdb_timestep_quarterly[[3]], 7:9), "mfdb_timestep_quarterly")
  +     ok(cmp(mfdb_timestep_quarterly[[4]], 10:12), "mfdb_timestep_quarterly")
  + })
  # Predefined timestep groups
  ok - mfdb_timestep_yearly
  ok - mfdb_timestep_biannually
  ok - mfdb_timestep_biannually
  ok - mfdb_timestep_quarterly
  ok - mfdb_timestep_quarterly
  ok - mfdb_timestep_quarterly
  ok - mfdb_timestep_quarterly
  > 
  > table_content <- data.frame(sample = 0, name = c('a', 'a', 'a'), value = 1:3)
  > mdb <- fake_mdb(save_temp_tables = TRUE)
  > mdb$ret_rows <- list(
  +     "SELECT sample, name, value FROM temp_" = table_content,
  +     "FROM information_schema.tables" = data.frame(count = 0))
  > g <- NULL
  > 
  > ok_group("Aggregates with mfdb_group", local({
  +     g <<- mfdb_group(a = c(1,"two",3), b = c(88))
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (0,'a','1'),(0,'a','two'),(0,'a','3'),(0,'b','88')"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok("mfdb_smallset" %in% class(pre_query(mdb, g, "col")), "Converted to an mfdb_smallset")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  + 
  +     g <<- mfdb_group(a1 = c(1,2,3), badger = c(88, 21), a3 = c(99))
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (0,'a1',1),(0,'a1',2),(0,'a1',3),(0,'badger',88),(0,'badger',21),(0,'a3',99)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_group
  ok - Created temporary table
  SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('temp_mccxu')
  CREATE  TABLE temp_mccxu (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )
  INSERT INTO temp_mccxu (sample,name,value) VALUES (0,'a','1'),(0,'a','two'),(0,'a','3'),(0,'b','88')
  CREATE INDEX idx_temp_mccxu_value_name_sample ON temp_mccxu (value,name,sample)
  SELECT sample, name, value FROM temp_mccxu
  ok - Converted to an mfdb_smallset
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Created temporary table
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  > 
  > ok_group("Large group aggregates don't attempt smallset", local({
  +     g <<- mfdb_group(a = c(1,"two",3), b = 1:100)
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (0,'a','1'),(0,'a','two'),(0,'a','3'),", paste0("(0,'b','", 1:100,"')", collapse=",")),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         NULL)), "Created temporary table")
  +     ok(!("mfdb_smallset" %in% class(pre_query(mdb, g, "col"))), "Not a a mfdb_smallset")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  + 
  +     g <<- mfdb_group(a1 = c(1,2,3), badger = c(88, 21), a3 = c(99))
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (0,'a1',1),(0,'a1',2),(0,'a1',3),(0,'badger',88),(0,'badger',21),(0,'a3',99)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  + }, asNamespace('mfdb')))
  # Large group aggregates don't attempt smallset
  ok - Created temporary table
  SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('temp_mndmz')
  CREATE  TABLE temp_mndmz (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )
  INSERT INTO temp_mndmz (sample,name,value) VALUES (0,'a','1'),(0,'a','two'),(0,'a','3'),(0,'b','1'),(0,'b','2'),(0,'b','3'),(0,'b','4'),(0,'b','5'),(0,'b','6'),(0,'b','7'),(0,'b','8'),(0,'b','9'),(0,'b','10'),(0,'b','11'),(0,'b','12'),(0,'b','13'),(0,'b','14'),(0,'b','15'),(0,'b','16'),(0,'b','17'),(0,'b','18'),(0,'b','19'),(0,'b','20'),(0,'b','21'),(0,'b','22'),(0,'b','23'),(0,'b','24'),(0,'b','25'),(0,'b','26'),(0,'b','27'),(0,'b','28'),(0,'b','29'),(0,'b','30'),(0,'b','31'),(0,'b','32'),(0,'b','33'),(0,'b','34'),(0,'b','35'),(0,'b','36'),(0,'b','37'),(0,'b','38'),(0,'b','39'),(0,'b','40'),(0,'b','41'),(0,'b','42'),(0,'b','43'),(0,'b','44'),(0,'b','45'),(0,'b','46'),(0,'b','47'),(0,'b','48'),(0,'b','49'),(0,'b','50'),(0,'b','51'),(0,'b','52'),(0,'b','53'),(0,'b','54'),(0,'b','55'),(0,'b','56'),(0,'b','57'),(0,'b','58'),(0,'b','59'),(0,'b','60'),(0,'b','61'),(0,'b','62'),(0,'b','63'),(0,'b','64'),(0,'b','65'),(0,'b','66'),(0,'b','67'),(0,'b','68'),(0,'b','69'),(0,'b','70'),(0,'b','71'),(0,'b','72'),(0,'b','73'),(0,'b','74'),(0,'b','75'),(0,'b','76'),(0,'b','77'),(0,'b','78'),(0,'b','79'),(0,'b','80'),(0,'b','81'),(0,'b','82'),(0,'b','83'),(0,'b','84'),(0,'b','85'),(0,'b','86'),(0,'b','87'),(0,'b','88'),(0,'b','89'),(0,'b','90'),(0,'b','91'),(0,'b','92'),(0,'b','93'),(0,'b','94'),(0,'b','95'),(0,'b','96'),(0,'b','97'),(0,'b','98'),(0,'b','99'),(0,'b','100')
  CREATE INDEX idx_temp_mndmz_value_name_sample ON temp_mndmz (value,name,sample)
  ok - Not a a mfdb_smallset
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Created temporary table
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  > 
  > mdb$ret_rows <- list(
  +     "SELECT sample, name, value FROM temp_" = data.frame(),
  +     "FROM information_schema.tables" = data.frame(count = 1))
  > ok_group("Aggregates with mfdb_group that's already been created", local({
  +     g <<- mfdb_group(a = c(1,"two",3), b = c(88))
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         NULL)), "Don't recreate temporary table")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_group that's already been created
  ok - Don't recreate temporary table
  > mdb$ret_rows <- list(
  +     "SELECT sample, name, value FROM temp_" = data.frame(),
  +     "FROM information_schema.tables" = data.frame(count = 0))
  > 
  > ok_group("Aggregates with mfdb_bootstrap_group", local({
  +     g <<- mfdb_bootstrap_group(2, mfdb_group(camels = c(44), aardvarks = c(88)))
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (1,'camels',44),(1,'aardvarks',88),(2,'camels',44),(2,'aardvarks',88)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".sample")), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "1.1.1"), 1), list(
  +         camels = 44,
  +         aardvarks = 88
  +     )), "Aggregation summary (sample 1)")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "2.2.2"), 2), list(
  +         camels = 44,
  +         aardvarks = 88
  +     )), "Aggregation summary (sample 2)")
  + 
  +     g <<- mfdb_bootstrap_group(2, mfdb_group(g1 = c(44, 55), g2 = c(88, 99)), seed = 123456)
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (1,'g1',55),(1,'g1',55),(1,'g2',88),(1,'g2',88),(2,'g1',44),(2,'g1',44),(2,'g2',99),(2,'g2',88)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".sample")), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), paste0(attr(g, 'table_name'), ".name AS out")), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), attr(g, 'table_name')), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), paste0("col = ", attr(g, 'table_name'), ".value")), "Where clause")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "1.1.1"), 1), list(
  +         g1 = c(55, 55),
  +         g2 = c(88, 88)
  +     )), "Aggregation summary (sample 1)")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "2.0.0"), 2), list(
  +         g1 = c(44, 44),
  +         g2 = c(99, 88)
  +     )), "Aggregation summary (sample 2)")
  + 
  +     # Test a few more random combinations
  +     g <<- mfdb_bootstrap_group(2, mfdb_group(g1 = c(44, 55), g2 = c(88, 99)), seed = 8081)
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (1,'g1',44),(1,'g1',55),(1,'g2',99),(1,'g2',99),(2,'g1',44),(2,'g1',55),(2,'g2',99),(2,'g2',99)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  + 
  +     g <<- mfdb_bootstrap_group(2, mfdb_group(g1 = c(44, 55), g2 = c(88, 99)), seed = 203785)
  +     ok(cmp(capture.output(pre_query(mdb, g, "col")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " (sample,name,value) VALUES (1,'g1',55),(1,'g1',55),(1,'g2',99),(1,'g2',99),(2,'g1',44),(2,'g1',44),(2,'g2',88),(2,'g2',99)"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "0.1"), 1), list(
  +         g1 = c(55, 55),
  +         g2 = c(99, 99)
  +     )), "Aggregation summary (sample 1)")
  +     ok(cmp(agg_summary(mdb, g, 'col', 'out', data.frame(bssample = "0.2"), 2), list(
  +         g1 = c(44, 44),
  +         g2 = c(88, 99)
  +     )), "Aggregation summary (sample 2)")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_bootstrap_group
  ok - Created temporary table
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Aggregation summary (sample 1)
  ok - Aggregation summary (sample 2)
  ok - Created temporary table
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Aggregation summary (sample 1)
  ok - Aggregation summary (sample 2)
  ok - Created temporary table
  ok - Created temporary table
  ok - Aggregation summary (sample 1)
  ok - Aggregation summary (sample 2)
  Warning messages:
  1: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  2: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  3: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  4: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  > 
  > ok_group("Aggregates with mfdb_group areas", local({
  +     # Areas are a special case, they have to be broken down into areacells first
  +     g <<- mfdb_group(a = c(1,2,3), b = c(88, 89))
  +     ok(cmp(capture.output(pre_query(mdb, g, "c.areacell_id")), c(
  +         paste0("SELECT COUNT(*) FROM information_schema.tables WHERE (table_schema IN ('fake_schema') OR table_schema = (SELECT nspname FROM pg_namespace WHERE oid = pg_my_temp_schema())) AND table_name IN ('", attr(g, 'table_name'), "')"),
  +         paste0("CREATE  TABLE ", attr(g, 'table_name'), " (sample INT DEFAULT 1 NOT NULL, name VARCHAR(10), value  INT )"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " SELECT 0 AS sample, 'a' AS name, areacell_id AS value FROM (SELECT division, areacell_id FROM division UNION SELECT name, areacell_id FROM areacell) divac WHERE division IN ('1','2','3')"),
  +         paste0("INSERT INTO ", attr(g, 'table_name'), " SELECT 0 AS sample, 'b' AS name, areacell_id AS value FROM (SELECT division, areacell_id FROM division UNION SELECT name, areacell_id FROM areacell) divac WHERE division IN ('88','89')"),
  +         paste0("CREATE INDEX idx_", attr(g, 'table_name') ,"_value_name_sample ON ", attr(g, 'table_name'), " (value,name,sample)"),
  +         paste0("SELECT sample, name, value FROM ", attr(g, 'table_name')),
  +         NULL)), "Created temporary table")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_group areas
  ok - Created temporary table
  > 
  > ok_group("Seed handling", {
  +     # Helper to define groups with a given seed
  +     orig_group <- mfdb_group(g1 = c(44, 55), g2 = c(88, 99))
  +     bs_group <- function (seed) { mfdb_bootstrap_group(2, orig_group, seed = seed) }
  + 
  +     # Repeatedly manage to make the same sample group (also tested by above tests)
  +     ok(cmp(bs_group(99), bs_group(99)), "Forced seed creates the same group")
  + 
  +     # Seed before == seed after
  +     old_seed <- .Random.seed
  +     bs_group(433)
  +     ok(cmp(old_seed, .Random.seed), "The PRNG state got restored with set seed")
  +     old_seed <- .Random.seed
  +     bs_group(NULL)
  +     ok(cmp(old_seed, .Random.seed), "The PRNG state got restored with NULL seed")
  + 
  +     # Works if there is no seed set yet
  +     remove(".Random.seed", pos = globalenv())
  +     ok(cmp_group(bs_group(123456), bs_group(123456)), "Managed to generate groups before seed is set")
  + })
  # Seed handling
  ok - Forced seed creates the same group
  ok - The PRNG state got restored with set seed
  ok - The PRNG state got restored with NULL seed
  ok - Managed to generate groups before seed is set
  Warning messages:
  1: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  2: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  3: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  4: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  5: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  6: In set.seed(seed, kind = "Mersenne-Twister", normal.kind = "Inversion",  :
    non-uniform 'Rounding' sampler used
  > 
  > proc.time()
     user  system elapsed 
     0.78    0.12    0.89 
Running the tests in 'tests/test-mfdb_aggregate_interval.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > g <- NULL
  > mdb <- fake_mdb()
  > 
  > ok_group("Can generate objects", {
  +     ok(ut_cmp_error(
  +         mfdb_interval("l", c()),
  +         "vect must at least be 2 items long"))
  +     ok(ut_cmp_error(
  +         mfdb_interval("l", c(1)),
  +         "vect must at least be 2 items long"))
  + 
  +     ok(ut_cmp_identical(
  +         class(mfdb_interval("l", c(1, 100))),
  +         c("mfdb_interval", "mfdb_aggregate")))
  + })
  # Can generate objects
  ok - ut_cmp_error(mfdb_interval("l", c()), "vect must at least be
  ok - ut_cmp_error(mfdb_interval("l", c(1)), "vect must at least b
  ok - ut_cmp_identical(class(mfdb_interval("l", c(1, 100))), c("mf
  > 
  > ok_group("Elements are named by prefixes", local({
  +     ok(ut_cmp_identical(
  +         agg_summary(mdb, mfdb_interval("l", c(10,20,25,30)), 'col', 'out', data.frame(), 0),
  +         list(
  +             l10 = structure(call("seq", 10, 19), min = 10, max = 20),
  +             l20 = structure(call("seq", 20, 24), min = 20, max = 25),
  +             l25 = structure(call("seq", 25, 29), min = 25, max = 30))))
  +     ok(ut_cmp_identical(
  +         agg_summary(mdb, mfdb_interval("l", c(5,15,25,30)), 'col', 'out', data.frame(), 0),
  +         list(
  +             l5  = structure(call("seq",  5, 14), min =  5, max = 15),
  +             l15 = structure(call("seq", 15, 24), min = 15, max = 25),
  +             l25 = structure(call("seq", 25, 29), min = 25, max = 30))))
  + 
  +     ok(ut_cmp_identical(
  +         agg_summary(mdb, mfdb_interval("l", c(5,15,25,30), open_ended = c('upper')), 'col', 'out', data.frame(), 0),
  +         list(
  +             l5  = structure(call("seq",  5, 14), min =  5, max = 15),
  +             l15 = structure(call("seq", 15, 24), min = 15, max = 25),
  +             l25 = structure(call("seq", 25, 29), min = 25, max = 30, max_open_ended = TRUE))), "agg_summary: open_ended=upper goes on final group")
  + 
  +     ok(ut_cmp_identical(
  +         agg_summary(mdb, mfdb_interval("l", c(5,15,25,30), open_ended = c('lower')), 'col', 'out', data.frame(), 0),
  +         list(
  +             l5  = structure(call("seq",  5, 14), min =  5, max = 15, min_open_ended = TRUE),
  +             l15 = structure(call("seq", 15, 24), min = 15, max = 25),
  +             l25 = structure(call("seq", 25, 29), min = 25, max = 30))), "agg_summary: open_ended=lower goes on first group")
  + 
  +     ok(ut_cmp_identical(
  +         agg_summary(mdb, mfdb_interval("l", c(5, 15), open_ended = c('lower', 'upper')), 'col', 'out', data.frame(), 0),
  +         list(
  +             l5  = structure(
  +                 call("seq",  5, 14),
  +                 min = 5,
  +                 max = 15,
  +                 min_open_ended = TRUE,
  +                 max_open_ended = TRUE))), "agg_summary: Can have both on a single group")
  + 
  + 
  + }, asNamespace('mfdb')))
  # Elements are named by prefixes
  ok - ut_cmp_identical(agg_summary(mdb, mfdb_interval("l", c(10, 2
  ok - ut_cmp_identical(agg_summary(mdb, mfdb_interval("l", c(5, 15
  ok - agg_summary: open_ended=upper goes on final group
  ok - agg_summary: open_ended=lower goes on first group
  ok - agg_summary: Can have both on a single group
  > 
  > ok_group("Can generate SQL", local({
  +     ok(ut_cmp_identical(
  +             select_clause(mdb, mfdb_interval("l", c(10,20,30)), "col", "outname"),
  +             "CASE WHEN col < CAST(20 AS REAL) THEN 'l10' WHEN col < CAST(30 AS REAL) THEN 'l20' ELSE 'l20' END AS outname"),
  +         "Generated select clause")
  + 
  +     ok(ut_cmp_identical(
  +             where_clause(mdb, mfdb_interval("l", c(10,20,25,30)), "col", "out"),
  +             c("col >= CAST(10 AS REAL)", "col < CAST(30 AS REAL)")),
  +         "Generated where clause")
  +     ok(ut_cmp_identical(
  +             where_clause(mdb, mfdb_interval("l", c(25,50)), "col", "out"),
  +             c("col >= CAST(25 AS REAL)", "col < CAST(50 AS REAL)")),
  +         "Generated where clause")
  + }, asNamespace('mfdb')))
  # Can generate SQL
  ok - Generated select clause
  ok - Generated where clause
  ok - Generated where clause
  > 
  > ok_group("Aggregates with open_ended mfdb_interval", local({
  +     g <<- mfdb_interval('l', c(10, 20, 100), open_ended = TRUE)
  +     ok(ut_cmp_identical(capture.output(pre_query(NULL, g, "out")), c(
  +         "NULL")), "Nothing happened pre_query")
  +     ok(ut_cmp_identical(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(ut_cmp_identical(select_clause(mdb, g, "col", "out"), "CASE WHEN col < CAST(20 AS REAL) THEN 'l10' WHEN col < CAST(100 AS REAL) THEN 'l20' ELSE 'l20' END AS out"), "Select clause")
  +     ok(ut_cmp_identical(from_clause(mdb, g, "col", "out"), c()), "From clause")
  +     ok(ut_cmp_identical(where_clause(mdb, g, "col", "out"), "col >= CAST(10 AS REAL)"), "Where clause")
  + 
  +     g <<- mfdb_interval('l', c(10, 20, 100), open_ended = c('upper'))
  +     ok(ut_cmp_identical(select_clause(mdb, g, "col", "out"), "CASE WHEN col < CAST(20 AS REAL) THEN 'l10' WHEN col < CAST(100 AS REAL) THEN 'l20' ELSE 'l20' END AS out"), "Select clause c('upper')")
  + 
  +     g <<- mfdb_interval('l', c(10, 20, 100), open_ended = c('lower'))
  +     ok(ut_cmp_identical(select_clause(mdb, g, "col", "out"), "CASE WHEN col < CAST(20 AS REAL) THEN 'l10' WHEN col < CAST(100 AS REAL) THEN 'l20' ELSE 'l20' END AS out"), "Select clause c('lower')")
  + 
  +     g <<- mfdb_interval('l', c(10, 20, 100), open_ended = c('lower', 'upper'))
  +     ok(ut_cmp_identical(select_clause(mdb, g, "col", "out"), "CASE WHEN col < CAST(20 AS REAL) THEN 'l10' WHEN col < CAST(100 AS REAL) THEN 'l20' ELSE 'l20' END AS out"), "Select clause c('lower', 'upper')")
  + 
  + }, asNamespace('mfdb')))
  # Aggregates with open_ended mfdb_interval
  ok - Nothing happened pre_query
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Select clause c('upper')
  ok - Select clause c('lower')
  ok - Select clause c('lower', 'upper')
  > 
  > proc.time()
     user  system elapsed 
     0.46    0.14    0.59 
Running the tests in 'tests/test-mfdb_aggregate_unaggregated.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > mdb <- fake_mdb()
  > g <- NULL
  > 
  > ok_group("Aggregates with mfdb_unaggregated(omitNA = FALSE)", local({
  +     g <<- mfdb_unaggregated()
  + 
  +     pre_query(mdb, g, "col")  # Just check nothing happens
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), "col AS out"), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), c()), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), c()), "Where clause")
  + 
  +     ok(cmp(
  +         agg_summary(mdb, mfdb_unaggregated(), 'c.year', 'year', data.frame(), 0),
  +         list()),
  +         "Empty data frame aggregates to empty list")
  + 
  +     ok(cmp_error(
  +         agg_summary(mdb, mfdb_unaggregated(), 'c.claire', 'claire', data.frame(year = c(1998,1998,1999,1999)), 0),
  +         "claire"), "Can't convert unaggregated without data")
  + 
  +     ok(cmp(
  +         agg_summary(mdb, mfdb_unaggregated(), 'c.year', 'year', data.frame(year = c(1998,1998,1999,1999)), 0),
  +         list("1998" = 1998, "1999" = 1999)),
  +         "Can convert unaggregated using returned data")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_unaggregated(omitNA = FALSE)
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  ok - Empty data frame aggregates to empty list
  ok - Can't convert unaggregated without data
  ok - Can convert unaggregated using returned data
  > 
  > ok_group("Aggregates with mfdb_unaggregated(omitNA = TRUE)", local({
  +     g <<- mfdb_unaggregated(omitNA = TRUE)
  + 
  +     pre_query(mdb, g, "col")  # Just check nothing happens
  +     ok(cmp(sample_clause(mdb, g, "col", "out"), "0"), "Sample clause")
  +     ok(cmp(select_clause(mdb, g, "col", "out"), "col AS out"), "Select clause")
  +     ok(cmp(from_clause(mdb, g, "col", "out"), c()), "From clause")
  +     ok(cmp(where_clause(mdb, g, "col", "out"), "col IS NOT NULL"), "Where clause")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_unaggregated(omitNA = TRUE)
  ok - Sample clause
  ok - Select clause
  ok - From clause
  ok - Where clause
  > 
  > ok_group("Aggregates with mfdb_unaggregated() taxonomies", local({
  +     g <<- mfdb_unaggregated()
  + 
  +     ok(cmp(
  +         select_clause(mdb, g, 'tbl.gear_id', 'out'),
  +         "(SELECT name FROM gear WHERE gear_id = tbl.gear_id) AS out"), "Select clause")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_unaggregated() taxonomies
  ok - Select clause
  > 
  > ok_group("Aggregates with mfdb_unaggregated(like / not_like)", local({
  +     g <<- mfdb_unaggregated(like = "fish%")
  +     ok(cmp(
  +         where_clause(mdb, g, "col", "out"),
  +         "(col LIKE 'fish%')"
  +     ), "Where clause (not-taxonomy)")
  +     ok(cmp(
  +         where_clause(mdb, g, "tbl.gear_id", "out"),
  +         "(tbl.gear_id IN (SELECT gear_id FROM gear WHERE name  LIKE 'fish%'))"
  +     ), "Where clause (taxonomy)")
  + 
  +     g <<- mfdb_unaggregated(like = c("fish%", "boops%"), not_like = c("crab%"))
  +     ok(cmp(
  +         where_clause(mdb, g, "col", "out"),
  +         c(
  +             "(col LIKE 'fish%' OR col LIKE 'boops%')",
  +             "(col NOT LIKE 'crab%')"
  +         )
  +     ), "Where clause (not-taxonomy, multiple terms)")
  +     ok(cmp(
  +         where_clause(mdb, g, "tbl.gear_id", "out"),
  +         c(
  +             "(tbl.gear_id IN (SELECT gear_id FROM gear WHERE name  LIKE 'fish%' OR name  LIKE 'boops%'))",
  +             "(tbl.gear_id IN (SELECT gear_id FROM gear WHERE name  NOT LIKE 'crab%'))"
  +         )
  +     ), "Where clause (taxonomy, multiple terms)")
  + }, asNamespace('mfdb')))
  # Aggregates with mfdb_unaggregated(like / not_like)
  ok - Where clause (not-taxonomy)
  ok - Where clause (taxonomy)
  ok - Where clause (not-taxonomy, multiple terms)
  ok - Where clause (taxonomy, multiple terms)
  > 
  > proc.time()
     user  system elapsed 
     0.54    0.14    0.68 
Running the tests in 'tests/test-mfdb_import.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > mdb <- fake_mdb()
  > even <- function (x) x %% 2 == 0
  > 
  > # Capture all output, filtering log messages
  > cap <- function(code) {
  +     grep("\\d{4}-\\d{2}-\\d{2}", capture.output({
  +         x <- code
  +         cat("Return Value:\n")
  +         str(x)
  +     }), value = TRUE, invert = TRUE)
  + }
  > 
  > ok_group("sanitise_col", local({
  +     # Case insensitive matching of column name (but no partial matching)
  +     ok(cmp(sanitise_col(mdb, data.frame(aaaa=1,b=2,aa=3), 'aaaa'), 1), "Picked correct column (aaaa)")
  +     ok(cmp(sanitise_col(mdb, data.frame(aaaa=1,b=2,aa=3), 'aa'), 3), "Picked correct column (aa)")
  +     ok(cmp(sanitise_col(mdb, data.frame(aaaa=9,b=8,aa=7), 'AaAa'), 9), "Case is insensitive (AaAa)")
  +     ok(cmp(sanitise_col(mdb, data.frame(aaaa=9,b=8,aa=7), 'Aa'), 7), "Case is insensitive (Aa)")
  + 
  +     # Defaults used if column name not mentioned
  +     ok(cmp_error(sanitise_col(mdb, data.frame(a=9,b=8,c=7), 'bueller'), 'bueller'), "Complained about missing column when no default supplied")
  +     ok(cmp(sanitise_col(mdb, data.frame(a=9,b=8,c=7), 'x', default = 99), 99), "No column x, used default")
  +     ok(cmp(sanitise_col(mdb, data.frame(a=9,b=8,x=7), 'x', default = 99), 7), "Column overrode default")
  + 
  +     # Checks test all column content
  +     ok(cmp(
  +         sanitise_col(mdb, data.frame(gerald = c(2,4,6,8), freda = c(1,2,3,5)), 'gerald', test = even),
  +         c(2,4,6,8)), "All of gerald passes test")
  +     ok(cmp_error(
  +         sanitise_col(mdb, data.frame(gerald = c(2,4,6,8), freda = c(1,2,3,5)), 'freda', test = even),
  +         "freda"), "Freda does not")
  +     ok(cmp_error(
  +         sanitise_col(mdb, data.frame(gerald = c(2,4,6,8), freda = c(1,2,3,5)), 'freda', test = even),
  +         "1,3,5$"), "Which items that don't match are mentioned")
  +     ok(cmp_error(
  +         sanitise_col(mdb, data.frame(freda = c(1:150)), 'freda', test = even),
  +         paste(c(seq(1, 50 * 2 - 1, 2), " \\.\\.\\.$"), collapse=",")), "Give up complaining after 50 items")
  +     
  + }, asNamespace('mfdb')))
  # sanitise_col
  ok - Picked correct column (aaaa)
  ok - Picked correct column (aa)
  ok - Case is insensitive (AaAa)
  ok - Case is insensitive (Aa)
  ok - Complained about missing column when no default supplied
  ok - No column x, used default
  ok - Column overrode default
  ok - All of gerald passes test
  ok - Freda does not
  ok - Which items that don't match are mentioned
  ok - Give up complaining after 50 items
  > 
  > proc.time()
     user  system elapsed 
     0.68    0.10    0.79 
Running the tests in 'tests/test-mfdb_queries.R' failed.
Complete output:
  > library(mfdb)
  > library(unittest, quietly = TRUE)
  > helpers <- c('utils/helpers.R', 'tests/utils/helpers.R') ; source(helpers[file.exists(helpers)])
  > 
  > mdb <- fake_mdb()
  > 
  > ok_group("mfdb_sample_totalweight", {
  +     ok(ut_cmp_error({
  +         mfdb_sample_totalweight(mdb, c(), list(), measurements = 'camel')
  +     }, "camel"), "Can't have unknown measurements, error included our mistake")
  +     ok(ut_cmp_error({
  +         mfdb_sample_totalweight(mdb, c(), list(), measurements = 'camel')
  +     }, "liver,"), "Can't have unknown measurements, error included correct columns")
  + })
  # mfdb_sample_totalweight
  ok - Can't have unknown measurements, error included our mistake
  ok - Can't have unknown measurements, error included correct columns
  > 
  > ok_group("mfdb_sample_meanweight", {
  +     ok(ut_cmp_error({
  +         mfdb_sample_meanweight(mdb, c(), list(), measurements = 'camel')
  +     }, "camel"), "Can't have unknown measurements, error included our mistake")
  +     ok(ut_cmp_error({
  +         mfdb_sample_meanweight(mdb, c(), list(), measurements = 'camel')
  +     }, "liver,"), "Can't have unknown measurements, error included correct columns")
  + })
  # mfdb_sample_meanweight
  ok - Can't have unknown measurements, error included our mistake
  ok - Can't have unknown measurements, error included correct columns
  > 
  > ok_group("mfdb_sample_meanweight_stddev", {
  +     ok(ut_cmp_error({
  +         mfdb_sample_meanweight_stddev(mdb, c(), list(), measurements = 'camel')
  +     }, "camel"), "Can't have unknown measurements, error included our mistake")
  +     ok(ut_cmp_error({
  +         mfdb_sample_meanweight_stddev(mdb, c(), list(), measurements = 'camel')
  +     }, "liver,"), "Can't have unknown measurements, error included correct columns")
  + })
  # mfdb_sample_meanweight_stddev
  ok - Can't have unknown measurements, error included our mistake
  ok - Can't have unknown measurements, error included correct columns
  > 
  > 
  > proc.time()
     user  system elapsed 
     0.54    0.04    0.57