more tests, some refactoring

This commit is contained in:
Mike Farah 2020-01-09 08:17:56 +11:00
parent 38d35185bc
commit 52eef67e37
11 changed files with 215 additions and 555 deletions

1
.gitignore vendored
View File

@ -23,6 +23,7 @@ _cgo_export.*
_testmain.go _testmain.go
coverage.out coverage.out
coverage.html
*.exe *.exe
*.test *.test
*.prof *.prof

View File

@ -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

View File

@ -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))
// })
// }

View File

@ -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(),
} }

View File

@ -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")
} // }
}) // })
} }

View File

@ -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"))
}

View File

@ -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}
} }

View File

@ -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)
}

View File

@ -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

View File

@ -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
View File

@ -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
} }