model

package
v0.8.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2023 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package Model allows its client to watch a go source folder for changes of its testing packages. A testing package is a package which contains at least one *_test.go source file having at least one Test*-function.

import (
    "fmt"

    "github.com/slukits/gounit/pkg/module"
)

func main() {
    var mdl module.Module // zero value defaults to working directory
    diff, ID, err := mdl.Watch() // may be called arbitrary many times
    if err != nil { // no go.mod file found traversing ascending
        panic(err)
    }
    countdown := 10

    for {
        diff := <- diff // block until next change
        countdown--
        diff.For(func(tp *module.TestingPackage) (stop bool) {
            fmt.Printf("changed/added: %s\n", tp.Name())
            tp.ForTest(func(t *module.Test) {
                fmt.Println(t.Name())
            })
            tp.ForSuite(func(ts *module.TestSuite) {
                fmt.Println(ts.Name())
            })
			return
        })
        diff.ForDel(func(tp *module.TestingPackage) (stop bool) {
            fmt.Printf("deleted: %s\n", tp.Rel())
			return
        })
        if countdown == 0 {
            mdl.Quit(ID) // remove watcher from registered watchers
            break
        }
    }

    mdl.QuitAll() // terminate reporting go routine; release resources
}

Index

Constants

View Source
const StdErr = "shell exit error: "

Variables

View Source
var DefaultIgnore = []string{".git", "node_modules", "testdata"}

DefaultIgnore is the default value for Module.Ignore a list of directories which is ignored when searching for testing packages in a go module's directory, e.g.:

m := Module{Ignore: append(DefaultIgnore, "my_additional_dir")}

It is set iff Module.Ignore is unset at the first call of [Module.Watch].

View Source
var DefaultInterval = 200 * time.Millisecond

DefaultInterval is the default value for Module.Interval which is used iff at the first call of [Module.Watch] no interval value is set.

View Source
var DefaultTimeout = 60 * time.Second

DefaultTimeout is the default value for Module.Timeout which sets the timeout for a module's testing package's tests run. It is set iff at the first call of [Module.Watch] no timeout is set.

View Source
var ErrNoModule = errors.New("module: no module found in path: ")

ErrNoModule is returned by [Module.Watch] in case set Module.Dir or the current working directory ascending to root doesn't contain a go.mod file.

Functions

func HumanReadable

func HumanReadable(name string) string

Types

type PackagesDiff

type PackagesDiff struct {
	// contains filtered or unexported fields
}

PackagesDiff reports the differences of a module's packages at two different points in time. PackagesDiff is immutable hence we can report an instance by sending a pointer over an according channel.

func (*PackagesDiff) For

func (d *PackagesDiff) For(cb func(*TestingPackage) (stop bool)) error

For returns all testing packages which were updated since the last reported diff in descending order by their modification time.

func (*PackagesDiff) ForDel

func (d *PackagesDiff) ForDel(cb func(*TestingPackage) (stop bool))

ForDel returns a testing package which got deleted. Note neither tests nor suites are provide by such a testing package.

func (*PackagesDiff) String

func (d *PackagesDiff) String() string

type Result

type Result struct {
	Passed  bool
	Skipped bool
	Panics  bool

	Output []string
	Start  time.Time
	End    time.Time
	Name   string
	// contains filtered or unexported fields
}

Result instance is embedded in a TestResult or SubResult and expresses their commonalities. There are two result types needed because a TestResult may represent a test suite which in turn may report test logs of the suites Init- or Finalize-method. While SubResult instances can't have this.

func (*Result) Descend

func (r *Result) Descend(sr *SubResult, cb func(parent, sr *SubResult))

Descend provides a depth first traversing of a sub test result having itself sub test results and so on.

func (*Result) For

func (r *Result) For(cb func(*SubResult))

For calls back for each sub test result of a test result. I.e. in case of a suite runner for each suite test. Since it never occurred to me to nest tests deeper than that the support for this use case is rather rudimentary see [result.Descend].

func (*Result) ForOrdered

func (r *Result) ForOrdered(cb func(*SubResult))

For calls back for each sub test result of a test result. I.e. in case of a suite runner for each suite test.

func (*Result) HasSubs

func (r *Result) HasSubs() bool

HasSubs allows to discriminate go-tests with one sub-test from a single go-test.

func (*Result) Len

func (r *Result) Len() int

Len is the number of executed test comprising given test result. I.e. it is either 1 given result has no sub test results or the number of executed sub tests. I.e. tests having sub tests are not counted.

func (*Result) LenFailed

func (r *Result) LenFailed() int

LenFailed returns the number of failed tests which is only interesting in case of sub results otherwise a Result's Passed property could be consulted.

func (*Result) OfTest

func (r *Result) OfTest(t *Test) *SubResult

Sub returns the result of the sub test with given name.

func (*Result) String

func (r *Result) String() string

type Results

type Results struct {

	// Duration of a test run.
	Duration time.Duration
	// contains filtered or unexported fields
}

