mirror of
				https://github.com/taigrr/yq
				synced 2025-01-18 04:53:17 -08:00 
			
		
		
		
	more tests, some refactoring
This commit is contained in:
		
							parent
							
								
									38d35185bc
								
							
						
					
					
						commit
						52eef67e37
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -23,6 +23,7 @@ _cgo_export.* | |||||||
| 
 | 
 | ||||||
| _testmain.go | _testmain.go | ||||||
| coverage.out | coverage.out | ||||||
|  | coverage.html | ||||||
| *.exe | *.exe | ||||||
| *.test | *.test | ||||||
| *.prof | *.prof | ||||||
|  | |||||||
| @ -6,7 +6,7 @@ | |||||||
| # New Features | # New Features | ||||||
|   - Keeps comments and formatting (e.g. inline arrays)! |   - Keeps comments and formatting (e.g. inline arrays)! | ||||||
|   - Handles anchors! |   - Handles anchors! | ||||||
|   - Can specify yaml tags (e.g. !!int) |   - Can specify yaml tags (e.g. !!int), quoting values no longer sufficient, need to specify the tag value instead. | ||||||
| 
 | 
 | ||||||
| # Update scripts file format has changed | # Update scripts file format has changed | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,397 +1 @@ | |||||||
| package yqlib | package yqlib | ||||||
| 
 |  | ||||||
| // import ( |  | ||||||
| // 	"fmt" |  | ||||||
| // 	"sort" |  | ||||||
| // 	"testing" |  | ||||||
| 
 |  | ||||||
| // 	"github.com/mikefarah/yq/v2/test" |  | ||||||
| // 	logging "gopkg.in/op/go-logging.v1" |  | ||||||
| // ) |  | ||||||
| 
 |  | ||||||
