Help us shape the future of Go! Take the 2026 Go Developer Survey

tests

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Example (RouteSharedMemory)
root, err := fs.Sub(fixturesFS, "fixtures/routing")
if err != nil {
	fmt.Println(err)
	return
}

shm := core.NewSharedMemory()
mux := http.NewServeMux()
err = annotations.NewRoute(root, annotations.WithRuntimeFunc(func(rt *runner.Runtime) {
	rt.SetContext(core.SharedMemoryContext(rt.Context(), shm))
	rt.RegisterConstructor("SharedMemory", core.NewSharedMemoryBinding)
})).RegisterMux(mux)
if err != nil {
	fmt.Println(err)
	return
}

post := httptest.NewRequest(http.MethodPost, "/kv/color", strings.NewReader("value=blue"))
post.Header.Set("Content-Type", "application/x-www-form-urlencoded")
postRR := httptest.NewRecorder()
mux.ServeHTTP(postRR, post)
fmt.Println(postRR.Body.String())

getRR := httptest.NewRecorder()
mux.ServeHTTP(getRR, httptest.NewRequest(http.MethodGet, "/kv/color", nil))
fmt.Println(getRR.Body.String())

statsRR := httptest.NewRecorder()
mux.ServeHTTP(statsRR, httptest.NewRequest(http.MethodGet, "/stats/requests", nil))
fmt.Println(statsRR.Body.String())
Output:
ok
blue
2

Index

Examples

Constants

View Source
const (
	CacheOff    = "off"
	CacheWorker = "worker"
)

Cache scopes, naming how far a parsed include and a compiled expression travel. The CLI spells them as --cache=off|worker.

SuiteFile is the file a directory of fixtures configures itself with. It is the same name an application root serves under, because it is the same file: a tree that is both a site and a suite writes one configuration, not two.

Variables

View Source
var ErrFlatstackUnsupported = errors.New("program not supported by flatstack")

ErrFlatstackUnsupported reports that the flat bytecode compiler rejected the fixture's program. The fixture is skipped for the flatstack runner rather than delegated: a fallback run would report the compatibility interpreter's result and cost under the flatstack column.

View Source
var ErrRunnerUnavailable = errors.New("runner unavailable")

ErrRunnerUnavailable reports that a runner cannot execute on this machine, which is a skip rather than a failure. The php runner returns it when no php binary is installed.

Runners lists every backend the test matrix covers, in report order.

Functions

func BindingFunc added in v0.2.5

func BindingFunc(name string) any

BindingFunc returns the raw (unregistered, unadapted) Go function behind a binding name, so benchmarks can measure the reflection return path on its own.

func BindingFuncs added in v0.2.5

func BindingFuncs() map[string]any

BindingFuncs returns the example bindings keyed by the PHP name they are registered under.

func RegisterBindings added in v0.2.5

func RegisterBindings(rt *runner.Runtime)

RegisterBindings installs the example bindings. It is passed to stdlib.Register as an extra installer, the same way a host contributes its own symbols.

func RunSetup added in v0.5.0

func RunSetup(ctx context.Context, suites []*Suite, out io.Writer) error

RunSetup runs the setup hooks of every suite, outermost first, and stops at the first failure. A suite whose state was not laid down has nothing for its fixtures to assert against, so the run fails before one executes rather than reporting the same missing table once per fixture.

func RunTeardown added in v0.5.0

func RunTeardown(ctx context.Context, suites []*Suite, out io.Writer) error

RunTeardown runs the teardown hooks in reverse, whatever the fixtures did.

Every hook runs and every failure is reported, rather than the run stopping at the first: the suites are independent, and a caller learns about all of them instead of the one that happened to be innermost.

func TestMain added in v0.2.0

func TestMain(m *testing.M)

func WithWorker added in v0.5.0

func WithWorker(ctx context.Context, id int) context.Context

WithWorker marks ctx as belonging to worker id, so a fixture run under it takes that worker's caches. The command's worker loop calls this once per goroutine; everything else inherits worker zero.

func WriteHTMLReport added in v0.2.1

func WriteHTMLReport(w io.Writer, results []*TestResult) error

WriteHTMLReport outputs an HTML report of the test results.

func WriteJSONReport added in v0.2.1

func WriteJSONReport(w io.Writer, results []*TestResult) error

WriteJSONReport outputs a JSON report of the test results.

Types

type BindingRecord added in v0.2.5

type BindingRecord struct {
	ID   int64
	Name string
}

BindingRecord is a plain Go struct handed to PHP as an object. Property access goes through runner.helperGet, which reads exported fields by reflection (case-insensitively), so `$r->name` and `$r->Name` both resolve.

func (BindingRecord) Label added in v0.2.5

func (r BindingRecord) Label() string

Label is an exported method so tests can exercise `$r->label()` dispatch on a forwarded Go value.

type Fixture added in v0.2.1

type Fixture struct {
	Name        string          `yaml:"name"`
	Description string          `yaml:"description"`
	Error       string          `yaml:"error"`   // optional: expected uncaught error substring
	Stdin       string          `yaml:"stdin"`   // optional: top-level stdin contents
	Options     runner.Options  `yaml:"options"` // optional: runtime options for both engines (memory_limit, ...)
	Root        string          `yaml:"root"`    // optional: include root, relative to the fixture's own directory
	Serial      bool            `yaml:"serial"`  // optional: do not overlap this fixture with peers in its area
	Runner      FixtureRunners  `yaml:"runner"`  // optional: runners the fixture opts out of
	Request     FixtureRequest  `yaml:"request"`
	Response    FixtureResponse `yaml:"response"`

	PHP      string `yaml:"-"`
	Expected string `yaml:"-"`
	Path     string `yaml:"-"`
	// contains filtered or unexported fields
}

Fixture is the parsed representation of a .phpt test file.

func FindFixtures added in v0.2.1

func FindFixtures(paths []string) ([]*Fixture, error)

FindFixtures locates all .phpt files in the specified paths (files or directories).

func ParseFixture added in v0.2.1

func ParseFixture(data []byte, path ...string) (*Fixture, error)

ParseFixture splits a .phpt file into its three sections and parses the YAML metadata.

func (*Fixture) Coverage added in v0.4.0

func (f *Fixture) Coverage() *coverage.Collector

Coverage returns the collector installed with SetCoverage, or nil.

func (*Fixture) RootDir added in v0.3.3

func (f *Fixture) RootDir() string

RootDir returns the directory a fixture's includes resolve against. That is the directory holding it, which is also where the php runner executes, unless the fixture named another one with `root:`.

func (*Fixture) Runs added in v0.3.0

func (f *Fixture) Runs(r Runner) bool

Runs reports whether the fixture is checked against r.

func (*Fixture) SetAppRoot added in v0.4.0

func (f *Fixture) SetAppRoot(root string, includes ...string)

SetAppRoot points the fixture at the application root it runs under: the directory the test command was invoked in, or the suite root of the phpscript.yml governing the fixture. The autoload folder convention and the prelude includes resolve there, while the fixture's own relative includes keep resolving against its directory: runnerOptions layers the two, fixture directory first.

An include that is not there is not an error; the setting says what to load when the application provides it, and a tree without an autoload.php simply runs without one.

func (*Fixture) SetCacheScope added in v0.5.0

func (f *Fixture) SetCacheScope(scope string)

SetCacheScope says how far this fixture's parse caches reach.

The caches are what a suite trades memory for speed with. Worker, the default, gives each worker loop one set, reused by the fixtures that worker runs serially, so what is held scales with --parallel rather than with the number of fixtures. Off gives a run its own and drops them - and its runtime - when it ends, so a run is charged its own parsing and holds nothing afterwards.

func (*Fixture) SetCoverage added in v0.4.0

