github.com/hashicorp/hcl/v2@v2.20.0/pos_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package hcl 5 6 import ( 7 "bytes" 8 "fmt" 9 "reflect" 10 "testing" 11 ) 12 13 func TestRangeOver(t *testing.T) { 14 tests := []struct { 15 A Range 16 B Range 17 Want Range 18 }{ 19 { 20 Range{ // ## 21 Start: Pos{Byte: 2, Line: 1, Column: 3}, 22 End: Pos{Byte: 4, Line: 1, Column: 5}, 23 }, 24 Range{ // #### 25 Start: Pos{Byte: 1, Line: 1, Column: 2}, 26 End: Pos{Byte: 5, Line: 1, Column: 6}, 27 }, 28 Range{ // #### 29 Start: Pos{Byte: 1, Line: 1, Column: 2}, 30 End: Pos{Byte: 5, Line: 1, Column: 6}, 31 }, 32 }, 33 { 34 Range{ // #### 35 Start: Pos{Byte: 0, Line: 1, Column: 1}, 36 End: Pos{Byte: 4, Line: 1, Column: 5}, 37 }, 38 Range{ // #### 39 Start: Pos{Byte: 1, Line: 1, Column: 2}, 40 End: Pos{Byte: 5, Line: 1, Column: 6}, 41 }, 42 Range{ // ##### 43 Start: Pos{Byte: 0, Line: 1, Column: 1}, 44 End: Pos{Byte: 5, Line: 1, Column: 6}, 45 }, 46 }, 47 { 48 Range{ // #### 49 Start: Pos{Byte: 2, Line: 1, Column: 3}, 50 End: Pos{Byte: 6, Line: 1, Column: 7}, 51 }, 52 Range{ // #### 53 Start: Pos{Byte: 1, Line: 1, Column: 2}, 54 End: Pos{Byte: 5, Line: 1, Column: 6}, 55 }, 56 Range{ // ##### 57 Start: Pos{Byte: 1, Line: 1, Column: 2}, 58 End: Pos{Byte: 6, Line: 1, Column: 7}, 59 }, 60 }, 61 { 62 Range{ // #### 63 Start: Pos{Byte: 1, Line: 1, Column: 2}, 64 End: Pos{Byte: 5, Line: 1, Column: 6}, 65 }, 66 Range{ // ## 67 Start: Pos{Byte: 2, Line: 1, Column: 3}, 68 End: Pos{Byte: 4, Line: 1, Column: 5}, 69 }, 70 Range{ // #### 71 Start: Pos{Byte: 1, Line: 1, Column: 2}, 72 End: Pos{Byte: 5, Line: 1, Column: 6}, 73 }, 74 }, 75 { 76 Range{ // ### 77 Start: Pos{Byte: 1, Line: 1, Column: 2}, 78 End: Pos{Byte: 4, Line: 1, Column: 5}, 79 }, 80 Range{ // #### 81 Start: Pos{Byte: 1, Line: 1, Column: 2}, 82 End: Pos{Byte: 5, Line: 1, Column: 6}, 83 }, 84 Range{ // #### 85 Start: Pos{Byte: 1, Line: 1, Column: 2}, 86 End: Pos{Byte: 5, Line: 1, Column: 6}, 87 }, 88 }, 89 { 90 Range{ // ### 91 Start: Pos{Byte: 2, Line: 1, Column: 3}, 92 End: Pos{Byte: 5, Line: 1, Column: 6}, 93 }, 94 Range{ // #### 95 Start: Pos{Byte: 1, Line: 1, Column: 2}, 96 End: Pos{Byte: 5, Line: 1, Column: 6}, 97 }, 98 Range{ // #### 99 Start: Pos{Byte: 1, Line: 1, Column: 2}, 100 End: Pos{Byte: 5, Line: 1, Column: 6}, 101 }, 102 }, 103 { 104 Range{ // #### 105 Start: Pos{Byte: 2, Line: 1, Column: 3}, 106 End: Pos{Byte: 5, Line: 1, Column: 6}, 107 }, 108 Range{ // #### 109 Start: Pos{Byte: 2, Line: 1, Column: 3}, 110 End: Pos{Byte: 5, Line: 1, Column: 6}, 111 }, 112 Range{ // #### 113 Start: Pos{Byte: 2, Line: 1, Column: 3}, 114 End: Pos{Byte: 5, Line: 1, Column: 6}, 115 }, 116 }, 117 { 118 Range{ // ## 119 Start: Pos{Byte: 0, Line: 1, Column: 1}, 120 End: Pos{Byte: 2, Line: 1, Column: 3}, 121 }, 122 Range{ // ## 123 Start: Pos{Byte: 4, Line: 1, Column: 5}, 124 End: Pos{Byte: 6, Line: 1, Column: 7}, 125 }, 126 Range{ // ###### 127 Start: Pos{Byte: 0, Line: 1, Column: 1}, 128 End: Pos{Byte: 6, Line: 1, Column: 7}, 129 }, 130 }, 131 { 132 Range{ // ## 133 Start: Pos{Byte: 4, Line: 1, Column: 5}, 134 End: Pos{Byte: 6, Line: 1, Column: 7}, 135 }, 136 Range{ // ## 137 Start: Pos{Byte: 0, Line: 1, Column: 1}, 138 End: Pos{Byte: 2, Line: 1, Column: 3}, 139 }, 140 Range{ // ###### 141 Start: Pos{Byte: 0, Line: 1, Column: 1}, 142 End: Pos{Byte: 6, Line: 1, Column: 7}, 143 }, 144 }, 145 } 146 147 for _, test := range tests { 148 t.Run(fmt.Sprintf("%s<=>%s", test.A, test.B), func(t *testing.T) { 149 got := RangeOver(test.A, test.B) 150 if !reflect.DeepEqual(got, test.Want) { 151 t.Errorf( 152 "wrong result\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s", 153 visRangeOffsets(test.A), test.A, 154 visRangeOffsets(test.B), test.B, 155 visRangeOffsets(got), got, 156 visRangeOffsets(test.Want), test.Want, 157 ) 158 } 159 }) 160 } 161 } 162 163 func TestPosOverlap(t *testing.T) { 164 tests := []struct { 165 A Range 166 B Range 167 Want Range 168 }{ 169 { 170 Range{ // ## 171 Start: Pos{Byte: 2, Line: 1, Column: 3}, 172 End: Pos{Byte: 4, Line: 1, Column: 5}, 173 }, 174 Range{ // #### 175 Start: Pos{Byte: 1, Line: 1, Column: 2}, 176 End: Pos{Byte: 5, Line: 1, Column: 6}, 177 }, 178 Range{ // ## 179 Start: Pos{Byte: 2, Line: 1, Column: 3}, 180 End: Pos{Byte: 4, Line: 1, Column: 5}, 181 }, 182 }, 183 { 184 Range{ // #### 185 Start: Pos{Byte: 0, Line: 1, Column: 1}, 186 End: Pos{Byte: 4, Line: 1, Column: 5}, 187 }, 188 Range{ // #### 189 Start: Pos{Byte: 1, Line: 1, Column: 2}, 190 End: Pos{Byte: 5, Line: 1, Column: 6}, 191 }, 192 Range{ // ### 193 Start: Pos{Byte: 1, Line: 1, Column: 2}, 194 End: Pos{Byte: 4, Line: 1, Column: 5}, 195 }, 196 }, 197 { 198 Range{ // #### 199 Start: Pos{Byte: 2, Line: 1, Column: 3}, 200 End: Pos{Byte: 6, Line: 1, Column: 7}, 201 }, 202 Range{ // #### 203 Start: Pos{Byte: 1, Line: 1, Column: 2}, 204 End: Pos{Byte: 5, Line: 1, Column: 6}, 205 }, 206 Range{ // ### 207 Start: Pos{Byte: 2, Line: 1, Column: 3}, 208 End: Pos{Byte: 5, Line: 1, Column: 6}, 209 }, 210 }, 211 { 212 Range{ // #### 213 Start: Pos{Byte: 1, Line: 1, Column: 2}, 214 End: Pos{Byte: 5, Line: 1, Column: 6}, 215 }, 216 Range{ // ## 217 Start: Pos{Byte: 2, Line: 1, Column: 3}, 218 End: Pos{Byte: 4, Line: 1, Column: 5}, 219 }, 220 Range{ // ## 221 Start: Pos{Byte: 2, Line: 1, Column: 3}, 222 End: Pos{Byte: 4, Line: 1, Column: 5}, 223 }, 224 }, 225 { 226 Range{ // ### 227 Start: Pos{Byte: 1, Line: 1, Column: 2}, 228 End: Pos{Byte: 4, Line: 1, Column: 5}, 229 }, 230 Range{ // #### 231 Start: Pos{Byte: 1, Line: 1, Column: 2}, 232 End: Pos{Byte: 5, Line: 1, Column: 6}, 233 }, 234 Range{ // ### 235 Start: Pos{Byte: 1, Line: 1, Column: 2}, 236 End: Pos{Byte: 4, Line: 1, Column: 5}, 237 }, 238 }, 239 { 240 Range{ // ### 241 Start: Pos{Byte: 2, Line: 1, Column: 3}, 242 End: Pos{Byte: 5, Line: 1, Column: 6}, 243 }, 244 Range{ // #### 245 Start: Pos{Byte: 1, Line: 1, Column: 2}, 246 End: Pos{Byte: 5, Line: 1, Column: 6}, 247 }, 248 Range{ // ### 249 Start: Pos{Byte: 2, Line: 1, Column: 3}, 250 End: Pos{Byte: 5, Line: 1, Column: 6}, 251 }, 252 }, 253 { 254 Range{ // #### 255 Start: Pos{Byte: 2, Line: 1, Column: 3}, 256 End: Pos{Byte: 5, Line: 1, Column: 6}, 257 }, 258 Range{ // #### 259 Start: Pos{Byte: 2, Line: 1, Column: 3}, 260 End: Pos{Byte: 5, Line: 1, Column: 6}, 261 }, 262 Range{ // #### 263 Start: Pos{Byte: 2, Line: 1, Column: 3}, 264 End: Pos{Byte: 5, Line: 1, Column: 6}, 265 }, 266 }, 267 { 268 Range{ // ## 269 Start: Pos{Byte: 0, Line: 1, Column: 1}, 270 End: Pos{Byte: 2, Line: 1, Column: 3}, 271 }, 272 Range{ // ## 273 Start: Pos{Byte: 4, Line: 1, Column: 5}, 274 End: Pos{Byte: 6, Line: 1, Column: 7}, 275 }, 276 Range{ // (no overlap) 277 Start: Pos{Byte: 0, Line: 1, Column: 1}, 278 End: Pos{Byte: 0, Line: 1, Column: 1}, 279 }, 280 }, 281 { 282 Range{ // ## 283 Start: Pos{Byte: 4, Line: 1, Column: 5}, 284 End: Pos{Byte: 6, Line: 1, Column: 7}, 285 }, 286 Range{ // ## 287 Start: Pos{Byte: 0, Line: 1, Column: 1}, 288 End: Pos{Byte: 2, Line: 1, Column: 3}, 289 }, 290 Range{ // (no overlap) 291 Start: Pos{Byte: 4, Line: 1, Column: 5}, 292 End: Pos{Byte: 4, Line: 1, Column: 5}, 293 }, 294 }, 295 } 296 297 for _, test := range tests { 298 t.Run(fmt.Sprintf("%s<=>%s", test.A, test.B), func(t *testing.T) { 299 got := test.A.Overlap(test.B) 300 if !reflect.DeepEqual(got, test.Want) { 301 t.Errorf( 302 "wrong result\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s", 303 visRangeOffsets(test.A), test.A, 304 visRangeOffsets(test.B), test.B, 305 visRangeOffsets(got), got, 306 visRangeOffsets(test.Want), test.Want, 307 ) 308 } 309 }) 310 } 311 } 312 313 func TestRangePartitionAround(t *testing.T) { 314 tests := []struct { 315 Outer Range 316 Inner Range 317 WantBefore Range 318 WantOverlap Range 319 WantAfter Range 320 }{ 321 { 322 Range{ // ## 323 Start: Pos{Byte: 2, Line: 1, Column: 3}, 324 End: Pos{Byte: 4, Line: 1, Column: 5}, 325 }, 326 Range{ // #### 327 Start: Pos{Byte: 1, Line: 1, Column: 2}, 328 End: Pos{Byte: 5, Line: 1, Column: 6}, 329 }, 330 Range{ // (empty) 331 Start: Pos{Byte: 2, Line: 1, Column: 3}, 332 End: Pos{Byte: 2, Line: 1, Column: 3}, 333 }, 334 Range{ // ## 335 Start: Pos{Byte: 2, Line: 1, Column: 3}, 336 End: Pos{Byte: 4, Line: 1, Column: 5}, 337 }, 338 Range{ // (empty) 339 Start: Pos{Byte: 4, Line: 1, Column: 5}, 340 End: Pos{Byte: 4, Line: 1, Column: 5}, 341 }, 342 }, 343 { 344 Range{ // #### 345 Start: Pos{Byte: 0, Line: 1, Column: 1}, 346 End: Pos{Byte: 4, Line: 1, Column: 5}, 347 }, 348 Range{ // #### 349 Start: Pos{Byte: 1, Line: 1, Column: 2}, 350 End: Pos{Byte: 5, Line: 1, Column: 6}, 351 }, 352 Range{ // # 353 Start: Pos{Byte: 0, Line: 1, Column: 1}, 354 End: Pos{Byte: 1, Line: 1, Column: 2}, 355 }, 356 Range{ // ### 357 Start: Pos{Byte: 1, Line: 1, Column: 2}, 358 End: Pos{Byte: 4, Line: 1, Column: 5}, 359 }, 360 Range{ // (empty) 361 Start: Pos{Byte: 4, Line: 1, Column: 5}, 362 End: Pos{Byte: 4, Line: 1, Column: 5}, 363 }, 364 }, 365 { 366 Range{ // #### 367 Start: Pos{Byte: 2, Line: 1, Column: 3}, 368 End: Pos{Byte: 5, Line: 1, Column: 6}, 369 }, 370 Range{ // #### 371 Start: Pos{Byte: 1, Line: 1, Column: 2}, 372 End: Pos{Byte: 5, Line: 1, Column: 6}, 373 }, 374 Range{ // (empty) 375 Start: Pos{Byte: 2, Line: 1, Column: 3}, 376 End: Pos{Byte: 2, Line: 1, Column: 3}, 377 }, 378 Range{ // ### 379 Start: Pos{Byte: 2, Line: 1, Column: 3}, 380 End: Pos{Byte: 5, Line: 1, Column: 6}, 381 }, 382 Range{ // # 383 Start: Pos{Byte: 5, Line: 1, Column: 6}, 384 End: Pos{Byte: 5, Line: 1, Column: 6}, 385 }, 386 }, 387 { 388 Range{ // #### 389 Start: Pos{Byte: 1, Line: 1, Column: 2}, 390 End: Pos{Byte: 5, Line: 1, Column: 6}, 391 }, 392 Range{ // ## 393 Start: Pos{Byte: 2, Line: 1, Column: 3}, 394 End: Pos{Byte: 4, Line: 1, Column: 5}, 395 }, 396 Range{ // # 397 Start: Pos{Byte: 1, Line: 1, Column: 2}, 398 End: Pos{Byte: 2, Line: 1, Column: 3}, 399 }, 400 Range{ // ## 401 Start: Pos{Byte: 2, Line: 1, Column: 3}, 402 End: Pos{Byte: 4, Line: 1, Column: 5}, 403 }, 404 Range{ // # 405 Start: Pos{Byte: 4, Line: 1, Column: 5}, 406 End: Pos{Byte: 5, Line: 1, Column: 6}, 407 }, 408 }, 409 } 410 411 for _, test := range tests { 412 t.Run(fmt.Sprintf("%s around %s", test.Outer, test.Inner), func(t *testing.T) { 413 gotBefore, gotOverlap, gotAfter := test.Outer.PartitionAround(test.Inner) 414 if !reflect.DeepEqual(gotBefore, test.WantBefore) { 415 t.Errorf( 416 "wrong before\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s", 417 visRangeOffsets(test.Outer), test.Outer, 418 visRangeOffsets(test.Inner), test.Inner, 419 visRangeOffsets(gotBefore), gotBefore, 420 visRangeOffsets(test.WantBefore), test.WantBefore, 421 ) 422 } 423 if !reflect.DeepEqual(gotOverlap, test.WantOverlap) { 424 t.Errorf( 425 "wrong overlap\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s", 426 visRangeOffsets(test.Outer), test.Outer, 427 visRangeOffsets(test.Inner), test.Inner, 428 visRangeOffsets(gotOverlap), gotOverlap, 429 visRangeOffsets(test.WantOverlap), test.WantOverlap, 430 ) 431 } 432 if !reflect.DeepEqual(gotAfter, test.WantAfter) { 433 t.Errorf( 434 "wrong after\nA : %-10s %s\nB : %-10s %s\ngot : %-10s %s\nwant: %-10s %s", 435 visRangeOffsets(test.Outer), test.Outer, 436 visRangeOffsets(test.Inner), test.Inner, 437 visRangeOffsets(gotAfter), gotAfter, 438 visRangeOffsets(test.WantAfter), test.WantAfter, 439 ) 440 } 441 }) 442 } 443 } 444 445 // visRangeOffsets is a helper that produces a visual representation of the 446 // start and end byte offsets of the given range, which can then be stacked 447 // with the same for other ranges to more easily see how the ranges relate 448 // to one another. 449 func visRangeOffsets(rng Range) string { 450 var buf bytes.Buffer 451 if rng.End.Byte < rng.Start.Byte { 452 // Should never happen, but we'll visualize it anyway so we can 453 // more easily debug failing tests. 454 for i := 0; i < rng.End.Byte; i++ { 455 buf.WriteByte(' ') 456 } 457 for i := rng.End.Byte; i < rng.Start.Byte; i++ { 458 buf.WriteByte('!') 459 } 460 return buf.String() 461 } 462 463 for i := 0; i < rng.Start.Byte; i++ { 464 buf.WriteByte(' ') 465 } 466 for i := rng.Start.Byte; i < rng.End.Byte; i++ { 467 buf.WriteByte('#') 468 } 469 return buf.String() 470 }