| // func TestDataNavigator(t *testing.T) { |  | ||||||
| // 	var log = logging.MustGetLogger("yq") |  | ||||||
| // 	subject := NewDataNavigator(log) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_simple", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"b", "c"}) |  | ||||||
| // 		test.AssertResult(t, 2, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_numberKey", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // 200: things |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"200"}) |  | ||||||
| // 		test.AssertResult(t, "things", got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_splat", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // mapSplat: |  | ||||||
| //   item1: things |  | ||||||
| //   item2: whatever |  | ||||||
| //   otherThing: cat |  | ||||||
| // `) |  | ||||||
| // 		res, _ := subject.ReadChildValue(data, []string{"mapSplat", "*"}) |  | ||||||
| // 		test.AssertResult(t, "[things whatever cat]", fmt.Sprintf("%v", res)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_prefixSplat", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // mapSplat: |  | ||||||
| //   item1: things |  | ||||||
| //   item2: whatever |  | ||||||
| //   otherThing: cat |  | ||||||
| // `) |  | ||||||
| // 		res, _ := subject.ReadChildValue(data, []string{"mapSplat", "item*"}) |  | ||||||
| // 		test.AssertResult(t, "[things whatever]", fmt.Sprintf("%v", res)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_deep_splat", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // mapSplatDeep: |  | ||||||
| //   item1: |  | ||||||
| //     cats: bananas |  | ||||||
| //   item2: |  | ||||||
| //     cats: apples |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		res, _ := subject.ReadChildValue(data, []string{"mapSplatDeep", "*", "cats"}) |  | ||||||
| // 		result := res.([]interface{}) |  | ||||||
| // 		var actual = []string{result[0].(string), result[1].(string)} |  | ||||||
| // 		sort.Strings(actual) |  | ||||||
| // 		test.AssertResult(t, "[apples bananas]", fmt.Sprintf("%v", actual)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_key_doesnt_exist", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"b", "x", "f", "c"}) |  | ||||||
| // 		test.AssertResult(t, nil, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_recurse_against_string", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // a: cat |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"a", "b"}) |  | ||||||
| // 		test.AssertResult(t, nil, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_array", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     - 3 |  | ||||||
| //     - 4 |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"b", "d", "1"}) |  | ||||||
| // 		test.AssertResult(t, 4, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_array_and_bad_index", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     - 3 |  | ||||||
| //     - 4 |  | ||||||
| // `) |  | ||||||
| // 		_, err := subject.ReadChildValue(data, []string{"b", "d", "x"}) |  | ||||||
| // 		if err == nil { |  | ||||||
| // 			t.Fatal("Expected error due to invalid path") |  | ||||||
| // 		} |  | ||||||
| // 		expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax` |  | ||||||
| // 		test.AssertResult(t, expectedOutput, err.Error()) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_mapsplat_array_and_bad_index", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     e: |  | ||||||
| //       - 3 |  | ||||||
| //       - 4 |  | ||||||
| //     f: |  | ||||||
| //       - 1 |  | ||||||
| //       - 2 |  | ||||||
| // `) |  | ||||||
| // 		_, err := subject.ReadChildValue(data, []string{"b", "d", "*", "x"}) |  | ||||||
| // 		if err == nil { |  | ||||||
| // 			t.Fatal("Expected error due to invalid path") |  | ||||||
| // 		} |  | ||||||
| // 		expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax` |  | ||||||
| // 		test.AssertResult(t, expectedOutput, err.Error()) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_arraysplat_map_array_and_bad_index", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     - names: |  | ||||||
| //         - fred |  | ||||||
| //         - smith |  | ||||||
| //     - names: |  | ||||||
| //         - sam |  | ||||||
| //         - bo |  | ||||||
| // `) |  | ||||||
| // 		_, err := subject.ReadChildValue(data, []string{"b", "d", "*", "names", "x"}) |  | ||||||
| // 		if err == nil { |  | ||||||
| // 			t.Fatal("Expected error due to invalid path") |  | ||||||
| // 		} |  | ||||||
| // 		expectedOutput := `error accessing array: strconv.ParseInt: parsing "x": invalid syntax` |  | ||||||
| // 		test.AssertResult(t, expectedOutput, err.Error()) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_array_out_of_bounds", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     - 3 |  | ||||||
| //     - 4 |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"b", "d", "3"}) |  | ||||||
| // 		test.AssertResult(t, nil, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_array_out_of_bounds_by_1", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // --- |  | ||||||
| // b: |  | ||||||
| //   d: |  | ||||||
| //     - 3 |  | ||||||
| //     - 4 |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"b", "d", "2"}) |  | ||||||
| // 		test.AssertResult(t, nil, got) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestReadMap_with_array_splat", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // e: |  | ||||||
| //   - |  | ||||||
| //     name: Fred |  | ||||||
| //     thing: cat |  | ||||||
| //   - |  | ||||||
| //     name: Sam |  | ||||||
| //     thing: dog |  | ||||||
| // `) |  | ||||||
| // 		got, _ := subject.ReadChildValue(data, []string{"e", "*", "name"}) |  | ||||||
| // 		test.AssertResult(t, "[Fred Sam]", fmt.Sprintf("%v", got)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_really_simple", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b 4}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_simple", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "c"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b [{c 4}]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_new", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "d"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b [{c 2} {d 4}]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_new_deep", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "d", "f"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b [{c 2} {d [{f 4}]}]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_array", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   - aa |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "0"}, "bb") |  | ||||||
| 
 |  | ||||||
| // 		test.AssertResult(t, "[{b [bb]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_new_array", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "0"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b [{c 2} {0 4}]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_new_array_deep", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: apple |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "+", "c"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{a apple} {b [[{c 4}]]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_new_map_array_deep", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "d", "+"}, "4") |  | ||||||
| // 		test.AssertResult(t, "[{b [{c 2} {d [4]}]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_add_to_array", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   - aa |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b", "1"}, "bb") |  | ||||||
| // 		test.AssertResult(t, "[{b [aa bb]}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWrite_with_no_tail", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| //   c: 2 |  | ||||||
| // `) |  | ||||||
| // 		updated := subject.UpdatedChildValue(data, []string{"b"}, "4") |  | ||||||
| 
 |  | ||||||
