|
| 1 | +package model |
| 2 | + |
| 3 | +import "testing" |
| 4 | + |
| 5 | +// TestSdkName locks in the naive PascalCase translation: split on underscores, |
| 6 | +// Title-case each segment (first rune upper, the rest lower), and never |
| 7 | +// special-case acronyms. The "no acronym uppercasing" cases (url, uuid, ID) |
| 8 | +// are the ones that keep generated code compiling against the SDK. |
| 9 | +func TestSdkName(t *testing.T) { |
| 10 | + tests := []struct { |
| 11 | + name string |
| 12 | + in string |
| 13 | + want string |
| 14 | + }{ |
| 15 | + // Basic cases |
| 16 | + {"two snake segments", "org_id", "OrgId"}, |
| 17 | + {"api key", "api_key", "ApiKey"}, |
| 18 | + {"single word", "url", "Url"}, |
| 19 | + {"compound word", "http_endpoint", "HttpEndpoint"}, |
| 20 | + {"acronym stays naive", "uuid", "Uuid"}, |
| 21 | + |
| 22 | + // Mixed cases: input casing is normalized, not preserved. |
| 23 | + {"upper acronym segment lowercased", "HTTP_endpoint", "HttpEndpoint"}, |
| 24 | + {"mixed segments normalized", "Org_ID", "OrgId"}, |
| 25 | + {"trailing digits preserved", "o_auth2", "OAuth2"}, |
| 26 | + {"camelCase split on case boundary", "isURL", "IsUrl"}, |
| 27 | + |
| 28 | + // Edge cases. |
| 29 | + {"empty input", "", ""}, |
| 30 | + {"stray underscores skipped", "__org__id__", "OrgId"}, |
| 31 | + {"leading underscore", "_id", "Id"}, |
| 32 | + |
| 33 | + // Generator parity: snake_case folds \W (spaces, hyphens) to |
| 34 | + // underscores, and acronyms stay naive |
| 35 | + {"whitespace folded", "foo bar", "FooBar"}, |
| 36 | + {"hyphen folded", "foo-bar", "FooBar"}, |
| 37 | + {"all-caps stays naive", "DASHBOARD_ID", "DashboardId"}, |
| 38 | + } |
| 39 | + |
| 40 | + for _, tt := range tests { |
| 41 | + t.Run(tt.name, func(t *testing.T) { |
| 42 | + if got := SdkName(tt.in); got != tt.want { |
| 43 | + t.Errorf("SdkName(%q) = %q, want %q", tt.in, got, tt.want) |
| 44 | + } |
| 45 | + }) |
| 46 | + } |
| 47 | +} |
| 48 | + |
| 49 | +// TestSdkNameIdempotent asserts SdkName is idempotent: applying it to an |
| 50 | +// already-converted name is a no-op, SdkName(SdkName(x)) == SdkName(x). This |
| 51 | +// guards the case where a name reaches the translator twice, and covers both |
| 52 | +// snake_case inputs and their PascalCase outputs (the latter must be fixed points). |
| 53 | +func TestSdkNameIdempotent(t *testing.T) { |
| 54 | + inputs := []string{ |
| 55 | + // snake_case inputs |
| 56 | + "org_id", "api_key", "url", "http_endpoint", "uuid", "team_id", "o_auth2", |
| 57 | + // already-cased / mixed inputs |
| 58 | + "HTTP_endpoint", "Org_ID", "isURL", "v2_api", |
| 59 | + // already-PascalCase outputs — these must map to themselves |
| 60 | + "OrgId", "ApiKey", "Url", "HttpEndpoint", "Uuid", "OAuth2", "IsUrl", "HttpServer", |
| 61 | + "", "_id", |
| 62 | + } |
| 63 | + |
| 64 | + for _, in := range inputs { |
| 65 | + t.Run(in, func(t *testing.T) { |
| 66 | + once := SdkName(in) |
| 67 | + twice := SdkName(once) |
| 68 | + if once != twice { |
| 69 | + t.Errorf("SdkName not idempotent: SdkName(%q) = %q, SdkName(%q) = %q", in, once, once, twice) |
| 70 | + } |
| 71 | + }) |
| 72 | + } |
| 73 | +} |
0 commit comments