github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/examples/gno.land/p/demo/json/escape_test.gno (about) 1 package json 2 3 import ( 4 "bytes" 5 "testing" 6 "unicode/utf8" 7 ) 8 9 func TestHexToInt(t *testing.T) { 10 tests := []struct { 11 name string 12 c byte 13 want int 14 }{ 15 {"Digit 0", '0', 0}, 16 {"Digit 9", '9', 9}, 17 {"Uppercase A", 'A', 10}, 18 {"Uppercase F", 'F', 15}, 19 {"Lowercase a", 'a', 10}, 20 {"Lowercase f", 'f', 15}, 21 {"Invalid character1", 'g', badHex}, 22 {"Invalid character2", 'G', badHex}, 23 {"Invalid character3", 'z', badHex}, 24 } 25 26 for _, tt := range tests { 27 t.Run(tt.name, func(t *testing.T) { 28 if got := h2i(tt.c); got != tt.want { 29 t.Errorf("h2i() = %v, want %v", got, tt.want) 30 } 31 }) 32 } 33 } 34 35 func TestIsSurrogatePair(t *testing.T) { 36 testCases := []struct { 37 name string 38 r rune 39 expected bool 40 }{ 41 {"high surrogate start", 0xD800, true}, 42 {"high surrogate end", 0xDBFF, true}, 43 {"low surrogate start", 0xDC00, true}, 44 {"low surrogate end", 0xDFFF, true}, 45 {"Non-surrogate", 0x0000, false}, 46 {"Non-surrogate 2", 0xE000, false}, 47 } 48 49 for _, tc := range testCases { 50 t.Run(tc.name, func(t *testing.T) { 51 if got := isSurrogatePair(tc.r); got != tc.expected { 52 t.Errorf("isSurrogate() = %v, want %v", got, tc.expected) 53 } 54 }) 55 } 56 } 57 58 func TestCombineSurrogates(t *testing.T) { 59 testCases := []struct { 60 high, low rune 61 expected rune 62 }{ 63 {0xD83D, 0xDC36, 0x1F436}, // 🐶 U+1F436 DOG FACE 64 {0xD83D, 0xDE00, 0x1F600}, // 😀 U+1F600 GRINNING FACE 65 {0xD83C, 0xDF03, 0x1F303}, // 🌃 U+1F303 NIGHT WITH STARS 66 } 67 68 for _, tc := range testCases { 69 result := combineSurrogates(tc.high, tc.low) 70 if result != tc.expected { 71 t.Errorf("combineSurrogates(%U, %U) = %U; want %U", tc.high, tc.low, result, tc.expected) 72 } 73 } 74 } 75 76 func TestDecodeSingleUnicodeEscape(t *testing.T) { 77 testCases := []struct { 78 input []byte 79 expected rune 80 isValid bool 81 }{ 82 // valid unicode escape sequences 83 {[]byte(`\u0041`), 'A', true}, 84 {[]byte(`\u03B1`), 'α', true}, 85 {[]byte(`\u00E9`), 'é', true}, // valid non-English character 86 {[]byte(`\u0021`), '!', true}, // valid special character 87 {[]byte(`\uFF11`), '1', true}, 88 {[]byte(`\uD83D`), 0xD83D, true}, 89 {[]byte(`\uDE03`), 0xDE03, true}, 90 91 // invalid unicode escape sequences 92 {[]byte(`\u004`), utf8.RuneError, false}, // too short 93 {[]byte(`\uXYZW`), utf8.RuneError, false}, // invalid hex 94 {[]byte(`\u00G1`), utf8.RuneError, false}, // non-hex character 95 } 96 97 for _, tc := range testCases { 98 result, isValid := decodeSingleUnicodeEscape(tc.input) 99 if result != tc.expected || isValid != tc.isValid { 100 t.Errorf("decodeSingleUnicodeEscape(%s) = (%U, %v); want (%U, %v)", tc.input, result, isValid, tc.expected, tc.isValid) 101 } 102 } 103 } 104 105 func TestDecodeUnicodeEscape(t *testing.T) { 106 testCases := []struct { 107 input string 108 expected rune 109 size int 110 }{ 111 {"\\u0041", 'A', 6}, 112 {"\\u03B1", 'α', 6}, 113 {"\\u1F600", 0x1F60, 6}, 114 {"\\uD830\\uDE03", 0x1C203, 12}, 115 {"\\uD800\\uDC00", 0x00010000, 12}, 116 117 {"\\u004", utf8.RuneError, -1}, 118 {"\\uXYZW", utf8.RuneError, -1}, 119 {"\\uD83D\\u0041", utf8.RuneError, -1}, 120 } 121 122 for _, tc := range testCases { 123 r, size := decodeUnicodeEscape([]byte(tc.input)) 124 if r != tc.expected || size != tc.size { 125 t.Errorf("decodeUnicodeEscape(%q) = (%U, %d); want (%U, %d)", tc.input, r, size, tc.expected, tc.size) 126 } 127 } 128 } 129 130 func TestUnescapeToUTF8(t *testing.T) { 131 testCases := []struct { 132 input []byte 133 expectedIn int 134 expectedOut int 135 isError bool 136 }{ 137 // valid escape sequences 138 {[]byte(`\n`), 2, 1, false}, 139 {[]byte(`\t`), 2, 1, false}, 140 {[]byte(`\u0041`), 6, 1, false}, 141 {[]byte(`\u03B1`), 6, 2, false}, 142 {[]byte(`\uD830\uDE03`), 12, 4, false}, 143 144 // invalid escape sequences 145 {[]byte(`\`), -1, -1, true}, // incomplete escape sequence 146 {[]byte(`\x`), -1, -1, true}, // invalid escape character 147 {[]byte(`\u`), -1, -1, true}, // incomplete unicode escape sequence 148 {[]byte(`\u004`), -1, -1, true}, // invalid unicode escape sequence 149 {[]byte(`\uXYZW`), -1, -1, true}, // invalid unicode escape sequence 150 {[]byte(`\uD83D\u0041`), -1, -1, true}, // invalid unicode escape sequence 151 } 152 153 for _, tc := range testCases { 154 input := make([]byte, len(tc.input)) 155 copy(input, tc.input) 156 output := make([]byte, utf8.UTFMax) 157 inLen, outLen, err := processEscapedUTF8(input, output) 158 if (err != nil) != tc.isError { 159 t.Errorf("processEscapedUTF8(%q) = %v; want %v", tc.input, err, tc.isError) 160 } 161 162 if inLen != tc.expectedIn || outLen != tc.expectedOut { 163 t.Errorf("processEscapedUTF8(%q) = (%d, %d); want (%d, %d)", tc.input, inLen, outLen, tc.expectedIn, tc.expectedOut) 164 } 165 } 166 } 167 168 func TestUnescape(t *testing.T) { 169 testCases := []struct { 170 name string 171 input []byte 172 expected []byte 173 }{ 174 {"NoEscape", []byte("hello world"), []byte("hello world")}, 175 {"SingleEscape", []byte("hello\\nworld"), []byte("hello\nworld")}, 176 {"MultipleEscapes", []byte("line1\\nline2\\r\\nline3"), []byte("line1\nline2\r\nline3")}, 177 {"UnicodeEscape", []byte("snowman:\\u2603"), []byte("snowman:\u2603")}, 178 {"Complex", []byte("tc\\n\\u2603\\r\\nend"), []byte("tc\n\u2603\r\nend")}, 179 } 180 181 for _, tc := range testCases { 182 t.Run(tc.name, func(t *testing.T) { 183 output, _ := Unescape(tc.input, make([]byte, len(tc.input)+10)) 184 if !bytes.Equal(output, tc.expected) { 185 t.Errorf("unescape(%q) = %q; want %q", tc.input, output, tc.expected) 186 } 187 }) 188 } 189 } 190 191 func TestUnquoteBytes(t *testing.T) { 192 tests := []struct { 193 input []byte 194 border byte 195 expected []byte 196 ok bool 197 }{ 198 {[]byte("\"hello\""), '"', []byte("hello"), true}, 199 {[]byte("'hello'"), '\'', []byte("hello"), true}, 200 {[]byte("\"hello"), '"', nil, false}, 201 {[]byte("hello\""), '"', nil, false}, 202 {[]byte("\"he\\\"llo\""), '"', []byte("he\"llo"), true}, 203 {[]byte("\"he\\nllo\""), '"', []byte("he\nllo"), true}, 204 {[]byte("\"\""), '"', []byte(""), true}, 205 {[]byte("''"), '\'', []byte(""), true}, 206 {[]byte("\"\\u0041\""), '"', []byte("A"), true}, 207 {[]byte(`"Hello, 世界"`), '"', []byte("Hello, 世界"), true}, 208 {[]byte(`"Hello, \x80"`), '"', nil, false}, 209 } 210 211 for _, tc := range tests { 212 result, pass := unquoteBytes(tc.input, tc.border) 213 214 if pass != tc.ok { 215 t.Errorf("unquoteBytes(%q) = %v; want %v", tc.input, pass, tc.ok) 216 } 217 218 if !bytes.Equal(result, tc.expected) { 219 t.Errorf("unquoteBytes(%q) = %q; want %q", tc.input, result, tc.expected) 220 } 221 } 222 }