mirror of
https://github.com/mikefarah/yq.git
synced 2024-12-19 20:19:04 +00:00
13d1bbb45f
Remove dependency on yaml.Node for internal AST representation. Yaml decoder is now just another decoder.
298 lines
7.2 KiB
Go
298 lines
7.2 KiB
Go
package yqlib
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/mikefarah/yq/v4/test"
|
|
)
|
|
|
|
var sampleTable = `
|
|
var = "x"
|
|
|
|
[owner.contact]
|
|
name = "Tom Preston-Werner"
|
|
age = 36
|
|
`
|
|
|
|
var sampleTableExpected = `var: x
|
|
owner:
|
|
contact:
|
|
name: Tom Preston-Werner
|
|
age: 36
|
|
`
|
|
|
|
var sampleArrayTable = `
|
|
[owner.contact]
|
|
name = "Tom Preston-Werner"
|
|
age = 36
|
|
|
|
[[owner.addresses]]
|
|
street = "first street"
|
|
suburb = "ok"
|
|
|
|
[[owner.addresses]]
|
|
street = "second street"
|
|
suburb = "nice"
|
|
`
|
|
|
|
var sampleArrayTableExpected = `owner:
|
|
contact:
|
|
name: Tom Preston-Werner
|
|
age: 36
|
|
addresses:
|
|
- street: first street
|
|
suburb: ok
|
|
- street: second street
|
|
suburb: nice
|
|
`
|
|
|
|
var sampleWithHeader = `
|
|
[servers]
|
|
|
|
[servers.alpha]
|
|
ip = "10.0.0.1"
|
|
`
|
|
|
|
var expectedSampleWithHeader = `servers:
|
|
alpha:
|
|
ip: 10.0.0.1
|
|
`
|
|
|
|
var tomlScenarios = []formatScenario{
|
|
{
|
|
skipDoc: true,
|
|
description: "blank",
|
|
input: "",
|
|
expected: "",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "datetime",
|
|
input: "A = 1979-05-27T07:32:00-08:00",
|
|
expected: "A: 1979-05-27T07:32:00-08:00\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "blank",
|
|
input: `A = "hello`,
|
|
expectedError: `bad file 'sample.yml': basic string not terminated by "`,
|
|
scenarioType: "decode-error",
|
|
},
|
|
{
|
|
description: "Parse: Simple",
|
|
input: "A = \"hello\"\nB = 12\n",
|
|
expected: "A: hello\nB: 12\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
description: "Parse: Deep paths",
|
|
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
|
|
expected: "person:\n name: hello\n address: 12 cat st\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "Parse: include key information",
|
|
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
|
|
expression: ".person.name | key",
|
|
expected: "name\n",
|
|
scenarioType: "roundtrip",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "Parse: include parent information",
|
|
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
|
|
expression: ".person.name | parent",
|
|
expected: "name: hello\naddress: 12 cat st\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "Parse: include path information",
|
|
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
|
|
expression: ".person.name | path",
|
|
expected: "- person\n- name\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
description: "Encode: Scalar",
|
|
input: "person.name = \"hello\"\nperson.address = \"12 cat st\"\n",
|
|
expression: ".person.name",
|
|
expected: "hello\n",
|
|
scenarioType: "roundtrip",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
input: `A.B = "hello"`,
|
|
expected: "A:\n B: hello\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "bool",
|
|
input: `A = true`,
|
|
expected: "A: true\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "bool false",
|
|
input: `A = false `,
|
|
expected: "A: false\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "number",
|
|
input: `A = 3 `,
|
|
expected: "A: 3\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "number",
|
|
input: `A = 0xDEADBEEF`,
|
|
expression: " .A += 1",
|
|
expected: "A: 0xDEADBEF0\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "float",
|
|
input: `A = 6.626e-34`,
|
|
expected: "A: 6.626e-34\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "empty arraY",
|
|
input: `A = []`,
|
|
expected: "A: []\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
description: "array",
|
|
input: `A = ["hello", ["world", "again"]]`,
|
|
expected: "A:\n - hello\n - - world\n - again\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
description: "Parse: inline table",
|
|
input: `name = { first = "Tom", last = "Preston-Werner" }`,
|
|
expected: "name:\n first: Tom\n last: Preston-Werner\n",
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
skipDoc: true,
|
|
input: sampleTable,
|
|
expected: sampleTableExpected,
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
description: "Parse: Array Table",
|
|
input: sampleArrayTable,
|
|
expected: sampleArrayTableExpected,
|
|
scenarioType: "decode",
|
|
},
|
|
{
|
|
description: "Parse: with header",
|
|
skipDoc: true,
|
|
input: sampleWithHeader,
|
|
expected: expectedSampleWithHeader,
|
|
scenarioType: "decode",
|
|
},
|
|
}
|
|
|
|
func testTomlScenario(t *testing.T, s formatScenario) {
|
|
switch s.scenarioType {
|
|
case "", "decode":
|
|
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewTomlDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences)), s.description)
|
|
case "decode-error":
|
|
result, err := processFormatScenario(s, NewTomlDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences))
|
|
if err == nil {
|
|
t.Errorf("Expected error '%v' but it worked: %v", s.expectedError, result)
|
|
} else {
|
|
test.AssertResultComplexWithContext(t, s.expectedError, err.Error(), s.description)
|
|
}
|
|
case "roundtrip":
|
|
test.AssertResultWithContext(t, s.expected, mustProcessFormatScenario(s, NewTomlDecoder(), NewTomlEncoder()), s.description)
|
|
}
|
|
}
|
|
|
|
func documentTomlDecodeScenario(w *bufio.Writer, s formatScenario) {
|
|
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
|
|
|
|
if s.subdescription != "" {
|
|
writeOrPanic(w, s.subdescription)
|
|
writeOrPanic(w, "\n\n")
|
|
}
|
|
|
|
writeOrPanic(w, "Given a sample.toml file of:\n")
|
|
writeOrPanic(w, fmt.Sprintf("```toml\n%v\n```\n", s.input))
|
|
|
|
writeOrPanic(w, "then\n")
|
|
expression := s.expression
|
|
if expression == "" {
|
|
expression = "."
|
|
}
|
|
writeOrPanic(w, fmt.Sprintf("```bash\nyq -oy '%v' sample.toml\n```\n", expression))
|
|
writeOrPanic(w, "will output\n")
|
|
|
|
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewTomlDecoder(), NewYamlEncoder(2, false, ConfiguredYamlPreferences))))
|
|
}
|
|
|
|
func documentTomlRoundtripScenario(w *bufio.Writer, s formatScenario) {
|
|
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
|
|
|
|
if s.subdescription != "" {
|
|
writeOrPanic(w, s.subdescription)
|
|
writeOrPanic(w, "\n\n")
|
|
}
|
|
|
|
writeOrPanic(w, "Given a sample.toml file of:\n")
|
|
writeOrPanic(w, fmt.Sprintf("```toml\n%v\n```\n", s.input))
|
|
|
|
writeOrPanic(w, "then\n")
|
|
expression := s.expression
|
|
if expression == "" {
|
|
expression = "."
|
|
}
|
|
writeOrPanic(w, fmt.Sprintf("```bash\nyq '%v' sample.toml\n```\n", expression))
|
|
writeOrPanic(w, "will output\n")
|
|
|
|
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", mustProcessFormatScenario(s, NewTomlDecoder(), NewTomlEncoder())))
|
|
}
|
|
|
|
func documentTomlScenario(t *testing.T, w *bufio.Writer, i interface{}) {
|
|
s := i.(formatScenario)
|
|
|
|
if s.skipDoc {
|
|
return
|
|
}
|
|
switch s.scenarioType {
|
|
case "", "decode":
|
|
documentTomlDecodeScenario(w, s)
|
|
case "roundtrip":
|
|
documentTomlRoundtripScenario(w, s)
|
|
|
|
default:
|
|
panic(fmt.Sprintf("unhandled scenario type %q", s.scenarioType))
|
|
}
|
|
}
|
|
|
|
func TestTomlScenarios(t *testing.T) {
|
|
for _, tt := range tomlScenarios {
|
|
testTomlScenario(t, tt)
|
|
}
|
|
genericScenarios := make([]interface{}, len(tomlScenarios))
|
|
for i, s := range tomlScenarios {
|
|
genericScenarios[i] = s
|
|
}
|
|
documentScenarios(t, "usage", "toml", genericScenarios, documentTomlScenario)
|
|
}
|