package f2 import ( "errors" "flag" "testing" "edge-infra.dev/test/f2/fctx" ) // TODO: add diagram for test execution flow // Context is a type alias type Context = fctx.Context // FrameworkFn is a framework-level lifecycle function defined by the user, called by // [Framework.Setup] and [Framework.Teardown]. // // Changes to context are expected to be returned to caller. type FrameworkFn func(Context) (Context, error) // FrameworkTestFn is a lifecycle function executed by [Framework] in the context // of a test run, e.g. [Framework.BeforeEachTest]. // // Changes to context are expected to be returned to caller. type FrameworkTestFn func(Context, *testing.T) (Context, error) // FeatureFn is a feature-level lifecycle function executed by [Framework], e.g. // before the framework executes each feature, in the context of a test run. It // is a [FrameworkTestFn] that gets information about the [Feature] being tested // injected. // // Changes to context are expected to be returned to caller. type FeatureFn func(Context, *testing.T, Feature) (Context, error) // ErrSkip can be returned by FrameworkFns to signal that the entire test suite // should be skipped. When this error is detected, the framework exits from // TestMain with an exit code of 0. Callers should wrap this error with a // specific reason for skipping that includes information on why the test suite // was skipped and how to remediate it. // // This error is not checked on Teardown, because what is the point in skipping // something which is already terminating? var ErrSkip = errors.New("skipping") type Extension interface { RegisterFns(Framework) IntoContext(Context) Context } type FlagBinder interface { BindFlags(*flag.FlagSet) } type Labeler interface { Labels() map[string]string } // StepFn is the function called for each step of a [Feature] test, including // actual test execution, executed by the [Feature], not by the [Framework] // directly. // // Changes to context are expected to be returned to caller. type StepFn func(Context, *testing.T) Context // Phase defines the individual lifecycle phases. type Phase uint8 // Test lifecycle phases listed in the order they are triggered during test // execution from the perspective of the framework, working outward (the // framework setup function) in and then back out (ending on framework teardown). // // Within a feature, the ordering is: // // phaseBeforeTest -> phaseTest -> phaseAfterTest const ( phaseSetup Phase = iota phaseBeforeTest phaseBeforeFeature phaseTest // where feature is executed, with its own before/after hooks phaseAfterFeature phaseAfterTest phaseTeardown ) func (p Phase) String() string { switch p { case phaseSetup: return "Setup" case phaseBeforeTest: return "BeforeEachTest" case phaseBeforeFeature: return "BeforeEachFeature" case phaseTest: return "Test" case phaseAfterFeature: return "AfterEachFeature" case phaseAfterTest: return "AfterEachTest" case phaseTeardown: return "Teardown" default: return "Impossible" } } // Interface for testing.M so that we can provide alternative implementations // for e.g. testing framework behavior. type TestingMain interface { Run() (code int) }