package flect import ( "bytes" "encoding/json" "testing" "github.com/stretchr/testify/require" ) type tt struct { act string exp string } func Test_LoadInflections(t *testing.T) { r := require.New(t) m := map[string]string{ "baby": "bebe", "xyz": "zyx", } b, err := json.Marshal(m) r.NoError(err) r.NoError(LoadInflections(bytes.NewReader(b))) for k, v := range m { r.Equal(v, Pluralize(k)) r.Equal(v, Pluralize(v)) r.Equal(k, Singularize(k)) r.Equal(k, Singularize(v)) } } func Test_LoadInflectionsWrongSingular(t *testing.T) { r := require.New(t) m := map[string]string{ "a file": "files", } b, err := json.Marshal(m) r.NoError(err) r.Error(LoadInflections(bytes.NewReader(b))) } func Test_LoadInflectionsWrongPlural(t *testing.T) { r := require.New(t) m := map[string]string{ "beatle": "the beatles", } b, err := json.Marshal(m) r.NoError(err) r.Error(LoadInflections(bytes.NewReader(b))) } func Test_LoadAcronyms(t *testing.T) { r := require.New(t) m := []string{ "ACC", "TLC", "LSA", } b, err := json.Marshal(m) r.NoError(err) r.NoError(LoadAcronyms(bytes.NewReader(b))) for _, acronym := range m { r.True(baseAcronyms[acronym]) } } type dict struct { singular string plural string doSingularizeTest bool doPluralizeTest bool } var singlePluralAssertions = []dict{ {"", "", true, true}, {"Car", "Cars", true, true}, {"Boy", "Boys", true, true}, {"GoodBoy", "GoodBoys", true, true}, {"Axis", "Axes", true, true}, {"Child", "Children", true, true}, {"GoodChild", "GoodChildren", true, true}, {"node_child", "node_children", true, true}, {"SmartPerson", "SmartPeople", true, true}, {"great_person", "great_people", true, true}, {"salesperson", "salespeople", true, true}, {"custom_field", "custom_fields", true, true}, {"funky jeans", "funky jeans", true, true}, {"payment_information", "payment_information", true, true}, {"sportsEquipment", "sportsEquipment", true, true}, {"status_code", "status_codes", true, true}, {"user_custom_field", "user_custom_fields", true, true}, {"SuperbOx", "SuperbOxen", true, true}, {"WildOx", "WildOxen", true, true}, {"wild_ox", "wild_oxen", true, true}, {"box", "boxes", true, true}, {"fox", "foxes", true, true}, {"comment", "comments", true, true}, {"edge", "edges", true, true}, {"equipment", "equipment", true, true}, {"experience", "experiences", true, true}, {"fleet", "fleets", true, true}, {"foobar", "foobars", true, true}, {"mouse", "mice", true, true}, {"newsletter", "newsletters", true, true}, {"stack", "stacks", true, true}, {"user", "users", true, true}, {"woman", "women", true, true}, {"human", "humans", true, true}, {"spokesman", "spokesmen", true, true}, // Words that end in -f or -fe change -f or -fe to -ves // https://en.wiktionary.org/wiki/Category:English_irregular_plurals_ending_in_"-ves" {"calf", "calves", true, true}, {"dwarf", "dwarves", true, false}, // dwarfs looks popular than dwarves {"dwarf", "dwarfs", true, true}, {"elf", "elves", true, true}, {"half", "halves", true, true}, {"knife", "knives", true, true}, {"leaf", "leaves", true, true}, {"life", "lives", true, true}, {"loaf", "loaves", true, true}, {"safe", "saves", true, true}, {"scarf", "scarves", true, true}, {"self", "selves", true, true}, {"sheaf", "sheaves", true, true}, {"shelf", "shelves", true, true}, {"thief", "thieves", true, true}, {"wharf", "wharves", true, true}, {"wife", "wives", true, true}, {"wolf", "wolves", true, true}, {"beef", "beef", true, true}, {"belief", "beliefs", true, true}, {"chef", "chefs", true, true}, {"chief", "chiefs", true, true}, {"hoof", "hoofs", true, true}, {"kerchief", "kerchiefs", true, true}, {"roof", "roofs", true, true}, {"archive", "archives", true, true}, {"perspective", "perspectives", true, true}, // Words that end in -y preceded by a consonant change -y to -ies {"day", "days", true, true}, {"hobby", "hobbies", true, true}, {"agency", "agencies", true, true}, {"body", "bodies", true, true}, {"abbey", "abbeys", true, true}, {"jiffy", "jiffies", true, true}, {"geology", "geologies", true, true}, {"geography", "geographies", true, true}, {"cookie", "cookies", true, true}, {"sky", "skies", true, true}, {"supply", "supplies", true, true}, {"academy", "academies", true, true}, {"ebony", "ebonies", true, true}, {"boy", "boys", true, true}, {"copy", "copies", true, true}, {"category", "categories", true, true}, {"embassy", "embassies", true, true}, {"entity", "entities", true, true}, {"guy", "guys", true, true}, {"obsequy", "obsequies", true, true}, {"navy", "navies", true, true}, {"proxy", "proxies", true, true}, {"crazy", "crazies", true, true}, // Words from French that end in -u add an x {"aboideau", "aboideaux", true, true}, {"beau", "beaux", true, true}, {"château", "châteaux", true, true}, {"chateau", "chateaux", true, true}, {"fabliau", "fabliaux", true, true}, {"tableau", "tableaux", true, true}, {"bureau", "bureaus", true, true}, {"adieu", "adieux", true, true}, // Words from Greek that end in -on change -on to -a {"tetrahedron", "tetrahedra", true, true}, // Words from Latin that end in -um change -um to -a {"stadium", "stadiums", true, true}, {"stadium", "stadia", true, false}, {"aquarium", "aquaria", true, true}, {"auditorium", "auditoria", true, true}, {"bacterium", "bacteria", true, true}, {"pretorium", "pretoriums", true, true}, {"symposium", "symposia", true, true}, {"symposium", "symposiums", true, false}, {"amoebaeum", "amoebaea", true, true}, {"coliseum", "coliseums", true, true}, {"museum", "museums", true, true}, {"agenda", "agendas", true, true}, {"curriculum", "curriculums", true, true}, {"collum", "colla", true, true}, {"datum", "data", true, true}, {"erratum", "errata", true, true}, {"maximum", "maxima", true, true}, {"platinum", "platinums", true, true}, {"serum", "sera", true, true}, {"spectrum", "spectra", true, true}, // Words from Latin that end in -us change -us to -i or -era {"opera", "operas", true, true}, // Words from Latin that end in -a change -a to -ae {"alumna", "alumnae", true, true}, {"larva", "larvae", true, true}, {"minutia", "minutiae", true, true}, {"nebula", "nebulae", true, true}, {"vertebra", "vertebrae", true, true}, {"vita", "vitae", true, true}, {"antenna", "antennas", true, true}, {"formula", "formulas", true, true}, {"tuna", "tuna", true, true}, {"quota", "quotas", true, true}, {"vedalia", "vedalias", true, true}, {"media", "media", true, true}, // instead of mediae, popular case {"multimedia", "multimedia", true, true}, // Words that end in -ch, -o, -s, -sh, -x, -z {"lunch", "lunches", true, true}, {"search", "searches", true, true}, {"switch", "switches", true, true}, {"headache", "headaches", true, true}, // ch vs. che {"marsh", "marshes", true, true}, {"wish", "wishes", true, true}, {"bus", "buses", true, true}, // end with u + s, but no -us rule {"campus", "campuses", true, true}, {"caucus", "caucuses", true, true}, {"circus", "circuses", true, true}, {"plus", "pluses", true, true}, {"prometheus", "prometheuses", true, true}, {"status", "statuses", true, true}, {"virus", "viruses", true, true}, {"use", "uses", true, true}, // -use {"fuse", "fuses", true, true}, {"house", "houses", true, true}, {"spouse", "spouses", true, true}, {"quiz", "quizzes", true, true}, {"buzz", "buzzes", true, true}, {"blitz", "blitzes", true, true}, {"quartz", "quartzes", true, true}, {"topaz", "topazes", true, true}, {"waltz", "waltzes", true, true}, {"prize", "prizes", true, true}, {"access", "accesses", true, true}, {"process", "processes", true, true}, {"address", "addresses", true, true}, {"case", "cases", true, true}, {"database", "databases", true, true}, {"glimpse", "glimpses", true, true}, {"horse", "horses", true, true}, {"lapse", "lapses", true, true}, {"collapse", "collapses", true, true}, {"truss", "trusses", true, true}, {"portfolio", "portfolios", true, true}, // -o -os {"piano", "pianos", true, true}, // -ano -anos {"hello", "hellos", true, true}, // -lo -los {"buffalo", "buffaloes", true, true}, // -lo -loes {"photo", "photos", true, true}, // -to -tos {"potato", "potatoes", true, true}, // exception of -to -tos {"tomato", "tomatoes", true, true}, {"graffiti", "graffiti", true, true}, {"foo", "foos", true, true}, {"zoo", "zoos", true, true}, // Words from Latin that end in -ex change -ex to -ices // Words from Latin that end in -ix change -ix to -ices {"appendix", "appendices", true, true}, // -dix {"codex", "codices", true, true}, // -dex {"index", "indices", true, true}, {"bodice", "bodices", true, true}, // -dice {"helix", "helices", true, true}, // -lix {"complex", "complexes", true, true}, // -lex {"duplex", "duplexes", true, true}, {"accomplice", "accomplices", true, true}, // -lice {"slice", "slices", true, true}, {"matrix", "matrices", true, true}, // -trix {"justice", "justices", true, true}, // -tice {"lattice", "lattices", true, true}, {"notice", "notices", true, true}, {"apex", "apices", true, true}, // -pex {"spice", "spices", true, true}, // -pice {"device", "devices", true, true}, // -vice {"service", "services", true, true}, {"fix", "fixes", true, true}, // -ix {"sex", "sexes", true, true}, // -ex {"invoice", "invoices", true, true}, // gobuffalo/flect#61 {"voice", "voices", true, true}, {"choice", "choices", true, true}, // Words from Latin that end in -is change -is to -es {"axis", "axes", true, true}, {"tax", "taxes", true, true}, // not taxis {"eclipse", "eclipses", true, true}, {"ellipse", "ellipses", true, true}, {"ellipsis", "ellipses", false, true}, // pluralize only {"oasis", "oases", true, true}, {"thesis", "theses", true, true}, // word thesis {"hypothesis", "hypotheses", true, true}, {"parenthesis", "parentheses", true, true}, {"analysis", "analyses", true, true}, // suffix lysis {"antithesis", "antitheses", true, true}, {"diagnosis", "diagnoses", true, true}, // suffix gnosis {"prognosis", "prognoses", true, true}, {"synopsis", "synopses", true, true}, // suffix opsis {"synapse", "synapses", true, true}, {"waste", "wastes", true, true}, {"psi", "psis", true, true}, {"pepsi", "pepsis", true, true}, // Acronyms {"widget_uuid", "widget_uuids", true, true}, {"WidgetUUID", "WidgetUUIDs", true, true}, {"widgetUUID", "widgetUUIDs", true, true}, {"widgetUuid", "widgetUuids", true, true}, {"widget_UUID", "widget_UUIDs", true, true}, {"ID", "IDs", true, true}, {"IDS", "IDSes", true, true}, // id to ids (ID), ids to idses (IDS) is not supported {"api", "apis", true, true}, {"API", "APIs", true, true}, {"html", "htmls", true, true}, {"HTML", "HTMLs", true, true}, {"FYI", "FYIs", true, true}, {"LAN", "LANs", true, true}, {"ssh", "sshs", true, true}, // sh {"SSH", "SSHs", true, true}, {"eia", "eias", true, true}, // ia {"EIA", "EIAs", true, true}, {"DNS", "DNSes", true, true}, } func init() { for _, wd := range dictionary { if wd.uncountable && wd.plural == "" { wd.plural = wd.singular } singlePluralAssertions = append(singlePluralAssertions, dict{ singular: wd.singular, plural: wd.plural, doSingularizeTest: !wd.unidirectional, }) if wd.alternative != "" { singlePluralAssertions = append(singlePluralAssertions, dict{ singular: wd.singular, plural: wd.alternative, doPluralizeTest: false, }) } } }