| // 		test.AssertResult(t, "[{b 4}]", fmt.Sprintf("%v", updated)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWriteMap_no_paths", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: 5 |  | ||||||
| // `) |  | ||||||
| // 		var new = test.ParseData(` |  | ||||||
| // c: 4 |  | ||||||
| // `) |  | ||||||
| // 		result := subject.UpdatedChildValue(data, []string{}, new) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", new), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestWriteArray_no_paths", func(t *testing.T) { |  | ||||||
| // 		var data = make([]interface{}, 1) |  | ||||||
| // 		data[0] = "mike" |  | ||||||
| // 		var new = test.ParseData(` |  | ||||||
| // c: 4 |  | ||||||
| // `) |  | ||||||
| // 		result := subject.UpdatedChildValue(data, []string{}, new) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", new), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_MapItem", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: 123 |  | ||||||
| // b: 456 |  | ||||||
| // `) |  | ||||||
| // 		var expected = test.ParseData(` |  | ||||||
| // b: 456 |  | ||||||
| // `) |  | ||||||
| 
 |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"a"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	// Ensure deleting an index into a string does nothing |  | ||||||
| // 	t.Run("TestDelete_index_to_string", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: mystring |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"a", "0"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_list_index", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: [3, 4] |  | ||||||
| // `) |  | ||||||
| // 		var expected = test.ParseData(` |  | ||||||
| // a: [3] |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"a", "1"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_list_index_beyond_bounds", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: [3, 4] |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"a", "5"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_list_index_out_of_bounds_by_1", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: [3, 4] |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"a", "2"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_no_paths", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // a: [3, 4] |  | ||||||
| // b: |  | ||||||
| //   - name: test |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", data), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| 
 |  | ||||||