Results reports the results for each go Test* function of a testing package's test run. Results of sub tests are reported by their parent test. Results may be queried leveraging a testing package's parsed tests, test suites and suite tests. E.g. let pkg be a TestingPackage instance reported to a module watcher.

rr, err := pkg.Run()
panic(err) // before executed "go test" command finished
if rr.HasErr() { // from stderr after command execution finished
        panic(rr.Err())
}
pkg.ForTest(func(t *module.Test) {
    fmt.Printf("%s passed: %v\n", t.Name(), rr.OfTest(t).Passed)
})
pkg.ForSuite(func(ts *module.TestSuite) {
    sr := rr.OfSuite(ts)
    fmt.Printf("suite %s passed: %v", ts.Name(), rr.OfSuite(ts).Passed)
    ts.ForTest(func(t *module.Test) {
        fmt.Printf("\t%s passed: %v\n", t.Name(), sr.Of(t).Passed)
    })
})

func (*Results) Err

func (r *Results) Err() string

Err reports a shell exit error of a tests run.

func (*Results) HasErr

func (r *Results) HasErr() bool

HasErr returns true if a tests run resulted in a shell exit error.

func (*Results) Len

func (r *Results) Len() int

Len reports the number of tests, i.e. the number of go Test* tests plus the suite runners. Results has no option to distinguish suite "runners" from "normal" go Test* tests. For this the parsed suite information of a testing package needs to be leveraged.

func (*Results) OfSuite

func (r *Results) OfSuite(ts *TestSuite) *TestResult

OfSuite returns the test result of given test suite and its suite tests.

func (*Results) OfTest

func (r *Results) OfTest(t *Test) *TestResult

OfTest returns the test result of given Test instance representing a go Test* function (which is not running a test-suite).

func (*Results) Passed

func (r *Results) Passed() bool

type RunMask

type RunMask uint8

RunMask controls set flags for a test run.

const (
	// RunVet removes the -vet=off flag from a test run
	RunVet RunMask = 1 << iota
	// RunRace adds the -race flag to a test run
	RunRace
)

type Sources

type Sources struct {

	// The directory of a go module's package which is watched.  If
	// unset Source.Watch initializes this property with the current
	// working directory.
	Dir string

	// Interval is the duration between two packages diff-reports  for a
	// watcher.
	Interval time.Duration

	// Timeout is the duration after which a testing package's tests run
	// is canceled.
	Timeout time.Duration

	// Ignore is the list of directory names which are ignored in the
	// search for a go module's testing packages.  It defaults to
	// DefaultIgnore iff unset at the first call of Watch.  Note once
	// Sources.Watch was called for the first time further modifications
	// of Ignore are not taken into account (until Sources.QuitAll was
	// called and then Sources.Watch again).
	Ignore []string
	// contains filtered or unexported fields
}

Sources represents a go module's directory which itself or its descendants is a (testing) go package. A Sources-instance can be watched for changes of testing packages. A Sources instance may not be copied after its first watcher has been registered by Sources.Watch. A Sources instance's methods may be used concurrently and arbitrary many watcher may be registered.

func (*Sources) IsWatched

func (m *Sources) IsWatched() bool

IsWatched returns true iff at least one watcher is registered. Note a false return value doesn't mean that there is no diffing go routine running. To guarantee this see [Module.QuitAll].

func (*Sources) ModuleDir

func (m *Sources) ModuleDir() string

ModuleDir return the directory of a module which has one of its (package) directories and its descendants watched for changes.

func (*Sources) ModuleName

func (m *Sources) ModuleName() string

ModuleName returns a watched module's name. Note if Sources.Watch wasn't called the zero string is returned.

func (*Sources) Quit

func (m *Sources) Quit(ID uint64)

Quit unregisters the watcher with given ID and closes its diff-channel. Quit is a no-op if no watcher with given ID exists.

func (*Sources) QuitAll

func (m *Sources) QuitAll()

QuitAll closes all diff channels which were provided by [Module.Watch] and terminates the go routine reporting package diffs to watchers.

func (*Sources) SourcesDir

func (m *Sources) SourcesDir() string

SourcesDir returns the watch (package) directory inside a go module.

func (*Sources) Watch

func (m *Sources) Watch() (diff <-chan *PackagesDiff, ID uint64, err error)

Watch reports to each of its callers changes about a module's testing packages through returned channel. The module which is reported about is the first module which is found in Sources.Dir ascending towards root. If Module.Dir is unset the current working directory is used. If no directory with a go.mod file is found a wrapped ErrNoModule error is returned. I.e. after this method's first call Sources.Dir is the found module directory and [Sources.Name] provides its name. Returned ID may be used to unregister the watcher with given ID, see Sources.Quit. If a watcher is unregistered its diff channel is closed. See Sources.QuitAll to learn how to release all resources acquired by this method.

type SrcStats

