Skip to content

Per-method test coverage: a unit test and a functional test for every provider method #635

Open

Description

@David-Noble-at-work

Epic: #444 — The resource model.

Every provider method gets a Go unit test and a devlore-test functional test; every compensation companion gets the same. One PR per provider, starting with file.Provider.

Why now

The resource-construction campaign and its successors have repeatedly found defects that only a test at the right altitude would have caught, and several were found by accident:

The pattern: behavior that no test names is behavior nobody notices changing. A per-method matrix turns those from lucky catches into guaranteed ones.

The shape

For each provider, per method:

  1. A Go unit test exercising the method directly — the contract at its own altitude, including the failure directions.
  2. A devlore-test functional test exercising it through a planned graph — the contract as an author meets it.
  3. The compensation companion, where one exists: forward, then undo, then the state assertion that proves the undo was real.

For file.Provider specifically: every method that accepts file.Resource must be tested against all three kinds — regular, directory, and symbolic link. That interface is new (#616), and the whole point of it is that kind is the disk's business rather than the author's; a method that quietly misbehaves on one kind is exactly the gotcha the type invites. The link cases matter most, since lstat-versus-stat is where this codebase has already been bitten twice.

Sequencing

file.Provider first — it is the largest surface, the one with a kind axis, and the one every other provider's pattern will be judged against. Then one PR per provider.

A gap analysis comes first within each PR: 3.5.x's status files already carry per-method test matrices, so the work starts by diffing that matrix against the tree rather than by writing tests blind.

Activity

  1. David-Noble-at-work commented on Aug 24, 2026

    @David-Noble-at-work
    ContributorAuthor

    Concrete gaps found by measuring #616's coverage (2026-08-24) — the feature is done; these are the holes a per-method matrix would have closed, recorded here rather than lost.

    A correctness item, not just coverage. file.resource.Exists (the unexported base) is at 0% coverage and is kind-blind — it uses a following Stat:

    func (r *resource) Exists() bool {
    	root := r.RuntimeEnvironment().Root()
    	_, err := root.Stat(root.NewPath(r.SourcePath.Abs()))
    	return err == nil
    }

    All four variants override it with lstat-plus-kind (#617/#621), so this is the pre-kind-honest predicate surviving in the one corner nothing tests. It stays reachable: the base's own UnmarshalJSON/UnmarshalText/UnmarshalYAML build a bare *resource via discoverResource. Decide whether a non-taxonomy base should answer Exists at all — it is not an Entry, so arguably it should not — or make it honest.

    Predicates with no test at all:

    • Regular.MismatchesKind and Directory.MismatchesKind — 0%. Only SymbolicLink's is pinned. These two are what protect a deployed copy replaced by a directory, the case the old unlink check never covered and The rest of the mutator surface: remove, unlink retirement, remove_all, backup #621 extended protection to.
    • ResourceKind's MarshalJSON, MarshalYAML, UnmarshalJSON, UnmarshalYAML — 0%. Only UnmarshalText is pinned, yet the enum is serialized into graph documents, so the JSON/YAML paths are the ones a saved plan actually travels through.

    Functional-only, no unit test: file.discover and file.resolve report 0% because make cover's per-package profile cannot see cross-package coverage — 9 devlore-test scenarios exercise them, and zero Go unit tests do. That asymmetry is precisely what this feature's "unit and functional" rule is for, and it means the reported number understates real coverage while still naming a real gap.

    Partial, worth a look when file.Provider is swept: bindAuthoredValue 62%, Move 74%, DiscoverAny 75%, checkVariableResourceSlots 77%, admits 83%, removeEntry 89%, verifyClaimBinding 87%.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions