Skip to content
Snippets Groups Projects
Commit 7aea95e4 authored by Ken Brooks's avatar Ken Brooks
Browse files

merged changes from upstream master

parents e17a5ddd 4ab3c311
No related branches found
No related tags found
No related merge requests found
......@@ -6,6 +6,7 @@ import (
"bufio"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
......@@ -20,7 +21,7 @@ import (
)
var (
version = "undefined"
version = "v1.3.0-dev"
schemaFlag = flag.String("s", "", "primary JSON schema to validate against, required")
quietFlag = flag.Bool("q", false, "quiet, only print validation failures and errors")
versionFlag = flag.Bool("v", false, "print version and exit")
......@@ -37,13 +38,13 @@ func init() {
func main() {
log.SetFlags(0)
os.Exit(realMain(os.Args[1:]))
os.Exit(realMain(os.Args[1:], os.Stdout))
}
func realMain(args []string) int {
func realMain(args []string, w io.Writer) int {
flag.CommandLine.Parse(args)
if *versionFlag {
fmt.Println(version)
fmt.Fprintln(w, version)
return 0
}
if *schemaFlag == "" {
......@@ -70,7 +71,6 @@ func realMain(args []string) int {
if !filepath.IsAbs(pattern) {
pattern = filepath.Join(dir, pattern)
}
docs = append(docs, glob(pattern)...)
}
if err := scanner.Err(); err != nil {
......@@ -89,9 +89,9 @@ func realMain(args []string) int {
}
for _, ref := range refFlags {
for _, p := range glob(ref) {
absPath, absPathErr := filepath.Abs(p)
if absPathErr != nil {
log.Fatalf("%s: unable to convert to absolute path: %s\n", absPath, absPathErr)
absPath, err := filepath.Abs(p)
if err != nil {
log.Fatalf("%s: unable to convert to absolute path: %s\n", absPath, err)
}
if absPath == schemaPath {
......@@ -125,17 +125,17 @@ func realMain(args []string) int {
failures := make([]string, 0)
errors := make([]string, 0)
for _, p := range docs {
//fmt.Println(p)
wg.Add(1)
go func(path string) {
defer wg.Done()
sem <- 0
defer func() { <-sem }()
loader, err := jsonLoader(path)
if err != nil {
msg := fmt.Sprintf("%s: error: load doc %s\n", path, err)
fmt.Println(msg)
msg := fmt.Sprintf("%s: error: load doc: %s", path, err)
fmt.Fprintln(w, msg)
errors = append(errors, msg)
return
}
......@@ -143,7 +143,7 @@ func realMain(args []string) int {
switch {
case err != nil:
msg := fmt.Sprintf("%s: error: validate: %s", path, err)
fmt.Println(msg)
fmt.Fprintln(w, msg)
errors = append(errors, msg)
case !result.Valid():
......@@ -152,11 +152,11 @@ func realMain(args []string) int {
lines[i] = fmt.Sprintf("%s: fail: %s", path, desc)
}
msg := strings.Join(lines, "\n")
fmt.Println(msg)
fmt.Fprintln(w, msg)
failures = append(failures, msg)
case !*quietFlag:
fmt.Printf("%s: pass\n", path)
fmt.Fprintf(w, "%s: pass\n", path)
}
}(p)
}
......@@ -165,12 +165,12 @@ func realMain(args []string) int {
// Summarize results (e.g. errors)
if !*quietFlag {
if len(failures) > 0 {
fmt.Printf("%d of %d failed validation\n", len(failures), len(docs))
fmt.Println(strings.Join(failures, "\n"))
fmt.Fprintf(w, "%d of %d failed validation\n", len(failures), len(docs))
fmt.Fprintln(w, strings.Join(failures, "\n"))
}
if len(errors) > 0 {
fmt.Printf("%d of %d malformed documents\n", len(errors), len(docs))
fmt.Println(strings.Join(errors, "\n"))
fmt.Fprintf(w, "%d of %d malformed documents\n", len(errors), len(docs))
fmt.Fprintln(w, strings.Join(errors, "\n"))
}
}
exit := 0
......@@ -234,18 +234,14 @@ func glob(pattern string) []string {
if err != nil {
log.Fatal(err)
}
universalPaths := make([]string, 0)
paths, err := filepath.Glob(pattern)
for _, mypath := range paths {
universalPaths = append(universalPaths, filepath.ToSlash(mypath))
}
if err != nil {
log.Fatal(err)
}
if len(universalPaths) == 0 {
if len(paths) == 0 {
log.Fatalf("%s: no such file or directory", pattern)
}
return universalPaths
return paths
}
type stringFlags []string
......
// +build windows !windows
package main
import (
"log"
"path/filepath"
"sort"
"strings"
"testing"
)
func ExampleMain_pass_ymlschema_ymldoc() {
exit := realMain([]string{"-s", "testdata/schema.yml", "testdata/data-pass.yml"})
if exit != 0 {
log.Fatalf("exit: got %d, want 0", exit)
}
// Output:
// testdata/data-pass.yml: pass
}
func ExampleMain_pass_jsonschema_ymldoc() {
exit := realMain([]string{"-s", "testdata/schema.json", "testdata/data-pass.yml"})
if exit != 0 {
log.Fatalf("exit: got %d, want 0", exit)
}
// Output:
// testdata/data-pass.yml: pass
}
func ExampleMain_pass_jsonschema_jsondoc() {
exit := realMain([]string{"-s", "testdata/schema.json", "testdata/data-pass.json"})
if exit != 0 {
log.Fatalf("exit: got %d, want 0", exit)
}
// Output:
// testdata/data-pass.json: pass
}
func ExampleMain_pass_ymlschema_jsondoc() {
exit := realMain([]string{"-s", "testdata/schema.yml", "testdata/data-pass.json"})
if exit != 0 {
log.Fatalf("exit: got %d, want 0", exit)
}
// Output:
// testdata/data-pass.json: pass
}
func ExampleMain_fail_ymlschema_ymldoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.yml", "testdata/data-fail.yml"})
if exit != 1 {
log.Fatalf("exit: got %d, want 1", exit)
}
// Output:
// testdata/data-fail.yml: fail: (root): foo is required
}
func ExampleMain_fail_jsonschema_ymldoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.json", "testdata/data-fail.yml"})
if exit != 1 {
log.Fatalf("exit: got %d, want 1", exit)
}
// Output:
// testdata/data-fail.yml: fail: (root): foo is required
}
func ExampleMain_fail_jsonschema_jsondoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.json", "testdata/data-fail.json"})
if exit != 1 {
log.Fatalf("exit: got %d, want 1", exit)
}
// Output:
// testdata/data-fail.json: fail: (root): foo is required
}
func ExampleMain_fail_ymlschema_jsondoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.yml", "testdata/data-fail.json"})
if exit != 1 {
log.Fatalf("exit: got %d, want 1", exit)
}
// Output:
// testdata/data-fail.json: fail: (root): foo is required
func TestMain(t *testing.T) {
tests := []struct {
in string
out []string
exit int
} {
{
"-s testdata/schema.yml testdata/data-pass.yml",
[]string{"testdata/data-pass.yml: pass"},
0,
}, {
"-s testdata/schema.json testdata/data-pass.yml",
[]string{"testdata/data-pass.yml: pass"},
0,
}, {
"-s testdata/schema.json testdata/data-pass.json",
[]string{"testdata/data-pass.json: pass"},
0,
}, {
"-s testdata/schema.yml testdata/data-pass.json",
[]string{"testdata/data-pass.json: pass"},
0,
}, {
"-q -s testdata/schema.yml testdata/data-fail.yml",
[]string{"testdata/data-fail.yml: fail: (root): foo is required"},
1,
}, {
"-q -s testdata/schema.json testdata/data-fail.yml",
[]string{"testdata/data-fail.yml: fail: (root): foo is required"},
1,
}, {
"-q -s testdata/schema.json testdata/data-fail.json",
[]string{"testdata/data-fail.json: fail: (root): foo is required"},
1,
}, {
"-q -s testdata/schema.yml testdata/data-fail.json",
[]string{"testdata/data-fail.json: fail: (root): foo is required"},
1,
}, {
"-q -s testdata/schema.json testdata/data-error.json",
[]string{"testdata/data-error.json: error: validate: invalid character 'o' in literal null (expecting 'u')"},
2,
}, {
"-q -s testdata/schema.yml testdata/data-error.yml",
[]string{"testdata/data-error.yml: error: load doc: yaml: found unexpected end of stream"},
2,
}, {
"-q -s testdata/schema.json testdata/data-*.json",
[]string{
"testdata/data-fail.json: fail: (root): foo is required",
"testdata/data-error.json: error: validate: invalid character 'o' in literal null (expecting 'u')",
}, 3,
}, {
"-q -s testdata/schema.yml testdata/data-*.yml",
[]string{
"testdata/data-error.yml: error: load doc: yaml: found unexpected end of stream",
"testdata/data-fail.yml: fail: (root): foo is required",
}, 3,
},
}
func ExampleMain_error_jsonschema_jsondoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.json", "testdata/data-error.json"})
if exit != 2 {
log.Fatalf("exit: got %d, want 2", exit)
}
// Output:
// testdata/data-error.json: error: validate: invalid character 'o' in literal null (expecting 'u')
}
for _, tt := range tests {
in := strings.ReplaceAll(tt.in, "/", string(filepath.Separator))
sort.Strings(tt.out)
out := strings.Join(tt.out, "\n")
out = strings.ReplaceAll(out, "/", string(filepath.Separator))
func ExampleMain_error_ymlschema_ymldoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.yml", "testdata/data-error.yml"})
if exit != 2 {
log.Fatalf("exit: got %d, want 2", exit)
t.Run(in, func(t *testing.T) {
var w strings.Builder
exit := realMain(strings.Split(in, " "), &w)
if exit != tt.exit {
t.Fatalf("exit: got %d, want %d", exit, tt.exit)
}
// Output:
// testdata/data-error.yml: error: load doc yaml: found unexpected end of stream
lines := strings.Split(w.String(), "\n")
sort.Strings(lines)
got := strings.Join(lines[1:], "\n")
if got != out {
t.Errorf("got\n%s\nwant\n%s", got, out)
}
func ExampleMain_glob_jsonschema_jsondoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.json", "testdata/data-*.json"})
if exit != 3 {
log.Fatalf("exit: got %d, want 3", exit)
})
}
// Unordered output:
// testdata/data-error.json: error: validate: invalid character 'o' in literal null (expecting 'u')
// testdata/data-fail.json: fail: (root): foo is required
}
func ExampleMain_glob_ymlschema_ymldoc() {
exit := realMain([]string{"-q", "-s", "testdata/schema.yml", "testdata/data-*.yml"})
if exit != 3 {
log.Fatalf("exit: got %d, want 3", exit)
}
// Unordered output:
// testdata/data-fail.yml: fail: (root): foo is required
//
// testdata/data-error.yml: error: load doc yaml: found unexpected end of stream
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment