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
- Variables
- func HumanReadable(name string) string
- type PackagesDiff
- type Result
- func (r *Result) Descend(sr *SubResult, cb func(parent, sr *SubResult))
- func (r *Result) For(cb func(*SubResult))
- func (r *Result) ForOrdered(cb func(*SubResult))
- func (r *Result) HasSubs() bool
- func (r *Result) Len() int
- func (r *Result) LenFailed() int
- func (r *Result) OfTest(t *Test) *SubResult
- func (r *Result) String() string
- type Results
- type RunMask
- type Sources
- type SrcStats
- type SubResult
- type Test
- type TestResult
- type TestSuite
- type TestingPackage
- func (tp TestingPackage) Abs() string
- func (tp *TestingPackage) ForSortedSuite(cb func(*TestSuite)) error
- func (tp *TestingPackage) ForSuite(cb func(*TestSuite)) error
- func (tp *TestingPackage) ForTest(cb func(*Test)) error
- func (tp *TestingPackage) HasSrcStats() bool
- func (tp TestingPackage) ID() string
- func (tp *TestingPackage) LastSuite() *TestSuite
- func (tp *TestingPackage) LenSuites() int
- func (tp *TestingPackage) LenTests() int
- func (tp TestingPackage) Name() string
- func (tp TestingPackage) Rel() string
- func (tp *TestingPackage) ResetSrcStats()
- func (tp *TestingPackage) Run(rm RunMask) (*Results, error)
- func (tp *TestingPackage) SrcStats() *SrcStats
- func (tp *TestingPackage) Suite(name string) *TestSuite
- func (tp *TestingPackage) TrimTo(rr *Results)
Constants ¶
const StdErr = "shell exit error: "
Variables ¶
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].
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.
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.
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 ¶
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 ¶
Descend provides a depth first traversing of a sub test result having itself sub test results and so on.
func (*Result) For ¶
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 ¶
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 ¶
HasSubs allows to discriminate go-tests with one sub-test from a single go-test.
func (*Result) Len ¶
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 ¶
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.
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) Len ¶
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).
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 ¶
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 ¶
ModuleDir return the directory of a module which has one of its (package) directories and its descendants watched for changes.
func (*Sources) ModuleName ¶
ModuleName returns a watched module's name. Note if Sources.Watch wasn't called the zero string is returned.
func (*Sources) Quit ¶
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 ¶
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.
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 }
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)