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  }