github.com/aretext/aretext@v1.3.0/syntax/languages/python_test.go (about) 1 package languages 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 8 "github.com/aretext/aretext/syntax/parser" 9 ) 10 11 func TestPythonParseFunc(t *testing.T) { 12 testCases := []struct { 13 name string 14 text string 15 expected []TokenWithText 16 }{ 17 { 18 name: "comment at start of document", 19 text: "# comment", 20 expected: []TokenWithText{ 21 {Text: `# comment`, Role: parser.TokenRoleComment}, 22 }, 23 }, 24 { 25 name: "single comment hash", 26 text: "#", 27 expected: []TokenWithText{ 28 {Text: `#`, Role: parser.TokenRoleComment}, 29 }, 30 }, 31 { 32 name: "identifier followed by comment", 33 text: "foobar #comment", 34 expected: []TokenWithText{ 35 {Text: `#comment`, Role: parser.TokenRoleComment}, 36 }, 37 }, 38 { 39 name: "comment followed by identifier on next line", 40 text: "foo\n# comment\nbar", 41 expected: []TokenWithText{ 42 {Text: "# comment\n", Role: parser.TokenRoleComment}, 43 }, 44 }, 45 { 46 name: "encoding declaration", 47 text: "# -*- coding: <encoding-name> -*-", 48 expected: []TokenWithText{ 49 {Text: "# -*- coding: <encoding-name> -*-", Role: parser.TokenRoleComment}, 50 }, 51 }, 52 { 53 name: "keywords in for-range loop", 54 text: "for i in range(len(l)):", 55 expected: []TokenWithText{ 56 {Text: "for", Role: parser.TokenRoleKeyword}, 57 {Text: "in", Role: parser.TokenRoleKeyword}, 58 }, 59 }, 60 { 61 name: "boolean keywords", 62 text: ` 63 x = True 64 y = False 65 `, 66 expected: []TokenWithText{ 67 {Text: "=", Role: parser.TokenRoleOperator}, 68 {Text: "True", Role: parser.TokenRoleKeyword}, 69 {Text: "=", Role: parser.TokenRoleOperator}, 70 {Text: "False", Role: parser.TokenRoleKeyword}, 71 }, 72 }, 73 { 74 name: "operators in equation", 75 text: "x + y - z", 76 expected: []TokenWithText{ 77 {Text: "+", Role: parser.TokenRoleOperator}, 78 {Text: "-", Role: parser.TokenRoleOperator}, 79 }, 80 }, 81 { 82 name: "comparison operators", 83 text: "a <= b and c > d or e != f and g == h", 84 expected: []TokenWithText{ 85 {Text: "<=", Role: parser.TokenRoleOperator}, 86 {Text: "and", Role: parser.TokenRoleKeyword}, 87 {Text: ">", Role: parser.TokenRoleOperator}, 88 {Text: "or", Role: parser.TokenRoleKeyword}, 89 {Text: "!=", Role: parser.TokenRoleOperator}, 90 {Text: "and", Role: parser.TokenRoleKeyword}, 91 {Text: "==", Role: parser.TokenRoleOperator}, 92 }, 93 }, 94 { 95 name: "assignment operator", 96 text: "a = 10", 97 expected: []TokenWithText{ 98 {Text: "=", Role: parser.TokenRoleOperator}, 99 {Text: "10", Role: parser.TokenRoleNumber}, 100 }, 101 }, 102 { 103 name: "test short string, single quote", 104 text: `'foo\nbar'`, 105 expected: []TokenWithText{ 106 {Text: `'foo\nbar'`, Role: parser.TokenRoleString}, 107 }, 108 }, 109 { 110 name: "test short string, double quote", 111 text: `"foo\nbar"`, 112 expected: []TokenWithText{ 113 {Text: `"foo\nbar"`, Role: parser.TokenRoleString}, 114 }, 115 }, 116 { 117 name: "test long string, single quote", 118 text: "'''foo\n'\nbar\n'''", 119 expected: []TokenWithText{ 120 {Text: "'''foo\n'\nbar\n'''", Role: parser.TokenRoleString}, 121 }, 122 }, 123 { 124 name: "test long string, double quote", 125 text: "\"\"\"foo\n\n\"\nbar\"\"\"", 126 expected: []TokenWithText{ 127 {Text: "\"\"\"foo\n\n\"\nbar\"\"\"", Role: parser.TokenRoleString}, 128 }, 129 }, 130 { 131 name: "string with byte prefix", 132 text: `b"foobar"`, 133 expected: []TokenWithText{ 134 {Text: `b"foobar"`, Role: parser.TokenRoleString}, 135 }, 136 }, 137 { 138 name: "decimal int literal, single digit", 139 text: "7", 140 expected: []TokenWithText{ 141 {Text: "7", Role: parser.TokenRoleNumber}, 142 }, 143 }, 144 { 145 name: "decimal int literal, multiple digits", 146 text: "2147483647", 147 expected: []TokenWithText{ 148 {Text: "2147483647", Role: parser.TokenRoleNumber}, 149 }, 150 }, 151 { 152 name: "decimal int literal, multiple digits with separators", 153 text: "100_000_000_000", 154 expected: []TokenWithText{ 155 {Text: "100_000_000_000", Role: parser.TokenRoleNumber}, 156 }, 157 }, 158 { 159 name: "binary literal", 160 text: "0b_1110_0101", 161 expected: []TokenWithText{ 162 {Text: "0b_1110_0101", Role: parser.TokenRoleNumber}, 163 }, 164 }, 165 { 166 name: "octal literal", 167 text: "0o377", 168 expected: []TokenWithText{ 169 {Text: "0o377", Role: parser.TokenRoleNumber}, 170 }, 171 }, 172 { 173 name: "hex literal", 174 text: "0xdeadbeef", 175 expected: []TokenWithText{ 176 {Text: "0xdeadbeef", Role: parser.TokenRoleNumber}, 177 }, 178 }, 179 { 180 name: "float literal, point between digits", 181 text: "3.14", 182 expected: []TokenWithText{ 183 {Text: "3.14", Role: parser.TokenRoleNumber}, 184 }, 185 }, 186 { 187 name: "float literal, point after digits", 188 text: "10.", 189 expected: []TokenWithText{ 190 {Text: "10.", Role: parser.TokenRoleNumber}, 191 }, 192 }, 193 { 194 name: "float literal, point before digits", 195 text: ".001", 196 expected: []TokenWithText{ 197 {Text: ".001", Role: parser.TokenRoleNumber}, 198 }, 199 }, 200 { 201 name: "float literal, exponent without point", 202 text: "1e100", 203 expected: []TokenWithText{ 204 {Text: "1e100", Role: parser.TokenRoleNumber}, 205 }, 206 }, 207 { 208 name: "float literal, negative exponent", 209 text: "3.14e-10", 210 expected: []TokenWithText{ 211 {Text: "3.14e-10", Role: parser.TokenRoleNumber}, 212 }, 213 }, 214 { 215 name: "float literal, zero digit and zero exponent", 216 text: "0e0", 217 expected: []TokenWithText{ 218 {Text: "0e0", Role: parser.TokenRoleNumber}, 219 }, 220 }, 221 { 222 name: "float literal, separators", 223 text: "3.14_15_93", 224 expected: []TokenWithText{ 225 {Text: "3.14_15_93", Role: parser.TokenRoleNumber}, 226 }, 227 }, 228 { 229 name: "imaginary number, point float decimal in middle", 230 text: "3.14j", 231 expected: []TokenWithText{ 232 {Text: "3.14j", Role: parser.TokenRoleNumber}, 233 }, 234 }, 235 { 236 name: "imaginary number, point float decimal at end", 237 text: "10.j", 238 expected: []TokenWithText{ 239 {Text: "10.j", Role: parser.TokenRoleNumber}, 240 }, 241 }, 242 { 243 name: "imaginary number, int literal", 244 text: "10j", 245 expected: []TokenWithText{ 246 {Text: "10j", Role: parser.TokenRoleNumber}, 247 }, 248 }, 249 { 250 name: "imaginary number, exponent ", 251 text: "3.14e-10j", 252 expected: []TokenWithText{ 253 {Text: "3.14e-10j", Role: parser.TokenRoleNumber}, 254 }, 255 }, 256 { 257 name: "imaginary number, separators ", 258 text: "3.14_15_93j", 259 expected: []TokenWithText{ 260 {Text: "3.14_15_93j", Role: parser.TokenRoleNumber}, 261 }, 262 }, 263 { 264 name: "async await", 265 text: ` 266 async def main(): 267 print('hello') 268 await asyncio.sleep(1) 269 print('world') 270 `, 271 expected: []TokenWithText{ 272 {Text: "async", Role: parser.TokenRoleKeyword}, 273 {Text: "def", Role: parser.TokenRoleKeyword}, 274 {Text: "'hello'", Role: parser.TokenRoleString}, 275 {Text: "await", Role: parser.TokenRoleKeyword}, 276 {Text: "1", Role: parser.TokenRoleNumber}, 277 {Text: "'world'", Role: parser.TokenRoleString}, 278 }, 279 }, 280 { 281 name: "full program", 282 text: `import sys 283 284 def main(): 285 if len(sys.argv) < 2: 286 print("Usage: {} NAME".format(sys.argv[0])) 287 sys.exit(1) 288 name = sys.argv[1] 289 print("Hello {}!".format(name)) 290 291 if __name__ == "__main__": 292 main() 293 `, 294 expected: []TokenWithText{ 295 {Role: parser.TokenRoleKeyword, Text: "import"}, 296 {Role: parser.TokenRoleKeyword, Text: "def"}, 297 {Role: parser.TokenRoleKeyword, Text: "if"}, 298 {Role: parser.TokenRoleOperator, Text: "<"}, 299 {Role: parser.TokenRoleNumber, Text: "2"}, 300 {Role: parser.TokenRoleString, Text: "\"Usage: {} NAME\""}, 301 {Role: parser.TokenRoleNumber, Text: "0"}, 302 {Role: parser.TokenRoleNumber, Text: "1"}, 303 {Role: parser.TokenRoleOperator, Text: "="}, 304 {Role: parser.TokenRoleNumber, Text: "1"}, 305 {Role: parser.TokenRoleString, Text: "\"Hello {}!\""}, 306 {Role: parser.TokenRoleKeyword, Text: "if"}, 307 {Role: parser.TokenRoleOperator, Text: "=="}, 308 {Role: parser.TokenRoleString, Text: "\"__main__\""}, 309 }, 310 }, 311 } 312 313 for _, tc := range testCases { 314 t.Run(tc.name, func(t *testing.T) { 315 tokens := ParseTokensWithText(PythonParseFunc(), tc.text) 316 assert.Equal(t, tc.expected, tokens) 317 }) 318 } 319 } 320 321 func BenchmarkPythonParser(b *testing.B) { 322 BenchmarkParser(b, PythonParseFunc(), "testdata/python/hello.py") 323 }