check command

This commit is contained in:
Arpad Ryszka 2018-01-08 17:28:08 +01:00
parent 6178b0c7a1
commit f45e6bab4b
9 changed files with 835 additions and 638 deletions

54
cmd/treerack/check.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"flag"
"io"
)
type checkOptions struct {
syntaxOptions
}
func flagSetCheck(o *checkOptions, output io.Writer) *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Usage = func() {}
fs.SetOutput(output)
fs.StringVar(&o.syntax, "syntax-string", "", syntaxStringUsage)
fs.StringVar(&o.syntaxFile, "syntax", "", syntaxFileUsage)
return fs
}
func flagErrorCheck(fs *flag.FlagSet) {
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func helpCheck() {
stdout(checkUsage)
stdout()
stdout("Options:")
fs := flagSetCheck(&checkOptions{}, wout)
fs.PrintDefaults()
stdout()
stdout(checkExample)
stdout()
stdout(docRef)
}
func check(args []string) int {
if len(args) > 0 && args[0] == "-help" {
helpCheck()
return 0
}
var options checkOptions
fs := flagSetCheck(&options, werr)
if err := fs.Parse(args); err != nil {
flagErrorCheck(fs)
return -1
}
_, code := open(options.syntaxOptions, fs)
return code
}

103
cmd/treerack/check_test.go Normal file
View File

@ -0,0 +1,103 @@
package main
import "testing"
func TestCheck(t *testing.T) {
runMainTest(t,
mainTest{
title: "help",
args: []string{
"treerack", "check", "-help",
},
stdout: []string{
checkUsage,
"-syntax",
"-syntax-string",
checkExample,
docRef,
},
},
mainTest{
title: "invalid flag",
args: []string{
"treerack", "check", "-foo",
},
exit: -1,
stderr: []string{
"-syntax",
"-syntax-string",
},
},
mainTest{
title: "multiple inputs",
args: []string{
"treerack", "check", "-syntax", "foo.treerack", "-syntax-string", `foo = "bar"`,
},
exit: -1,
stderr: []string{
"only one",
"-syntax",
"-syntax-string",
},
},
mainTest{
title: "no input",
args: []string{
"treerack", "check",
},
exit: -1,
stderr: []string{
"missing syntax input",
"-syntax",
"-syntax-string",
},
},
mainTest{
title: "invalid input",
args: []string{
"treerack", "check", "-syntax-string", "foo",
},
exit: -1,
stderr: []string{
"parse failed",
},
},
mainTest{
title: "file open fails",
args: []string{
"treerack", "check", "-syntax", "noexist.treerack",
},
exit: -1,
stderr: []string{
"file",
},
},
mainTest{
title: "syntax as stdin",
args: []string{
"treerack", "check",
},
stdin: `foo = "bar"`,
},
mainTest{
title: "syntax as file",
args: []string{
"treerack", "generate", "-syntax", "foo_test.treerack",
},
},
mainTest{
title: "syntax as string",
args: []string{
"treerack", "generate", "-syntax-string", `foo = "bar"`,
},
},
)
}

View File

@ -23,3 +23,8 @@ const generateUsage = `treerack generate takes a syntax description from the sta
const generateExample = `Example: const generateExample = `Example:
treerack generate -syntax syntax.treerack > parser.go` treerack generate -syntax syntax.treerack > parser.go`
const checkUsage = `treerack check takes a syntax description from the standard input, or a file, or inline string, and validates it to check whether it represents a valid syntax. It returns with non-zero exit code and prints the problem if the syntax is not valid.`
const checkExample = `Example:
treerack check -syntax syntax.treerack`

View File

@ -1,24 +1,19 @@
package main package main
import ( import (
"bytes"
"flag" "flag"
"io" "io"
"os"
"github.com/aryszka/treerack" "github.com/aryszka/treerack"
"golang.org/x/crypto/ssh/terminal"
) )
type generateOptions struct { type generateOptions struct {
syntax string syntaxOptions
syntaxFile string
packageName string packageName string
export bool export bool
} }
func flagSet(o *generateOptions, output io.Writer) *flag.FlagSet { func flagSetGenerate(o *generateOptions, output io.Writer) *flag.FlagSet {
fs := flag.NewFlagSet("", flag.ContinueOnError) fs := flag.NewFlagSet("", flag.ContinueOnError)
fs.Usage = func() {} fs.Usage = func() {}
fs.SetOutput(output) fs.SetOutput(output)
@ -29,11 +24,17 @@ func flagSet(o *generateOptions, output io.Writer) *flag.FlagSet {
return fs return fs
} }
func flagErrorGenerate(fs *flag.FlagSet) {
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func helpGenerate() { func helpGenerate() {
stdout(generateUsage) stdout(generateUsage)
stdout() stdout()
stdout("Options:") stdout("Options:")
fs := flagSet(&generateOptions{}, wout) fs := flagSetGenerate(&generateOptions{}, wout)
fs.PrintDefaults() fs.PrintDefaults()
stdout() stdout()
stdout(generateExample) stdout(generateExample)
@ -41,26 +42,6 @@ func helpGenerate() {
stdout(docRef) stdout(docRef)
} }
func flagError(fs *flag.FlagSet) {
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func multipleInputsError(fs *flag.FlagSet) {
stderr("only one of syntax file or syntax string is allowed")
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func noInputError(fs *flag.FlagSet) {
stderr("missing syntax input")
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func generate(args []string) int { func generate(args []string) int {
if len(args) > 0 && args[0] == "-help" { if len(args) > 0 && args[0] == "-help" {
helpGenerate() helpGenerate()
@ -68,47 +49,15 @@ func generate(args []string) int {
} }
var options generateOptions var options generateOptions
fs := flagSet(&options, werr) fs := flagSetGenerate(&options, werr)
if err := fs.Parse(args); err != nil { if err := fs.Parse(args); err != nil {
flagError(fs) flagErrorGenerate(fs)
return -1 return -1
} }
if options.syntaxFile != "" && options.syntax != "" { s, code := open(options.syntaxOptions, fs)
multipleInputsError(fs) if code != 0 {
return -1 return code
}
var hasInput bool
if options.syntaxFile == "" && options.syntax == "" {
hasInput = isTest && rin != nil || !isTest && !terminal.IsTerminal(0)
}
if !hasInput && options.syntaxFile == "" && options.syntax == "" {
noInputError(fs)
return -1
}
var input io.Reader
if hasInput {
input = rin
} else if options.syntaxFile != "" {
f, err := os.Open(options.syntaxFile)
if err != nil {
stderr(err)
return -1
}
defer f.Close()
input = f
} else if options.syntax != "" {
input = bytes.NewBufferString(options.syntax)
}
s := &treerack.Syntax{}
if err := s.ReadSyntax(input); err != nil {
stderr(err)
return -1
} }
var goptions treerack.GeneratorOptions var goptions treerack.GeneratorOptions

View File

@ -22,6 +22,9 @@ func main() {
} }
switch os.Args[1] { switch os.Args[1] {
case "check":
code := check(os.Args[2:])
exit(code)
case "generate": case "generate":
code := generate(os.Args[2:]) code := generate(os.Args[2:])
exit(code) exit(code)

View File

@ -123,20 +123,30 @@ func (mt mainTest) run(t *testing.T) {
} }
if stdout != nil { if stdout != nil {
var failed bool
for i := range mt.stdout { for i := range mt.stdout {
if !strings.Contains(stdout.String(), mt.stdout[i]) { if !strings.Contains(stdout.String(), mt.stdout[i]) {
t.Error("invalid output") t.Error("invalid output")
t.Log(stdout.String()) failed = true
}
} }
} }
if failed {
t.Log(stdout.String())
}
}
var failed bool
for i := range mt.stderr { for i := range mt.stderr {
if !strings.Contains(stderr.String(), mt.stderr[i]) { if !strings.Contains(stderr.String(), mt.stderr[i]) {
t.Error("invalid error output") t.Error("invalid error output")
t.Log(stderr.String()) failed = true
} }
} }
if failed {
t.Log(stderr.String())
}
} }
if mt.title == "" { if mt.title == "" {

71
cmd/treerack/open.go Normal file
View File

@ -0,0 +1,71 @@
package main
import (
"bytes"
"flag"
"io"
"os"
"github.com/aryszka/treerack"
"golang.org/x/crypto/ssh/terminal"
)
type syntaxOptions struct {
syntax string
syntaxFile string
}
func multipleSyntaxesError(fs *flag.FlagSet) {
stderr("only one of syntax file or syntax string is allowed")
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func missingSyntaxError(fs *flag.FlagSet) {
stderr("missing syntax input")
stderr()
stderr("Options:")
fs.PrintDefaults()
}
func open(options syntaxOptions, fs *flag.FlagSet) (*treerack.Syntax, int) {
if options.syntaxFile != "" && options.syntax != "" {
multipleSyntaxesError(fs)
return nil, -1
}
var hasInput bool
if options.syntaxFile == "" && options.syntax == "" {
hasInput = isTest && rin != nil || !isTest && !terminal.IsTerminal(0)
}
if !hasInput && options.syntaxFile == "" && options.syntax == "" {
missingSyntaxError(fs)
return nil, -1
}
var input io.Reader
if hasInput {
input = rin
} else if options.syntaxFile != "" {
f, err := os.Open(options.syntaxFile)
if err != nil {
stderr(err)
return nil, -1
}
defer f.Close()
input = f
} else if options.syntax != "" {
input = bytes.NewBufferString(options.syntax)
}
s := &treerack.Syntax{}
if err := s.ReadSyntax(input); err != nil {
stderr(err)
return nil, -1
}
return s, 0
}

View File

@ -9,6 +9,8 @@ read, with error reporting
what was the bug with the large json from eskip? what was the bug with the large json from eskip?
[next] [next]
check
parse
error reports error reports
- take the last - take the last
simplify generator output simplify generator output

File diff suppressed because it is too large Load Diff