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