Genealogy-Occupation
view release on metacpan or search on metacpan
t/edge_cases.t view on Meta::CPAN
#!/usr/bin/env perl
# edge_cases.t - destructive, pathological, and boundary-condition tests
# for Genealogy::Occupation.
#
# Tests are deliberately adversarial: malformed input, boundary-straddling
# strings, homoglyphs, empty arrays, enormous arrays, regex-hostile
# characters, filter-vs-normalise ordering traps, and known false-positive
# risks in the filter patterns. Each subtest documents the exact behaviour
# that results, even when that behaviour is surprising.
use strict;
use warnings;
use 5.014;
use Test::Most;
use Test::Mockingbird 0.10 qw(mock_scoped);
use_ok('Genealogy::Occupation') or BAIL_OUT('Cannot load Genealogy::Occupation');
# Convenience: English-locale object with language detection mocked out
# so that individual test environment locale cannot affect results.
# Returns ($obj, $guard); caller must keep $guard in scope.
sub _en {
my %args = @_;
delete local $ENV{LANGUAGE};
delete local $ENV{LC_ALL};
delete local $ENV{LC_MESSAGES};
local $ENV{LANG} = 'en_GB.UTF-8';
my $guard = mock_scoped('I18N::LangTags::Detect::detect' => sub { () });
my $obj = Genealogy::Occupation->new(%args);
# Return guard separately so the caller can keep it alive past return
return ($obj, $guard);
}
# -----------------------------------------------------------------------
# String-cleaning step boundary conditions
# The cleaning pipeline runs in this order:
# tr/\r\n/ / -> s/\.+$// -> s/[\(\)]//g ->
# s/\s\s+/ /g -> s/\s+$// -> s/\./;/g
# -----------------------------------------------------------------------
subtest 'cleaning - dots-only string collapses to empty and is skipped' => sub {
delete local $ENV{LANGUAGE};
delete local $ENV{LC_ALL};
delete local $ENV{LC_MESSAGES};
local $ENV{LANG} = 'en_GB.UTF-8';
my $guard = mock_scoped('I18N::LangTags::Detect::detect' => sub { () });
my $obj = Genealogy::Occupation->new();
# '...' -> s/\.+$// -> '' -> length 0 -> skipped entirely
is_deeply($obj->normalise(occupation => '...'), [],
'dots-only string produces empty result');
};
subtest 'cleaning - parentheses-only string collapses to empty and is skipped' => sub {
delete local $ENV{LANGUAGE};
delete local $ENV{LC_ALL};
delete local $ENV{LC_MESSAGES};
local $ENV{LANG} = 'en_GB.UTF-8';
my $guard = mock_scoped('I18N::LangTags::Detect::detect' => sub { () });
my $obj = Genealogy::Occupation->new();
# '()' -> s/[\(\)]//g -> '' -> length 0 -> skipped
is_deeply($obj->normalise(occupation => '()'), [],
'parentheses-only string produces empty result');
# Parens with only whitespace inside also collapses
is_deeply($obj->normalise(occupation => '( )'), [],
'whitespace-inside-parens string produces empty result');
};
subtest 'cleaning - embedded CR+LF normalised to single space' => sub {
delete local $ENV{LANGUAGE};
delete local $ENV{LC_ALL};
delete local $ENV{LC_MESSAGES};
local $ENV{LANG} = 'en_GB.UTF-8';
my $guard = mock_scoped('I18N::LangTags::Detect::detect' => sub { () });
my $obj = Genealogy::Occupation->new();
# tr/\r\n/ / converts each \r and \n to a space, then s/\s\s+/ /g
# collapses them, restoring the string to a matchable form
is_deeply($obj->normalise(occupation => "Ag\r\nLab"), ['Agricultural Labourer'],
'CRLF within occupation string cleaned to single space before lookup');
# Multiple newlines also collapse
is_deeply($obj->normalise(occupation => "Ag\n\n\nLab"), ['Agricultural Labourer'],
'multiple newlines collapsed to single space');
};
subtest 'cleaning - trailing dots stripped, internal dots become semicolons' => sub {
delete local $ENV{LANGUAGE};
( run in 1.963 second using v1.01-cache-2.11-cpan-14f38c9f855 )