type SrcStats struct {

	// Files is the number of *.go files of a testing package.
	Files int

	// TestFiles is the number of *_test.go files of a testing package.
	TestFiles int

	// Code is the number of code lines of a testing package.
	Code int

	// TestCode is the number of test code lines of a testing package.
	TestCode int

	// Doc is the number of documenting lines of a testing package.
	Doc int
}

SrcStats provides information about a testing package in terms of the number of code files, tests files, code lines, test code lines and documentation lines.

type SubResult

type SubResult struct {
	*Result
}

A SubResult of a run sub test is reported by a Result instance r:

r.For(func(sr *SubResult) {
    // do some thing with sub test result
})

type Test

type Test struct {
	// contains filtered or unexported fields
}

A Test provides information about a go test, i.e. Test*-function.

func (*Test) Name

func (t *Test) Name() string

Name returns a tests name.

func (*Test) Pos

func (t *Test) Pos() string

Pos returns a tests absolute filename with line and column number.

func (*Test) String

func (t *Test) String() string

type TestResult

type TestResult struct {
	*Result

	// InitOut reports the output of a test suites Init-method.
	InitOut []string

	// FinalizeOut reports the output of a test suites Finalize-method.
	FinalizeOut []string
}

TestResult indicates if a test has passed and what output it has generated.

type TestSuite

type TestSuite struct {
	Test
	// contains filtered or unexported fields
}

func (*TestSuite) ForTest

func (s *TestSuite) ForTest(cb func(*Test))

ForTest provides given test suite's tests.

func (*TestSuite) Runner

func (s *TestSuite) Runner() string

Runner returns the Test*-function's name which is executing given test suite.

type TestingPackage

type TestingPackage struct {
	ModTime time.Time

	Timeout time.Duration
	// contains filtered or unexported fields
}

A TestingPackage provides information on a module's package's tests and test suites. As well as the feature to execute and report on a package's tests.

func (TestingPackage) Abs

func (tp TestingPackage) Abs() string

Abs returns the absolute path *to* the testing package, i.e. Abs doesn't include the packages name.

func (*TestingPackage) ForSortedSuite

func (tp *TestingPackage) ForSortedSuite(cb func(*TestSuite)) error

ForSortedSuite calls back for each suite of given package whereas the suites are ordered by name instead of the modification date of the test file they belong to.

func (*TestingPackage) ForSuite

func (tp *TestingPackage) ForSuite(cb func(*TestSuite)) error

ForSuite provides given testing package's suites. ForSuite fails in case of an parse error. Note the last suite is of the package's most recently modified test file.

func (*TestingPackage) ForTest

func (tp *TestingPackage) ForTest(cb func(*Test)) error

ForTest provides given testing package's tests. ForTest fails in case of an parse error.

func (*TestingPackage) HasSrcStats

func (tp *TestingPackage) HasSrcStats() bool

HasSrcStats returns true if given testing package has its source stats calculation stored.

func (TestingPackage) ID

func (tp TestingPackage) ID() string

ID returns the module-relative package path including the package's name. Hence ID() is a module-global unique identifier of given package.

func (*TestingPackage) LastSuite

func (tp *TestingPackage) LastSuite() *TestSuite

LastSuite returns the last parsed suite of the most recently modified test file in given testing package.

func (*TestingPackage) LenSuites

func (tp *TestingPackage) LenSuites() int

LenSuites returns the number of suites of a testing package.

func (*TestingPackage) LenTests

func (tp *TestingPackage) LenTests() int

LenTests returns the number of go tests of a testing package.

func (TestingPackage) Name

func (tp TestingPackage) Name() string

Name returns the testing package's name.

func (TestingPackage) Rel

func (tp TestingPackage) Rel() string

Rel returns the module relative path *to* the testing package, i.e. Rel doesn't include the packages name.

func (*TestingPackage) ResetSrcStats

func (tp *TestingPackage) ResetSrcStats()

ResetSrcStats resets the source stats, i.e. HasSrcStats will return false after a call of ResetSrcStats until SrcStats is requested again.

func (*TestingPackage) Run

func (tp *TestingPackage) Run(rm RunMask) (*Results, error)

Run executes go test for the testing package and returns its result. Returned error if any is the error of command execution, i.e. a timeout. While Result.Err reflects errors from the error console. Note the output of the go testing tool is sadly not enough to report tests in the order they were written if tests run concurrently. Hence to achieve the goal that the test reporting outlines the documentation and thought process of the production code, i.e. tests are reported in the order they were written, it is necessary to parse the test files separately and then match the findings to the result of the test run.

func (*TestingPackage) SrcStats

func (tp *TestingPackage) SrcStats() *SrcStats

SrcStats provides statistics about code files/lines and documentation of a testing package.

func (*TestingPackage) Suite

func (tp *TestingPackage) Suite(name string) *TestSuite

Suite returns the test suite with given name or nil.

func (*TestingPackage) TrimTo

func (tp *TestingPackage) TrimTo(rr *Results)

TrimTo removes all parsed tests and suites which are not found in given results. (This may happen if tests are excluded due to build tags)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL