Documentation
¶
Overview ¶
Package contracttest holds the executable contract every client adapter has to satisfy, in-tree and out-of-tree alike. It is the counterweight to clients.As[T]: a capability is discovered by type assertion, so a renamed or misspelled method makes an adapter silently stop implementing an interface, and nothing but a test notices.
The harness grows with the refactor: RunAdapter covers identity today, and RunHostDetector, RunPlanRefiner and the rest arrive with the parts that move each capability into the adapters.
Each Run* function is a thin reporter over a pure violations function, so the harness can prove that it rejects a bad adapter instead of only that it accepts a good one.
Index ¶
- func RunAdapter(t *testing.T, adapter clients.Adapter)
- func RunHostDetector(t *testing.T, adapter clients.Adapter)
- func RunLifecycle(t *testing.T, adapter clients.Adapter)
- func RunPlanRefiner(t *testing.T, adapter clients.Adapter)
- func RunPlanRefinerWithHost(t *testing.T, adapter clients.Adapter, host domain.OpenCodeHostAuthority)
- func RunProjector(t *testing.T, adapter clients.Adapter)
- func RunRegistryInspector(t *testing.T, adapter clients.Adapter)
- func RunTraitParity(t *testing.T, registry *clients.Registry, requirements []CapabilityRequirement)
- type CapabilityRequirement
- type OpenCodeV1Host
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RunAdapter ¶
RunAdapter asserts the mandatory part of the contract: the adapter reports a stable id that domain actually defines.
func RunHostDetector ¶
RunHostDetector asserts the detection half of the contract on each supported operating system, against a host whose probes answer "nothing is installed":
- surface ids are non-empty and unique, and an undetected surface carries no evidence;
- every selection surface is one of the reported surfaces;
- repeated observations of the same host are identical, in content, in surface order and in the number of probe calls;
- nothing is reported as present, because the host says nothing is.
The last one is how far this harness gets towards "the adapter observes the machine only through clients.Host". It catches the case that matters - an adapter that stats a real path or resolves a real binary behind the host's back reports evidence the host never gave it - but it is a necessary condition, not a proof: an ambient read whose result does not reach the Detection is invisible here.
The properties under test are structural. What each client reports for a real installation is frozen by the detector's golden files instead.
func RunLifecycle ¶
RunLifecycle asserts the activation half of the contract when the adapter implements it. A client without Lifecycle is activated by the operator, and that absence is not a violation.
func RunPlanRefiner ¶
RunPlanRefiner asserts the planning half of the contract. A refiner speaks last, on a plan the generic pipeline has already shaped, and it may only add to it:
- the plan identity is the planner's: ClientID, Scope, PhysicalArtifactID, TargetRoot and ActivePath come back unchanged;
- an unsupported plan is never promoted, because readiness is an upgrade over a usable plan and not a way to overrule the generic verdict;
- refining an already refined plan changes nothing, because a caller that revisits a target refines the same plan again.
What each client adds is frozen by the planner's golden files instead.
func RunPlanRefinerWithHost ¶
func RunPlanRefinerWithHost(t *testing.T, adapter clients.Adapter, host domain.OpenCodeHostAuthority)
RunPlanRefinerWithHost supplies caller-qualified fixture authority without deriving a native host or physical-root identity from synthetic locators.
func RunProjector ¶
RunProjector asserts the staging half of the contract. A projector writes only inside the staging tree it was given, never claims the generic managed_package_directory object, and is deterministic: a second Project on a clean copy of the same tree returns the same objects.
func RunRegistryInspector ¶
RunRegistryInspector asserts the identity-inspection half of the contract when the adapter implements it. A client without RegistryInspector is observed only through the generic prepared-root walk.
func RunTraitParity ¶
func RunTraitParity(t *testing.T, registry *clients.Registry, requirements []CapabilityRequirement)
RunTraitParity fails for every registered adapter whose client declares a trait that the adapter does not implement. It closes the hole As[T] opens: a renamed method turns a capability off silently, and only a declaration checked against the implementation catches that.
An empty requirement set is a valid no-op so the harness can stay wired when a caller has nothing to declare yet. Parity is deliberately one-directional: declaring a trait requires the interface, while implementing an interface nobody declared yet is how a capability is normally introduced.
Types ¶
type CapabilityRequirement ¶
type CapabilityRequirement struct {
// Name is how a failure names the trait, for example "LifecycleKind=native_config".
Name string
Holds func(definition domain.ClientDefinition) bool
Implements func(adapter clients.Adapter) bool
}
CapabilityRequirement is one "declaring this trait promises implementing this interface" rule. Holds reads the declaration from the domain definition; Implements answers the same question about the adapter, normally with a type assertion such as:
func(a clients.Adapter) bool { _, ok := a.(clients.Lifecycle); return ok }
type OpenCodeV1Host ¶
type OpenCodeV1Host struct{}
OpenCodeV1Host supplies explicit, pure qualified authority for direct adapter and usecase fixtures that bypass Engine.Prepare. It is not host probe evidence. Each Profile call returns a separately owned qualification-ledger snapshot.
func (OpenCodeV1Host) ConfigDialect ¶
func (h OpenCodeV1Host) ConfigDialect() string
func (OpenCodeV1Host) Profile ¶
func (OpenCodeV1Host) Profile() opencodehost.Profile
func (OpenCodeV1Host) ValidateNative ¶
func (h OpenCodeV1Host) ValidateNative(skills bool, transports []string) error