github.com/hashicorp/hcl/v2@v2.20.0/json/parser_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package json
     5  
     6  import (
     7  	"math/big"
     8  	"testing"
     9  
    10  	"github.com/go-test/deep"
    11  	"github.com/hashicorp/hcl/v2"
    12  )
    13  
    14  func init() {
    15  	deep.MaxDepth = 999
    16  }
    17  
    18  func TestParse(t *testing.T) {
    19  	tests := []struct {
    20  		Input     string
    21  		Want      node
    22  		DiagCount int
    23  	}{
    24  		// Simple, single-token constructs
    25  		{
    26  			`true`,
    27  			&booleanVal{
    28  				Value: true,
    29  				SrcRange: hcl.Range{
    30  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    31  					End:   hcl.Pos{Line: 1, Column: 5, Byte: 4},
    32  				},
    33  			},
    34  			0,
    35  		},
    36  		{
    37  			`false`,
    38  			&booleanVal{
    39  				Value: false,
    40  				SrcRange: hcl.Range{
    41  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    42  					End:   hcl.Pos{Line: 1, Column: 6, Byte: 5},
    43  				},
    44  			},
    45  			0,
    46  		},
    47  		{
    48  			`null`,
    49  			&nullVal{
    50  				SrcRange: hcl.Range{
    51  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    52  					End:   hcl.Pos{Line: 1, Column: 5, Byte: 4},
    53  				},
    54  			},
    55  			0,
    56  		},
    57  		{
    58  			`undefined`,
    59  			invalidVal{hcl.Range{
    60  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    61  				End:   hcl.Pos{Line: 1, Column: 10, Byte: 9},
    62  			}},
    63  			1,
    64  		},
    65  		{
    66  			`flase`,
    67  			invalidVal{hcl.Range{
    68  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    69  				End:   hcl.Pos{Line: 1, Column: 6, Byte: 5},
    70  			}},
    71  			1,
    72  		},
    73  		{
    74  			`"hello"`,
    75  			&stringVal{
    76  				Value: "hello",
    77  				SrcRange: hcl.Range{
    78  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    79  					End:   hcl.Pos{Line: 1, Column: 8, Byte: 7},
    80  				},
    81  			},
    82  			0,
    83  		},
    84  		{
    85  			`"hello\nworld"`,
    86  			&stringVal{
    87  				Value: "hello\nworld",
    88  				SrcRange: hcl.Range{
    89  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
    90  					End:   hcl.Pos{Line: 1, Column: 15, Byte: 14},
    91  				},
    92  			},
    93  			0,
    94  		},
    95  		{
    96  			`"hello \"world\""`,
    97  			&stringVal{
    98  				Value: `hello "world"`,
    99  				SrcRange: hcl.Range{
   100  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   101  					End:   hcl.Pos{Line: 1, Column: 18, Byte: 17},
   102  				},
   103  			},
   104  			0,
   105  		},
   106  		{
   107  			`"hello \\"`,
   108  			&stringVal{
   109  				Value: "hello \\",
   110  				SrcRange: hcl.Range{
   111  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   112  					End:   hcl.Pos{Line: 1, Column: 11, Byte: 10},
   113  				},
   114  			},
   115  			0,
   116  		},
   117  		{
   118  			`"hello`,
   119  			invalidVal{hcl.Range{
   120  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   121  				End:   hcl.Pos{Line: 1, Column: 7, Byte: 6},
   122  			}},
   123  			1,
   124  		},
   125  		{
   126  			`"he\llo"`,
   127  			invalidVal{hcl.Range{
   128  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   129  				End:   hcl.Pos{Line: 1, Column: 9, Byte: 8},
   130  			}},
   131  			1,
   132  		},
   133  		{
   134  			`1`,
   135  			&numberVal{
   136  				Value: mustBigFloat("1"),
   137  				SrcRange: hcl.Range{
   138  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   139  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   140  				},
   141  			},
   142  			0,
   143  		},
   144  		{
   145  			`1.2`,
   146  			&numberVal{
   147  				Value: mustBigFloat("1.2"),
   148  				SrcRange: hcl.Range{
   149  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   150  					End:   hcl.Pos{Line: 1, Column: 4, Byte: 3},
   151  				},
   152  			},
   153  			0,
   154  		},
   155  		{
   156  			`-1`,
   157  			&numberVal{
   158  				Value: mustBigFloat("-1"),
   159  				SrcRange: hcl.Range{
   160  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   161  					End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   162  				},
   163  			},
   164  			0,
   165  		},
   166  		{
   167  			`1.2e5`,
   168  			&numberVal{
   169  				Value: mustBigFloat("120000"),
   170  				SrcRange: hcl.Range{
   171  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   172  					End:   hcl.Pos{Line: 1, Column: 6, Byte: 5},
   173  				},
   174  			},
   175  			0,
   176  		},
   177  		{
   178  			`1.2e+5`,
   179  			&numberVal{
   180  				Value: mustBigFloat("120000"),
   181  				SrcRange: hcl.Range{
   182  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   183  					End:   hcl.Pos{Line: 1, Column: 7, Byte: 6},
   184  				},
   185  			},
   186  			0,
   187  		},
   188  		{
   189  			`1.2e-5`,
   190  			&numberVal{
   191  				Value: mustBigFloat("1.2e-5"),
   192  				SrcRange: hcl.Range{
   193  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   194  					End:   hcl.Pos{Line: 1, Column: 7, Byte: 6},
   195  				},
   196  			},
   197  			0,
   198  		},
   199  		{
   200  			`.1`,
   201  			invalidVal{hcl.Range{
   202  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   203  				End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   204  			}},
   205  			1,
   206  		},
   207  		{
   208  			`+2`,
   209  			invalidVal{hcl.Range{
   210  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   211  				End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   212  			}},
   213  			1,
   214  		},
   215  		{
   216  			`1 2`,
   217  			&numberVal{
   218  				Value: mustBigFloat("1"),
   219  				SrcRange: hcl.Range{
   220  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   221  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   222  				},
   223  			},
   224  			1,
   225  		},
   226  
   227  		// Objects
   228  		{
   229  			`{"hello": true}`,
   230  			&objectVal{
   231  				Attrs: []*objectAttr{
   232  					{
   233  						Name: "hello",
   234  						Value: &booleanVal{
   235  							Value: true,
   236  							SrcRange: hcl.Range{
   237  								Start: hcl.Pos{Line: 1, Column: 11, Byte: 10},
   238  								End:   hcl.Pos{Line: 1, Column: 15, Byte: 14},
   239  							},
   240  						},
   241  						NameRange: hcl.Range{
   242  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   243  							End:   hcl.Pos{Line: 1, Column: 9, Byte: 8},
   244  						},
   245  					},
   246  				},
   247  				SrcRange: hcl.Range{
   248  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   249  					End:   hcl.Pos{Line: 1, Column: 16, Byte: 15},
   250  				},
   251  				OpenRange: hcl.Range{
   252  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   253  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   254  				},
   255  				CloseRange: hcl.Range{
   256  					Start: hcl.Pos{Line: 1, Column: 15, Byte: 14},
   257  					End:   hcl.Pos{Line: 1, Column: 16, Byte: 15},
   258  				},
   259  			},
   260  			0,
   261  		},
   262  		{
   263  			`{"hello": true, "bye": false}`,
   264  			&objectVal{
   265  				Attrs: []*objectAttr{
   266  					{
   267  						Name: "hello",
   268  						Value: &booleanVal{
   269  							Value: true,
   270  							SrcRange: hcl.Range{
   271  								Start: hcl.Pos{Line: 1, Column: 11, Byte: 10},
   272  								End:   hcl.Pos{Line: 1, Column: 15, Byte: 14},
   273  							},
   274  						},
   275  						NameRange: hcl.Range{
   276  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   277  							End:   hcl.Pos{Line: 1, Column: 9, Byte: 8},
   278  						},
   279  					},
   280  					{
   281  						Name: "bye",
   282  						Value: &booleanVal{
   283  							Value: false,
   284  							SrcRange: hcl.Range{
   285  								Start: hcl.Pos{Line: 1, Column: 24, Byte: 23},
   286  								End:   hcl.Pos{Line: 1, Column: 29, Byte: 28},
   287  							},
   288  						},
   289  						NameRange: hcl.Range{
   290  							Start: hcl.Pos{Line: 1, Column: 17, Byte: 16},
   291  							End:   hcl.Pos{Line: 1, Column: 22, Byte: 21},
   292  						},
   293  					},
   294  				},
   295  				SrcRange: hcl.Range{
   296  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   297  					End:   hcl.Pos{Line: 1, Column: 30, Byte: 29},
   298  				},
   299  				OpenRange: hcl.Range{
   300  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   301  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   302  				},
   303  				CloseRange: hcl.Range{
   304  					Start: hcl.Pos{Line: 1, Column: 29, Byte: 28},
   305  					End:   hcl.Pos{Line: 1, Column: 30, Byte: 29},
   306  				},
   307  			},
   308  			0,
   309  		},
   310  		{
   311  			`{}`,
   312  			&objectVal{
   313  				Attrs: []*objectAttr{},
   314  				SrcRange: hcl.Range{
   315  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   316  					End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   317  				},
   318  				OpenRange: hcl.Range{
   319  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   320  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   321  				},
   322  				CloseRange: hcl.Range{
   323  					Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   324  					End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   325  				},
   326  			},
   327  			0,
   328  		},
   329  		{
   330  			`{"hello":true`,
   331  			invalidVal{hcl.Range{
   332  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   333  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   334  			}},
   335  			1,
   336  		},
   337  		{
   338  			`{"hello":true]`,
   339  			invalidVal{hcl.Range{
   340  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   341  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   342  			}},
   343  			1,
   344  		},
   345  		{
   346  			`{"hello":true,}`,
   347  			invalidVal{hcl.Range{
   348  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   349  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   350  			}},
   351  			1,
   352  		},
   353  		{
   354  			`{true:false}`,
   355  			invalidVal{hcl.Range{
   356  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   357  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   358  			}},
   359  			1,
   360  		},
   361  		{
   362  			`{"hello": true, "hello": true}`,
   363  			&objectVal{
   364  				Attrs: []*objectAttr{
   365  					{
   366  						Name: "hello",
   367  						Value: &booleanVal{
   368  							Value: true,
   369  							SrcRange: hcl.Range{
   370  								Start: hcl.Pos{Line: 1, Column: 11, Byte: 10},
   371  								End:   hcl.Pos{Line: 1, Column: 15, Byte: 14},
   372  							},
   373  						},
   374  						NameRange: hcl.Range{
   375  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   376  							End:   hcl.Pos{Line: 1, Column: 9, Byte: 8},
   377  						},
   378  					},
   379  					{
   380  						Name: "hello",
   381  						Value: &booleanVal{
   382  							Value: true,
   383  							SrcRange: hcl.Range{
   384  								Start: hcl.Pos{Line: 1, Column: 26, Byte: 25},
   385  								End:   hcl.Pos{Line: 1, Column: 30, Byte: 29},
   386  							},
   387  						},
   388  						NameRange: hcl.Range{
   389  							Start: hcl.Pos{Line: 1, Column: 17, Byte: 16},
   390  							End:   hcl.Pos{Line: 1, Column: 24, Byte: 23},
   391  						},
   392  					},
   393  				},
   394  				SrcRange: hcl.Range{
   395  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   396  					End:   hcl.Pos{Line: 1, Column: 31, Byte: 30},
   397  				},
   398  				OpenRange: hcl.Range{
   399  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   400  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   401  				},
   402  				CloseRange: hcl.Range{
   403  					Start: hcl.Pos{Line: 1, Column: 30, Byte: 29},
   404  					End:   hcl.Pos{Line: 1, Column: 31, Byte: 30},
   405  				},
   406  			},
   407  			0,
   408  		},
   409  		{
   410  			`{"hello": true, "hello": true, "hello", true}`,
   411  			invalidVal{hcl.Range{
   412  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   413  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   414  			}},
   415  			1, // comma used where colon is expected
   416  		},
   417  		{
   418  			`{"hello", "world"}`,
   419  			invalidVal{hcl.Range{
   420  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   421  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   422  			}},
   423  			1,
   424  		},
   425  		{
   426  			`[]`,
   427  			&arrayVal{
   428  				Values: []node{},
   429  				SrcRange: hcl.Range{
   430  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   431  					End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   432  				},
   433  				OpenRange: hcl.Range{
   434  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   435  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   436  				},
   437  			},
   438  			0,
   439  		},
   440  		{
   441  			`[true]`,
   442  			&arrayVal{
   443  				Values: []node{
   444  					&booleanVal{
   445  						Value: true,
   446  						SrcRange: hcl.Range{
   447  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   448  							End:   hcl.Pos{Line: 1, Column: 6, Byte: 5},
   449  						},
   450  					},
   451  				},
   452  				SrcRange: hcl.Range{
   453  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   454  					End:   hcl.Pos{Line: 1, Column: 7, Byte: 6},
   455  				},
   456  				OpenRange: hcl.Range{
   457  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   458  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   459  				},
   460  			},
   461  			0,
   462  		},
   463  		{
   464  			`[true, false]`,
   465  			&arrayVal{
   466  				Values: []node{
   467  					&booleanVal{
   468  						Value: true,
   469  						SrcRange: hcl.Range{
   470  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   471  							End:   hcl.Pos{Line: 1, Column: 6, Byte: 5},
   472  						},
   473  					},
   474  					&booleanVal{
   475  						Value: false,
   476  						SrcRange: hcl.Range{
   477  							Start: hcl.Pos{Line: 1, Column: 8, Byte: 7},
   478  							End:   hcl.Pos{Line: 1, Column: 13, Byte: 12},
   479  						},
   480  					},
   481  				},
   482  				SrcRange: hcl.Range{
   483  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   484  					End:   hcl.Pos{Line: 1, Column: 14, Byte: 13},
   485  				},
   486  				OpenRange: hcl.Range{
   487  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   488  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   489  				},
   490  			},
   491  			0,
   492  		},
   493  		{
   494  			`[[]]`,
   495  			&arrayVal{
   496  				Values: []node{
   497  					&arrayVal{
   498  						Values: []node{},
   499  						SrcRange: hcl.Range{
   500  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   501  							End:   hcl.Pos{Line: 1, Column: 4, Byte: 3},
   502  						},
   503  						OpenRange: hcl.Range{
   504  							Start: hcl.Pos{Line: 1, Column: 2, Byte: 1},
   505  							End:   hcl.Pos{Line: 1, Column: 3, Byte: 2},
   506  						},
   507  					},
   508  				},
   509  				SrcRange: hcl.Range{
   510  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   511  					End:   hcl.Pos{Line: 1, Column: 5, Byte: 4},
   512  				},
   513  				OpenRange: hcl.Range{
   514  					Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   515  					End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   516  				},
   517  			},
   518  			0,
   519  		},
   520  		{
   521  			`[`,
   522  			invalidVal{hcl.Range{
   523  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   524  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   525  			}},
   526  			2,
   527  		},
   528  		{
   529  			`[true`,
   530  			invalidVal{hcl.Range{
   531  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   532  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   533  			}},
   534  			1,
   535  		},
   536  		{
   537  			`]`,
   538  			invalidVal{hcl.Range{
   539  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   540  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   541  			}},
   542  			1,
   543  		},
   544  		{
   545  			`[true,]`,
   546  			invalidVal{hcl.Range{
   547  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   548  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   549  			}},
   550  			1,
   551  		},
   552  		{
   553  			`[[],]`,
   554  			invalidVal{hcl.Range{
   555  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   556  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   557  			}},
   558  			1,
   559  		},
   560  		{
   561  			`["hello":true]`,
   562  			invalidVal{hcl.Range{
   563  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   564  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   565  			}},
   566  			1,
   567  		},
   568  		{
   569  			`[true}`,
   570  			invalidVal{hcl.Range{
   571  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   572  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   573  			}},
   574  			1,
   575  		},
   576  		{
   577  			`{"wrong"=true}`,
   578  			invalidVal{hcl.Range{
   579  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   580  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   581  			}},
   582  			1,
   583  		},
   584  		{
   585  			`{"wrong" = true}`,
   586  			invalidVal{hcl.Range{
   587  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   588  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   589  			}},
   590  			1,
   591  		},
   592  		{
   593  			`{"wrong" true}`,
   594  			invalidVal{hcl.Range{
   595  				Start: hcl.Pos{Line: 1, Column: 1, Byte: 0},
   596  				End:   hcl.Pos{Line: 1, Column: 2, Byte: 1},
   597  			}},
   598  			1,
   599  		},
   600  	}
   601  
   602  	for _, test := range tests {
   603  		t.Run(test.Input, func(t *testing.T) {
   604  			got, diag := parseFileContent([]byte(test.Input), "", hcl.Pos{Byte: 0, Line: 1, Column: 1})
   605  
   606  			if len(diag) != test.DiagCount {
   607  				t.Errorf("got %d diagnostics; want %d", len(diag), test.DiagCount)
   608  				for _, d := range diag {
   609  					t.Logf("  - %s", d.Error())
   610  				}
   611  			}
   612  
   613  			if diff := deep.Equal(got, test.Want); diff != nil {
   614  				for _, problem := range diff {
   615  					t.Error(problem)
   616  				}
   617  			}
   618  		})
   619  	}
   620  }
   621  
   622  func TestParseWithPos(t *testing.T) {
   623  	tests := []struct {
   624  		Input     string
   625  		StartPos  hcl.Pos
   626  		Want      node
   627  		DiagCount int
   628  	}{
   629  		// Simple, single-token constructs
   630  		{
   631  			`true`,
   632  			hcl.Pos{Byte: 0, Line: 3, Column: 10},
   633  			&booleanVal{
   634  				Value: true,
   635  				SrcRange: hcl.Range{
   636  					Start: hcl.Pos{Line: 3, Column: 10, Byte: 0},
   637  					End:   hcl.Pos{Line: 3, Column: 14, Byte: 4},
   638  				},
   639  			},
   640  			0,
   641  		},
   642  	}
   643  
   644  	for _, test := range tests {
   645  		t.Run(test.Input, func(t *testing.T) {
   646  			got, diag := parseFileContent([]byte(test.Input), "", test.StartPos)
   647  
   648  			if len(diag) != test.DiagCount {
   649  				t.Errorf("got %d diagnostics; want %d", len(diag), test.DiagCount)
   650  				for _, d := range diag {
   651  					t.Logf("  - %s", d.Error())
   652  				}
   653  			}
   654  
   655  			if diff := deep.Equal(got, test.Want); diff != nil {
   656  				for _, problem := range diff {
   657  					t.Error(problem)
   658  				}
   659  			}
   660  		})
   661  	}
   662  }
   663  
   664  func mustBigFloat(s string) *big.Float {
   665  	f, _, err := (&big.Float{}).Parse(s, 10)
   666  	if err != nil {
   667  		panic(err)
   668  	}
   669  	return f
   670  }