| // 	t.Run("TestDelete_array_map_item", func(t *testing.T) { |  | ||||||
| // 		var data = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| // - name: fred |  | ||||||
| //   value: blah |  | ||||||
| // - name: john |  | ||||||
| //   value: test |  | ||||||
| // `) |  | ||||||
| // 		var expected = test.ParseData(` |  | ||||||
| // b: |  | ||||||
| // - value: blah |  | ||||||
| // - name: john |  | ||||||
| //   value: test |  | ||||||
| // `) |  | ||||||
| // 		result, _ := subject.DeleteChildValue(data, []string{"b", "0", "name"}) |  | ||||||
| // 		test.AssertResult(t, fmt.Sprintf("%v", expected), fmt.Sprintf("%v", result)) |  | ||||||
| // 	}) |  | ||||||
| // } |  | ||||||
|  | |||||||
| @ -96,7 +96,7 @@ type lib struct { | |||||||
| 	parser    PathParser | 	parser    PathParser | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewYqLib(l *logging.Logger) YqLib { | func NewYqLib() YqLib { | ||||||
| 	return &lib{ | 	return &lib{ | ||||||
| 		parser: NewPathParser(), | 		parser: NewPathParser(), | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -1,166 +1,162 @@ | |||||||
| package yqlib | package yqlib | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" |  | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 |  | ||||||
| 	"github.com/mikefarah/yq/v3/test" |  | ||||||
| 	logging "gopkg.in/op/go-logging.v1" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestLib(t *testing.T) { | func TestLib(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| 	var log = logging.MustGetLogger("yq") | 	// var log = logging.MustGetLogger("yq") | ||||||
| 	subject := NewYqLib(log) | 	// subject := NewYqLib(log) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestReadPath", func(t *testing.T) { | 	// 	t.Run("TestReadPath", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   2: c | 	//   2: c | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		got, _ := subject.ReadPath(data, "b.2") | 	// 		got, _ := subject.ReadPath(data, "b.2") | ||||||
| 		test.AssertResult(t, `c`, got) | 	// 		test.AssertResult(t, `c`, got) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestReadPath_WithError", func(t *testing.T) { | 	// 	t.Run("TestReadPath_WithError", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   - c | 	//   - c | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		_, err := subject.ReadPath(data, "b.[a]") | 	// 		_, err := subject.ReadPath(data, "b.[a]") | ||||||
| 		if err == nil { | 	// 		if err == nil { | ||||||
| 			t.Fatal("Expected error due to invalid path") | 	// 			t.Fatal("Expected error due to invalid path") | ||||||
| 		} | 	// 		} | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestWritePath", func(t *testing.T) { | 	// 	t.Run("TestWritePath", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   2: c | 	//   2: c | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		got := subject.WritePath(data, "b.3", "a") | 	// 		got := subject.WritePath(data, "b.3", "a") | ||||||
| 		test.AssertResult(t, `[{b [{2 c} {3 a}]}]`, fmt.Sprintf("%v", got)) | 	// 		test.AssertResult(t, `[{b [{2 c} {3 a}]}]`, fmt.Sprintf("%v", got)) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestPrefixPath", func(t *testing.T) { | 	// 	t.Run("TestPrefixPath", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   2: c | 	//   2: c | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		got := subject.PrefixPath(data, "a.d") | 	// 		got := subject.PrefixPath(data, "a.d") | ||||||
| 		test.AssertResult(t, `[{a [{d [{b [{2 c}]}]}]}]`, fmt.Sprintf("%v", got)) | 	// 		test.AssertResult(t, `[{a [{d [{b [{2 c}]}]}]}]`, fmt.Sprintf("%v", got)) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestDeletePath", func(t *testing.T) { | 	// 	t.Run("TestDeletePath", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   2: c | 	//   2: c | ||||||
|   3: a | 	//   3: a | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		got, _ := subject.DeletePath(data, "b.2") | 	// 		got, _ := subject.DeletePath(data, "b.2") | ||||||
| 		test.AssertResult(t, `[{b [{3 a}]}]`, fmt.Sprintf("%v", got)) | 	// 		test.AssertResult(t, `[{b [{3 a}]}]`, fmt.Sprintf("%v", got)) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestDeletePath_WithError", func(t *testing.T) { | 	// 	t.Run("TestDeletePath_WithError", func(t *testing.T) { | ||||||
| 		var data = test.ParseData(` | 	// 		var data = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| b: | 	// b: | ||||||
|   - c | 	//   - c | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		_, err := subject.DeletePath(data, "b.[a]") | 	// 		_, err := subject.DeletePath(data, "b.[a]") | ||||||
| 		if err == nil { | 	// 		if err == nil { | ||||||
| 			t.Fatal("Expected error due to invalid path") | 	// 			t.Fatal("Expected error due to invalid path") | ||||||
| 		} | 	// 		} | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestMerge", func(t *testing.T) { | 	// 	t.Run("TestMerge", func(t *testing.T) { | ||||||
| 		var dst = test.ParseData(` | 	// 		var dst = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: b | 	// a: b | ||||||
| c: d | 	// c: d | ||||||
| `) | 	// `) | ||||||
| 		var src = test.ParseData(` | 	// 		var src = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: 1 | 	// a: 1 | ||||||
| b: 2 | 	// b: 2 | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		var mergedData = make(map[interface{}]interface{}) | 	// 		var mergedData = make(map[interface{}]interface{}) | ||||||
| 		mergedData["root"] = dst | 	// 		mergedData["root"] = dst | ||||||
| 		var mapDataBucket = make(map[interface{}]interface{}) | 	// 		var mapDataBucket = make(map[interface{}]interface{}) | ||||||
| 		mapDataBucket["root"] = src | 	// 		mapDataBucket["root"] = src | ||||||
| 
 | 
 | ||||||
| 		err := subject.Merge(&mergedData, mapDataBucket, false, false) | 	// 		err := subject.Merge(&mergedData, mapDataBucket, false, false) | ||||||
| 		if err != nil { | 	// 		if err != nil { | ||||||
| 			t.Fatal("Unexpected error") | 	// 			t.Fatal("Unexpected error") | ||||||
| 		} | 	// 		} | ||||||
| 		test.AssertResult(t, `[{a b} {c d}]`, fmt.Sprintf("%v", mergedData["root"])) | 	// 		test.AssertResult(t, `[{a b} {c d}]`, fmt.Sprintf("%v", mergedData["root"])) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestMerge_WithOverwrite", func(t *testing.T) { | 	// 	t.Run("TestMerge_WithOverwrite", func(t *testing.T) { | ||||||
| 		var dst = test.ParseData(` | 	// 		var dst = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: b | 	// a: b | ||||||
| c: d | 	// c: d | ||||||
| `) | 	// `) | ||||||
| 		var src = test.ParseData(` | 	// 		var src = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: 1 | 	// a: 1 | ||||||
| b: 2 | 	// b: 2 | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		var mergedData = make(map[interface{}]interface{}) | 	// 		var mergedData = make(map[interface{}]interface{}) | ||||||
| 		mergedData["root"] = dst | 	// 		mergedData["root"] = dst | ||||||
| 		var mapDataBucket = make(map[interface{}]interface{}) | 	// 		var mapDataBucket = make(map[interface{}]interface{}) | ||||||
| 		mapDataBucket["root"] = src | 	// 		mapDataBucket["root"] = src | ||||||
| 
 | 
 | ||||||
| 		err := subject.Merge(&mergedData, mapDataBucket, true, false) | 	// 		err := subject.Merge(&mergedData, mapDataBucket, true, false) | ||||||
| 		if err != nil { | 	// 		if err != nil { | ||||||
| 			t.Fatal("Unexpected error") | 	// 			t.Fatal("Unexpected error") | ||||||
| 		} | 	// 		} | ||||||
| 		test.AssertResult(t, `[{a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"])) | 	// 		test.AssertResult(t, `[{a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"])) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestMerge_WithAppend", func(t *testing.T) { | 	// 	t.Run("TestMerge_WithAppend", func(t *testing.T) { | ||||||
| 		var dst = test.ParseData(` | 	// 		var dst = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: b | 	// a: b | ||||||
| c: d | 	// c: d | ||||||
| `) | 	// `) | ||||||
| 		var src = test.ParseData(` | 	// 		var src = test.ParseData(` | ||||||
| --- | 	// --- | ||||||
| a: 1 | 	// a: 1 | ||||||
| b: 2 | 	// b: 2 | ||||||
| `) | 	// `) | ||||||
| 
 | 
 | ||||||
| 		var mergedData = make(map[interface{}]interface{}) | 	// 		var mergedData = make(map[interface{}]interface{}) | ||||||
| 		mergedData["root"] = dst | 	// 		mergedData["root"] = dst | ||||||
| 		var mapDataBucket = make(map[interface{}]interface{}) | 	// 		var mapDataBucket = make(map[interface{}]interface{}) | ||||||
| 		mapDataBucket["root"] = src | 	// 		mapDataBucket["root"] = src | ||||||
| 
 | 
 | ||||||
| 		err := subject.Merge(&mergedData, mapDataBucket, false, true) | 	// 		err := subject.Merge(&mergedData, mapDataBucket, false, true) | ||||||
| 		if err != nil { | 	// 		if err != nil { | ||||||
| 			t.Fatal("Unexpected error") | 	// 			t.Fatal("Unexpected error") | ||||||
| 		} | 	// 		} | ||||||
| 		test.AssertResult(t, `[{a b} {c d} {a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"])) | 	// 		test.AssertResult(t, `[{a b} {c d} {a 1} {b 2}]`, fmt.Sprintf("%v", mergedData["root"])) | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| 	t.Run("TestMerge_WithError", func(t *testing.T) { | 	// 	t.Run("TestMerge_WithError", func(t *testing.T) { | ||||||
| 		err := subject.Merge(nil, nil, false, false) | 	// 		err := subject.Merge(nil, nil, false, false) | ||||||
| 		if err == nil { | 	// 		if err == nil { | ||||||
| 			t.Fatal("Expected error due to nil") | 	// 			t.Fatal("Expected error due to nil") | ||||||
| 		} | 	// 		} | ||||||
| 	}) | 	// 	}) | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,11 +6,15 @@ import ( | |||||||
| 	"github.com/mikefarah/yq/v3/test" | 	"github.com/mikefarah/yq/v3/test" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  | var parser = NewPathParser() | ||||||
|  | 
 | ||||||
| var parsePathsTests = []struct { | var parsePathsTests = []struct { | ||||||
| 	path          string | 	path          string | ||||||
| 	expectedPaths []string | 	expectedPaths []string | ||||||
| }{ | }{ | ||||||
| 	{"a.b", []string{"a", "b"}}, | 	{"a.b", []string{"a", "b"}}, | ||||||
|  | 	{"a.b.**", []string{"a", "b", "**"}}, | ||||||
|  | 	{"a.b.*", []string{"a", "b", "*"}}, | ||||||
| 	{"a.b[0]", []string{"a", "b", "0"}}, | 	{"a.b[0]", []string{"a", "b", "0"}}, | ||||||
| 	{"a.b.d[+]", []string{"a", "b", "d", "+"}}, | 	{"a.b.d[+]", []string{"a", "b", "d", "+"}}, | ||||||
| 	{"a", []string{"a"}}, | 	{"a", []string{"a"}}, | ||||||
| @ -22,8 +26,53 @@ var parsePathsTests = []struct { | |||||||
| 	{"[0]", []string{"0"}}, | 	{"[0]", []string{"0"}}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestParsePath(t *testing.T) { | func TestPathParserParsePath(t *testing.T) { | ||||||
| 	for _, tt := range parsePathsTests { | 	for _, tt := range parsePathsTests { | ||||||
| 		test.AssertResultComplex(t, tt.expectedPaths, NewPathParser().ParsePath(tt.path)) | 		test.AssertResultComplex(t, tt.expectedPaths, parser.ParsePath(tt.path)) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementSplat(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "*"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementDeepSplat(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "**"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementAppendArrayValid(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "+"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "3")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementAppendArrayInvalid(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "+"} | ||||||
|  | 	test.AssertResult(t, false, parser.MatchesNextPathElement(node, "cat")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementPrefixMatchesWhole(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "cat*"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "cat")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementPrefixMatchesStart(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "cat*"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "caterpillar")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementPrefixMismatch(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "cat*"} | ||||||
|  | 	test.AssertResult(t, false, parser.MatchesNextPathElement(node, "dog")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementExactMatch(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "farahtek"} | ||||||
|  | 	test.AssertResult(t, true, parser.MatchesNextPathElement(node, "farahtek")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPathParserMatchesNextPathElementExactMismatch(t *testing.T) { | ||||||
|  | 	var node = NodeContext{Head: "farahtek"} | ||||||
|  | 	test.AssertResult(t, false, parser.MatchesNextPathElement(node, "othertek")) | ||||||
|  | } | ||||||
|  | |||||||
| @ -3,7 +3,6 @@ package yqlib | |||||||
| import ( | import ( | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 
 | 
 | ||||||
| 	logging "gopkg.in/op/go-logging.v1" |  | ||||||
| 	yaml "gopkg.in/yaml.v3" | 	yaml "gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -12,20 +11,17 @@ type ValueParser interface { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type valueParser struct { | type valueParser struct { | ||||||
| 	log *logging.Logger |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func NewValueParser(l *logging.Logger) ValueParser { | func NewValueParser() ValueParser { | ||||||
| 	return &valueParser{log: l} | 	return &valueParser{} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (v *valueParser) Parse(argument string, customTag string) *yaml.Node { | func (v *valueParser) Parse(argument string, customTag string) *yaml.Node { | ||||||
| 	var err interface{} | 	var err interface{} | ||||||
| 	var tag = customTag | 	var tag = customTag | ||||||
| 
 | 
 | ||||||
| 	var inQuotes = len(argument) > 0 && argument[0] == '"' | 	if tag == "" { | ||||||
| 	if tag == "" && !inQuotes { |  | ||||||
| 
 |  | ||||||
| 		_, err = strconv.ParseBool(argument) | 		_, err = strconv.ParseBool(argument) | ||||||
| 		if err == nil { | 		if err == nil { | ||||||
| 			tag = "!!bool" | 			tag = "!!bool" | ||||||
| @ -46,6 +42,6 @@ func (v *valueParser) Parse(argument string, customTag string) *yaml.Node { | |||||||
| 			return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode} | 			return &yaml.Node{Tag: "!!seq", Kind: yaml.SequenceNode} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	v.log.Debugf("parsed value '%v', tag: '%v'", argument, tag) | 	log.Debugf("parsed value '%v', tag: '%v'", argument, tag) | ||||||
| 	return &yaml.Node{Value: argument, Tag: tag, Kind: yaml.ScalarNode} | 	return &yaml.Node{Value: argument, Tag: tag, Kind: yaml.ScalarNode} | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,22 +4,35 @@ import ( | |||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"github.com/mikefarah/yq/v3/test" | 	"github.com/mikefarah/yq/v3/test" | ||||||
|  | 	yaml "gopkg.in/yaml.v3" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var parseValueTests = []struct { | var parseValueTests = []struct { | ||||||
| 	argument        string | 	argument        string | ||||||
| 	expectedResult  interface{} | 	customTag       string | ||||||
|  | 	expectedTag     string | ||||||
| 	testDescription string | 	testDescription string | ||||||
| }{ | }{ | ||||||
| 	{"true", true, "boolean"}, | 	{"true", "", "!!bool", "boolean"}, | ||||||
| 	{"\"true\"", "true", "boolean as string"}, | 	{"true", "!!string", "!!string", "boolean forced as string"}, | ||||||
| 	{"3.4", 3.4, "number"}, | 	{"3.4", "", "!!float", "float"}, | ||||||
| 	{"\"3.4\"", "3.4", "number as string"}, | 	{"1212121", "", "!!int", "big number"}, | ||||||
| 	{"", "", "empty string"}, | 	{"1212121.1", "", "!!float", "big float number"}, | ||||||
|  | 	{"3", "", "!!int", "int"}, | ||||||
|  | 	{"null", "", "!!null", "null"}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestParseValue(t *testing.T) { | func TestValueParserParse(t *testing.T) { | ||||||
| 	for _, tt := range parseValueTests { | 	for _, tt := range parseValueTests { | ||||||
| 		test.AssertResultWithContext(t, tt.expectedResult, NewValueParser().ParseValue(tt.argument), tt.testDescription) | 		actual := NewValueParser().Parse(tt.argument, tt.customTag) | ||||||
|  | 		test.AssertResultWithContext(t, tt.argument, actual.Value, tt.testDescription) | ||||||
|  | 		test.AssertResultWithContext(t, tt.expectedTag, actual.Tag, tt.testDescription) | ||||||
|  | 		test.AssertResult(t, yaml.ScalarNode, actual.Kind) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestValueParserParseEmptyArray(t *testing.T) { | ||||||
|  | 	actual := NewValueParser().Parse("[]", "") | ||||||
|  | 	test.AssertResult(t, "!!seq", actual.Tag) | ||||||
|  | 	test.AssertResult(t, yaml.SequenceNode, actual.Kind) | ||||||
|  | } | ||||||
|  | |||||||
| @ -2,5 +2,5 @@ | |||||||
| 
 | 
 | ||||||
| set -e | set -e | ||||||
| 
 | 
 | ||||||
| go test -coverprofile=coverage.out ./... | go test -coverprofile=coverage.out -v $(go list ./... | grep -v -E 'examples' | grep -v -E 'test') | ||||||
| go tool cover -html=coverage.out -o cover/coverage.html | go tool cover -html=coverage.out -o coverage.html | ||||||
|  | |||||||
| @ -1,3 +1,3 @@ | |||||||
| #!/bin/bash | #!/bin/bash | ||||||
| 
 | 
 | ||||||
| go test -v $(go list ./... | grep -v -E 'examples') | go test -v $(go list ./... | grep -v -E 'examples' | grep -v -E 'test') | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								yq.go
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								yq.go
									
									
									
									
									
								
							| @ -30,8 +30,8 @@ var verbose = false | |||||||
| var version = false | var version = false | ||||||
| var docIndex = "0" | var docIndex = "0" | ||||||
| var log = logging.MustGetLogger("yq") | var log = logging.MustGetLogger("yq") | ||||||
| var lib = yqlib.NewYqLib(log) | var lib = yqlib.NewYqLib() | ||||||
| var valueParser = yqlib.NewValueParser(log) | var valueParser = yqlib.NewValueParser() | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	cmd := newCommandCLI() | 	cmd := newCommandCLI() | ||||||
| @ -210,6 +210,7 @@ Note that you can give a create script to perform more sophisticated yaml. This | |||||||
| 		RunE: newProperty, | 		RunE: newProperty, | ||||||
| 	} | 	} | ||||||
| 	cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml") | 	cmdNew.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml") | ||||||
|  | 	cmdNew.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)") | ||||||
| 	return cmdNew | 	return cmdNew | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user