|
| 1 | +## Unit tests for the string-manipulation helpers used by the codegen. |
| 2 | +## These names map identifier conventions between Nim (camelCase), |
| 3 | +## Rust (snake_case) and C++ (PascalCase types), and they're load-bearing |
| 4 | +## for binding generation, so it's worth pinning their behaviour with tests. |
| 5 | + |
| 6 | +import unittest |
| 7 | +import ../ffi/codegen/meta |
| 8 | + |
| 9 | +suite "camelToSnakeCase": |
| 10 | + test "empty string": |
| 11 | + check camelToSnakeCase("") == "" |
| 12 | + |
| 13 | + test "single lowercase character": |
| 14 | + check camelToSnakeCase("a") == "a" |
| 15 | + |
| 16 | + test "single uppercase character": |
| 17 | + check camelToSnakeCase("A") == "a" |
| 18 | + |
| 19 | + test "all lowercase passes through": |
| 20 | + check camelToSnakeCase("hello") == "hello" |
| 21 | + |
| 22 | + test "simple camelCase": |
| 23 | + check camelToSnakeCase("camelCase") == "camel_case" |
| 24 | + |
| 25 | + test "two-letter suffix": |
| 26 | + check camelToSnakeCase("delayMs") == "delay_ms" |
| 27 | + |
| 28 | + test "PascalCase input — leading capital stays at start": |
| 29 | + check camelToSnakeCase("PascalCase") == "pascal_case" |
| 30 | + |
| 31 | + test "consecutive uppercase letters each get their own underscore": |
| 32 | + check camelToSnakeCase("ABC") == "a_b_c" |
| 33 | + |
| 34 | + test "multiple word boundaries": |
| 35 | + check camelToSnakeCase("abcDefGhi") == "abc_def_ghi" |
| 36 | + |
| 37 | + test "already snake_case passes through": |
| 38 | + check camelToSnakeCase("already_snake") == "already_snake" |
| 39 | + |
| 40 | +suite "capitalizeFirstLetter": |
| 41 | + test "empty string": |
| 42 | + check capitalizeFirstLetter("") == "" |
| 43 | + |
| 44 | + test "single lowercase character": |
| 45 | + check capitalizeFirstLetter("a") == "A" |
| 46 | + |
| 47 | + test "single uppercase character": |
| 48 | + check capitalizeFirstLetter("A") == "A" |
| 49 | + |
| 50 | + test "lowercase word": |
| 51 | + check capitalizeFirstLetter("abc") == "Abc" |
| 52 | + |
| 53 | + test "already capitalised": |
| 54 | + check capitalizeFirstLetter("Abc") == "Abc" |
| 55 | + |
| 56 | + test "all-caps stays unchanged except first stays cap": |
| 57 | + check capitalizeFirstLetter("ABC") == "ABC" |
| 58 | + |
| 59 | + test "leading non-letter is left alone": |
| 60 | + check capitalizeFirstLetter("_hello") == "_hello" |
| 61 | + |
| 62 | +suite "snakeToPascalCase": |
| 63 | + test "empty string": |
| 64 | + check snakeToPascalCase("") == "" |
| 65 | + |
| 66 | + test "single lowercase word": |
| 67 | + check snakeToPascalCase("hello") == "Hello" |
| 68 | + |
| 69 | + test "two-part snake_case": |
| 70 | + check snakeToPascalCase("hello_world") == "HelloWorld" |
| 71 | + |
| 72 | + test "three-part snake_case": |
| 73 | + check snakeToPascalCase("testlib_create") == "TestlibCreate" |
| 74 | + |
| 75 | + test "single-letter parts each capitalised": |
| 76 | + check snakeToPascalCase("a_b_c") == "ABC" |
| 77 | + |
| 78 | + test "trailing underscore yields empty trailing part": |
| 79 | + check snakeToPascalCase("foo_") == "Foo" |
| 80 | + |
| 81 | + test "leading underscore yields empty leading part": |
| 82 | + check snakeToPascalCase("_foo") == "Foo" |
| 83 | + |
| 84 | + test "already-mixed parts preserve their existing case after the first": |
| 85 | + # split on '_', capitalize first letter of each part; "HasCaps" first |
| 86 | + # letter is already 'H' so it's untouched. |
| 87 | + check snakeToPascalCase("already_HasCaps") == "AlreadyHasCaps" |
0 commit comments