1# Copyright (C) 2020 ycmd contributors
2#
3# This file is part of ycmd.
4#
5# ycmd is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# (at your option) any later version.
9#
10# ycmd is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with ycmd.  If not, see <http://www.gnu.org/licenses/>.
17
18import pytest
19from hamcrest import ( assert_that, calling, contains_exactly, empty, equal_to,
20                       has_entry, has_string, raises )
21
22from ycmd.utils import ToBytes
23from ycmd.request_wrap import RequestWrap
24
25
26def PrepareJson( contents = '',
27                 line_num = 1,
28                 column_num = 1,
29                 filetype = '',
30                 force_semantic = None,
31                 extra_conf_data = None ):
32  message = {
33    'line_num': line_num,
34    'column_num': column_num,
35    'filepath': '/foo',
36    'file_data': {
37      '/foo': {
38        'filetypes': [ filetype ],
39        'contents': contents
40      }
41    }
42  }
43  if force_semantic is not None:
44    message[ 'force_semantic' ] = force_semantic
45  if extra_conf_data is not None:
46    message[ 'extra_conf_data' ] = extra_conf_data
47
48  return message
49
50
51@pytest.mark.parametrize( 'line,col,prefix', [
52    ( 'abc.def', 5, 'abc.' ),
53    ( 'abc.def', 6, 'abc.' ),
54    ( 'abc.def', 8, 'abc.' ),
55    ( 'abc.def', 4, '' ),
56    ( 'abc.', 5, 'abc.' ),
57    ( 'abc.', 4, '' ),
58    ( '', 1, '' ),
59  ] )
60def Prefix_test( line, col, prefix ):
61  assert_that( prefix,
62               equal_to( RequestWrap(
63                 PrepareJson( line_num = 1,
64                              contents = line,
65                              column_num = col ) )[ 'prefix' ] ) )
66
67
68def LineValue_OneLine_test():
69  assert_that( 'zoo',
70               equal_to( RequestWrap(
71                 PrepareJson( line_num = 1,
72                              contents = 'zoo' ) )[ 'line_value' ] ) )
73
74
75def LineValue_LastLine_test():
76  assert_that( 'zoo',
77               equal_to( RequestWrap(
78                 PrepareJson( line_num = 3,
79                              contents = 'goo\nbar\nzoo' ) )[ 'line_value' ] ) )
80
81
82def LineValue_MiddleLine_test():
83  assert_that( 'zoo',
84               equal_to( RequestWrap(
85                 PrepareJson( line_num = 2,
86                              contents = 'goo\nzoo\nbar' ) )[ 'line_value' ] ) )
87
88
89def LineValue_WindowsLines_test():
90  assert_that( 'zoo',
91               equal_to( RequestWrap(
92                 PrepareJson(
93                   line_num = 3,
94                   contents = 'goo\r\nbar\r\nzoo' ) )[ 'line_value' ] ) )
95
96
97def LineValue_MixedFormatLines_test():
98  assert_that( 'zoo',
99               equal_to( RequestWrap(
100                 PrepareJson(
101                   line_num = 3,
102                   contents = 'goo\nbar\r\nzoo' ) )[ 'line_value' ] ) )
103
104
105def LineValue_EmptyContents_test():
106  assert_that( '',
107               equal_to( RequestWrap(
108                 PrepareJson( line_num = 1,
109                              contents = '' ) )[ 'line_value' ] ) )
110
111
112def StartColumn_RightAfterDot_test():
113  assert_that( 5,
114               equal_to( RequestWrap(
115                 PrepareJson( column_num = 5,
116                              contents = 'foo.' ) )[ 'start_column' ] ) )
117
118
119def StartColumn_Dot_test():
120  assert_that( 5,
121               equal_to( RequestWrap(
122                 PrepareJson( column_num = 8,
123                              contents = 'foo.bar' ) )[ 'start_column' ] ) )
124
125
126def StartColumn_DotWithUnicode_test():
127  assert_that( 7,
128               equal_to( RequestWrap(
129                 PrepareJson( column_num = 11,
130                              contents = 'fäö.bär' ) )[ 'start_column' ] ) )
131
132
133def StartColumn_UnicodeNotIdentifier_test():
134  contents = "var x = '†es†ing'."
135
136  # † not considered an identifier character
137
138  for i in range( 13, 15 ):
139    print( ToBytes( contents )[ i - 1 : i ] )
140    assert_that( 13,
141                 equal_to( RequestWrap(
142                   PrepareJson( column_num = i,
143                                contents = contents ) )[ 'start_column' ] ) )
144
145  assert_that( 13,
146               equal_to( RequestWrap(
147                 PrepareJson( column_num = 15,
148                              contents = contents ) )[ 'start_column' ] ) )
149
150  for i in range( 18, 20 ):
151    print( ToBytes( contents )[ i - 1 : i ] )
152    assert_that( 18,
153                 equal_to( RequestWrap(
154                   PrepareJson( column_num = i,
155                                contents = contents ) )[ 'start_column' ] ) )
156
157
158def StartColumn_QueryIsUnicode_test():
159  contents = "var x = ålpha.alphå"
160  assert_that( 16,
161               equal_to( RequestWrap(
162                 PrepareJson( column_num = 16,
163                              contents = contents ) )[ 'start_column' ] ) )
164  assert_that( 16,
165               equal_to( RequestWrap(
166                 PrepareJson( column_num = 19,
167                              contents = contents ) )[ 'start_column' ] ) )
168
169
170def StartColumn_QueryStartsWithUnicode_test():
171  contents = "var x = ålpha.ålpha"
172  assert_that( 16,
173               equal_to( RequestWrap(
174                 PrepareJson( column_num = 16,
175                              contents = contents ) )[ 'start_column' ] ) )
176  assert_that( 16,
177               equal_to( RequestWrap(
178                 PrepareJson( column_num = 19,
179                              contents = contents ) )[ 'start_column' ] ) )
180
181
182def StartColumn_ThreeByteUnicode_test():
183  contents = "var x = '†'."
184  assert_that( 15,
185               equal_to( RequestWrap(
186                 PrepareJson( column_num = 15,
187                              contents = contents ) )[ 'start_column' ] ) )
188
189
190def StartColumn_Paren_test():
191  assert_that( 5,
192               equal_to( RequestWrap(
193                 PrepareJson( column_num = 8,
194                              contents = 'foo(bar' ) )[ 'start_column' ] ) )
195
196
197def StartColumn_AfterWholeWord_test():
198  assert_that( 1,
199               equal_to( RequestWrap(
200                 PrepareJson( column_num = 7,
201                              contents = 'foobar' ) )[ 'start_column' ] ) )
202
203
204def StartColumn_AfterWholeWord_Html_test():
205  assert_that( 1,
206               equal_to( RequestWrap(
207                 PrepareJson( column_num = 7, filetype = 'html',
208                              contents = 'fo-bar' ) )[ 'start_column' ] ) )
209
210
211def StartColumn_AfterWholeUnicodeWord_test():
212  assert_that( 1, equal_to( RequestWrap(
213                   PrepareJson( column_num = 6,
214                                contents = u'fäö' ) )[ 'start_column' ] ) )
215
216
217def StartColumn_InMiddleOfWholeWord_test():
218  assert_that( 1, equal_to( RequestWrap(
219                   PrepareJson( column_num = 4,
220                                contents = 'foobar' ) )[ 'start_column' ] ) )
221
222
223def StartColumn_ColumnOne_test():
224  assert_that( 1, equal_to( RequestWrap(
225                     PrepareJson( column_num = 1,
226                                  contents = 'foobar' ) )[ 'start_column' ] ) )
227
228
229def Query_AtWordEnd_test():
230  assert_that( 'foo', equal_to( RequestWrap(
231                        PrepareJson( column_num = 4,
232                                     contents = 'foo' ) )[ 'query' ] ) )
233
234
235def Query_InWordMiddle_test():
236  assert_that( 'foo', equal_to( RequestWrap(
237                        PrepareJson( column_num = 4,
238                                     contents = 'foobar' ) )[ 'query' ] ) )
239
240
241def Query_StartOfLine_test():
242  assert_that( '', equal_to( RequestWrap(
243                     PrepareJson( column_num = 1,
244                                   contents = 'foobar' ) )[ 'query' ] ) )
245
246
247def Query_StopsAtParen_test():
248  assert_that( 'bar', equal_to( RequestWrap(
249                        PrepareJson( column_num = 8,
250                                     contents = 'foo(bar' ) )[ 'query' ] ) )
251
252
253def Query_InWhiteSpace_test():
254  assert_that( '', equal_to( RequestWrap(
255                     PrepareJson( column_num = 8,
256                                   contents = 'foo       ' ) )[ 'query' ] ) )
257
258
259def Query_UnicodeSinglecharInclusive_test():
260  assert_that( 'ø', equal_to( RequestWrap(
261                      PrepareJson( column_num = 7,
262                                   contents = 'abc.ø' ) )[ 'query' ] ) )
263
264
265def Query_UnicodeSinglecharExclusive_test():
266  assert_that( '', equal_to( RequestWrap(
267                     PrepareJson( column_num = 5,
268                                  contents = 'abc.ø' ) )[ 'query' ] ) )
269
270
271def StartColumn_Set_test():
272  wrap = RequestWrap( PrepareJson( column_num = 11,
273                                   contents = 'this \'test',
274                                   filetype = 'javascript' ) )
275  assert_that( wrap[ 'start_column' ], equal_to( 7 ) )
276  assert_that( wrap[ 'start_codepoint' ], equal_to( 7 ) )
277  assert_that( wrap[ 'query' ], equal_to( "test" ) )
278  assert_that( wrap[ 'prefix' ], equal_to( "this '" ) )
279
280  wrap[ 'start_column' ] = 6
281  assert_that( wrap[ 'start_column' ], equal_to( 6 ) )
282  assert_that( wrap[ 'start_codepoint' ], equal_to( 6 ) )
283  assert_that( wrap[ 'query' ], equal_to( "'test" ) )
284  assert_that( wrap[ 'prefix' ], equal_to( "this " ) )
285
286
287def StartColumn_SetUnicode_test():
288  wrap = RequestWrap( PrepareJson( column_num = 14,
289                                   contents = '†e߆ \'test',
290                                   filetype = 'javascript' ) )
291  assert_that( 7, equal_to( wrap[ 'start_codepoint' ] ) )
292  assert_that( 12, equal_to( wrap[ 'start_column' ] ) )
293  assert_that( wrap[ 'query' ], equal_to( "te" ) )
294  assert_that( wrap[ 'prefix' ], equal_to( "†e߆ \'" ) )
295
296  wrap[ 'start_column' ] = 11
297  assert_that( wrap[ 'start_column' ], equal_to( 11 ) )
298  assert_that( wrap[ 'start_codepoint' ], equal_to( 6 ) )
299  assert_that( wrap[ 'query' ], equal_to( "'te" ) )
300  assert_that( wrap[ 'prefix' ], equal_to( "†e߆ " ) )
301
302
303def StartCodepoint_Set_test():
304  wrap = RequestWrap( PrepareJson( column_num = 11,
305                                   contents = 'this \'test',
306                                   filetype = 'javascript' ) )
307  assert_that( wrap[ 'start_column' ], equal_to( 7 ) )
308  assert_that( wrap[ 'start_codepoint' ], equal_to( 7 ) )
309  assert_that( wrap[ 'query' ], equal_to( "test" ) )
310  assert_that( wrap[ 'prefix' ], equal_to( "this '" ) )
311
312  wrap[ 'start_codepoint' ] = 6
313  assert_that( wrap[ 'start_column' ], equal_to( 6 ) )
314  assert_that( wrap[ 'start_codepoint' ], equal_to( 6 ) )
315  assert_that( wrap[ 'query' ], equal_to( "'test" ) )
316  assert_that( wrap[ 'prefix' ], equal_to( "this " ) )
317
318
319def StartCodepoint_SetUnicode_test():
320  wrap = RequestWrap( PrepareJson( column_num = 14,
321                                   contents = '†e߆ \'test',
322                                   filetype = 'javascript' ) )
323  assert_that( 7, equal_to( wrap[ 'start_codepoint' ] ) )
324  assert_that( 12, equal_to( wrap[ 'start_column' ] ) )
325  assert_that( wrap[ 'query' ], equal_to( "te" ) )
326  assert_that( wrap[ 'prefix' ], equal_to( "†e߆ \'" ) )
327
328  wrap[ 'start_codepoint' ] = 6
329  assert_that( wrap[ 'start_column' ], equal_to( 11 ) )
330  assert_that( wrap[ 'start_codepoint' ], equal_to( 6 ) )
331  assert_that( wrap[ 'query' ], equal_to( "'te" ) )
332  assert_that( wrap[ 'prefix' ], equal_to( "†e߆ " ) )
333
334
335def Calculated_SetMethod_test():
336  assert_that(
337    calling( RequestWrap( PrepareJson() ).__setitem__ ).with_args(
338      'line_value', '' ),
339    raises( ValueError, 'Key "line_value" is read-only' ) )
340
341
342def Calculated_SetOperator_test():
343  # Differs from the above in that it use [] operator rather than __setitem__
344  # directly. And it uses a different property for extra credit.
345  wrap = RequestWrap( PrepareJson() )
346  try:
347    wrap[ 'query' ] = 'test'
348  except ValueError as error:
349    assert_that( str( error ),
350                 equal_to( 'Key "query" is read-only' ) )
351  else:
352    raise AssertionError( 'Expected setting "query" to fail' )
353
354
355def NonCalculated_Set_test():
356  # Differs from the above in that it use [] operator rather than __setitem__
357  # directly. And it uses a different property for extra credit.
358  wrap = RequestWrap( PrepareJson() )
359  try:
360    wrap[ 'column_num' ] = 10
361  except ValueError as error:
362    assert_that( str( error ),
363                 equal_to( 'Key "column_num" is read-only' ) )
364  else:
365    raise AssertionError( 'Expected setting "column_num" to fail' )
366
367
368def ForceSemanticCompletion_test():
369  wrap = RequestWrap( PrepareJson() )
370  assert_that( wrap[ 'force_semantic' ], equal_to( False ) )
371
372  wrap = RequestWrap( PrepareJson( force_semantic = True ) )
373  assert_that( wrap[ 'force_semantic' ], equal_to( True ) )
374
375  wrap = RequestWrap( PrepareJson( force_semantic = 1 ) )
376  assert_that( wrap[ 'force_semantic' ], equal_to( True ) )
377
378  wrap = RequestWrap( PrepareJson( force_semantic = 0 ) )
379  assert_that( wrap[ 'force_semantic' ], equal_to( False ) )
380
381  wrap = RequestWrap( PrepareJson( force_semantic = 'No' ) )
382  assert_that( wrap[ 'force_semantic' ], equal_to( True ) )
383
384
385def ExtraConfData_test():
386  wrap = RequestWrap( PrepareJson() )
387  assert_that( wrap[ 'extra_conf_data' ], empty() )
388
389  wrap = RequestWrap( PrepareJson( extra_conf_data = { 'key': [ 'value' ] } ) )
390  extra_conf_data = wrap[ 'extra_conf_data' ]
391  assert_that( extra_conf_data,
392               has_entry( 'key', contains_exactly( 'value' ) ) )
393  assert_that(
394    extra_conf_data,
395    has_string(
396      equal_to( "<HashableDict {'key': ['value']}>" )
397    )
398  )
399
400  # Check that extra_conf_data can be used as a dictionary's key.
401  assert_that( { extra_conf_data: 'extra conf data' },
402               has_entry( extra_conf_data, 'extra conf data' ) )
403
404  # Check that extra_conf_data's values are immutable.
405  extra_conf_data[ 'key' ].append( 'another_value' )
406  assert_that( extra_conf_data,
407               has_entry( 'key', contains_exactly( 'value' ) ) )
408
409
410def Dummy_test():
411  # Workaround for https://github.com/pytest-dev/pytest-rerunfailures/issues/51
412  assert True
413