github.com/tomwright/dasel@v1.27.3/node_test.go (about)

     1  package dasel_test
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"github.com/tomwright/dasel/storage"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/tomwright/dasel"
    14  )
    15  
    16  // ExampleNode_ReadmeExample tests the code from the readme explanation.
    17  func ExampleNode_ReadmeExample() {
    18  	printNodeValue := func(nodes ...*dasel.Node) {
    19  		for _, n := range nodes {
    20  			fmt.Println(n.InterfaceValue())
    21  		}
    22  	}
    23  
    24  	var data interface{}
    25  	_ = json.Unmarshal([]byte(`[{"name": "Tom"}, {"name": "Jim"}]`), &data)
    26  
    27  	rootNode := dasel.New(data)
    28  
    29  	result, _ := rootNode.Query(".[0].name")
    30  	printNodeValue(result) // Tom
    31  
    32  	results, _ := rootNode.QueryMultiple(".[*].name")
    33  	printNodeValue(results...) // Tom \n Jim
    34  
    35  	_ = rootNode.Put(".[0].name", "Frank")
    36  	printNodeValue(rootNode) // [ map[name:Frank] map[name:Jim] ]
    37  
    38  	_ = rootNode.PutMultiple(".[*].name", "Joe")
    39  	printNodeValue(rootNode) // [ map[name:Joe] map[name:Joe] ]
    40  
    41  	outputBytes, _ := json.Marshal(rootNode.InterfaceValue())
    42  	fmt.Println(string(outputBytes)) // [{"name": "Joe"}, {"name": "Joe"}]
    43  
    44  	// Output:
    45  	// Tom
    46  	// Tom
    47  	// Jim
    48  	// [map[name:Frank] map[name:Jim]]
    49  	// [map[name:Joe] map[name:Joe]]
    50  	// [{"name":"Joe"},{"name":"Joe"}]
    51  }
    52  
    53  // ExampleNode_Query shows how to query data from go code.
    54  func ExampleNode_Query() {
    55  	myData := []byte(`{"name": "Tom"}`)
    56  	var data interface{}
    57  	if err := json.Unmarshal(myData, &data); err != nil {
    58  		panic(err)
    59  	}
    60  	rootNode := dasel.New(data)
    61  	result, err := rootNode.Query(".name")
    62  	if err != nil {
    63  		panic(err)
    64  	}
    65  	fmt.Println(result.InterfaceValue())
    66  
    67  	// Output:
    68  	// Tom
    69  }
    70  
    71  // ExampleNode_Put shows how to update data from go code.
    72  func ExampleNode_Put() {
    73  	myData := []byte(`{"name": "Tom"}`)
    74  	var data interface{}
    75  	if err := json.Unmarshal(myData, &data); err != nil {
    76  		panic(err)
    77  	}
    78  	rootNode := dasel.New(data)
    79  	if err := rootNode.Put(".name", "Jim"); err != nil {
    80  		panic(err)
    81  	}
    82  	fmt.Println(rootNode.InterfaceValue())
    83  
    84  	// Output:
    85  	// map[name:Jim]
    86  }
    87  
    88  var (
    89  	tom = map[string]interface{}{
    90  		"name": "Tom",
    91  		"age":  28,
    92  	}
    93  	amelia = map[string]interface{}{
    94  		"name": "Amelia",
    95  		"age":  26,
    96  	}
    97  	people = []map[string]interface{}{tom, amelia}
    98  	mapC   = map[string]interface{}{
    99  		"thing": "1",
   100  	}
   101  	mapB = map[string]interface{}{
   102  		"c":      mapC,
   103  		"people": people,
   104  	}
   105  	mapA = map[string]interface{}{
   106  		"b": mapB,
   107  	}
   108  	mapRoot = map[string]interface{}{
   109  		"a": mapA,
   110  	}
   111  )
   112  
   113  func testParseSelector(in string, exp dasel.Selector) func(t *testing.T) {
   114  	return func(t *testing.T) {
   115  		got, err := dasel.ParseSelector(in)
   116  		if err != nil {
   117  			t.Errorf("unexpected error: %s", err)
   118  		}
   119  		if !reflect.DeepEqual(exp, got) {
   120  			t.Errorf("expected %v, got %v", exp, got)
   121  		}
   122  	}
   123  }
   124  
   125  func TestParseSelector(t *testing.T) {
   126  	t.Run("NonIntIndex", func(t *testing.T) {
   127  		_, err := dasel.ParseSelector(".[a]")
   128  		exp := &dasel.InvalidIndexErr{Index: "a"}
   129  		if err == nil || err.Error() != exp.Error() {
   130  			t.Errorf("expected error %v, got %v", exp, err)
   131  		}
   132  	})
   133  	t.Run("InvalidDynamicBracketCount", func(t *testing.T) {
   134  		_, err := dasel.ParseSelector(".((name=x)")
   135  		exp := dasel.ErrDynamicSelectorBracketMismatch
   136  		if err == nil || !errors.Is(err, exp) {
   137  			t.Errorf("expected error %v, got %v", exp, err)
   138  		}
   139  	})
   140  	t.Run("InvalidDynamicComparison", func(t *testing.T) {
   141  		_, err := dasel.ParseSelector(".(x@2)")
   142  		exp := &dasel.UnknownComparisonOperatorErr{Operator: ""}
   143  		if err == nil || err.Error() != exp.Error() {
   144  			t.Errorf("expected error %v, got %v", exp, err)
   145  		}
   146  	})
   147  	t.Run("MultipleSearchGroups", func(t *testing.T) {
   148  		_, err := dasel.ParseSelector(".(?:a=b)(a=b)")
   149  		exp := "require exactly 1 group in search selector"
   150  		if err == nil || err.Error() != exp {
   151  			t.Errorf("expected error %v, got %v", exp, err)
   152  		}
   153  	})
   154  	t.Run("UnknownComparisonOperator", func(t *testing.T) {
   155  		_, err := dasel.ParseSelector(".(a@b)")
   156  		exp := "unknown comparison operator: "
   157  		if err == nil || err.Error() != exp {
   158  			t.Errorf("expected error %v, got %v", exp, err)
   159  		}
   160  	})
   161  	t.Run("UnknownSearchComparisonOperator", func(t *testing.T) {
   162  		_, err := dasel.ParseSelector(".(?:a@b)")
   163  		exp := "unknown comparison operator: "
   164  		if err == nil || err.Error() != exp {
   165  			t.Errorf("expected error %v, got %v", exp, err)
   166  		}
   167  	})
   168  	t.Run("UnknownSearchKeyComparisonOperator", func(t *testing.T) {
   169  		_, err := dasel.ParseSelector(".(?:->b)")
   170  		exp := "unknown comparison operator: >"
   171  		if err == nil || err.Error() != exp {
   172  			t.Errorf("expected error %v, got %v", exp, err)
   173  		}
   174  	})
   175  	t.Run("SearchEqual", testParseSelector(".(?:name=asd)", dasel.Selector{
   176  		Raw:       ".(?:name=asd)",
   177  		Current:   ".(?:name=asd)",
   178  		Remaining: "",
   179  		Type:      "SEARCH",
   180  		Conditions: []dasel.Condition{
   181  			&dasel.EqualCondition{
   182  				Key:   "name",
   183  				Value: "asd",
   184  			},
   185  		},
   186  	}))
   187  	t.Run("SearchNotEqual", testParseSelector(".(?:name!=asd)", dasel.Selector{
   188  		Raw:       ".(?:name!=asd)",
   189  		Current:   ".(?:name!=asd)",
   190  		Remaining: "",
   191  		Type:      "SEARCH",
   192  		Conditions: []dasel.Condition{
   193  			&dasel.EqualCondition{
   194  				Key:   "name",
   195  				Value: "asd",
   196  				Not:   true,
   197  			},
   198  		},
   199  	}))
   200  	t.Run("SearchMoreThan", testParseSelector(".(?:name.[#]>3)", dasel.Selector{
   201  		Raw:       ".(?:name.[#]>3)",
   202  		Current:   ".(?:name.[#]>3)",
   203  		Remaining: "",
   204  		Type:      "SEARCH",
   205  		Conditions: []dasel.Condition{
   206  			&dasel.SortedComparisonCondition{
   207  				Key:   "name.[#]",
   208  				Value: "3",
   209  				After: true,
   210  			},
   211  		},
   212  	}))
   213  	t.Run("SearchMoreThanEqual", testParseSelector(".(?:name.[#]>=3)", dasel.Selector{
   214  		Raw:       ".(?:name.[#]>=3)",
   215  		Current:   ".(?:name.[#]>=3)",
   216  		Remaining: "",
   217  		Type:      "SEARCH",
   218  		Conditions: []dasel.Condition{
   219  			&dasel.SortedComparisonCondition{
   220  				Key:   "name.[#]",
   221  				Value: "3",
   222  				After: true,
   223  				Equal: true,
   224  			},
   225  		},
   226  	}))
   227  	t.Run("SearchLessThan", testParseSelector(".(?:name.[#]<3)", dasel.Selector{
   228  		Raw:       ".(?:name.[#]<3)",
   229  		Current:   ".(?:name.[#]<3)",
   230  		Remaining: "",
   231  		Type:      "SEARCH",
   232  		Conditions: []dasel.Condition{
   233  			&dasel.SortedComparisonCondition{
   234  				Key:   "name.[#]",
   235  				Value: "3",
   236  			},
   237  		},
   238  	}))
   239  	t.Run("SearchLessThanEqual", testParseSelector(".(?:name.[#]<=3)", dasel.Selector{
   240  		Raw:       ".(?:name.[#]<=3)",
   241  		Current:   ".(?:name.[#]<=3)",
   242  		Remaining: "",
   243  		Type:      "SEARCH",
   244  		Conditions: []dasel.Condition{
   245  			&dasel.SortedComparisonCondition{
   246  				Key:   "name.[#]",
   247  				Value: "3",
   248  				Equal: true,
   249  			},
   250  		},
   251  	}))
   252  	t.Run("SearchKey", testParseSelector(".(?:-=asd)", dasel.Selector{
   253  		Raw:       ".(?:-=asd)",
   254  		Current:   ".(?:-=asd)",
   255  		Remaining: "",
   256  		Type:      "SEARCH",
   257  		Conditions: []dasel.Condition{
   258  			&dasel.KeyEqualCondition{
   259  				Value: "asd",
   260  			},
   261  		},
   262  	}))
   263  	t.Run("SearchKeyNotEqual", testParseSelector(".(?:-!=asd)", dasel.Selector{
   264  		Raw:       ".(?:-!=asd)",
   265  		Current:   ".(?:-!=asd)",
   266  		Remaining: "",
   267  		Type:      "SEARCH",
   268  		Conditions: []dasel.Condition{
   269  			&dasel.KeyEqualCondition{
   270  				Value: "asd",
   271  				Not:   true,
   272  			},
   273  		},
   274  	}))
   275  	t.Run("DynamicKey", testParseSelector(".(-=asd)", dasel.Selector{
   276  		Raw:       ".(-=asd)",
   277  		Current:   ".(-=asd)",
   278  		Remaining: "",
   279  		Type:      "DYNAMIC",
   280  		Conditions: []dasel.Condition{
   281  			&dasel.KeyEqualCondition{
   282  				Value: "asd",
   283  			},
   284  		},
   285  	}))
   286  	t.Run("DynamicKeyNotEqual", testParseSelector(".(-!=asd)", dasel.Selector{
   287  		Raw:       ".(-!=asd)",
   288  		Current:   ".(-!=asd)",
   289  		Remaining: "",
   290  		Type:      "DYNAMIC",
   291  		Conditions: []dasel.Condition{
   292  			&dasel.KeyEqualCondition{
   293  				Value: "asd",
   294  				Not:   true,
   295  			},
   296  		},
   297  	}))
   298  	t.Run("DynamicEqual", testParseSelector(".(name=asd)", dasel.Selector{
   299  		Raw:       ".(name=asd)",
   300  		Current:   ".(name=asd)",
   301  		Remaining: "",
   302  		Type:      "DYNAMIC",
   303  		Conditions: []dasel.Condition{
   304  			&dasel.EqualCondition{
   305  				Key:   "name",
   306  				Value: "asd",
   307  			},
   308  		},
   309  	}))
   310  	t.Run("DynamicNotEqual", testParseSelector(".(name!=asd)", dasel.Selector{
   311  		Raw:       ".(name!=asd)",
   312  		Current:   ".(name!=asd)",
   313  		Remaining: "",
   314  		Type:      "DYNAMIC",
   315  		Conditions: []dasel.Condition{
   316  			&dasel.EqualCondition{
   317  				Key:   "name",
   318  				Value: "asd",
   319  				Not:   true,
   320  			},
   321  		},
   322  	}))
   323  	t.Run("DynamicMoreThan", testParseSelector(".(name.[#]>3)", dasel.Selector{
   324  		Raw:       ".(name.[#]>3)",
   325  		Current:   ".(name.[#]>3)",
   326  		Remaining: "",
   327  		Type:      "DYNAMIC",
   328  		Conditions: []dasel.Condition{
   329  			&dasel.SortedComparisonCondition{
   330  				Key:   "name.[#]",
   331  				Value: "3",
   332  				After: true,
   333  			},
   334  		},
   335  	}))
   336  	t.Run("DynamicMoreThanEqual", testParseSelector(".(name.[#]>=3)", dasel.Selector{
   337  		Raw:       ".(name.[#]>=3)",
   338  		Current:   ".(name.[#]>=3)",
   339  		Remaining: "",
   340  		Type:      "DYNAMIC",
   341  		Conditions: []dasel.Condition{
   342  			&dasel.SortedComparisonCondition{
   343  				Key:   "name.[#]",
   344  				Value: "3",
   345  				After: true,
   346  				Equal: true,
   347  			},
   348  		},
   349  	}))
   350  	t.Run("DynamicLessThan", testParseSelector(".(name.[#]<3)", dasel.Selector{
   351  		Raw:       ".(name.[#]<3)",
   352  		Current:   ".(name.[#]<3)",
   353  		Remaining: "",
   354  		Type:      "DYNAMIC",
   355  		Conditions: []dasel.Condition{
   356  			&dasel.SortedComparisonCondition{
   357  				Key:   "name.[#]",
   358  				Value: "3",
   359  			},
   360  		},
   361  	}))
   362  	t.Run("DynamicLessThanEqual", testParseSelector(".(name.[#]<=3)", dasel.Selector{
   363  		Raw:       ".(name.[#]<=3)",
   364  		Current:   ".(name.[#]<=3)",
   365  		Remaining: "",
   366  		Type:      "DYNAMIC",
   367  		Conditions: []dasel.Condition{
   368  			&dasel.SortedComparisonCondition{
   369  				Key:   "name.[#]",
   370  				Value: "3",
   371  				Equal: true,
   372  			},
   373  		},
   374  	}))
   375  	t.Run("Unicode", testParseSelector(".(name=Ägir).b", dasel.Selector{
   376  		Raw:       ".(name=Ägir).b",
   377  		Current:   ".(name=Ägir)",
   378  		Remaining: ".b",
   379  		Type:      "DYNAMIC",
   380  		Conditions: []dasel.Condition{
   381  			&dasel.EqualCondition{
   382  				Key:   "name",
   383  				Value: "Ägir",
   384  			},
   385  		},
   386  	}))
   387  }
   388  
   389  func extractValues(nodes []*dasel.Node) []interface{} {
   390  	gotValues := make([]interface{}, len(nodes))
   391  	for i, n := range nodes {
   392  		gotValues[i] = n.InterfaceValue()
   393  	}
   394  	return gotValues
   395  }
   396  
   397  func testNodeQueryMultipleArray(selector string, expValues []interface{}) func(t *testing.T) {
   398  	return func(t *testing.T) {
   399  		nodes, err := dasel.New([]map[string]interface{}{
   400  			{
   401  				"name": "Tom",
   402  				"age":  "27",
   403  			},
   404  			{
   405  				"name": "Jim",
   406  				"age":  "27",
   407  			},
   408  			{
   409  				"name": "Amelia",
   410  				"age":  "25",
   411  			},
   412  		}).QueryMultiple(selector)
   413  		if err != nil {
   414  			t.Errorf("unexpected query error: %s", err)
   415  			return
   416  		}
   417  
   418  		gotValues := extractValues(nodes)
   419  
   420  		if !valuesAreEqual(expValues, gotValues) {
   421  			t.Errorf("expected %v, got %v", expValues, gotValues)
   422  		}
   423  	}
   424  }
   425  
   426  func testNodeQueryMultipleMap(selector string, expValues []interface{}) func(t *testing.T) {
   427  	return func(t *testing.T) {
   428  		nodes, err := dasel.New(map[string]interface{}{
   429  			"personA": map[string]interface{}{
   430  				"name": "Tom",
   431  				"age":  27,
   432  			},
   433  			"personB": map[string]interface{}{
   434  				"name": "Jim",
   435  				"age":  27,
   436  			},
   437  			"personC": map[string]interface{}{
   438  				"name": "Amelia",
   439  				"age":  25,
   440  			},
   441  		}).QueryMultiple(selector)
   442  		if err != nil {
   443  			t.Errorf("unexpected query error: %s", err)
   444  			return
   445  		}
   446  
   447  		gotValues := extractValues(nodes)
   448  
   449  		if !valuesAreEqual(expValues, gotValues) {
   450  			t.Errorf("expected %v, got %v", expValues, gotValues)
   451  		}
   452  	}
   453  }
   454  
   455  func TestNode_QueryMultiple(t *testing.T) {
   456  	t.Run("SingleResult", testNodeQueryMultipleArray(".[0].name", []interface{}{
   457  		"Tom",
   458  	}))
   459  	t.Run("SingleResultDynamicEqual", testNodeQueryMultipleArray(".(age=25).name", []interface{}{
   460  		"Amelia",
   461  	}))
   462  	t.Run("SingleResultDynamicNotEqual", testNodeQueryMultipleArray(".(age!=27).name", []interface{}{
   463  		"Amelia",
   464  	}))
   465  	t.Run("SingleResultDynamicKeyEqual", testNodeQueryMultipleArray(".(-=0).name", []interface{}{
   466  		"Tom",
   467  	}))
   468  	t.Run("MultipleResultDynamicKeyNotEqual", testNodeQueryMultipleArray(".(-!=0).name", []interface{}{
   469  		"Jim", "Amelia",
   470  	}))
   471  	t.Run("MultipleResultSearchKeyNotEqual", testNodeQueryMultipleArray(".[*].(?:-!=name)", []interface{}{
   472  		"27", "27", "25",
   473  	}))
   474  	t.Run("MultipleResultDynamic", testNodeQueryMultipleArray(".(age=27).name", []interface{}{
   475  		"Tom",
   476  		"Jim",
   477  	}))
   478  	t.Run("MultipleResultAnyIndex", testNodeQueryMultipleArray(".[*].name", []interface{}{
   479  		"Tom",
   480  		"Jim",
   481  		"Amelia",
   482  	}))
   483  
   484  	t.Run("MapSingleResult", testNodeQueryMultipleMap(".personA.name", []interface{}{
   485  		"Tom",
   486  	}))
   487  	t.Run("MapSingleResultDynamic", testNodeQueryMultipleMap(".(age=25).name", []interface{}{
   488  		"Amelia",
   489  	}))
   490  	t.Run("MapSingleResultDynamic", testNodeQueryMultipleMap(".(age=27).name", []interface{}{
   491  		"Tom",
   492  		"Jim",
   493  	}))
   494  	t.Run("MapMultipleResultAnyIndex", testNodeQueryMultipleMap(".[*].name", []interface{}{
   495  		"Tom",
   496  		"Jim",
   497  		"Amelia",
   498  	}))
   499  }
   500  
   501  func valuesAreEqual(exp []interface{}, got []interface{}) bool {
   502  	if len(exp) != len(got) {
   503  		return false
   504  	}
   505  	for _, g := range got {
   506  		found := false
   507  		for _, e := range exp {
   508  			if reflect.DeepEqual(g, e) {
   509  				found = true
   510  				break
   511  			}
   512  		}
   513  		if !found {
   514  			return false
   515  		}
   516  	}
   517  	return true
   518  }
   519  
   520  func TestNode_PutMultiple(t *testing.T) {
   521  	t.Run("SingleResult", func(t *testing.T) {
   522  		value := []map[string]interface{}{
   523  			{
   524  				"name": "Tom",
   525  				"age":  "27",
   526  			},
   527  			{
   528  				"name": "Jim",
   529  				"age":  "27",
   530  			},
   531  			{
   532  				"name": "Amelia",
   533  				"age":  "25",
   534  			},
   535  		}
   536  		err := dasel.New(value).PutMultiple(".[0].name", "Frank")
   537  		if err != nil {
   538  			t.Errorf("unexpected query error: %s", err)
   539  			return
   540  		}
   541  
   542  		exp := []map[string]interface{}{
   543  			{
   544  				"name": "Frank",
   545  				"age":  "27",
   546  			},
   547  			{
   548  				"name": "Jim",
   549  				"age":  "27",
   550  			},
   551  			{
   552  				"name": "Amelia",
   553  				"age":  "25",
   554  			},
   555  		}
   556  
   557  		if !reflect.DeepEqual(exp, value) {
   558  			t.Errorf("expected %v, got %v", exp, value)
   559  		}
   560  	})
   561  	t.Run("SingleResultDynamic", func(t *testing.T) {
   562  		value := []map[string]interface{}{
   563  			{
   564  				"name": "Frank",
   565  				"age":  "27",
   566  			},
   567  			{
   568  				"name": "Jim",
   569  				"age":  "27",
   570  			},
   571  			{
   572  				"name": "Amelia",
   573  				"age":  "25",
   574  			},
   575  		}
   576  		err := dasel.New(value).PutMultiple(".(age=25).name", "Frank")
   577  		if err != nil {
   578  			t.Errorf("unexpected query error: %s", err)
   579  			return
   580  		}
   581  
   582  		exp := []map[string]interface{}{
   583  			{
   584  				"name": "Frank",
   585  				"age":  "27",
   586  			},
   587  			{
   588  				"name": "Jim",
   589  				"age":  "27",
   590  			},
   591  			{
   592  				"name": "Frank",
   593  				"age":  "25",
   594  			},
   595  		}
   596  
   597  		if !reflect.DeepEqual(exp, value) {
   598  			t.Errorf("expected %v, got %v", exp, value)
   599  		}
   600  	})
   601  	t.Run("MultipleResultDynamic", func(t *testing.T) {
   602  		value := []map[string]interface{}{
   603  			{
   604  				"name": "Tom",
   605  				"age":  "27",
   606  			},
   607  			{
   608  				"name": "Jim",
   609  				"age":  "27",
   610  			},
   611  			{
   612  				"name": "Amelia",
   613  				"age":  "25",
   614  			},
   615  		}
   616  		err := dasel.New(value).PutMultiple(".(age=27).name", "Frank")
   617  		if err != nil {
   618  			t.Errorf("unexpected query error: %s", err)
   619  			return
   620  		}
   621  
   622  		exp := []map[string]interface{}{
   623  			{
   624  				"name": "Frank",
   625  				"age":  "27",
   626  			},
   627  			{
   628  				"name": "Frank",
   629  				"age":  "27",
   630  			},
   631  			{
   632  				"name": "Amelia",
   633  				"age":  "25",
   634  			},
   635  		}
   636  
   637  		if !reflect.DeepEqual(exp, value) {
   638  			t.Errorf("expected %v, got %v", exp, value)
   639  		}
   640  	})
   641  	t.Run("MultipleResultAnyIndex", func(t *testing.T) {
   642  		value := []map[string]interface{}{
   643  			{
   644  				"name": "Tom",
   645  				"age":  "27",
   646  			},
   647  			{
   648  				"name": "Jim",
   649  				"age":  "27",
   650  			},
   651  			{
   652  				"name": "Amelia",
   653  				"age":  "25",
   654  			},
   655  		}
   656  		err := dasel.New(value).PutMultiple(".[*].name", "Frank")
   657  		if err != nil {
   658  			t.Errorf("unexpected query error: %s", err)
   659  			return
   660  		}
   661  
   662  		exp := []map[string]interface{}{
   663  			{
   664  				"name": "Frank",
   665  				"age":  "27",
   666  			},
   667  			{
   668  				"name": "Frank",
   669  				"age":  "27",
   670  			},
   671  			{
   672  				"name": "Frank",
   673  				"age":  "25",
   674  			},
   675  		}
   676  
   677  		if !reflect.DeepEqual(exp, value) {
   678  			t.Errorf("expected %v, got %v", exp, value)
   679  		}
   680  	})
   681  	t.Run("StructAnyIndex", func(t *testing.T) {
   682  		type user struct {
   683  			Name string
   684  			Age  int
   685  		}
   686  		value := []user{
   687  			{
   688  				Name: "Tom",
   689  				Age:  27,
   690  			},
   691  			{
   692  				Name: "Jim",
   693  				Age:  27,
   694  			},
   695  			{
   696  				Name: "Amelia",
   697  				Age:  25,
   698  			},
   699  		}
   700  		err := dasel.New(value).PutMultiple(".[*].Name", "Frank")
   701  		if err != nil {
   702  			t.Errorf("unexpected query error: %s", err)
   703  			return
   704  		}
   705  
   706  		exp := []user{
   707  			{
   708  				Name: "Frank",
   709  				Age:  27,
   710  			},
   711  			{
   712  				Name: "Frank",
   713  				Age:  27,
   714  			},
   715  			{
   716  				Name: "Frank",
   717  				Age:  25,
   718  			},
   719  		}
   720  
   721  		if !reflect.DeepEqual(exp, value) {
   722  			t.Errorf("expected %v, got %v", exp, value)
   723  		}
   724  	})
   725  }
   726  
   727  func TestNode_Query(t *testing.T) {
   728  	parser, err := storage.NewReadParserFromFilename("./tests/assets/example.json")
   729  	if err != nil {
   730  		t.Errorf("could not get parser: %s", err)
   731  		return
   732  	}
   733  
   734  	value, err := storage.LoadFromFile("./tests/assets/example.json", parser)
   735  	if err != nil {
   736  		t.Errorf("could not load value from file: %s", err)
   737  		return
   738  	}
   739  
   740  	t.Run("Valid", func(t *testing.T) {
   741  		node, err := dasel.New(value).Query("preferences.favouriteColour")
   742  		if err != nil {
   743  			t.Errorf("unexpected query error: %s", err)
   744  			return
   745  		}
   746  		if exp, got := "red", fmt.Sprint(node.InterfaceValue()); exp != got {
   747  			t.Errorf("expected value `%s`, got `%s`", exp, got)
   748  		}
   749  	})
   750  	t.Run("NotFound", func(t *testing.T) {
   751  		_, err := dasel.New(value).Query(".colours.[0].a")
   752  		expErr := fmt.Errorf("could not find value: selector [type:PROPERTY selector:.a] does not support value: [kind:string type:string] red")
   753  		if err == nil {
   754  			t.Errorf("expected err %v, got %v", expErr, err)
   755  			return
   756  		}
   757  		if err.Error() != expErr.Error() {
   758  			t.Errorf("expected err %v, got %v", expErr, err)
   759  			return
   760  		}
   761  	})
   762  	t.Run("InvalidSelector", func(t *testing.T) {
   763  		_, err := dasel.New(value).Query(".colours.[a]")
   764  		expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"})
   765  		if err == nil {
   766  			t.Errorf("expected err %v, got %v", expErr, err)
   767  			return
   768  		}
   769  		if err.Error() != expErr.Error() {
   770  			t.Errorf("expected err %v, got %v", expErr, err)
   771  			return
   772  		}
   773  	})
   774  }
   775  
   776  func TestNode_Query_File(t *testing.T) {
   777  	tests := []struct {
   778  		Name     string
   779  		Selector string
   780  		Exp      string
   781  	}{
   782  		{Name: "Property", Selector: "name", Exp: "Tom"},
   783  		{Name: "ChildProperty", Selector: "preferences.favouriteColour", Exp: "red"},
   784  		{Name: "Index", Selector: "colours.[0]", Exp: "red"},
   785  		{Name: "Index", Selector: "colours.[1]", Exp: "green"},
   786  		{Name: "Index", Selector: "colours.[2]", Exp: "blue"},
   787  		{Name: "IndexProperty", Selector: "colourCodes.[0].name", Exp: "red"},
   788  		{Name: "IndexProperty", Selector: "colourCodes.[1].name", Exp: "green"},
   789  		{Name: "IndexProperty", Selector: "colourCodes.[2].name", Exp: "blue"},
   790  		{Name: "DynamicProperty", Selector: "colourCodes.(name=red).rgb", Exp: "ff0000"},
   791  		{Name: "DynamicProperty", Selector: "colourCodes.(name=green).rgb", Exp: "00ff00"},
   792  		{Name: "DynamicProperty", Selector: "colourCodes.(name=blue).rgb", Exp: "0000ff"},
   793  		{Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=red)(rgb=ff0000).name", Exp: "red"},
   794  		{Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=green)(rgb=00ff00).name", Exp: "green"},
   795  		{Name: "MultipleDynamicProperty", Selector: "colourCodes.(name=blue)(rgb=0000ff).name", Exp: "blue"},
   796  	}
   797  
   798  	fileTest := func(filename string) func(t *testing.T) {
   799  		return func(t *testing.T) {
   800  			parser, err := storage.NewReadParserFromFilename(filename)
   801  			if err != nil {
   802  				t.Errorf("could not get parser: %s", err)
   803  				return
   804  			}
   805  
   806  			value, err := storage.LoadFromFile(filename, parser)
   807  			if err != nil {
   808  				t.Errorf("could not load value from file: %s", err)
   809  				return
   810  			}
   811  
   812  			for _, testCase := range tests {
   813  				tc := testCase
   814  				t.Run(tc.Name, func(t *testing.T) {
   815  					node, err := dasel.New(value).Query(tc.Selector)
   816  					if err != nil {
   817  						t.Errorf("unexpected query error: %s", err)
   818  						return
   819  					}
   820  
   821  					if exp, got := tc.Exp, fmt.Sprint(node.InterfaceValue()); exp != got {
   822  						t.Errorf("expected value `%s`, got `%s`", exp, got)
   823  					}
   824  				})
   825  			}
   826  		}
   827  	}
   828  
   829  	t.Run("JSON", fileTest("./tests/assets/example.json"))
   830  	t.Run("YAML", fileTest("./tests/assets/example.yaml"))
   831  }
   832  
   833  func TestNode_Query_Data(t *testing.T) {
   834  	t.Run("ParentChildPathToProperty", func(t *testing.T) {
   835  		rootNode := dasel.New(mapRoot)
   836  
   837  		got, err := rootNode.Query(".a.b.c.thing")
   838  		if err != nil {
   839  			t.Errorf("unexpected query error: %v", err)
   840  			return
   841  		}
   842  
   843  		if exp, got := "1", got.InterfaceValue().(string); exp != got {
   844  			t.Errorf("expected %s, got %s", exp, got)
   845  		}
   846  	})
   847  	t.Run("ParentChildPathToIndexProperty", func(t *testing.T) {
   848  		rootNode := dasel.New(mapRoot)
   849  
   850  		got, err := rootNode.Query(".a.b.people.[1].name")
   851  		if err != nil {
   852  			t.Errorf("unexpected query error: %v", err)
   853  			return
   854  		}
   855  
   856  		if exp, got := "Amelia", got.InterfaceValue().(string); exp != got {
   857  			t.Errorf("expected %s, got %s", exp, got)
   858  		}
   859  	})
   860  	t.Run("ParentChildPathToDynamicProperty", func(t *testing.T) {
   861  		rootNode := dasel.New(mapRoot)
   862  
   863  		got, err := rootNode.Query(".a.b.people.(name=Tom).name")
   864  		if err != nil {
   865  			t.Errorf("unexpected query error: %v", err)
   866  			return
   867  		}
   868  
   869  		if exp, got := "Tom", got.InterfaceValue().(string); exp != got {
   870  			t.Errorf("expected %s, got %s", exp, got)
   871  		}
   872  	})
   873  	t.Run("ParentChildPathToMultipleDynamicProperty", func(t *testing.T) {
   874  		rootNode := dasel.New(mapRoot)
   875  
   876  		got, err := rootNode.Query(".a.b.people.(name=Tom)(age=28).name")
   877  		if err != nil {
   878  			t.Errorf("unexpected query error: %v", err)
   879  			return
   880  		}
   881  
   882  		if exp, got := "Tom", got.InterfaceValue().(string); exp != got {
   883  			t.Errorf("expected %s, got %s", exp, got)
   884  		}
   885  	})
   886  	t.Run("DynamicPropertyOnMap", func(t *testing.T) {
   887  		rootNode := dasel.New(map[string]interface{}{
   888  			"personA": map[string]interface{}{
   889  				"name": "Tom",
   890  			},
   891  			"personB": map[string]interface{}{
   892  				"name": "Jim",
   893  			},
   894  		})
   895  
   896  		got, err := rootNode.Query(".(name=Tom).name")
   897  		if err != nil {
   898  			t.Errorf("unexpected query error: %v", err)
   899  			return
   900  		}
   901  
   902  		if exp, got := "Tom", got.InterfaceValue().(string); exp != got {
   903  			t.Errorf("expected %s, got %s", exp, got)
   904  		}
   905  	})
   906  	t.Run("SelectFromStruct", func(t *testing.T) {
   907  		rootNode := dasel.New([]struct {
   908  			Name string
   909  		}{
   910  			{Name: "Tom"},
   911  			{Name: "Jim"},
   912  		})
   913  
   914  		got, err := rootNode.Query(".[0].Name")
   915  		if err != nil {
   916  			t.Errorf("unexpected query error: %v", err)
   917  			return
   918  		}
   919  
   920  		if exp, got := "Tom", got.InterfaceValue().(string); exp != got {
   921  			t.Errorf("expected %s, got %s", exp, got)
   922  		}
   923  	})
   924  	t.Run("ConditionalSelectFromStruct", func(t *testing.T) {
   925  		rootNode := dasel.New([]struct {
   926  			Name string
   927  		}{
   928  			{Name: "Tom"},
   929  			{Name: "Jim"},
   930  		})
   931  
   932  		got, err := rootNode.Query(".(Name=Tom).Name")
   933  		if err != nil {
   934  			t.Errorf("unexpected query error: %v", err)
   935  			return
   936  		}
   937  
   938  		if exp, got := "Tom", got.InterfaceValue().(string); exp != got {
   939  			t.Errorf("expected %s, got %s", exp, got)
   940  		}
   941  	})
   942  }
   943  
   944  func putQueryTest(rootNode *dasel.Node, putSelector string, newValue interface{}, querySelector string) func(t *testing.T) {
   945  	return func(t *testing.T) {
   946  		err := rootNode.Put(putSelector, newValue)
   947  		if err != nil {
   948  			t.Errorf("unexpected put error: %v", err)
   949  			return
   950  		}
   951  
   952  		got, err := rootNode.Query(querySelector)
   953  		if err != nil {
   954  			t.Errorf("unexpected query error: %v", err)
   955  			return
   956  		}
   957  
   958  		if !reflect.DeepEqual(newValue, got.InterfaceValue()) {
   959  			t.Errorf("expected %v, got %v", newValue, got.InterfaceValue())
   960  		}
   961  	}
   962  }
   963  
   964  func deleteTest(rootNode *dasel.Node, deleteSelector string, exp interface{}) func(t *testing.T) {
   965  	return func(t *testing.T) {
   966  		err := rootNode.Delete(deleteSelector)
   967  		if err != nil {
   968  			t.Errorf("unexpected delete error: %v", err)
   969  			return
   970  		}
   971  
   972  		gotVal := rootNode.InterfaceValue()
   973  		if !reflect.DeepEqual(exp, gotVal) && exp != gotVal {
   974  			t.Errorf("expected [%T] %v, got [%T] %v", exp, exp, gotVal, gotVal)
   975  		}
   976  	}
   977  }
   978  
   979  func deleteMultipleTest(rootNode *dasel.Node, deleteSelector string, exp interface{}) func(t *testing.T) {
   980  	return func(t *testing.T) {
   981  		err := rootNode.DeleteMultiple(deleteSelector)
   982  		if err != nil {
   983  			t.Errorf("unexpected delete error: %v", err)
   984  			return
   985  		}
   986  
   987  		if !reflect.DeepEqual(exp, rootNode.InterfaceValue()) {
   988  			t.Errorf("expected %v, got %v", exp, rootNode.InterfaceValue())
   989  		}
   990  	}
   991  }
   992  
   993  func putQueryMultipleTest(rootNode *dasel.Node, putSelector string, newValue interface{}, querySelector string) func(t *testing.T) {
   994  	return func(t *testing.T) {
   995  		err := rootNode.PutMultiple(putSelector, newValue)
   996  		if err != nil {
   997  			t.Errorf("unexpected put error: %v", err)
   998  			return
   999  		}
  1000  
  1001  		got, err := rootNode.QueryMultiple(querySelector)
  1002  		if err != nil {
  1003  			t.Errorf("unexpected query error: %v", err)
  1004  			return
  1005  		}
  1006  
  1007  		for _, n := range got {
  1008  			if !reflect.DeepEqual(newValue, n.InterfaceValue()) {
  1009  				t.Errorf("expected %v, got %v", newValue, n.InterfaceValue())
  1010  			}
  1011  		}
  1012  	}
  1013  }
  1014  
  1015  func TestNode_Put_Query(t *testing.T) {
  1016  	data := map[string]interface{}{
  1017  		"id": "123",
  1018  		"people": []map[string]interface{}{
  1019  			{
  1020  				"id":   1,
  1021  				"name": "Tom",
  1022  			},
  1023  			{
  1024  				"id":   2,
  1025  				"name": "Jim",
  1026  			},
  1027  		},
  1028  		"names": []string{
  1029  			"Tom",
  1030  			"Jim",
  1031  		},
  1032  	}
  1033  	rootNode := dasel.New(data)
  1034  
  1035  	t.Run("InvalidSelector", func(t *testing.T) {
  1036  		err := rootNode.Put("people.[a].name", "Thomas")
  1037  		expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"})
  1038  		if err == nil {
  1039  			t.Errorf("expected err %v, got %v", expErr, err)
  1040  			return
  1041  		}
  1042  		if err.Error() != expErr.Error() {
  1043  			t.Errorf("expected err %v, got %v", expErr, err)
  1044  			return
  1045  		}
  1046  	})
  1047  	t.Run("ExistingSingleString", putQueryTest(rootNode, "id", "456", "id"))
  1048  	t.Run("ExistingStringValue", putQueryTest(rootNode, "people.[0].name", "Thomas", "people.(id=1).name"))
  1049  	t.Run("ExistingIntValue", putQueryTest(rootNode, "people.(id=1).id", 3, "people.(id=3).id"))
  1050  	t.Run("NewPropertyOnExistingObject", putQueryTest(rootNode, "people.(id=3).age", 27, "people.[0].age"))
  1051  	t.Run("AppendObjectToList", func(t *testing.T) {
  1052  		err := rootNode.Put("people.[]", map[string]interface{}{
  1053  			"id":   1,
  1054  			"name": "Bob",
  1055  		})
  1056  		if err != nil {
  1057  			t.Errorf("unexpected put error: %v", err)
  1058  			return
  1059  		}
  1060  
  1061  		got, err := rootNode.Query("people.[2].id")
  1062  		if err != nil {
  1063  			t.Errorf("unexpected query [1] error: %v", err)
  1064  			return
  1065  		}
  1066  		if exp, got := 1, got.InterfaceValue().(int); exp != got {
  1067  			t.Errorf("expected %d, got %d", exp, got)
  1068  		}
  1069  		got, err = rootNode.Query("people.[2].name")
  1070  		if err != nil {
  1071  			t.Errorf("unexpected query [2] error: %v", err)
  1072  			return
  1073  		}
  1074  		if exp, got := "Bob", got.InterfaceValue().(string); exp != got {
  1075  			t.Errorf("expected %s, got %s", exp, got)
  1076  		}
  1077  	})
  1078  	t.Run("AppendStringToList", putQueryTest(rootNode, "names.[]", "Bob", "names.[2]"))
  1079  	t.Run("NilRootNode", putQueryTest(dasel.New(nil), "name", "Thomas", "name"))
  1080  	t.Run("NilChain", putQueryTest(dasel.New(nil), "my.name", "Thomas", "my.name"))
  1081  	t.Run("NilChainToListIndex", putQueryTest(dasel.New(nil), "my.favourite.people.[0]", "Tom", "my.favourite.people.[0]"))
  1082  	t.Run("NilChainToListNextAvailableIndex", putQueryTest(dasel.New(nil), "my.favourite.people.[]", "Tom", "my.favourite.people.[0]"))
  1083  	t.Run("NilChainToDynamic", putQueryTest(dasel.New(nil), "(name=Jim).name", "Tom", "[0].name"))
  1084  }
  1085  
  1086  func TestNode_PutMultiple_Query(t *testing.T) {
  1087  	data := map[string]interface{}{
  1088  		"id": "123",
  1089  		"people": []map[string]interface{}{
  1090  			{
  1091  				"id":   1,
  1092  				"name": "Tom",
  1093  			},
  1094  			{
  1095  				"id":   2,
  1096  				"name": "Jim",
  1097  			},
  1098  		},
  1099  		"names": []string{
  1100  			"Tom",
  1101  			"Jim",
  1102  		},
  1103  	}
  1104  	rootNode := dasel.New(data)
  1105  
  1106  	t.Run("InvalidSelector", func(t *testing.T) {
  1107  		err := rootNode.PutMultiple("people.[a].name", "Thomas")
  1108  		expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"})
  1109  		if err == nil {
  1110  			t.Errorf("expected err %v, got %v", expErr, err)
  1111  			return
  1112  		}
  1113  		if err.Error() != expErr.Error() {
  1114  			t.Errorf("expected err %v, got %v", expErr, err)
  1115  			return
  1116  		}
  1117  	})
  1118  	t.Run("ExistingSingleString", putQueryMultipleTest(rootNode, "id", "456", "id"))
  1119  	t.Run("ExistingStringValue", putQueryMultipleTest(rootNode, "people.[0].name", "Thomas", "people.(id=1).name"))
  1120  	t.Run("ExistingIntValue", putQueryMultipleTest(rootNode, "people.(id=1).id", 3, "people.(id=3).id"))
  1121  	t.Run("NewPropertyOnExistingObject", putQueryMultipleTest(rootNode, "people.(id=3).age", 27, "people.[0].age"))
  1122  	t.Run("AppendObjectToList", func(t *testing.T) {
  1123  		err := rootNode.PutMultiple("people.[]", map[string]interface{}{
  1124  			"id":   1,
  1125  			"name": "Bob",
  1126  		})
  1127  		if err != nil {
  1128  			t.Errorf("unexpected put error: %v", err)
  1129  			return
  1130  		}
  1131  
  1132  		got, err := rootNode.Query("people.[2].id")
  1133  		if err != nil {
  1134  			t.Errorf("unexpected query [1] error: %v", err)
  1135  			return
  1136  		}
  1137  		if exp, got := 1, got.InterfaceValue().(int); exp != got {
  1138  			t.Errorf("expected %d, got %d", exp, got)
  1139  		}
  1140  		got, err = rootNode.Query("people.[2].name")
  1141  		if err != nil {
  1142  			t.Errorf("unexpected query [2] error: %v", err)
  1143  			return
  1144  		}
  1145  		if exp, got := "Bob", got.InterfaceValue().(string); exp != got {
  1146  			t.Errorf("expected %s, got %s", exp, got)
  1147  		}
  1148  	})
  1149  	t.Run("AppendStringToList", putQueryMultipleTest(rootNode, "names.[]", "Bob", "names.[2]"))
  1150  	t.Run("NilRootNode", putQueryMultipleTest(dasel.New(nil), "name", "Thomas", "name"))
  1151  	t.Run("NilChain", putQueryMultipleTest(dasel.New(nil), "my.name", "Thomas", "my.name"))
  1152  	t.Run("NilChainToListIndex", putQueryMultipleTest(dasel.New(nil), "my.favourite.people.[0]", "Tom", "my.favourite.people.[0]"))
  1153  	t.Run("NilChainToListNextAvailableIndex", putQueryMultipleTest(dasel.New(nil), "my.favourite.people.[]", "Tom", "my.favourite.people.[0]"))
  1154  }
  1155  
  1156  func TestNode_Delete(t *testing.T) {
  1157  	data := func() map[string]interface{} {
  1158  		return map[string]interface{}{
  1159  			"id": "123",
  1160  			"names": []string{
  1161  				"Tom",
  1162  				"Jim",
  1163  			},
  1164  			"people": []map[string]interface{}{
  1165  				{
  1166  					"id":   1,
  1167  					"name": "Tom",
  1168  				},
  1169  				{
  1170  					"id":   2,
  1171  					"name": "Jim",
  1172  				},
  1173  			},
  1174  		}
  1175  	}
  1176  
  1177  	t.Run("InvalidSelector", func(t *testing.T) {
  1178  		err := dasel.New(data()).Delete("people.[a].name")
  1179  		expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"})
  1180  		if err == nil {
  1181  			t.Errorf("expected err %v, got %v", expErr, err)
  1182  			return
  1183  		}
  1184  		if err.Error() != expErr.Error() {
  1185  			t.Errorf("expected err %v, got %v", expErr, err)
  1186  			return
  1187  		}
  1188  	})
  1189  	t.Run("ExistingSingleString", deleteTest(dasel.New(data()), "id", map[string]interface{}{
  1190  		"names": []string{
  1191  			"Tom",
  1192  			"Jim",
  1193  		},
  1194  		"people": []map[string]interface{}{
  1195  			{
  1196  				"id":   1,
  1197  				"name": "Tom",
  1198  			},
  1199  			{
  1200  				"id":   2,
  1201  				"name": "Jim",
  1202  			},
  1203  		},
  1204  	}))
  1205  	t.Run("ExistingStringValue", deleteTest(dasel.New(data()), "people.[0].name", map[string]interface{}{
  1206  		"id": "123",
  1207  		"names": []string{
  1208  			"Tom",
  1209  			"Jim",
  1210  		},
  1211  		"people": []map[string]interface{}{
  1212  			{
  1213  				"id": 1,
  1214  			},
  1215  			{
  1216  				"id":   2,
  1217  				"name": "Jim",
  1218  			},
  1219  		},
  1220  	}))
  1221  	t.Run("ExistingStringInStruct", deleteTest(dasel.New(&struct {
  1222  		Name string
  1223  		Age  int
  1224  	}{
  1225  		Name: "Tom",
  1226  		Age:  123,
  1227  	}), ".Name", &struct {
  1228  		Name string
  1229  		Age  int
  1230  	}{
  1231  		Age: 123,
  1232  	}))
  1233  	t.Run("AnyIndexInStruct", deleteMultipleTest(dasel.New(&struct {
  1234  		Name string
  1235  		Age  int
  1236  	}{
  1237  		Name: "Tom",
  1238  		Age:  123,
  1239  	}), ".[*]", &struct {
  1240  		Name string
  1241  		Age  int
  1242  	}{}))
  1243  	t.Run("ExistingObjectInArray", deleteTest(dasel.New(data()), "people.[0]", map[string]interface{}{
  1244  		"id": "123",
  1245  		"names": []string{
  1246  			"Tom",
  1247  			"Jim",
  1248  		},
  1249  		"people": []map[string]interface{}{
  1250  			{
  1251  				"id":   2,
  1252  				"name": "Jim",
  1253  			},
  1254  		},
  1255  	}))
  1256  	t.Run("ExistingIntValue", deleteTest(dasel.New(data()), "people.(id=1).id", map[string]interface{}{
  1257  		"id": "123",
  1258  		"names": []string{
  1259  			"Tom",
  1260  			"Jim",
  1261  		},
  1262  		"people": []map[string]interface{}{
  1263  			{
  1264  				"name": "Tom",
  1265  			},
  1266  			{
  1267  				"id":   2,
  1268  				"name": "Jim",
  1269  			},
  1270  		},
  1271  	}))
  1272  	t.Run("ExistingArray", deleteMultipleTest(dasel.New(data()), "names", map[string]interface{}{
  1273  		"id": "123",
  1274  		"people": []map[string]interface{}{
  1275  			{
  1276  				"id":   1,
  1277  				"name": "Tom",
  1278  			},
  1279  			{
  1280  				"id":   2,
  1281  				"name": "Jim",
  1282  			},
  1283  		},
  1284  	}))
  1285  	t.Run("RootNodeObject", deleteTest(dasel.New(map[string]interface{}{
  1286  		"name": "Tom",
  1287  	}), ".", map[string]interface{}{}))
  1288  	t.Run("RootNodeArray", deleteTest(dasel.New([]interface{}{
  1289  		"name", "Tom",
  1290  	}), ".", []interface{}{}))
  1291  	t.Run("RootNodeUnknown", deleteTest(dasel.New(false), ".", map[string]interface{}{}))
  1292  }
  1293  
  1294  func TestNode_DeleteMultiple_Query(t *testing.T) {
  1295  	data := func() map[string]interface{} {
  1296  		return map[string]interface{}{
  1297  			"id": "123",
  1298  			"names": []string{
  1299  				"Tom",
  1300  				"Jim",
  1301  			},
  1302  			"people": []map[string]interface{}{
  1303  				{
  1304  					"id":   1,
  1305  					"name": "Tom",
  1306  				},
  1307  				{
  1308  					"id":   2,
  1309  					"name": "Jim",
  1310  				},
  1311  			},
  1312  		}
  1313  	}
  1314  
  1315  	t.Run("InvalidSelector", func(t *testing.T) {
  1316  		err := dasel.New(data()).DeleteMultiple("people.[a].name")
  1317  		expErr := fmt.Errorf("failed to parse selector: %w", &dasel.InvalidIndexErr{Index: "a"})
  1318  		if err == nil {
  1319  			t.Errorf("expected err %v, got %v", expErr, err)
  1320  			return
  1321  		}
  1322  		if err.Error() != expErr.Error() {
  1323  			t.Errorf("expected err %v, got %v", expErr, err)
  1324  			return
  1325  		}
  1326  	})
  1327  	t.Run("ExistingSingleString", deleteMultipleTest(dasel.New(data()), "id", map[string]interface{}{
  1328  		"people": []map[string]interface{}{
  1329  			{
  1330  				"id":   1,
  1331  				"name": "Tom",
  1332  			},
  1333  			{
  1334  				"id":   2,
  1335  				"name": "Jim",
  1336  			},
  1337  		},
  1338  		"names": []string{
  1339  			"Tom",
  1340  			"Jim",
  1341  		},
  1342  	}))
  1343  	t.Run("ExistingStringValue", deleteMultipleTest(dasel.New(data()), "people.[0].name", map[string]interface{}{
  1344  		"id": "123",
  1345  		"names": []string{
  1346  			"Tom",
  1347  			"Jim",
  1348  		},
  1349  		"people": []map[string]interface{}{
  1350  			{
  1351  				"id": 1,
  1352  			},
  1353  			{
  1354  				"id":   2,
  1355  				"name": "Jim",
  1356  			},
  1357  		},
  1358  	}))
  1359  	t.Run("WildcardProperty", deleteMultipleTest(dasel.New(data()), "people.[*].name", map[string]interface{}{
  1360  		"id": "123",
  1361  		"names": []string{
  1362  			"Tom",
  1363  			"Jim",
  1364  		},
  1365  		"people": []map[string]interface{}{
  1366  			{
  1367  				"id": 1,
  1368  			},
  1369  			{
  1370  				"id": 2,
  1371  			},
  1372  		},
  1373  	}))
  1374  	t.Run("ExistingIntValue", deleteMultipleTest(dasel.New(data()), "people.(id=1).id", map[string]interface{}{
  1375  		"id": "123",
  1376  		"names": []string{
  1377  			"Tom",
  1378  			"Jim",
  1379  		},
  1380  		"people": []map[string]interface{}{
  1381  			{
  1382  				"name": "Tom",
  1383  			},
  1384  			{
  1385  				"id":   2,
  1386  				"name": "Jim",
  1387  			},
  1388  		},
  1389  	}))
  1390  	t.Run("AllObjectsInArray", deleteMultipleTest(dasel.New(data()), "people.[*]", map[string]interface{}{
  1391  		"id": "123",
  1392  		"names": []string{
  1393  			"Tom",
  1394  			"Jim",
  1395  		},
  1396  		"people": []map[string]interface{}{},
  1397  	}))
  1398  	t.Run("ExistingArray", deleteMultipleTest(dasel.New(data()), "names", map[string]interface{}{
  1399  		"id": "123",
  1400  		"people": []map[string]interface{}{
  1401  			{
  1402  				"id":   1,
  1403  				"name": "Tom",
  1404  			},
  1405  			{
  1406  				"id":   2,
  1407  				"name": "Jim",
  1408  			},
  1409  		},
  1410  	}))
  1411  	t.Run("AllItemsInObject", deleteMultipleTest(dasel.New(data()), ".[*]", map[string]interface{}{}))
  1412  	t.Run("RootNodeObject", deleteMultipleTest(dasel.New(map[string]interface{}{
  1413  		"name": "Tom",
  1414  	}), ".", map[string]interface{}{}))
  1415  	t.Run("RootNodeArray", deleteMultipleTest(dasel.New([]interface{}{
  1416  		"name", "Tom",
  1417  	}), ".", []interface{}{}))
  1418  	t.Run("RootNodeUnknown", deleteMultipleTest(dasel.New(false), ".", map[string]interface{}{}))
  1419  }
  1420  
  1421  // TestNode_NewFromFile tests parsing from file.
  1422  func TestNode_NewFromFile(t *testing.T) {
  1423  	noSuchFileName := "no_such_file"
  1424  	noSuchFileErrMsg := "could not open file: open " + noSuchFileName
  1425  	unmarshalFailMsg := "could not unmarshal data"
  1426  
  1427  	tests := []struct {
  1428  		name   string
  1429  		file   string
  1430  		parser string
  1431  		err    error
  1432  	}{
  1433  		{
  1434  			name:   "Existing JSON file and JSON Read parser specified",
  1435  			file:   "./tests/assets/example.json",
  1436  			parser: "json",
  1437  			err:    nil,
  1438  		},
  1439  		{
  1440  			name:   "Existing JSON file and YAML Read parser specified",
  1441  			file:   "./tests/assets/example.json",
  1442  			parser: "yaml",
  1443  			// JSON is a subset of YAML v1.2
  1444  			// https://stackoverflow.com/questions/21584985/what-valid-json-files-are-not-valid-yaml-1-1-files
  1445  			err: nil,
  1446  		},
  1447  		{
  1448  			name:   "Existing YAML file and YAML Read parser specified",
  1449  			file:   "./tests/assets/example.yaml",
  1450  			parser: "yaml",
  1451  			err:    nil,
  1452  		},
  1453  		{
  1454  			name:   "Existing YAML file and XML Read parser specified",
  1455  			file:   "./tests/assets/example.yaml",
  1456  			parser: "xml",
  1457  			err:    errors.New(unmarshalFailMsg),
  1458  		},
  1459  		{
  1460  			name:   "Existing XML file and XML Read parser specified",
  1461  			file:   "./tests/assets/example.xml",
  1462  			parser: "xml",
  1463  			err:    nil,
  1464  		},
  1465  		{
  1466  			name:   "Existing XML file and JSON Read parser specified",
  1467  			file:   "./tests/assets/example.xml",
  1468  			parser: "json",
  1469  			err:    errors.New(unmarshalFailMsg),
  1470  		},
  1471  		{
  1472  			name:   "Existing JSON file and invalid Read parser specified",
  1473  			file:   "./tests/assets/example.json",
  1474  			parser: "bad",
  1475  			err:    storage.UnknownParserErr{Parser: "bad"},
  1476  		},
  1477  		{
  1478  			name:   "File doesn't exist and JSON Read parser specified",
  1479  			file:   noSuchFileName,
  1480  			parser: "json",
  1481  			err:    errors.New(noSuchFileErrMsg),
  1482  		},
  1483  		{
  1484  			name:   "File doesn't exist and YAML Read parser specified",
  1485  			file:   noSuchFileName,
  1486  			parser: "yaml",
  1487  			err:    errors.New(noSuchFileErrMsg),
  1488  		},
  1489  		{
  1490  			name:   "File doesn't exist and YML Read parser specified",
  1491  			file:   noSuchFileName,
  1492  			parser: "yml",
  1493  			err:    errors.New(noSuchFileErrMsg),
  1494  		},
  1495  		{
  1496  			name:   "File doesn't exist and TOML Read parser specified",
  1497  			file:   noSuchFileName,
  1498  			parser: "toml",
  1499  			err:    errors.New(noSuchFileErrMsg),
  1500  		},
  1501  		{
  1502  			name:   "File doesn't exist and XML Read parser specified",
  1503  			file:   noSuchFileName,
  1504  			parser: "xml",
  1505  			err:    errors.New(noSuchFileErrMsg),
  1506  		},
  1507  		{
  1508  			name:   "File doesn't exist and CSV Read parser specified",
  1509  			file:   noSuchFileName,
  1510  			parser: "csv",
  1511  			err:    errors.New(noSuchFileErrMsg),
  1512  		},
  1513  		{
  1514  			name:   "File doesn't exist and invalid ('bad') Read parser specified",
  1515  			file:   noSuchFileName,
  1516  			parser: "bad",
  1517  			err:    storage.UnknownParserErr{Parser: "bad"},
  1518  		},
  1519  		{
  1520  			name:   "File doesn't exist and invalid ('-') Read parser specified",
  1521  			file:   noSuchFileName,
  1522  			parser: "-",
  1523  			err:    storage.UnknownParserErr{Parser: "-"},
  1524  		},
  1525  	}
  1526  
  1527  	for _, testCase := range tests {
  1528  		tc := testCase
  1529  		t.Run(tc.name, func(t *testing.T) {
  1530  			_, err := dasel.NewFromFile(tc.file, tc.parser)
  1531  
  1532  			if tc.err == nil && err != nil {
  1533  				t.Errorf("expected err %v, got %v", tc.err, err)
  1534  				return
  1535  			}
  1536  			if tc.err != nil && err == nil {
  1537  				t.Errorf("expected err %v, got %v", tc.err, err)
  1538  				return
  1539  			}
  1540  			if tc.err != nil && err != nil && !strings.Contains(err.Error(), tc.err.Error()) {
  1541  				t.Errorf("expected err %v, got %v", tc.err, err)
  1542  				return
  1543  			}
  1544  		})
  1545  	}
  1546  }
  1547  
  1548  // TestNode_Write tests writing to Writer.
  1549  func TestNode_Write(t *testing.T) {
  1550  	type testData = map[string]interface{}
  1551  	type args struct {
  1552  		parser     string
  1553  		compact    bool
  1554  		escapeHTML bool
  1555  	}
  1556  
  1557  	commonData := testData{">": "&"}
  1558  	xmlData := testData{
  1559  		"key": testData{
  1560  			"value": "<&>",
  1561  		},
  1562  	}
  1563  	xmlEscapedData := testData{
  1564  		"key": testData{
  1565  			"value": "&lt;&amp;&gt;",
  1566  		},
  1567  	}
  1568  
  1569  	tests := []struct {
  1570  		name       string
  1571  		data       testData
  1572  		args       args
  1573  		wantWriter string
  1574  		wantErr    bool
  1575  	}{
  1576  		{
  1577  			name: "JSON, compact, no escape",
  1578  			data: commonData,
  1579  			args: args{
  1580  				parser:     "json",
  1581  				compact:    true,
  1582  				escapeHTML: false,
  1583  			},
  1584  			wantWriter: "{\">\":\"&\"}\n",
  1585  			wantErr:    false,
  1586  		},
  1587  		{
  1588  			name: "JSON, pretty, escape",
  1589  			data: commonData,
  1590  			args: args{
  1591  				parser:     "json",
  1592  				compact:    false,
  1593  				escapeHTML: true,
  1594  			},
  1595  			wantWriter: "{\n  \"\\u003e\": \"\\u0026\"\n}\n",
  1596  			wantErr:    false,
  1597  		},
  1598  
  1599  		{
  1600  			name: "YAML, compact, no escape",
  1601  			data: commonData,
  1602  			args: args{
  1603  				parser:     "yaml",
  1604  				compact:    true,
  1605  				escapeHTML: false,
  1606  			},
  1607  			wantWriter: "'>': '&'\n",
  1608  			wantErr:    false,
  1609  		},
  1610  		{
  1611  			name: "YAML, pretty, escape",
  1612  			data: commonData,
  1613  			args: args{
  1614  				parser:     "yaml",
  1615  				compact:    false,
  1616  				escapeHTML: true,
  1617  			},
  1618  			wantWriter: "'>': '&'\n",
  1619  			wantErr:    false,
  1620  		},
  1621  
  1622  		{
  1623  			name: "YML, compact, no escape",
  1624  			data: commonData,
  1625  			args: args{
  1626  				parser:     "yml",
  1627  				compact:    true,
  1628  				escapeHTML: false,
  1629  			},
  1630  			wantWriter: "'>': '&'\n",
  1631  			wantErr:    false,
  1632  		},
  1633  		{
  1634  			name: "YML, pretty, escape",
  1635  			data: commonData,
  1636  			args: args{
  1637  				parser:     "yml",
  1638  				compact:    false,
  1639  				escapeHTML: true,
  1640  			},
  1641  			wantWriter: "'>': '&'\n",
  1642  			wantErr:    false,
  1643  		},
  1644  
  1645  		{
  1646  			name: "TOML, compact, no escape",
  1647  			data: commonData,
  1648  			args: args{
  1649  				parser:     "toml",
  1650  				compact:    true,
  1651  				escapeHTML: false,
  1652  			},
  1653  			wantWriter: "\">\" = \"&\"\n",
  1654  			wantErr:    false,
  1655  		},
  1656  		{
  1657  			name: "TOML, pretty, escape",
  1658  			data: commonData,
  1659  			args: args{
  1660  				parser:     "toml",
  1661  				compact:    false,
  1662  				escapeHTML: true,
  1663  			},
  1664  			wantWriter: "\">\" = \"&\"\n",
  1665  			wantErr:    false,
  1666  		},
  1667  
  1668  		{
  1669  			name: "PLAIN, pretty, escape",
  1670  			data: commonData,
  1671  			args: args{
  1672  				parser:     "plain",
  1673  				compact:    false,
  1674  				escapeHTML: true,
  1675  			},
  1676  			wantWriter: "map[>:&]\n",
  1677  			wantErr:    false,
  1678  		},
  1679  		{
  1680  			name: "PLAIN, pretty, no escape",
  1681  			data: commonData,
  1682  			args: args{
  1683  				parser:     "plain",
  1684  				compact:    false,
  1685  				escapeHTML: false,
  1686  			},
  1687  			wantWriter: "map[>:&]\n",
  1688  			wantErr:    false,
  1689  		},
  1690  
  1691  		{
  1692  			name: "-, pretty, escape",
  1693  			data: commonData,
  1694  			args: args{
  1695  				parser:     "-",
  1696  				compact:    false,
  1697  				escapeHTML: true,
  1698  			},
  1699  			wantWriter: "map[>:&]\n",
  1700  			wantErr:    false,
  1701  		},
  1702  		{
  1703  			name: "-, pretty, no escape",
  1704  			data: commonData,
  1705  			args: args{
  1706  				parser:     "-",
  1707  				compact:    false,
  1708  				escapeHTML: false,
  1709  			},
  1710  			wantWriter: "map[>:&]\n",
  1711  			wantErr:    false,
  1712  		},
  1713  
  1714  		{
  1715  			name: "XML, pretty, no escape",
  1716  			data: xmlData,
  1717  			args: args{
  1718  				parser:     "xml",
  1719  				compact:    false,
  1720  				escapeHTML: false,
  1721  			},
  1722  			// Invalid XML, but since we were asked not to escape,
  1723  			// this is probably the best we should do
  1724  			wantWriter: "<key>\n  <value><&></value>\n</key>\n",
  1725  			wantErr:    false,
  1726  		},
  1727  		{
  1728  			name: "Pre-escaped XML, pretty, no escape",
  1729  			data: xmlEscapedData,
  1730  			args: args{
  1731  				parser:     "xml",
  1732  				compact:    false,
  1733  				escapeHTML: false,
  1734  			},
  1735  			wantWriter: "<key>\n  <value>&lt;&amp;&gt;</value>\n</key>\n",
  1736  			wantErr:    false,
  1737  		},
  1738  
  1739  		{
  1740  			name: "Invalid Write parser: bad",
  1741  			data: commonData,
  1742  			args: args{
  1743  				parser:     "bad",
  1744  				compact:    false,
  1745  				escapeHTML: false,
  1746  			},
  1747  			wantWriter: "",
  1748  			wantErr:    true,
  1749  		},
  1750  	}
  1751  	for _, tt := range tests {
  1752  		t.Run(tt.name, func(t *testing.T) {
  1753  			writer := &bytes.Buffer{}
  1754  			node := dasel.New(tt.data)
  1755  			if err := node.Write(writer, tt.args.parser, []storage.ReadWriteOption{
  1756  				storage.EscapeHTMLOption(tt.args.escapeHTML),
  1757  				storage.PrettyPrintOption(!tt.args.compact),
  1758  			}); (err != nil) != tt.wantErr {
  1759  				t.Errorf("Node.Write() error = %v, wantErr %v", err, tt.wantErr)
  1760  				return
  1761  			}
  1762  			if gotWriter := writer.String(); gotWriter != tt.wantWriter {
  1763  				t.Errorf("Node.Write() = %v want %v", gotWriter, tt.wantWriter)
  1764  			}
  1765  		})
  1766  	}
  1767  }