func (f *Fixture) SetCoverage(c *coverage.Collector)

SetCoverage installs a statement-coverage collector for the fixture's runtime runner. Only that runner reports coverage: flatstack carries no coverage support, and the php runner is another process.

func (*Fixture) SetDatabase added in v0.5.0

func (f *Fixture) SetDatabase(provider model.DatabaseProvider)

SetDatabase names the connections this fixture's Database and Database\Migrate bindings resolve through. Nil leaves the binding on the process environment, which is what a fixture whose suite declared no env of its own has always had.

A suite passes the provider its setup hook applied the schema through, so the fixtures below it query the database the hook prepared rather than a second pool opened over the same DSN.

func (*Fixture) SetRootFS added in v0.3.3

func (f *Fixture) SetRootFS(root fs.FS)

SetRootFS binds the filesystem a fixture's includes resolve against. The directory holding the .phpt is the right answer for every caller: it is what the php runner uses as its working directory, so all three runners resolve a relative include to the same file.

type FixtureRequest added in v0.2.1

type FixtureRequest struct {
	Args    any               `yaml:"args"` // map[string]string or []string or scalar
	Get     map[string]string `yaml:"get"`
	Post    map[string]string `yaml:"post"`
	Cookie  map[string]string `yaml:"cookie"`
	Env     map[string]string `yaml:"env"`
	Headers map[string]string `yaml:"headers"`
	Stdin   string            `yaml:"stdin"`
	Body    string            `yaml:"body"`
}

FixtureRequest contains request data exposed to PHP as superglobals.

type FixtureResponse added in v0.2.1

type FixtureResponse struct {
	Headers map[string]string `yaml:"headers"`
}

FixtureResponse contains expected response assertions.

type FixtureRunners added in v0.3.0

type FixtureRunners struct {
	Flatstack *bool `yaml:"flatstack"`
	PHP       *bool `yaml:"php"`
}

FixtureRunners opts a fixture out of individual runners. An absent field means the runner is used; the default runtime can not be opted out of because it defines the fixture's expected output.

type Record

type Record struct {
	Key   string
	Value string
}

Record is a rich value type returned to PHP. Its exported fields are read from PHP via property access (`$rec->key`, `$rec->value`), matched case-insensitively.

type Runner added in v0.3.0

type Runner string

Runner names an execution backend a fixture can be checked against.

const (
	// RunnerFlatstack executes the fixture through the flat bytecode runtime,
	// which falls back to the compatibility interpreter for unsupported syntax.
	RunnerFlatstack Runner = "flatstack"

	// RunnerRuntime executes the fixture through the default interpreter.
	RunnerRuntime Runner = "runtime"

	// RunnerPHP executes the fixture through the php binary found in PATH.
	RunnerPHP Runner = "php"
)

type Storage

type Storage interface {
	Set(ctx context.Context, key, value string)
	Get(ctx context.Context, key string) (Record, error)
	All(ctx context.Context) ([]Record, error)
	Len() int64
	Tenant() string
}

Storage is a host-provided key/value capability whose context parameters are supplied automatically when PHP invokes its methods.

Example
ctx := context.WithValue(context.Background(), tenantKey, "acme")
storage, err := NewStorage(ctx)
if err != nil {
	fmt.Println(err)
	return
}

storage.Set(ctx, "color", "blue")
record, err := storage.Get(ctx, "color")
if err != nil {
	fmt.Println(err)
	return
}
fmt.Println(storage.Tenant())
fmt.Println(record.Key, record.Value)
fmt.Println(storage.Len())
Output:
acme
color blue
1

func NewFailStorage

func NewFailStorage(ctx context.Context) (Storage, error)

NewFailStorage is a constructor that always fails, used to exercise the thrown-error path of `new`.

func NewStorage

func NewStorage(ctx context.Context) (Storage, error)

NewStorage is the constructor registered for `new Storage`. Its first parameter is a context.Context, filled in automatically by the runner, so PHP calls `new Storage` with no arguments.

