1package inflect 2 3import ( 4 "testing" 5) 6 7// assert helper 8 9func assertEqual(t *testing.T, a, b string) { 10 if a != b { 11 t.Errorf("inflect: expected %v got %v", a, b) 12 } 13} 14 15// test data 16 17var SingularToPlural = map[string]string{ 18 "search": "searches", 19 "switch": "switches", 20 "fix": "fixes", 21 "box": "boxes", 22 "process": "processes", 23 "address": "addresses", 24 "case": "cases", 25 "stack": "stacks", 26 "wish": "wishes", 27 "fish": "fish", 28 "jeans": "jeans", 29 "funky jeans": "funky jeans", 30 "category": "categories", 31 "query": "queries", 32 "ability": "abilities", 33 "agency": "agencies", 34 "movie": "movies", 35 "archive": "archives", 36 "index": "indices", 37 "wife": "wives", 38 "safe": "saves", 39 "half": "halves", 40 "move": "moves", 41 "salesperson": "salespeople", 42 "person": "people", 43 "spokesman": "spokesmen", 44 "man": "men", 45 "woman": "women", 46 "basis": "bases", 47 "diagnosis": "diagnoses", 48 "diagnosis_a": "diagnosis_as", 49 "datum": "data", 50 "medium": "media", 51 "stadium": "stadia", 52 "analysis": "analyses", 53 "node_child": "node_children", 54 "child": "children", 55 "experience": "experiences", 56 "day": "days", 57 "comment": "comments", 58 "foobar": "foobars", 59 "newsletter": "newsletters", 60 "old_news": "old_news", 61 "news": "news", 62 "series": "series", 63 "species": "species", 64 "quiz": "quizzes", 65 "perspective": "perspectives", 66 "ox": "oxen", 67 "photo": "photos", 68 "buffalo": "buffaloes", 69 "tomato": "tomatoes", 70 "dwarf": "dwarves", 71 "elf": "elves", 72 "information": "information", 73 "equipment": "equipment", 74 "bus": "buses", 75 "status": "statuses", 76 "status_code": "status_codes", 77 "mouse": "mice", 78 "louse": "lice", 79 "house": "houses", 80 "octopus": "octopi", 81 "virus": "viri", 82 "alias": "aliases", 83 "portfolio": "portfolios", 84 "vertex": "vertices", 85 "matrix": "matrices", 86 "matrix_fu": "matrix_fus", 87 "axis": "axes", 88 "testis": "testes", 89 "crisis": "crises", 90 "rice": "rice", 91 "shoe": "shoes", 92 "horse": "horses", 93 "prize": "prizes", 94 "edge": "edges", 95 "database": "databases", 96} 97 98var CapitalizeMixture = map[string]string{ 99 "product": "Product", 100 "special_guest": "Special_guest", 101 "applicationController": "ApplicationController", 102 "Area51Controller": "Area51Controller", 103} 104 105var CamelToUnderscore = map[string]string{ 106 "Product": "product", 107 "SpecialGuest": "special_guest", 108 "ApplicationController": "application_controller", 109 "Area51Controller": "area51_controller", 110} 111 112var UnderscoreToLowerCamel = map[string]string{ 113 "product": "product", 114 "special_guest": "specialGuest", 115 "application_controller": "applicationController", 116 "area51_controller": "area51Controller", 117} 118 119var CamelToUnderscoreWithoutReverse = map[string]string{ 120 "HTMLTidy": "html_tidy", 121 "HTMLTidyGenerator": "html_tidy_generator", 122 "FreeBsd": "free_bsd", 123 "HTML": "html", 124} 125 126var ClassNameToForeignKeyWithUnderscore = map[string]string{ 127 "Person": "person_id", 128 "Account": "account_id", 129} 130 131var PluralToForeignKeyWithUnderscore = map[string]string{ 132 "people": "person_id", 133 "accounts": "account_id", 134} 135 136var ClassNameToForeignKeyWithoutUnderscore = map[string]string{ 137 "Person": "personid", 138 "Account": "accountid", 139} 140 141var ClassNameToTableName = map[string]string{ 142 "PrimarySpokesman": "primary_spokesmen", 143 "NodeChild": "node_children", 144} 145 146var StringToParameterized = map[string]string{ 147 "Donald E. Knuth": "donald-e-knuth", 148 "Random text with *(bad)* characters": "random-text-with-bad-characters", 149 "Allow_Under_Scores": "allow_under_scores", 150 "Trailing bad characters!@#": "trailing-bad-characters", 151 "!@#Leading bad characters": "leading-bad-characters", 152 "Squeeze separators": "squeeze-separators", 153 "Test with + sign": "test-with-sign", 154 "Test with malformed utf8 \251": "test-with-malformed-utf8", 155} 156 157var StringToParameterizeWithNoSeparator = map[string]string{ 158 "Donald E. Knuth": "donaldeknuth", 159 "With-some-dashes": "with-some-dashes", 160 "Random text with *(bad)* characters": "randomtextwithbadcharacters", 161 "Trailing bad characters!@#": "trailingbadcharacters", 162 "!@#Leading bad characters": "leadingbadcharacters", 163 "Squeeze separators": "squeezeseparators", 164 "Test with + sign": "testwithsign", 165 "Test with malformed utf8 \251": "testwithmalformedutf8", 166} 167 168var StringToParameterizeWithUnderscore = map[string]string{ 169 "Donald E. Knuth": "donald_e_knuth", 170 "Random text with *(bad)* characters": "random_text_with_bad_characters", 171 "With-some-dashes": "with-some-dashes", 172 "Retain_underscore": "retain_underscore", 173 "Trailing bad characters!@#": "trailing_bad_characters", 174 "!@#Leading bad characters": "leading_bad_characters", 175 "Squeeze separators": "squeeze_separators", 176 "Test with + sign": "test_with_sign", 177 "Test with malformed utf8 \251": "test_with_malformed_utf8", 178} 179 180var StringToParameterizedAndNormalized = map[string]string{ 181 "Malmö": "malmo", 182 "Garçons": "garcons", 183 "Opsů": "opsu", 184 "Ærøskøbing": "aeroskobing", 185 "Aßlar": "asslar", 186 "Japanese: 日本語": "japanese", 187} 188 189var UnderscoreToHuman = map[string]string{ 190 "employee_salary": "Employee salary", 191 "employee_id": "Employee", 192 "underground": "Underground", 193} 194 195var MixtureToTitleCase = map[string]string{ 196 "active_record": "Active Record", 197 "ActiveRecord": "Active Record", 198 "action web service": "Action Web Service", 199 "Action Web Service": "Action Web Service", 200 "Action web service": "Action Web Service", 201 "actionwebservice": "Actionwebservice", 202 "Actionwebservice": "Actionwebservice", 203 "david's code": "David's Code", 204 "David's code": "David's Code", 205 "david's Code": "David's Code", 206} 207 208var OrdinalNumbers = map[string]string{ 209 "-1": "-1st", 210 "-2": "-2nd", 211 "-3": "-3rd", 212 "-4": "-4th", 213 "-5": "-5th", 214 "-6": "-6th", 215 "-7": "-7th", 216 "-8": "-8th", 217 "-9": "-9th", 218 "-10": "-10th", 219 "-11": "-11th", 220 "-12": "-12th", 221 "-13": "-13th", 222 "-14": "-14th", 223 "-20": "-20th", 224 "-21": "-21st", 225 "-22": "-22nd", 226 "-23": "-23rd", 227 "-24": "-24th", 228 "-100": "-100th", 229 "-101": "-101st", 230 "-102": "-102nd", 231 "-103": "-103rd", 232 "-104": "-104th", 233 "-110": "-110th", 234 "-111": "-111th", 235 "-112": "-112th", 236 "-113": "-113th", 237 "-1000": "-1000th", 238 "-1001": "-1001st", 239 "0": "0th", 240 "1": "1st", 241 "2": "2nd", 242 "3": "3rd", 243 "4": "4th", 244 "5": "5th", 245 "6": "6th", 246 "7": "7th", 247 "8": "8th", 248 "9": "9th", 249 "10": "10th", 250 "11": "11th", 251 "12": "12th", 252 "13": "13th", 253 "14": "14th", 254 "20": "20th", 255 "21": "21st", 256 "22": "22nd", 257 "23": "23rd", 258 "24": "24th", 259 "100": "100th", 260 "101": "101st", 261 "102": "102nd", 262 "103": "103rd", 263 "104": "104th", 264 "110": "110th", 265 "111": "111th", 266 "112": "112th", 267 "113": "113th", 268 "1000": "1000th", 269 "1001": "1001st", 270} 271 272var UnderscoresToDashes = map[string]string{ 273 "street": "street", 274 "street_address": "street-address", 275 "person_street_address": "person-street-address", 276} 277 278var Irregularities = map[string]string{ 279 "person": "people", 280 "man": "men", 281 "child": "children", 282 "sex": "sexes", 283 "move": "moves", 284} 285 286type AcronymCase struct { 287 camel string 288 under string 289 human string 290 title string 291} 292 293var AcronymCases = []*AcronymCase{ 294 // camelize underscore humanize titleize 295 &AcronymCase{"API", "api", "API", "API"}, 296 &AcronymCase{"APIController", "api_controller", "API controller", "API Controller"}, 297 &AcronymCase{"Nokogiri::HTML", "nokogiri/html", "Nokogiri/HTML", "Nokogiri/HTML"}, 298 &AcronymCase{"HTTPAPI", "http_api", "HTTP API", "HTTP API"}, 299 &AcronymCase{"HTTP::Get", "http/get", "HTTP/get", "HTTP/Get"}, 300 &AcronymCase{"SSLError", "ssl_error", "SSL error", "SSL Error"}, 301 &AcronymCase{"RESTful", "restful", "RESTful", "RESTful"}, 302 &AcronymCase{"RESTfulController", "restful_controller", "RESTful controller", "RESTful Controller"}, 303 &AcronymCase{"IHeartW3C", "i_heart_w3c", "I heart W3C", "I Heart W3C"}, 304 &AcronymCase{"PhDRequired", "phd_required", "PhD required", "PhD Required"}, 305 &AcronymCase{"IRoRU", "i_ror_u", "I RoR u", "I RoR U"}, 306 &AcronymCase{"RESTfulHTTPAPI", "restful_http_api", "RESTful HTTP API", "RESTful HTTP API"}, 307 // misdirection 308 &AcronymCase{"Capistrano", "capistrano", "Capistrano", "Capistrano"}, 309 &AcronymCase{"CapiController", "capi_controller", "Capi controller", "Capi Controller"}, 310 &AcronymCase{"HttpsApis", "https_apis", "Https apis", "Https Apis"}, 311 &AcronymCase{"Html5", "html5", "Html5", "Html5"}, 312 &AcronymCase{"Restfully", "restfully", "Restfully", "Restfully"}, 313 &AcronymCase{"RoRails", "ro_rails", "Ro rails", "Ro Rails"}, 314} 315 316// tests 317 318func TestPluralizePlurals(t *testing.T) { 319 assertEqual(t, "plurals", Pluralize("plurals")) 320 assertEqual(t, "Plurals", Pluralize("Plurals")) 321} 322 323func TestPluralizeEmptyString(t *testing.T) { 324 assertEqual(t, "", Pluralize("")) 325} 326 327func TestUncountables(t *testing.T) { 328 for word := range Uncountables() { 329 assertEqual(t, word, Singularize(word)) 330 assertEqual(t, word, Pluralize(word)) 331 assertEqual(t, Pluralize(word), Singularize(word)) 332 } 333} 334 335func TestUncountableWordIsNotGreedy(t *testing.T) { 336 uncountableWord := "ors" 337 countableWord := "sponsor" 338 339 AddUncountable(uncountableWord) 340 341 assertEqual(t, uncountableWord, Singularize(uncountableWord)) 342 assertEqual(t, uncountableWord, Pluralize(uncountableWord)) 343 assertEqual(t, Pluralize(uncountableWord), Singularize(uncountableWord)) 344 assertEqual(t, "sponsor", Singularize(countableWord)) 345 assertEqual(t, "sponsors", Pluralize(countableWord)) 346 assertEqual(t, "sponsor", Singularize(Pluralize(countableWord))) 347} 348 349func TestPluralizeSingular(t *testing.T) { 350 for singular, plural := range SingularToPlural { 351 assertEqual(t, plural, Pluralize(singular)) 352 assertEqual(t, Capitalize(plural), Capitalize(Pluralize(singular))) 353 } 354} 355 356func TestSingularizePlural(t *testing.T) { 357 for singular, plural := range SingularToPlural { 358 assertEqual(t, singular, Singularize(plural)) 359 assertEqual(t, Capitalize(singular), Capitalize(Singularize(plural))) 360 } 361} 362 363func TestPluralizePlural(t *testing.T) { 364 for _, plural := range SingularToPlural { 365 assertEqual(t, plural, Pluralize(plural)) 366 assertEqual(t, Capitalize(plural), Capitalize(Pluralize(plural))) 367 } 368} 369 370func TestOverwritePreviousInflectors(t *testing.T) { 371 assertEqual(t, "series", Singularize("series")) 372 AddSingular("series", "serie") 373 assertEqual(t, "serie", Singularize("series")) 374 AddUncountable("series") // reset 375} 376 377func TestTitleize(t *testing.T) { 378 for before, titleized := range MixtureToTitleCase { 379 assertEqual(t, titleized, Titleize(before)) 380 } 381} 382 383func TestCapitalize(t *testing.T) { 384 for lower, capitalized := range CapitalizeMixture { 385 assertEqual(t, capitalized, Capitalize(lower)) 386 } 387} 388 389func TestCamelize(t *testing.T) { 390 for camel, underscore := range CamelToUnderscore { 391 assertEqual(t, camel, Camelize(underscore)) 392 } 393} 394 395func TestCamelizeWithLowerDowncasesTheFirstLetter(t *testing.T) { 396 assertEqual(t, "capital", CamelizeDownFirst("Capital")) 397} 398 399func TestCamelizeWithUnderscores(t *testing.T) { 400 assertEqual(t, "CamelCase", Camelize("Camel_Case")) 401} 402 403// func TestAcronyms(t *testing.T) { 404// AddAcronym("API") 405// AddAcronym("HTML") 406// AddAcronym("HTTP") 407// AddAcronym("RESTful") 408// AddAcronym("W3C") 409// AddAcronym("PhD") 410// AddAcronym("RoR") 411// AddAcronym("SSL") 412// // each in table 413// for _,x := range AcronymCases { 414// assertEqual(t, x.camel, Camelize(x.under)) 415// assertEqual(t, x.camel, Camelize(x.camel)) 416// assertEqual(t, x.under, Underscore(x.under)) 417// assertEqual(t, x.under, Underscore(x.camel)) 418// assertEqual(t, x.title, Titleize(x.under)) 419// assertEqual(t, x.title, Titleize(x.camel)) 420// assertEqual(t, x.human, Humanize(x.under)) 421// } 422// } 423 424// func TestAcronymOverride(t *testing.T) { 425// AddAcronym("API") 426// AddAcronym("LegacyApi") 427// assertEqual(t, "LegacyApi", Camelize("legacyapi")) 428// assertEqual(t, "LegacyAPI", Camelize("legacy_api")) 429// assertEqual(t, "SomeLegacyApi", Camelize("some_legacyapi")) 430// assertEqual(t, "Nonlegacyapi", Camelize("nonlegacyapi")) 431// } 432 433// func TestAcronymsCamelizeLower(t *testing.T) { 434// AddAcronym("API") 435// AddAcronym("HTML") 436// assertEqual(t, "htmlAPI", CamelizeDownFirst("html_api")) 437// assertEqual(t, "htmlAPI", CamelizeDownFirst("htmlAPI")) 438// assertEqual(t, "htmlAPI", CamelizeDownFirst("HTMLAPI")) 439// } 440 441func TestUnderscoreAcronymSequence(t *testing.T) { 442 AddAcronym("API") 443 AddAcronym("HTML5") 444 AddAcronym("HTML") 445 assertEqual(t, "html5_html_api", Underscore("HTML5HTMLAPI")) 446} 447 448func TestUnderscore(t *testing.T) { 449 for camel, underscore := range CamelToUnderscore { 450 assertEqual(t, underscore, Underscore(camel)) 451 } 452 for camel, underscore := range CamelToUnderscoreWithoutReverse { 453 assertEqual(t, underscore, Underscore(camel)) 454 } 455} 456 457func TestForeignKey(t *testing.T) { 458 for klass, foreignKey := range ClassNameToForeignKeyWithUnderscore { 459 assertEqual(t, foreignKey, ForeignKey(klass)) 460 } 461 for word, foreignKey := range PluralToForeignKeyWithUnderscore { 462 assertEqual(t, foreignKey, ForeignKey(word)) 463 } 464 for klass, foreignKey := range ClassNameToForeignKeyWithoutUnderscore { 465 assertEqual(t, foreignKey, ForeignKeyCondensed(klass)) 466 } 467} 468 469func TestTableize(t *testing.T) { 470 for klass, table := range ClassNameToTableName { 471 assertEqual(t, table, Tableize(klass)) 472 } 473} 474 475func TestParameterize(t *testing.T) { 476 for str, parameterized := range StringToParameterized { 477 assertEqual(t, parameterized, Parameterize(str)) 478 } 479} 480 481func TestParameterizeAndNormalize(t *testing.T) { 482 for str, parameterized := range StringToParameterizedAndNormalized { 483 assertEqual(t, parameterized, Parameterize(str)) 484 } 485} 486 487func TestParameterizeWithCustomSeparator(t *testing.T) { 488 for str, parameterized := range StringToParameterizeWithUnderscore { 489 assertEqual(t, parameterized, ParameterizeJoin(str, "_")) 490 } 491} 492 493func TestTypeify(t *testing.T) { 494 for klass, table := range ClassNameToTableName { 495 assertEqual(t, klass, Typeify(table)) 496 assertEqual(t, klass, Typeify("table_prefix."+table)) 497 } 498} 499 500func TestTypeifyWithLeadingSchemaName(t *testing.T) { 501 assertEqual(t, "FooBar", Typeify("schema.foo_bar")) 502} 503 504func TestHumanize(t *testing.T) { 505 for underscore, human := range UnderscoreToHuman { 506 assertEqual(t, human, Humanize(underscore)) 507 } 508} 509 510func TestHumanizeByString(t *testing.T) { 511 AddHuman("col_rpted_bugs", "reported bugs") 512 assertEqual(t, "90 reported bugs recently", Humanize("90 col_rpted_bugs recently")) 513} 514 515func TestOrdinal(t *testing.T) { 516 for number, ordinalized := range OrdinalNumbers { 517 assertEqual(t, ordinalized, Ordinalize(number)) 518 } 519} 520 521func TestDasherize(t *testing.T) { 522 for underscored, dasherized := range UnderscoresToDashes { 523 assertEqual(t, dasherized, Dasherize(underscored)) 524 } 525} 526 527func TestUnderscoreAsReverseOfDasherize(t *testing.T) { 528 for underscored := range UnderscoresToDashes { 529 assertEqual(t, underscored, Underscore(Dasherize(underscored))) 530 } 531} 532 533func TestUnderscoreToLowerCamel(t *testing.T) { 534 for underscored, lower := range UnderscoreToLowerCamel { 535 assertEqual(t, lower, CamelizeDownFirst(underscored)) 536 } 537} 538 539func Test_clear_all(t *testing.T) { 540 // test a way of resetting inflexions 541} 542 543func TestIrregularityBetweenSingularAndPlural(t *testing.T) { 544 for singular, plural := range Irregularities { 545 AddIrregular(singular, plural) 546 assertEqual(t, singular, Singularize(plural)) 547 assertEqual(t, plural, Pluralize(singular)) 548 } 549} 550 551func TestPluralizeOfIrregularity(t *testing.T) { 552 for singular, plural := range Irregularities { 553 AddIrregular(singular, plural) 554 assertEqual(t, plural, Pluralize(plural)) 555 } 556} 557