test_that("addr_match stages zipcode street and number matching", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229", "10 ELM ST CINCINNATI OH 45220" )) x <- as_addr(c( "10 MAINE STREET CINCINNATI OH 45220", "99 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229", "10 OAK ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45103", NA_character_ )) out <- addr_match(x, y, progress = FALSE) expect_true(inherits(out, "addr")) expect_equal(format(out[1]), format(y[1])) expect_true(is.na(out[2]@number)) expect_equal(out[2]@street@name, "MAIN") expect_equal(out[2]@place@zipcode, "45220") expect_equal(format(out[3]), format(y[3])) expect_true(is.na(out[4]@number)) expect_true(is.na(out[4]@street)) expect_equal(out[4]@place@zipcode, "45220") expect_true(is.na(out[5])) expect_true(is.na(out[6])) }) test_that("addr_match progress output uses zipcode text and 80-char bars", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) x <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) expect_equal(nchar(addr_progress_bar(1, 3), type = "width"), 80) progress_output <- capture.output({ out <- addr_match(x, y, progress = TRUE) }) progress_text <- paste(progress_output, collapse = "\n") progress_text <- gsub("\033\\[[0-9;]*[[:alpha:]]", "", progress_text) bar_lines <- regmatches( progress_text, gregexpr("\\[[=.]+\\]", progress_text) )[[1]] expect_true(grepl( "preparing reference addr vector", progress_text )) expect_true(grepl( "prepared reference addr vector in [0-9]+\\.[0-9]{2} seconds", progress_text )) expect_true(grepl( "matching addr vectors in 45220 \\(2 to 2\\)", progress_text )) expect_true(grepl( "matching addr vectors in 45229 \\(1 to 1\\)", progress_text )) expect_true(grepl( "matched addr vectors in [0-9]+\\.[0-9]{2} seconds", progress_text )) expect_true(length(bar_lines) > 0L) expect_true(all(nchar(bar_lines, type = "width") <= 80)) expect_true(inherits(out, "addr")) }) test_that("addr_match_prepare can show its own progress bar", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) progress_output <- capture.output({ prepared <- addr_match_prepare(y, progress = TRUE) }) progress_text <- paste(progress_output, collapse = "\n") progress_text <- gsub("\033\\[[0-9;]*[[:alpha:]]", "", progress_text) bar_lines <- regmatches( progress_text, gregexpr("\\[[=.]+\\]", progress_text) )[[1]] expect_true(grepl("preparing reference addr vector", progress_text)) expect_true(grepl( "preparing reference addr vector in 45220 \\(2 addrs\\)", progress_text )) expect_true(grepl( "preparing reference addr vector in 45229 \\(1 addrs\\)", progress_text )) expect_true(grepl( "prepared reference addr vector in [0-9]+\\.[0-9]{2} seconds", progress_text )) expect_true(length(bar_lines) > 0L) expect_s3_class(prepared, "addr_match_index") }) test_that("addr_match skips preparation message for prepared references", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) x <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) progress_output <- capture.output({ out <- addr_match( x, addr_match_prepare(y, progress = FALSE), progress = TRUE ) }) progress_text <- paste(progress_output, collapse = "\n") progress_text <- gsub("\033\\[[0-9;]*[[:alpha:]]", "", progress_text) expect_false(grepl("preparing reference addr vector", progress_text)) expect_true(inherits(out, "addr")) }) test_that("addr_match progress text formats counts with commas", { expect_equal( addr_progress_text("45219", 143L, 4599L), "matching addr vectors in 45219 (143 to 4,599)" ) expect_equal( addr_progress_text("45219", 1234L, 56789L), "matching addr vectors in 45219 (1,234 to 56,789)" ) }) test_that("addr_match_prepare caches reference data for repeated matching", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229", "10 MAIN ST CINCINNATI OH 45220" )) x <- as_addr(c( "10 MAINE STREET CINCINNATI OH 45220", "99 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229" )) prepared <- addr_match_prepare(y) out_raw <- addr_match(x, y, progress = FALSE) out_prepared <- addr_match(x, prepared, progress = FALSE) expect_s3_class(prepared, "addr_match_index") expect_equal(prepared$n_unique, 3L) expect_equal(sort(prepared$zipcodes), c("45220", "45229")) expect_equal(format(out_prepared), format(out_raw)) }) test_that("addr_match_stage classifies staged addr_match results", { y <- as_addr(c( "10 MAIN ST CINCINNATI OH 45220", "11 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229", "10 ELM ST CINCINNATI OH 45220" )) x <- as_addr(c( "10 MAINE STREET CINCINNATI OH 45220", "99 MAIN ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45229", "10 OAK ST CINCINNATI OH 45220", "10 MAIN ST CINCINNATI OH 45103", NA_character_ )) out <- addr_match(x, y, progress = FALSE) expect_equal( addr_match_stage(out), ordered( c("number", "street", "number", "zip", "none", "none"), levels = c("none", "zip", "street", "number") ) ) }) test_that("addr_match_stage rejects non-addr_match structures in strict mode", { x <- addr( number = addr_number(digits = "10"), street = addr_street(), place = addr_place(zipcode = "45220") ) expect_error( addr_match_stage(x), "x does not look like an addr_match result" ) expect_equal( addr_match_stage(x, strict = FALSE), ordered("number", levels = c("none", "zip", "street", "number")) ) }) test_that("addr_match works with packaged prepared example data", { # Reordered matches, a duplicate, and ZIP-only fallbacks exercise the full # packaged reference without repeating the same work for 100 input rows. addresses <- voter_addresses()[c(3, 1, 2, 1, 87, 88)] addresses[5:6] <- paste( "1 SYNTHETIC EXAMPLE RD CINCINNATI OH", sub(".* ", "", addresses[5:6]) ) x <- as_addr(addresses) y <- nad_example_data(match_prepared = TRUE) out <- addr_match(x, y, progress = FALSE) stage <- addr_match_stage(out) expect_gte(length(unique(x@place@zipcode)), 3L) expect_equal(sum(!is.na(out@number)), 4) expect_equal(sum(!is.na(out@street)), 4) expect_equal(out@place@zipcode, x@place@zipcode) expect_equal( as.integer(table(stage)), c(0L, 2L, 0L, 4L) ) expect_identical(as.character(stage), c(rep("number", 4), rep("zip", 2))) expect_true(inherits(out, "addr")) expect_length(out, 6L) expect_equal(sum(!is.na(out)), 4) expect_equal( format(out[1:4]), c( "9960 DALY RD CINCINNATI OH 45231", "3359 QUEEN CITY AVE CINCINNATI OH 45238", "1040 KREIS LN CINCINNATI OH 45205", "3359 QUEEN CITY AVE CINCINNATI OH 45238" ) ) }) test_that("addr_match honors matching tuning arguments", { y <- nad_example_data(match_prepared = TRUE) demo_addr <- function(number, street, type, zipcode, map_ordinal = TRUE) { addr( addr_number(prefix = "", digits = number, suffix = ""), addr_street( predirectional = "", premodifier = "", pretype = "", name = street, posttype = type, postdirectional = "", map_ordinal = map_ordinal ), addr_place(name = "", state = "", zipcode = zipcode) ) } zip_true <- addr_match( demo_addr("2700", "Alice", "St", "45222"), y, zip_variants = TRUE, progress = FALSE ) zip_false <- addr_match( demo_addr("2700", "Alice", "St", "45222"), y, zip_variants = FALSE, progress = FALSE ) zip_limited <- addr_match( demo_addr("2700", "Alice", "St", "45222"), y, zip_variant = "swap", progress = FALSE ) expect_identical( format(zip_true), "2700 ALICE ST CINCINNATI OH 45221" ) expect_identical(as.character(addr_match_stage(zip_true)), "number") expect_identical(format(zip_false), "") expect_identical(as.character(addr_match_stage(zip_false)), "none") expect_identical(format(zip_limited), "") expect_identical(as.character(addr_match_stage(zip_limited)), "none") fuzzy_name_on <- addr_match( demo_addr("10623", "Srpingfield", "Pike", "45215"), y, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, progress = FALSE ) fuzzy_name_off <- addr_match( demo_addr("10623", "Srpingfield", "Pike", "45215"), y, name_phonetic_dist = 0L, name_fuzzy_dist = 0L, progress = FALSE ) expect_identical( format(fuzzy_name_on), "10623 SPRINGFIELD PIKE CINCINNATI OH 45215" ) expect_identical(as.character(addr_match_stage(fuzzy_name_on)), "number") expect_identical(format(fuzzy_name_off), "45215") expect_identical(as.character(addr_match_stage(fuzzy_name_off)), "zip") phonetic_exact <- addr_match( demo_addr("173", "Wuhlper", "Ave", "45220"), y, name_phonetic_dist = 0L, name_fuzzy_dist = 0L, progress = FALSE ) expect_identical( format(phonetic_exact), "173 WOOLPER AVE CINCINNATI OH 45220" ) expect_identical(as.character(addr_match_stage(phonetic_exact)), "number") ordinal_phonetic_on <- addr_match( demo_addr("12176", "8TH", "Ave", "45249"), y, name_phonetic_dist = 1L, name_fuzzy_dist = 0L, progress = FALSE ) ordinal_phonetic_off <- addr_match( demo_addr("12176", "8TH", "Ave", "45249"), y, name_phonetic_dist = 0L, name_fuzzy_dist = 0L, progress = FALSE ) expect_identical( format(ordinal_phonetic_on), "12176 7TH AVE CINCINNATI OH 45249" ) expect_identical( as.character(addr_match_stage(ordinal_phonetic_on)), "number" ) expect_identical(format(ordinal_phonetic_off), "45249") expect_identical(as.character(addr_match_stage(ordinal_phonetic_off)), "zip") ordinal_fuzzy_on <- addr_match( demo_addr("12176", "7HT", "Ave", "45249", map_ordinal = FALSE), y, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, progress = FALSE ) ordinal_fuzzy_off <- addr_match( demo_addr("12176", "7HT", "Ave", "45249", map_ordinal = FALSE), y, name_phonetic_dist = 0L, name_fuzzy_dist = 0L, progress = FALSE ) expect_identical( format(ordinal_fuzzy_on), "12176 7TH AVE CINCINNATI OH 45249" ) expect_identical(as.character(addr_match_stage(ordinal_fuzzy_on)), "number") expect_identical(format(ordinal_fuzzy_off), "45249") expect_identical(as.character(addr_match_stage(ordinal_fuzzy_off)), "zip") fuzzy_number_on <- addr_match( demo_addr("10622", "Springfield", "Pike", "45215"), y, number_fuzzy_dist = 1L, progress = FALSE ) fuzzy_number_off <- addr_match( demo_addr("10622", "Springfield", "Pike", "45215"), y, number_fuzzy_dist = 0L, progress = FALSE ) expect_identical( format(fuzzy_number_on), "10623 SPRINGFIELD PIKE CINCINNATI OH 45215" ) expect_identical(as.character(addr_match_stage(fuzzy_number_on)), "number") expect_identical(format(fuzzy_number_off), "SPRINGFIELD PIKE 45215") expect_identical(as.character(addr_match_stage(fuzzy_number_off)), "street") }) test_that("addr_match honors street type and directional matching modes", { demo_addr <- function(number, name, pretype = "", postdirectional = "") { addr( addr_number(prefix = "", digits = number, suffix = ""), addr_street( predirectional = "", premodifier = "", pretype = pretype, name = name, posttype = "Rd", postdirectional = postdirectional, map_pretype = FALSE, map_posttype = FALSE, map_directional = FALSE, map_ordinal = FALSE ), addr_place(name = "Testville", state = "OH", zipcode = "45220") ) } y <- vctrs::vec_c( demo_addr("10", "Main"), demo_addr("10", "Main", pretype = "US Hwy", postdirectional = "E") ) x <- demo_addr("10", "Mian", pretype = "US Hwy", postdirectional = "E") out_relaxed <- addr_match( x, y, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, match_street_type = "ignore", match_street_directional = "ignore", progress = FALSE ) out_default <- addr_match( x, y, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, progress = FALSE ) out_explicit_exact <- addr_match( x, y, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, match_street_type = "exact", match_street_directional = "exact", progress = FALSE ) expect_identical( format(out_relaxed), "10 MAIN RD TESTVILLE OH 45220" ) expect_identical( format(out_default), "10 US HWY MAIN RD E TESTVILLE OH 45220" ) expect_identical( format(out_explicit_exact), "10 US HWY MAIN RD E TESTVILLE OH 45220" ) }) test_that("addr_match can ignore directionals and street type", { demo_addr <- function(name, type = "Rd", predirectional = "") { addr( addr_number(prefix = "", digits = "10", suffix = ""), addr_street( predirectional = predirectional, premodifier = "", pretype = "", name = name, posttype = type, postdirectional = "", map_pretype = FALSE, map_posttype = FALSE, map_directional = FALSE, map_ordinal = FALSE ), addr_place(name = "Testville", state = "OH", zipcode = "45220") ) } y_pred <- demo_addr("14th", type = "St", predirectional = "E") x_pred <- demo_addr("14th", type = "St") out_pred_required <- addr_match(x_pred, y_pred, progress = FALSE) out_pred_optional <- addr_match( x_pred, y_pred, match_street_directional = "ignore", progress = FALSE ) expect_identical(format(out_pred_required), "45220") expect_identical(format(out_pred_optional), "10 E 14TH ST TESTVILLE OH 45220") y_type <- demo_addr("Oak", type = "Rd") x_type <- demo_addr("Oka", type = "Ave") out_type_required <- addr_match( x_type, y_type, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, progress = FALSE ) out_type_optional <- addr_match( x_type, y_type, name_phonetic_dist = 0L, name_fuzzy_dist = 1L, match_street_type = "ignore", progress = FALSE ) expect_identical(format(out_type_required), "45220") expect_identical(format(out_type_optional), "10 OAK RD TESTVILLE OH 45220") }) test_that("nad_example_data can return prepared match data", { prepared <- nad_example_data(match_prepared = TRUE) expect_s3_class(prepared, "addr_match_index") expect_identical(attr(prepared, "addr_match_index_version"), 1L) }) test_that("legacy prepared match indexes must be rebuilt", { x <- as_addr("10 MAIN ST CINCINNATI OH 45220") prepared <- addr_match_prepare(x, progress = FALSE) attr(prepared, "addr_match_index_version") <- NULL expect_error( addr_match(x, prepared, progress = FALSE), "rebuild it with addr_match_prepare()", fixed = TRUE ) expect_error( addr_left_join( tibble::tibble(addr = x), tibble::tibble(addr = x), match_prepared = prepared, progress = FALSE ), "rebuild it with addr_match_prepare()", fixed = TRUE ) })