Skip to content

Commit

Permalink
Merge github.com/mndrix/tap-go into util
Browse files Browse the repository at this point in the history
This commit migrates github.com/mndrix/tap-go with commit history into
a new directory util as part of fixing problematic dependencies. tap-go
dependency has not been maintained for a long time and it is currently
archieved.

Signed-off-by: Muyassarov, Feruzjon <[email protected]>
  • Loading branch information
fmuyassarov committed May 4, 2023
2 parents e931285 + 5181037 commit 0b42308
Show file tree
Hide file tree
Showing 3 changed files with 210 additions and 0 deletions.
165 changes: 165 additions & 0 deletions util/tap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Package tap provides support for automated Test Anything Protocol ("TAP")
// tests in Go. For example:
//
// package main
//
// import "github.com/mndrix/tap-go"
//
// func main() {
// t := tap.New()
// t.Header(2)
// t.Ok(true, "first test")
// t.Ok(true, "second test")
// }
//
// generates the following output
//
// TAP version 13
// 1..2
// ok 1 - first test
// ok 2 - second test
package tap // import "github.com/mndrix/tap-go"

import (
"fmt"
"io"
"os"
"strings"
)
import "testing/quick"

// T is a type to encapsulate test state. Methods on this type generate TAP
// output.
type T struct {
nextTestNumber *int

// TODO toggles the TODO directive for Ok, Fail, Pass, and similar.
TODO bool

// Writer indicates where TAP output should be sent. The default is os.Stdout.
Writer io.Writer
}

// New creates a new Tap value
func New() *T {
nextTestNumber := 1
return &T{
nextTestNumber: &nextTestNumber,
}
}

func (t *T) w() io.Writer {
if t.Writer == nil {
return os.Stdout
}
return t.Writer
}

func (t *T) printf(format string, a ...interface{}) {
fmt.Fprintf(t.w(), format, a...)
}

// Header displays a TAP header including version number and expected
// number of tests to run. For an unknown number of tests, set
// testCount to zero (in which case the plan is not written); this is
// useful with AutoPlan.
func (t *T) Header(testCount int) {
t.printf("TAP version 13\n")
if testCount > 0 {
t.printf("1..%d\n", testCount)
}
}

// Ok generates TAP output indicating whether a test passed or failed.
func (t *T) Ok(test bool, description string) {
// did the test pass or not?
ok := "ok"
if !test {
ok = "not ok"
}

if t.TODO {
t.printf("%s %d # TODO %s\n", ok, *t.nextTestNumber, description)
} else {
t.printf("%s %d - %s\n", ok, *t.nextTestNumber, description)
}
(*t.nextTestNumber)++
}

// Fail indicates that a test has failed. This is typically only used when the
// logic is too complex to fit naturally into an Ok() call.
func (t *T) Fail(description string) {
t.Ok(false, description)
}

// Pass indicates that a test has passed. This is typically only used when the
// logic is too complex to fit naturally into an Ok() call.
func (t *T) Pass(description string) {
t.Ok(true, description)
}

// Check runs randomized tests against a function just as "testing/quick.Check"
// does. Success or failure generate appropriate TAP output.
func (t *T) Check(function interface{}, description string) {
err := quick.Check(function, nil)
if err == nil {
t.Ok(true, description)
return
}

t.Diagnostic(err.Error())
t.Ok(false, description)
}

// Count returns the number of tests completed so far.
func (t *T) Count() int {
return *t.nextTestNumber - 1
}

// AutoPlan generates a test plan based on the number of tests that were run.
func (t *T) AutoPlan() {
t.printf("1..%d\n", t.Count())
}

func escapeNewlines(s string) string {
return strings.Replace(strings.TrimRight(s, "\n"), "\n", "\n# ", -1)
}

// Todo returns copy of the test-state with TODO set.
func (t *T) Todo() *T {
newT := *t
newT.TODO = true
return &newT
}

// Skip indicates that a test has been skipped.
func (t *T) Skip(count int, description string) {
for i := 0; i < count; i++ {
t.printf("ok %d # SKIP %s\n", *t.nextTestNumber, description)
(*t.nextTestNumber)++
}
}

// Diagnostic generates a diagnostic from the message,
// which may span multiple lines.
func (t *T) Diagnostic(message string) {
t.printf("# %s\n", escapeNewlines(message))
}

// Diagnosticf generates a diagnostic from the format string and arguments,
// which may span multiple lines.
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 := yaml(message, " ")
if err != nil {
return err
}
t.printf(" ---\n ")
t.printf(string(bytes))
t.printf(" ...\n")
return nil
}
22 changes: 22 additions & 0 deletions util/yaml_json.go
Original file line number Diff line number Diff line change
@@ -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
}
23 changes: 23 additions & 0 deletions util/yaml_yaml.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 0b42308

Please sign in to comment.