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  }