type Suite added in v0.5.0

type Suite struct {
	// Dir is the suite root as the caller spells it, which is what an error
	// names and what stdlib.RegisterFS is rooted at.
	Dir string

	// Config is the file read over the configuration the run started with.
	Config config.Config

	// Declared holds the keys the file itself named, so a caller can tell a
	// setting the suite asked for from one it inherited.
	Declared map[string]any
	// contains filtered or unexported fields
}

Suite is one phpscript.yml governing the fixtures below the directory holding it: the connections they resolve, the prelude they load, and the hooks the session runs around them.

The provider is built once and held, because the setup hook and the fixtures have to share a pool. Two providers over one DSN are two pool caches, and a schema applied through the first is not in the database the second queries when the DSN names no shared file.

func LoadSuite added in v0.5.0

func LoadSuite(dir string, base config.Config, forbidden bool) (*Suite, error)

LoadSuite reads dir/phpscript.yml off disk over base, and returns nil when the directory holds no such file. A directory without one is not a suite root; it is a folder of fixtures that configures nothing.

forbidden refuses the keys that describe a whole run rather than one folder. It is false for the configuration found at or above the invocation root, which is the run's own, and true for one discovered below it.

func LoadSuiteFS added in v0.5.0

func LoadSuiteFS(root fs.FS, dir string, base config.Config) (*Suite, error)

LoadSuiteFS is LoadSuite over a directory inside root, for a tree that is not on disk. The embedded fixtures the Go tests run are read this way.

func (*Suite) Include added in v0.5.0

func (s *Suite) Include() string

Include is the prelude the fixtures below this suite root load, or "".

func (*Suite) Provider added in v0.5.0

func (s *Suite) Provider() model.DatabaseProvider

Provider answers the connections the fixtures below this suite root resolve.

A suite that declared no env of its own resolves what the run does, which is the process environment: a folder that named no connections is not asking for a set of its own. A suite that declared one gets only what it named, the rule a virtual host is already held to, so a fixture cannot reach a database its folder did not configure.

func (*Suite) RunHook added in v0.5.0

func (s *Suite) RunHook(ctx context.Context, file string, out io.Writer) error

RunHook executes one hook file on a runtime carrying what a fixture below this suite root carries: the standard library rooted at the suite, the host bindings the fixtures use, and the suite's own connections.

The suite root is the runtime's filesystem, so a hook names its migrations the way an application does, relative to itself. Output goes to out, which a caller not reporting the hook may discard.

func (*Suite) Setup added in v0.5.0

func (s *Suite) Setup() string

Setup names the hook the session runs before the fixtures, or "".

func (*Suite) Teardown added in v0.5.0

func (s *Suite) Teardown() string

Teardown names the hook the session runs after them, or "".

type TestResult added in v0.2.1

type TestResult struct {
	Name          string `json:"name"`
	Description   string `json:"description"`
	Path          string `json:"path"`
	Passed        bool   `json:"passed"`
	DurationMs    int64  `json:"duration_ms"`
	FailureReason string `json:"failure_reason,omitempty"`
	GotOutput     string `json:"got_output,omitempty"`
	WantOutput    string `json:"want_output,omitempty"`
	Error         string `json:"error,omitempty"`
	Runner        Runner `json:"runner,omitempty"`
	Skipped       bool   `json:"skipped,omitempty"`
}

TestResult carries execution outcome for a single fixture.

func RunFixture added in v0.2.1

func RunFixture(ctx context.Context, f *Fixture) *TestResult

RunFixture executes a single fixture against the default runtime.

func RunFixtureOn added in v0.3.0

func RunFixtureOn(ctx context.Context, f *Fixture, r Runner) *TestResult

RunFixtureOn executes a single fixture against one runner. Every runner is held to the same expected output; the runner only decides how the source is executed.

Jump to

Keyboard shortcuts

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