mirror of
https://github.com/mikefarah/yq.git
synced 2026-08-24 08:22:13 +08:00
readStream opened an *os.File but returned a *bufio.Reader, so the *os.File type switch in streamEvaluator.EvaluateFiles never matched and no input file was ever closed. allAtOnceEvaluator.EvaluateFiles did not attempt to close them at all. Descriptors were only released at process exit or by the os.File finaliser, so a multi-file run could exhaust the file descriptor limit. readStream now returns an explicit cleanup function alongside the reader, which both evaluators call once the file has been processed. Co-authored-by: Pablo Garcia <pablito@MacBook-Neo-de-Pablo.local> Co-authored-by: Mike Farah <mikefarah@gmail.com> Co-authored-by: Cursor <cursoragent@cursor.com>
280 lines
5.5 KiB
Go
280 lines
5.5 KiB
Go
package yqlib
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/mikefarah/yq/v4/test"
|
|
)
|
|
|
|
func createTestFile(content string) string {
|
|
tempFile, err := createTempFile()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
_, err = tempFile.Write([]byte(content))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
safelyCloseFile(tempFile)
|
|
|
|
return tempFile.Name()
|
|
}
|
|
|
|
func readFile(filename string) string {
|
|
bytes, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return string(bytes)
|
|
}
|
|
|
|
func TestFrontMatterSplitWithLeadingSep(t *testing.T) {
|
|
file := createTestFile(`---
|
|
a: apple
|
|
b: banana
|
|
---
|
|
not a
|
|
yaml: doc
|
|
`)
|
|
|
|
expectedYamlFm := `---
|
|
a: apple
|
|
b: banana
|
|
`
|
|
|
|
expectedContent := `---
|
|
not a
|
|
yaml: doc
|
|
`
|
|
|
|
fmHandler := NewFrontMatterHandler(file)
|
|
err := fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
|
|
|
|
test.AssertResult(t, expectedYamlFm, yamlFm)
|
|
|
|
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
test.AssertResult(t, expectedContent, string(contentBytes))
|
|
|
|
tryRemoveTempFile(file)
|
|
fmHandler.CleanUp()
|
|
}
|
|
|
|
func TestFrontMatterSplitWithNoLeadingSep(t *testing.T) {
|
|
file := createTestFile(`a: apple
|
|
b: banana
|
|
---
|
|
not a
|
|
yaml: doc
|
|
`)
|
|
|
|
expectedYamlFm := `a: apple
|
|
b: banana
|
|
`
|
|
|
|
expectedContent := `---
|
|
not a
|
|
yaml: doc
|
|
`
|
|
|
|
fmHandler := NewFrontMatterHandler(file)
|
|
err := fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
|
|
|
|
test.AssertResult(t, expectedYamlFm, yamlFm)
|
|
|
|
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
test.AssertResult(t, expectedContent, string(contentBytes))
|
|
|
|
tryRemoveTempFile(file)
|
|
fmHandler.CleanUp()
|
|
}
|
|
|
|
func TestFrontMatterFilenamePreserved(t *testing.T) {
|
|
// Regression test for https://github.com/mikefarah/yq/issues/2538
|
|
// When using --front-matter, the filename operator should return
|
|
// the original filename, not the path to the temporary file.
|
|
file := createTestFile(`---
|
|
name: john
|
|
---
|
|
Some content
|
|
`)
|
|
originalFilename := "/path/to/original/file.md"
|
|
|
|
fmHandler := NewFrontMatterHandler(file)
|
|
err := fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
tempFilename := fmHandler.GetYamlFrontMatterFilename()
|
|
|
|
// Register the alias (as the command code does)
|
|
SetFilenameAlias(tempFilename, originalFilename)
|
|
defer ClearFilenameAliases()
|
|
|
|
// Verify resolveFilename returns the original name
|
|
resolved := resolveFilename(tempFilename)
|
|
test.AssertResult(t, originalFilename, resolved)
|
|
|
|
// Read documents using the temp file, verify they get the original filename
|
|
reader, cleanup, err := readStream(tempFilename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
defer cleanup()
|
|
decoder := NewYamlDecoder(ConfiguredYamlPreferences)
|
|
docs, err := readDocuments(reader, tempFilename, 0, decoder)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if docs.Len() == 0 {
|
|
t.Fatal("expected at least one document")
|
|
}
|
|
|
|
firstDoc := docs.Front().Value.(*CandidateNode)
|
|
test.AssertResult(t, originalFilename, firstDoc.filename)
|
|
|
|
tryRemoveTempFile(file)
|
|
fmHandler.CleanUp()
|
|
}
|
|
|
|
func TestFrontMatterSplitWithBOM(t *testing.T) {
|
|
// Regression test for https://github.com/mikefarah/yq/issues/2496
|
|
// A UTF-8 BOM before the opening --- must be skipped, otherwise the
|
|
// separator isn't recognised and the opening --- is lost.
|
|
file := createTestFile("\ufeff---\na: apple\nb: banana\n---\nnot a\nyaml: doc\n")
|
|
|
|
expectedYamlFm := `---
|
|
a: apple
|
|
b: banana
|
|
`
|
|
|
|
expectedContent := `---
|
|
not a
|
|
yaml: doc
|
|
`
|
|
|
|
fmHandler := NewFrontMatterHandler(file)
|
|
err := fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
|
|
|
|
test.AssertResult(t, expectedYamlFm, yamlFm)
|
|
|
|
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
test.AssertResult(t, expectedContent, string(contentBytes))
|
|
|
|
tryRemoveTempFile(file)
|
|
fmHandler.CleanUp()
|
|
}
|
|
|
|
func TestFrontMatterSplitWithBOMFromStdin(t *testing.T) {
|
|
// Regression test for https://github.com/mikefarah/yq/issues/2496
|
|
// A UTF-8 BOM must also be skipped when reading front matter from stdin.
|
|
originalStdin := os.Stdin
|
|
defer func() { os.Stdin = originalStdin }()
|
|
|
|
r, w, err := os.Pipe()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
os.Stdin = r
|
|
defer safelyCloseFile(r)
|
|
|
|
go func() {
|
|
_, writeErr := w.WriteString("\ufeff---\na: apple\nb: banana\n---\nnot a\nyaml: doc\n")
|
|
if writeErr != nil {
|
|
t.Errorf("failed to write front matter to the stdin pipe: %v", writeErr)
|
|
}
|
|
safelyCloseFile(w)
|
|
}()
|
|
|
|
expectedYamlFm := `---
|
|
a: apple
|
|
b: banana
|
|
`
|
|
|
|
expectedContent := `---
|
|
not a
|
|
yaml: doc
|
|
`
|
|
|
|
fmHandler := NewFrontMatterHandler("-")
|
|
err = fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
|
|
|
|
test.AssertResult(t, expectedYamlFm, yamlFm)
|
|
|
|
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
test.AssertResult(t, expectedContent, string(contentBytes))
|
|
|
|
fmHandler.CleanUp()
|
|
}
|
|
|
|
func TestFrontMatterSplitWithArray(t *testing.T) {
|
|
file := createTestFile(`[1,2,3]
|
|
---
|
|
not a
|
|
yaml: doc
|
|
`)
|
|
|
|
expectedYamlFm := "[1,2,3]\n"
|
|
|
|
expectedContent := `---
|
|
not a
|
|
yaml: doc
|
|
`
|
|
|
|
fmHandler := NewFrontMatterHandler(file)
|
|
err := fmHandler.Split()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
yamlFm := readFile(fmHandler.GetYamlFrontMatterFilename())
|
|
|
|
test.AssertResult(t, expectedYamlFm, yamlFm)
|
|
|
|
contentBytes, err := io.ReadAll(fmHandler.GetContentReader())
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
test.AssertResult(t, expectedContent, string(contentBytes))
|
|
|
|
tryRemoveTempFile(file)
|
|
fmHandler.CleanUp()
|
|
}
|