| 📦 Turbo Python 6fc62ea k33g 8h ago | 1 | package pythonlang |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | |
| 7 | "rickub.com/turbo-editors/turbo-core/syntax" |
| 8 | ) |
| 9 | |
| 10 | // TestTheLanguagesReferenceIsTrue holds docs/*/reference/languages.md to the |
| 11 | // scanner. Every row of its Python table that no other test here covers is |
| 12 | // checked, so a reference claim and the code cannot drift apart quietly. |
| 13 | // |
| 14 | // The last three cases document *limitations* rather than features — an |
| 15 | // all-capital class name read as a constant, `type` read as the builtin rather |
| 16 | // than as a soft keyword, an f-string's braces left inside the string. The |
| 17 | // reference says each of those in so many words, and these rows are what stops |
| 18 | // somebody "fixing" one without also fixing the sentence. |
| 19 | func TestTheLanguagesReferenceIsTrue(t *testing.T) { |
| 20 | tests := []struct { |
| 21 | src string |
| 22 | word string |
| 23 | want syntax.Class |
| 24 | }{ |
| 25 | {"assert x is not None", "assert", syntax.ClassKeyword}, |
| 26 | {"nonlocal counter", "nonlocal", syntax.ClassKeyword}, |
| 27 | {"async def f() -> None:\n pass\n", "async", syntax.ClassKeyword}, |
| 28 | {"x = NotImplemented", "NotImplemented", syntax.ClassConstant}, |
| 29 | {"x = Ellipsis", "Ellipsis", syntax.ClassConstant}, |
| 30 | {"if __debug__:\n pass\n", "__debug__", syntax.ClassConstant}, |
| 31 | {"x: frozenset = frozenset()", "frozenset", syntax.ClassType}, |
| 32 | {"x: memoryview = m", "memoryview", syntax.ClassType}, |
| 33 | {"x = isinstance(v, int)", "isinstance", syntax.ClassBuiltin}, |
| 34 | {"x = sorted(v)", "sorted", syntax.ClassBuiltin}, |
| 35 | {"def f(cls) -> None:\n pass\n", "cls", syntax.ClassBuiltin}, |
| 36 | {"x = obj.__name__", "__name__", syntax.ClassBuiltin}, |
| 37 | {`x = rb"raw bytes"`, `rb"raw bytes"`, syntax.ClassString}, |
| 38 | {`x = BR"raw bytes"`, `BR"raw bytes"`, syntax.ClassString}, |
| 39 | {`x = u"text"`, `u"text"`, syntax.ClassString}, |
| 40 | {"x = 0o17", "0o17", syntax.ClassNumber}, |
| 41 | {"x = 0b1010", "0b1010", syntax.ClassNumber}, |
| 42 | {"x = 3j", "3j", syntax.ClassNumber}, |
| 43 | {"x = 1E+7", "1E+7", syntax.ClassNumber}, |
| 44 | {"#!/usr/bin/env python3", "#!/usr/bin/env python3", syntax.ClassComment}, |
| 45 | {"@property\ndef x(self):\n pass\n", "@property", syntax.ClassAttribute}, |
| 46 | {"if (n := f()) > 1:\n pass\n", ":=", syntax.ClassOperator}, |
| 47 | {"d = {1: 2}", ":", syntax.ClassPunctuation}, |
| 48 | {"x = a @ b", "@", syntax.ClassOperator}, |
| 49 | {"x = 1 + \\", "\\", syntax.ClassPunctuation}, |
| 50 | {"x = [1, 2]", "[", syntax.ClassPunctuation}, |
| 51 | |
| 52 | // The documented limitations. |
| 53 | {"HTTP = 1", "HTTP", syntax.ClassConstant}, |
| 54 | {"type Alias = int", "type", syntax.ClassType}, |
| 55 | {"match value: # dispatch\n", "match", syntax.ClassIdentifier}, |
| 56 | } |
| 57 | |
| 58 | for _, test := range tests { |
| 59 | t.Run(test.word, func(t *testing.T) { |
| 60 | index := strings.Index(test.src, test.word) |
| 61 | if index < 0 { |
| 62 | t.Fatalf("%q not in %q", test.word, test.src) |
| 63 | } |
| 64 | got, ok := classAt(Highlight(test.src), 0, index) |
| 65 | if !ok || got != test.want { |
| 66 | t.Errorf("%q in %q is %v (covered %v), want %v", test.word, test.src, got, ok, test.want) |
| 67 | } |
| 68 | }) |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | // The reference's Python table says the class `char` is produced by nothing |
| 73 | // here, because Python has no character type. That is a claim about every span |
| 74 | // the scanner can ever emit, so it is checked over a file that uses every |
| 75 | // construct the table names. |
| 76 | func TestTheScannerNeverProducesACharacterClass(t *testing.T) { |
| 77 | const src = "#!/usr/bin/env python3\n" + |
| 78 | "x = 'single'\n" + |
| 79 | "y = \"double\"\n" + |
| 80 | "z = b'bytes'\n" + |
| 81 | "w = '''triple'''\n" |
| 82 | |
| 83 | for line, spans := range Highlight(src) { |
| 84 | for _, span := range spans { |
| 85 | if span.Class == syntax.ClassChar { |
| 86 | t.Errorf("line %d holds a char span at %d; Python has no character literal", line, span.Start) |
| 87 | } |
| 88 | } |
| 89 | } |
| 90 | } |