From 026e06dd4e29617e9ff27a19ecf3f37807250d93 Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Thu, 30 Nov 2017 10:56:18 -0800 Subject: [PATCH 1/2] Add YAML() for generating YAML blocks Docs in [1]. I've used Go's JSON serializer to avoid external dependencies, since JSON is a subset of YAML [2]. Prove is currently choking on the results: $ prove test/yaml/test test/yaml/test .. Failed 1/2 subtests Test Summary Report ------------------- test/yaml/test (Wstat: (none) Tests: 1 Failed: 0) Parse errors: Unsupported YAMLish syntax: '{' at /usr/lib64/perl5/5.22.3/TAP/Parser/YAMLish/Reader.pm line 101. Bad plan. You planned 2 tests but ran 1. Files=1, Tests=1, 0 wallclock secs ( 0.01 usr + 0.00 sys = 0.01 CPU) Result: FAIL $ prove --version TAP::Harness v3.35_01 and Perl v5.22.3 but node-tap [3] parses it fine: $ tap test/yaml/test test/yaml/test ........................................ 2/2 total ................................................. 2/2 2 passing (32.15ms) ok $ tap --version 11.0.0 [1]: https://testanything.org/tap-version-13-specification.html#yaml-blocks [2]: http://www.yaml.org/spec/1.2/spec.html $ curl -s http://www.yaml.org/spec/1.2/spec.html | grep -B1 JSON | head -n2 The primary objective of this revision is to bring YAML into compliance with JSON as an official subset. YAML 1.2 is compatible with 1.1 for [3]: http://www.node-tap.org/ --- Makefile | 2 +- tap.go | 13 +++++++++++++ test/yaml/main.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/yaml/main.go diff --git a/Makefile b/Makefile index 986541d7c..6fabe6270 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -TESTS = auto check diagnostic failing known skip todo writer +TESTS = auto check diagnostic failing known skip todo writer yaml GOPATH = $(CURDIR)/gopath .PHONY: $(TESTS) diff --git a/tap.go b/tap.go index 477fddc3f..5a07d7ff4 100644 --- a/tap.go +++ b/tap.go @@ -21,6 +21,7 @@ package tap // import "github.com/mndrix/tap-go" import ( + "encoding/json" "fmt" "io" "os" @@ -151,3 +152,15 @@ func (t *T) Diagnostic(message string) { func (t *T) Diagnosticf(format string, a ...interface{}) { t.printf("# "+escapeNewlines(format)+"\n", a...) } + +// YAML generates a YAML block from the message. +func (t *T) YAML(message interface{}) error { + bytes, err := json.MarshalIndent(message, " ", " ") + if err != nil { + return err + } + t.printf(" ---\n ") + t.printf(string(bytes)) + t.printf("\n ...\n") + return nil +} diff --git a/test/yaml/main.go b/test/yaml/main.go new file mode 100644 index 000000000..21938ccab --- /dev/null +++ b/test/yaml/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "bytes" + "io" + "os" + + tap "github.com/mndrix/tap-go" +) + +func main() { + // collect output for comparison later + buf := new(bytes.Buffer) + t := tap.New() + t.Writer = io.MultiWriter(os.Stdout, buf) + + t.Header(2) + t.Pass("test for anchoring the YAML block") + message := map[string]interface{}{ + "message": "testing YAML blocks", + "code": 3, + } + t.YAML(message) + got := buf.String() + t.Ok(got == expected, "diagnostics gave expected output") +} + +const expected = `TAP version 13 +1..2 +ok 1 - test for anchoring the YAML block + --- + { + "code": 3, + "message": "testing YAML blocks" + } + ... +` From 4656fa9699ebfc77fff69a265c5a545d61368dea Mon Sep 17 00:00:00 2001 From: "W. Trevor King" Date: Fri, 1 Dec 2017 09:31:28 -0800 Subject: [PATCH 2/2] Add 'yaml' build tag for conditionally using gopkg.in/yaml.v2 So folks who are comfortable with the additional dependency can get prove-compatible output. Michael wants to stick with prove for tap-go because it is widely installed [1], but folks using node-tap or other consumers that can handle the JSON subset of YAML probably don't want the external dependency. Folks who want yaml.v2 can enable the yaml build tag [2]. Folks who are ok with JSON don't have to set any build tags. The go-yaml dependency is the only Go producer listed in [3]. There may be others, I haven't checked. The Makefile changes include new uses of wildcards [4] to pick up test/%/*.go siblings. And I'm using the stem variable $* [5] in the rule to pick up the whole test package (and not just main.go). I'm not sure how Michael wants vendoring to work. For the moment, I've softened the 'GOPATH =' to a 'GOPATH ?=' and installed the package in my local GOPATH. It's possible that we want to stick with 'GOPATH =' and drop the package under gopath/ (via a Git submodule?). [1]: https://github.com/mndrix/tap-go/pull/7#issuecomment-348424097 [2]: https://golang.org/pkg/go/build/#hdr-Build_Constraints [3]: http://yaml.org/ [4]: https://www.gnu.org/software/make/manual/html_node/Wildcard-Examples.html [5]: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html --- Makefile | 6 +++--- tap.go | 5 ++--- test/yaml/json.go | 14 ++++++++++++++ test/yaml/main.go | 11 ----------- test/yaml/yaml.go | 12 ++++++++++++ yaml_json.go | 22 ++++++++++++++++++++++ yaml_yaml.go | 23 +++++++++++++++++++++++ 7 files changed, 76 insertions(+), 17 deletions(-) create mode 100644 test/yaml/json.go create mode 100644 test/yaml/yaml.go create mode 100644 yaml_json.go create mode 100644 yaml_yaml.go diff --git a/Makefile b/Makefile index 6fabe6270..5911e250e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ TESTS = auto check diagnostic failing known skip todo writer yaml -GOPATH = $(CURDIR)/gopath +GOPATH ?= $(CURDIR)/gopath .PHONY: $(TESTS) @@ -9,8 +9,8 @@ all: $(foreach t,$(TESTS),test/$(t)/test) clean: rm -f test/*/test -test/%/test: test/%/main.go tap.go - go build -o $@ $< +test/%/test: test/%/*.go tap.go yaml_json.go yaml_yaml.go + go build -o $@ -tags yaml ./test/$* $(TESTS): %: test/%/test prove -v -e '' test/$@/test diff --git a/tap.go b/tap.go index 5a07d7ff4..3be970656 100644 --- a/tap.go +++ b/tap.go @@ -21,7 +21,6 @@ package tap // import "github.com/mndrix/tap-go" import ( - "encoding/json" "fmt" "io" "os" @@ -155,12 +154,12 @@ func (t *T) Diagnosticf(format string, a ...interface{}) { // YAML generates a YAML block from the message. func (t *T) YAML(message interface{}) error { - bytes, err := json.MarshalIndent(message, " ", " ") + bytes, err := yaml(message, " ") if err != nil { return err } t.printf(" ---\n ") t.printf(string(bytes)) - t.printf("\n ...\n") + t.printf(" ...\n") return nil } diff --git a/test/yaml/json.go b/test/yaml/json.go new file mode 100644 index 000000000..09ee91c47 --- /dev/null +++ b/test/yaml/json.go @@ -0,0 +1,14 @@ +// +build !yaml + +package main + +const expected = `TAP version 13 +1..2 +ok 1 - test for anchoring the YAML block + --- + { + "code": 3, + "message": "testing YAML blocks" + } + ... +` diff --git a/test/yaml/main.go b/test/yaml/main.go index 21938ccab..895e3ad31 100644 --- a/test/yaml/main.go +++ b/test/yaml/main.go @@ -24,14 +24,3 @@ func main() { got := buf.String() t.Ok(got == expected, "diagnostics gave expected output") } - -const expected = `TAP version 13 -1..2 -ok 1 - test for anchoring the YAML block - --- - { - "code": 3, - "message": "testing YAML blocks" - } - ... -` diff --git a/test/yaml/yaml.go b/test/yaml/yaml.go new file mode 100644 index 000000000..d9824dffb --- /dev/null +++ b/test/yaml/yaml.go @@ -0,0 +1,12 @@ +// +build yaml + +package main + +const expected = `TAP version 13 +1..2 +ok 1 - test for anchoring the YAML block + --- + code: 3 + message: testing YAML blocks + ... +` diff --git a/yaml_json.go b/yaml_json.go new file mode 100644 index 000000000..f848e6426 --- /dev/null +++ b/yaml_json.go @@ -0,0 +1,22 @@ +// +build !yaml + +package tap + +import ( + "encoding/json" +) + +// yaml serializes a message to YAML. This implementation uses JSON, +// which is a subset of YAML [1] and is implemented by Go's standard +// library. +// +// [1]: http://www.yaml.org/spec/1.2/spec.html#id2759572 +func yaml(message interface{}, prefix string) (marshaled []byte, err error) { + marshaled, err = json.MarshalIndent(message, prefix, " ") + if err != nil { + return marshaled, err + } + + marshaled = append(marshaled, []byte("\n")...) + return marshaled, err +} diff --git a/yaml_yaml.go b/yaml_yaml.go new file mode 100644 index 000000000..93c6f2e80 --- /dev/null +++ b/yaml_yaml.go @@ -0,0 +1,23 @@ +// +build yaml + +package tap + +import ( + "bytes" + + goyaml "gopkg.in/yaml.v2" +) + +// yaml serializes a message to YAML. This implementation uses +// non-JSON YAML, which has better prove support [1]. +// +// [1]: https://rt.cpan.org/Public/Bug/Display.html?id=121606 +func yaml(message interface{}, prefix string) (marshaled []byte, err error) { + marshaled, err = goyaml.Marshal(message) + if err != nil { + return marshaled, err + } + + marshaled = bytes.Replace(marshaled, []byte("\n"), []byte("\n"+prefix), -1) + return marshaled[:len(marshaled)-len(prefix)], err +}