...

Source file src/github.com/pelletier/go-toml/query/parser_test.go

Documentation: github.com/pelletier/go-toml/query

     1  package query
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"sort"
     7  	"strings"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/pelletier/go-toml"
    12  )
    13  
    14  type queryTestNode struct {
    15  	value    interface{}
    16  	position toml.Position
    17  }
    18  
    19  func valueString(root interface{}) string {
    20  	result := "" //fmt.Sprintf("%T:", root)
    21  	switch node := root.(type) {
    22  	case *Result:
    23  		items := []string{}
    24  		for i, v := range node.Values() {
    25  			items = append(items, fmt.Sprintf("%s:%s",
    26  				node.Positions()[i].String(), valueString(v)))
    27  		}
    28  		sort.Strings(items)
    29  		result = "[" + strings.Join(items, ", ") + "]"
    30  	case queryTestNode:
    31  		result = fmt.Sprintf("%s:%s",
    32  			node.position.String(), valueString(node.value))
    33  	case []interface{}:
    34  		items := []string{}
    35  		for _, v := range node {
    36  			items = append(items, valueString(v))
    37  		}
    38  		sort.Strings(items)
    39  		result = "[" + strings.Join(items, ", ") + "]"
    40  	case *toml.Tree:
    41  		// workaround for unreliable map key ordering
    42  		items := []string{}
    43  		for _, k := range node.Keys() {
    44  			v := node.GetPath([]string{k})
    45  			items = append(items, k+":"+valueString(v))
    46  		}
    47  		sort.Strings(items)
    48  		result = "{" + strings.Join(items, ", ") + "}"
    49  	case map[string]interface{}:
    50  		// workaround for unreliable map key ordering
    51  		items := []string{}
    52  		for k, v := range node {
    53  			items = append(items, k+":"+valueString(v))
    54  		}
    55  		sort.Strings(items)
    56  		result = "{" + strings.Join(items, ", ") + "}"
    57  	case int64:
    58  		result += fmt.Sprintf("%d", node)
    59  	case string:
    60  		result += "'" + node + "'"
    61  	case float64:
    62  		result += fmt.Sprintf("%f", node)
    63  	case bool:
    64  		result += fmt.Sprintf("%t", node)
    65  	case time.Time:
    66  		result += fmt.Sprintf("'%v'", node)
    67  	}
    68  	return result
    69  }
    70  
    71  func assertValue(t *testing.T, result, ref interface{}) {
    72  	pathStr := valueString(result)
    73  	refStr := valueString(ref)
    74  	if pathStr != refStr {
    75  		t.Errorf("values do not match")
    76  		t.Log("test:", pathStr)
    77  		t.Log("ref: ", refStr)
    78  	}
    79  }
    80  
    81  func assertParseError(t *testing.T, query string, errString string) {
    82  	_, err := Compile(query)
    83  	if err == nil {
    84  		t.Error("error should be non-nil")
    85  		return
    86  	}
    87  	if err.Error() != errString {
    88  		t.Errorf("error does not match")
    89  		t.Log("test:", err.Error())
    90  		t.Log("ref: ", errString)
    91  	}
    92  }
    93  
    94  func assertQueryPositions(t *testing.T, tomlDoc string, query string, ref []interface{}) {
    95  	tree, err := toml.Load(tomlDoc)
    96  	if err != nil {
    97  		t.Errorf("Non-nil toml parse error: %v", err)
    98  		return
    99  	}
   100  	q, err := Compile(query)
   101  	if err != nil {
   102  		t.Error(err)
   103  		return
   104  	}
   105  	results := q.Execute(tree)
   106  	assertValue(t, results, ref)
   107  }
   108  
   109  func TestQueryRoot(t *testing.T) {
   110  	assertQueryPositions(t,
   111  		"a = 42",
   112  		"$",
   113  		[]interface{}{
   114  			queryTestNode{
   115  				map[string]interface{}{
   116  					"a": int64(42),
   117  				}, toml.Position{1, 1},
   118  			},
   119  		})
   120  }
   121  
   122  func TestQueryKey(t *testing.T) {
   123  	assertQueryPositions(t,
   124  		"[foo]\na = 42",
   125  		"$.foo.a",
   126  		[]interface{}{
   127  			queryTestNode{
   128  				int64(42), toml.Position{2, 1},
   129  			},
   130  		})
   131  }
   132  
   133  func TestQueryKeyString(t *testing.T) {
   134  	assertQueryPositions(t,
   135  		"[foo]\na = 42",
   136  		"$.foo['a']",
   137  		[]interface{}{
   138  			queryTestNode{
   139  				int64(42), toml.Position{2, 1},
   140  			},
   141  		})
   142  }
   143  
   144  func TestQueryKeyUnicodeString(t *testing.T) {
   145  	assertQueryPositions(t,
   146  		"['f𝟘.o']\na = 42",
   147  		"$['f𝟘.o']['a']",
   148  		[]interface{}{
   149  			queryTestNode{
   150  				int64(42), toml.Position{2, 1},
   151  			},
   152  		})
   153  }
   154  
   155  func TestQueryIndexError1(t *testing.T) {
   156  	assertParseError(t, "$.foo.a[5", "(1, 10): expected ',' or ']', not ''")
   157  }
   158  
   159  func TestQueryIndexError2(t *testing.T) {
   160  	assertParseError(t, "$.foo.a[]", "(1, 9): expected union sub expression, not ']', 0")
   161  }
   162  
   163  func TestQueryIndex(t *testing.T) {
   164  	assertQueryPositions(t,
   165  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   166  		"$.foo.a[5]",
   167  		[]interface{}{
   168  			queryTestNode{int64(5), toml.Position{2, 1}},
   169  		})
   170  }
   171  
   172  func TestQueryIndexNegative(t *testing.T) {
   173  	assertQueryPositions(t,
   174  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   175  		"$.foo.a[-2]",
   176  		[]interface{}{
   177  			queryTestNode{int64(8), toml.Position{2, 1}},
   178  		})
   179  }
   180  
   181  func TestQueryIndexWrong(t *testing.T) {
   182  	assertQueryPositions(t,
   183  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   184  		"$.foo.a[99]",
   185  		[]interface{}{})
   186  }
   187  
   188  func TestQueryIndexEmpty(t *testing.T) {
   189  	assertQueryPositions(t,
   190  		"[foo]\na = []",
   191  		"$.foo.a[5]",
   192  		[]interface{}{})
   193  }
   194  
   195  func TestQueryIndexTree(t *testing.T) {
   196  	assertQueryPositions(t,
   197  		"[[foo]]\na = [0,1,2,3,4,5,6,7,8,9]\n[[foo]]\nb = 3",
   198  		"$.foo[1].b",
   199  		[]interface{}{
   200  			queryTestNode{int64(3), toml.Position{4, 1}},
   201  		})
   202  }
   203  
   204  func TestQuerySliceError1(t *testing.T) {
   205  	assertParseError(t, "$.foo.a[3:?]", "(1, 11): expected ']' or ':'")
   206  }
   207  
   208  func TestQuerySliceError2(t *testing.T) {
   209  	assertParseError(t, "$.foo.a[:::]", "(1, 11): expected ']'")
   210  }
   211  
   212  func TestQuerySliceError3(t *testing.T) {
   213  	assertParseError(t, "$.foo.a[::0]", "(1, 11): step cannot be zero")
   214  }
   215  
   216  func TestQuerySliceRange(t *testing.T) {
   217  	assertQueryPositions(t,
   218  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   219  		"$.foo.a[:5]",
   220  		[]interface{}{
   221  			queryTestNode{int64(0), toml.Position{2, 1}},
   222  			queryTestNode{int64(1), toml.Position{2, 1}},
   223  			queryTestNode{int64(2), toml.Position{2, 1}},
   224  			queryTestNode{int64(3), toml.Position{2, 1}},
   225  			queryTestNode{int64(4), toml.Position{2, 1}},
   226  		})
   227  }
   228  
   229  func TestQuerySliceStep(t *testing.T) {
   230  	assertQueryPositions(t,
   231  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   232  		"$.foo.a[0:5:2]",
   233  		[]interface{}{
   234  			queryTestNode{int64(0), toml.Position{2, 1}},
   235  			queryTestNode{int64(2), toml.Position{2, 1}},
   236  			queryTestNode{int64(4), toml.Position{2, 1}},
   237  		})
   238  }
   239  
   240  func TestQuerySliceStartNegative(t *testing.T) {
   241  	assertQueryPositions(t,
   242  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   243  		"$.foo.a[-3:]",
   244  		[]interface{}{
   245  			queryTestNode{int64(7), toml.Position{2, 1}},
   246  			queryTestNode{int64(8), toml.Position{2, 1}},
   247  			queryTestNode{int64(9), toml.Position{2, 1}},
   248  		})
   249  }
   250  
   251  func TestQuerySliceEndNegative(t *testing.T) {
   252  	assertQueryPositions(t,
   253  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   254  		"$.foo.a[:-6]",
   255  		[]interface{}{
   256  			queryTestNode{int64(0), toml.Position{2, 1}},
   257  			queryTestNode{int64(1), toml.Position{2, 1}},
   258  			queryTestNode{int64(2), toml.Position{2, 1}},
   259  			queryTestNode{int64(3), toml.Position{2, 1}},
   260  		})
   261  }
   262  
   263  func TestQuerySliceStepNegative(t *testing.T) {
   264  	assertQueryPositions(t,
   265  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   266  		"$.foo.a[::-2]",
   267  		[]interface{}{
   268  			queryTestNode{int64(9), toml.Position{2, 1}},
   269  			queryTestNode{int64(7), toml.Position{2, 1}},
   270  			queryTestNode{int64(5), toml.Position{2, 1}},
   271  			queryTestNode{int64(3), toml.Position{2, 1}},
   272  			queryTestNode{int64(1), toml.Position{2, 1}},
   273  		})
   274  }
   275  
   276  func TestQuerySliceStartOverRange(t *testing.T) {
   277  	assertQueryPositions(t,
   278  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   279  		"$.foo.a[-99:3]",
   280  		[]interface{}{
   281  			queryTestNode{int64(0), toml.Position{2, 1}},
   282  			queryTestNode{int64(1), toml.Position{2, 1}},
   283  			queryTestNode{int64(2), toml.Position{2, 1}},
   284  		})
   285  }
   286  
   287  func TestQuerySliceStartOverRangeNegative(t *testing.T) {
   288  	assertQueryPositions(t,
   289  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   290  		"$.foo.a[99:7:-1]",
   291  		[]interface{}{
   292  			queryTestNode{int64(9), toml.Position{2, 1}},
   293  			queryTestNode{int64(8), toml.Position{2, 1}},
   294  		})
   295  }
   296  
   297  func TestQuerySliceEndOverRange(t *testing.T) {
   298  	assertQueryPositions(t,
   299  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   300  		"$.foo.a[7:99]",
   301  		[]interface{}{
   302  			queryTestNode{int64(7), toml.Position{2, 1}},
   303  			queryTestNode{int64(8), toml.Position{2, 1}},
   304  			queryTestNode{int64(9), toml.Position{2, 1}},
   305  		})
   306  }
   307  
   308  func TestQuerySliceEndOverRangeNegative(t *testing.T) {
   309  	assertQueryPositions(t,
   310  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   311  		"$.foo.a[2:-99:-1]",
   312  		[]interface{}{
   313  			queryTestNode{int64(2), toml.Position{2, 1}},
   314  			queryTestNode{int64(1), toml.Position{2, 1}},
   315  			queryTestNode{int64(0), toml.Position{2, 1}},
   316  		})
   317  }
   318  
   319  func TestQuerySliceWrongRange(t *testing.T) {
   320  	assertQueryPositions(t,
   321  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   322  		"$.foo.a[5:3]",
   323  		[]interface{}{})
   324  }
   325  
   326  func TestQuerySliceWrongRangeNegative(t *testing.T) {
   327  	assertQueryPositions(t,
   328  		"[foo]\na = [0,1,2,3,4,5,6,7,8,9]",
   329  		"$.foo.a[3:5:-1]",
   330  		[]interface{}{})
   331  }
   332  
   333  func TestQuerySliceEmpty(t *testing.T) {
   334  	assertQueryPositions(t,
   335  		"[foo]\na = []",
   336  		"$.foo.a[5:]",
   337  		[]interface{}{})
   338  }
   339  
   340  func TestQuerySliceTree(t *testing.T) {
   341  	assertQueryPositions(t,
   342  		"[[foo]]\na='nok'\n[[foo]]\na = [0,1,2,3,4,5,6,7,8,9]\n[[foo]]\na='ok'\nb = 3",
   343  		"$.foo[1:].a",
   344  		[]interface{}{
   345  			queryTestNode{
   346  				[]interface{}{
   347  					int64(0), int64(1), int64(2), int64(3), int64(4),
   348  					int64(5), int64(6), int64(7), int64(8), int64(9)},
   349  				toml.Position{4, 1}},
   350  			queryTestNode{"ok", toml.Position{6, 1}},
   351  		})
   352  }
   353  
   354  func TestQueryAny(t *testing.T) {
   355  	assertQueryPositions(t,
   356  		"[foo.bar]\na=1\nb=2\n[foo.baz]\na=3\nb=4",
   357  		"$.foo.*",
   358  		[]interface{}{
   359  			queryTestNode{
   360  				map[string]interface{}{
   361  					"a": int64(1),
   362  					"b": int64(2),
   363  				}, toml.Position{1, 1},
   364  			},
   365  			queryTestNode{
   366  				map[string]interface{}{
   367  					"a": int64(3),
   368  					"b": int64(4),
   369  				}, toml.Position{4, 1},
   370  			},
   371  		})
   372  }
   373  func TestQueryUnionSimple(t *testing.T) {
   374  	assertQueryPositions(t,
   375  		"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
   376  		"$.*[bar,foo]",
   377  		[]interface{}{
   378  			queryTestNode{
   379  				map[string]interface{}{
   380  					"a": int64(1),
   381  					"b": int64(2),
   382  				}, toml.Position{1, 1},
   383  			},
   384  			queryTestNode{
   385  				map[string]interface{}{
   386  					"a": int64(3),
   387  					"b": int64(4),
   388  				}, toml.Position{4, 1},
   389  			},
   390  			queryTestNode{
   391  				map[string]interface{}{
   392  					"a": int64(5),
   393  					"b": int64(6),
   394  				}, toml.Position{7, 1},
   395  			},
   396  		})
   397  }
   398  
   399  func TestQueryRecursionAll(t *testing.T) {
   400  	assertQueryPositions(t,
   401  		"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
   402  		"$..*",
   403  		[]interface{}{
   404  			queryTestNode{
   405  				map[string]interface{}{
   406  					"foo": map[string]interface{}{
   407  						"bar": map[string]interface{}{
   408  							"a": int64(1),
   409  							"b": int64(2),
   410  						},
   411  					},
   412  					"baz": map[string]interface{}{
   413  						"foo": map[string]interface{}{
   414  							"a": int64(3),
   415  							"b": int64(4),
   416  						},
   417  					},
   418  					"gorf": map[string]interface{}{
   419  						"foo": map[string]interface{}{
   420  							"a": int64(5),
   421  							"b": int64(6),
   422  						},
   423  					},
   424  				}, toml.Position{1, 1},
   425  			},
   426  			queryTestNode{
   427  				map[string]interface{}{
   428  					"bar": map[string]interface{}{
   429  						"a": int64(1),
   430  						"b": int64(2),
   431  					},
   432  				}, toml.Position{1, 1},
   433  			},
   434  			queryTestNode{
   435  				map[string]interface{}{
   436  					"a": int64(1),
   437  					"b": int64(2),
   438  				}, toml.Position{1, 1},
   439  			},
   440  			queryTestNode{int64(1), toml.Position{2, 1}},
   441  			queryTestNode{int64(2), toml.Position{3, 1}},
   442  			queryTestNode{
   443  				map[string]interface{}{
   444  					"foo": map[string]interface{}{
   445  						"a": int64(3),
   446  						"b": int64(4),
   447  					},
   448  				}, toml.Position{4, 1},
   449  			},
   450  			queryTestNode{
   451  				map[string]interface{}{
   452  					"a": int64(3),
   453  					"b": int64(4),
   454  				}, toml.Position{4, 1},
   455  			},
   456  			queryTestNode{int64(3), toml.Position{5, 1}},
   457  			queryTestNode{int64(4), toml.Position{6, 1}},
   458  			queryTestNode{
   459  				map[string]interface{}{
   460  					"foo": map[string]interface{}{
   461  						"a": int64(5),
   462  						"b": int64(6),
   463  					},
   464  				}, toml.Position{7, 1},
   465  			},
   466  			queryTestNode{
   467  				map[string]interface{}{
   468  					"a": int64(5),
   469  					"b": int64(6),
   470  				}, toml.Position{7, 1},
   471  			},
   472  			queryTestNode{int64(5), toml.Position{8, 1}},
   473  			queryTestNode{int64(6), toml.Position{9, 1}},
   474  		})
   475  }
   476  
   477  func TestQueryRecursionUnionSimple(t *testing.T) {
   478  	assertQueryPositions(t,
   479  		"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
   480  		"$..['foo','bar']",
   481  		[]interface{}{
   482  			queryTestNode{
   483  				map[string]interface{}{
   484  					"bar": map[string]interface{}{
   485  						"a": int64(1),
   486  						"b": int64(2),
   487  					},
   488  				}, toml.Position{1, 1},
   489  			},
   490  			queryTestNode{
   491  				map[string]interface{}{
   492  					"a": int64(3),
   493  					"b": int64(4),
   494  				}, toml.Position{4, 1},
   495  			},
   496  			queryTestNode{
   497  				map[string]interface{}{
   498  					"a": int64(1),
   499  					"b": int64(2),
   500  				}, toml.Position{1, 1},
   501  			},
   502  			queryTestNode{
   503  				map[string]interface{}{
   504  					"a": int64(5),
   505  					"b": int64(6),
   506  				}, toml.Position{7, 1},
   507  			},
   508  		})
   509  }
   510  
   511  func TestQueryFilterFn(t *testing.T) {
   512  	buff, err := ioutil.ReadFile("../example.toml")
   513  	if err != nil {
   514  		t.Error(err)
   515  		return
   516  	}
   517  
   518  	assertQueryPositions(t, string(buff),
   519  		"$..[?(int)]",
   520  		[]interface{}{
   521  			queryTestNode{int64(8001), toml.Position{13, 1}},
   522  			queryTestNode{int64(8001), toml.Position{13, 1}},
   523  			queryTestNode{int64(8002), toml.Position{13, 1}},
   524  			queryTestNode{int64(5000), toml.Position{14, 1}},
   525  		})
   526  
   527  	assertQueryPositions(t, string(buff),
   528  		"$..[?(string)]",
   529  		[]interface{}{
   530  			queryTestNode{"TOML Example", toml.Position{3, 1}},
   531  			queryTestNode{"Tom Preston-Werner", toml.Position{6, 1}},
   532  			queryTestNode{"GitHub", toml.Position{7, 1}},
   533  			queryTestNode{"GitHub Cofounder & CEO\nLikes tater tots and beer.", toml.Position{8, 1}},
   534  			queryTestNode{"192.168.1.1", toml.Position{12, 1}},
   535  			queryTestNode{"10.0.0.1", toml.Position{21, 3}},
   536  			queryTestNode{"eqdc10", toml.Position{22, 3}},
   537  			queryTestNode{"10.0.0.2", toml.Position{25, 3}},
   538  			queryTestNode{"eqdc10", toml.Position{26, 3}},
   539  		})
   540  
   541  	assertQueryPositions(t, string(buff),
   542  		"$..[?(float)]",
   543  		[]interface{}{
   544  			queryTestNode{4e-08, toml.Position{30, 1}},
   545  		})
   546  
   547  	tv, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
   548  	assertQueryPositions(t, string(buff),
   549  		"$..[?(tree)]",
   550  		[]interface{}{
   551  			queryTestNode{
   552  				map[string]interface{}{
   553  					"name":         "Tom Preston-Werner",
   554  					"organization": "GitHub",
   555  					"bio":          "GitHub Cofounder & CEO\nLikes tater tots and beer.",
   556  					"dob":          tv,
   557  				}, toml.Position{5, 1},
   558  			},
   559  			queryTestNode{
   560  				map[string]interface{}{
   561  					"server":         "192.168.1.1",
   562  					"ports":          []interface{}{int64(8001), int64(8001), int64(8002)},
   563  					"connection_max": int64(5000),
   564  					"enabled":        true,
   565  				}, toml.Position{11, 1},
   566  			},
   567  			queryTestNode{
   568  				map[string]interface{}{
   569  					"alpha": map[string]interface{}{
   570  						"ip": "10.0.0.1",
   571  						"dc": "eqdc10",
   572  					},
   573  					"beta": map[string]interface{}{
   574  						"ip": "10.0.0.2",
   575  						"dc": "eqdc10",
   576  					},
   577  				}, toml.Position{17, 1},
   578  			},
   579  			queryTestNode{
   580  				map[string]interface{}{
   581  					"ip": "10.0.0.1",
   582  					"dc": "eqdc10",
   583  				}, toml.Position{20, 3},
   584  			},
   585  			queryTestNode{
   586  				map[string]interface{}{
   587  					"ip": "10.0.0.2",
   588  					"dc": "eqdc10",
   589  				}, toml.Position{24, 3},
   590  			},
   591  			queryTestNode{
   592  				map[string]interface{}{
   593  					"data": []interface{}{
   594  						[]interface{}{"gamma", "delta"},
   595  						[]interface{}{int64(1), int64(2)},
   596  					},
   597  					"score": 4e-08,
   598  				}, toml.Position{28, 1},
   599  			},
   600  		})
   601  
   602  	assertQueryPositions(t, string(buff),
   603  		"$..[?(time)]",
   604  		[]interface{}{
   605  			queryTestNode{tv, toml.Position{9, 1}},
   606  		})
   607  
   608  	assertQueryPositions(t, string(buff),
   609  		"$..[?(bool)]",
   610  		[]interface{}{
   611  			queryTestNode{true, toml.Position{15, 1}},
   612  		})
   613  }
   614  

View as plain text