2020-11-03 23:48:43 +00:00
|
|
|
package yqlib
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
2020-11-06 03:37:01 +00:00
|
|
|
"container/list"
|
2020-11-03 23:48:43 +00:00
|
|
|
"fmt"
|
2020-11-13 09:58:01 +00:00
|
|
|
"io"
|
2020-11-03 23:48:43 +00:00
|
|
|
"os"
|
2020-11-06 01:11:38 +00:00
|
|
|
"strings"
|
2020-11-03 23:48:43 +00:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/mikefarah/yq/v4/test"
|
2020-12-01 03:06:49 +00:00
|
|
|
yaml "gopkg.in/yaml.v3"
|
2020-11-03 23:48:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type expressionScenario struct {
|
2020-11-14 23:50:30 +00:00
|
|
|
description string
|
2020-11-17 23:32:30 +00:00
|
|
|
subdescription string
|
2020-11-14 23:50:30 +00:00
|
|
|
document string
|
|
|
|
expression string
|
|
|
|
expected []string
|
|
|
|
skipDoc bool
|
|
|
|
dontFormatInputForDoc bool // dont format input doc for documentation generation
|
2020-11-03 23:48:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func testScenario(t *testing.T, s *expressionScenario) {
|
2020-11-06 03:37:01 +00:00
|
|
|
var results *list.List
|
|
|
|
var err error
|
2020-11-13 02:19:54 +00:00
|
|
|
|
|
|
|
node, err := treeCreator.ParsePath(s.expression)
|
|
|
|
if err != nil {
|
2020-11-22 02:50:32 +00:00
|
|
|
t.Error(fmt.Errorf("Error parsing expression %v of %v: %v", s.expression, s.description, err))
|
2020-11-13 02:19:54 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
inputs := list.New()
|
|
|
|
|
2020-11-06 03:37:01 +00:00
|
|
|
if s.document != "" {
|
2020-11-20 11:57:32 +00:00
|
|
|
inputs, err = readDocuments(strings.NewReader(s.document), "sample.yml", 0)
|
2020-11-13 02:19:54 +00:00
|
|
|
if err != nil {
|
2020-12-26 10:37:08 +00:00
|
|
|
t.Error(err, s.document, s.expression)
|
2020-11-13 02:19:54 +00:00
|
|
|
return
|
|
|
|
}
|
2020-12-01 03:06:49 +00:00
|
|
|
} else {
|
|
|
|
candidateNode := &CandidateNode{
|
|
|
|
Document: 0,
|
|
|
|
Filename: "",
|
|
|
|
Node: &yaml.Node{Tag: "!!null"},
|
|
|
|
FileIndex: 0,
|
|
|
|
}
|
|
|
|
inputs.PushBack(candidateNode)
|
|
|
|
|
2020-11-03 23:48:43 +00:00
|
|
|
}
|
|
|
|
|
2020-11-13 02:19:54 +00:00
|
|
|
results, err = treeNavigator.GetMatchingNodes(inputs, node)
|
|
|
|
|
2020-11-06 03:37:01 +00:00
|
|
|
if err != nil {
|
2020-12-26 10:37:08 +00:00
|
|
|
t.Error(fmt.Errorf("%v: %v", err, s.expression))
|
2020-11-03 23:48:43 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
test.AssertResultComplexWithContext(t, s.expected, resultsToString(results), fmt.Sprintf("exp: %v\ndoc: %v", s.expression, s.document))
|
|
|
|
}
|
|
|
|
|
2020-11-16 01:09:57 +00:00
|
|
|
func resultsToString(results *list.List) []string {
|
|
|
|
var pretty []string = make([]string, 0)
|
|
|
|
for el := results.Front(); el != nil; el = el.Next() {
|
|
|
|
n := el.Value.(*CandidateNode)
|
|
|
|
pretty = append(pretty, NodeToString(n))
|
|
|
|
}
|
|
|
|
return pretty
|
|
|
|
}
|
|
|
|
|
2020-11-13 03:07:11 +00:00
|
|
|
func writeOrPanic(w *bufio.Writer, text string) {
|
|
|
|
_, err := w.WriteString(text)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-13 10:22:05 +00:00
|
|
|
func copyFromHeader(title string, out *os.File) error {
|
2020-11-13 09:58:01 +00:00
|
|
|
source := fmt.Sprintf("doc/headers/%v.md", title)
|
|
|
|
_, err := os.Stat(source)
|
|
|
|
if os.IsNotExist(err) {
|
2020-11-13 10:22:05 +00:00
|
|
|
return nil
|
2020-11-13 09:58:01 +00:00
|
|
|
}
|
|
|
|
in, err := os.Open(source) // nolint gosec
|
|
|
|
if err != nil {
|
2020-11-13 10:22:05 +00:00
|
|
|
return err
|
2020-11-13 09:58:01 +00:00
|
|
|
}
|
|
|
|
defer safelyCloseFile(in)
|
|
|
|
_, err = io.Copy(out, in)
|
2020-11-13 10:22:05 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
func formatYaml(yaml string) string {
|
|
|
|
var output bytes.Buffer
|
|
|
|
printer := NewPrinter(bufio.NewWriter(&output), false, true, false, 2, true)
|
|
|
|
|
|
|
|
node, err := treeCreator.ParsePath(".. style= \"\"")
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2020-11-22 00:56:28 +00:00
|
|
|
streamEvaluator := NewStreamEvaluator()
|
|
|
|
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(yaml), node, printer)
|
2020-11-13 10:22:05 +00:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return output.String()
|
2020-11-13 09:58:01 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 23:48:43 +00:00
|
|
|
func documentScenarios(t *testing.T, title string, scenarios []expressionScenario) {
|
|
|
|
f, err := os.Create(fmt.Sprintf("doc/%v.md", title))
|
|
|
|
|
|
|
|
if err != nil {
|
2020-11-13 02:19:54 +00:00
|
|
|
t.Error(err)
|
2020-11-13 09:58:01 +00:00
|
|
|
return
|
2020-11-03 23:48:43 +00:00
|
|
|
}
|
|
|
|
defer f.Close()
|
2020-11-13 09:58:01 +00:00
|
|
|
|
2020-11-13 10:22:05 +00:00
|
|
|
err = copyFromHeader(title, f)
|
2020-11-13 09:58:01 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-11-03 23:48:43 +00:00
|
|
|
w := bufio.NewWriter(f)
|
2020-11-22 02:16:54 +00:00
|
|
|
writeOrPanic(w, "\n")
|
2020-11-13 09:58:01 +00:00
|
|
|
|
2020-11-22 02:16:54 +00:00
|
|
|
for _, s := range scenarios {
|
2020-11-06 00:45:18 +00:00
|
|
|
if !s.skipDoc {
|
2020-11-03 23:48:43 +00:00
|
|
|
|
2020-11-22 02:16:54 +00:00
|
|
|
writeOrPanic(w, fmt.Sprintf("## %v\n", s.description))
|
|
|
|
|
2020-11-17 23:32:30 +00:00
|
|
|
if s.subdescription != "" {
|
|
|
|
writeOrPanic(w, s.subdescription)
|
|
|
|
writeOrPanic(w, "\n\n")
|
|
|
|
}
|
2020-11-14 23:50:30 +00:00
|
|
|
formattedDoc := ""
|
2020-11-06 00:45:18 +00:00
|
|
|
if s.document != "" {
|
2020-11-14 23:50:30 +00:00
|
|
|
if s.dontFormatInputForDoc {
|
2020-11-22 02:16:54 +00:00
|
|
|
formattedDoc = s.document + "\n"
|
2020-11-14 23:50:30 +00:00
|
|
|
} else {
|
|
|
|
formattedDoc = formatYaml(s.document)
|
|
|
|
}
|
2020-11-13 09:58:01 +00:00
|
|
|
//TODO: pretty here
|
|
|
|
writeOrPanic(w, "Given a sample.yml file of:\n")
|
2020-11-13 10:22:05 +00:00
|
|
|
|
2020-11-14 23:50:30 +00:00
|
|
|
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n", formattedDoc))
|
2020-11-13 09:58:01 +00:00
|
|
|
writeOrPanic(w, "then\n")
|
2020-11-13 10:22:05 +00:00
|
|
|
if s.expression != "" {
|
|
|
|
writeOrPanic(w, fmt.Sprintf("```bash\nyq eval '%v' sample.yml\n```\n", s.expression))
|
|
|
|
} else {
|
|
|
|
writeOrPanic(w, "```bash\nyq eval sample.yml\n```\n")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
writeOrPanic(w, "Running\n")
|
|
|
|
writeOrPanic(w, fmt.Sprintf("```bash\nyq eval --null-input '%v'\n```\n", s.expression))
|
2020-11-06 00:45:18 +00:00
|
|
|
}
|
2020-11-03 23:48:43 +00:00
|
|
|
|
2020-11-13 09:58:01 +00:00
|
|
|
writeOrPanic(w, "will output\n")
|
2020-11-06 00:45:18 +00:00
|
|
|
|
|
|
|
var output bytes.Buffer
|
2020-11-06 03:37:01 +00:00
|
|
|
var err error
|
2020-11-13 02:19:54 +00:00
|
|
|
printer := NewPrinter(bufio.NewWriter(&output), false, true, false, 2, true)
|
2020-12-01 03:06:49 +00:00
|
|
|
streamEvaluator := NewStreamEvaluator()
|
2020-11-13 02:19:54 +00:00
|
|
|
|
2020-11-06 03:37:01 +00:00
|
|
|
if s.document != "" {
|
2020-11-13 02:19:54 +00:00
|
|
|
node, err := treeCreator.ParsePath(s.expression)
|
|
|
|
if err != nil {
|
2020-12-26 10:37:08 +00:00
|
|
|
t.Error(err, s.expression)
|
2020-11-13 02:19:54 +00:00
|
|
|
}
|
2020-11-22 00:56:28 +00:00
|
|
|
err = streamEvaluator.Evaluate("sample.yaml", strings.NewReader(formattedDoc), node, printer)
|
2020-12-01 03:06:49 +00:00
|
|
|
|
2020-11-13 03:07:11 +00:00
|
|
|
if err != nil {
|
2020-12-26 10:37:08 +00:00
|
|
|
t.Error(err, s.expression)
|
2020-11-13 03:07:11 +00:00
|
|
|
}
|
2020-11-06 03:37:01 +00:00
|
|
|
} else {
|
2020-12-01 03:06:49 +00:00
|
|
|
err = streamEvaluator.EvaluateNew(s.expression, printer)
|
2020-11-13 03:07:11 +00:00
|
|
|
if err != nil {
|
2020-12-26 10:37:08 +00:00
|
|
|
t.Error(err, s.expression)
|
2020-11-13 03:07:11 +00:00
|
|
|
}
|
2020-11-06 03:37:01 +00:00
|
|
|
}
|
|
|
|
|
2020-11-13 10:22:05 +00:00
|
|
|
writeOrPanic(w, fmt.Sprintf("```yaml\n%v```\n\n", output.String()))
|
2020-11-03 23:48:43 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
w.Flush()
|
|
|
|
}
|