It's been a while since a release here had anything in it but dependency bumps. This one closes some of the oldest issues on the tracker: fakes can be generated into the interface's own package or into <package>_test, flags on the -generate line apply to every directive, loading is two to three times faster, and the README documents every flag.
counterfeiter now requires go 1.26. go 1.27 is out, and counterfeiter follows go's support policy, so 1.26 and 1.27 are the supported versions.
Where fakes can go
- ๐ A fake can be generated into the same package as its interface. Point
-oat the package's own directory (-o ., or-o fake_foo_test.goso it is only compiled for tests) and the fake becomes a member of that package: no self-import, unqualified names, and the compile-time assertion stays, unexported interfaces included. Tests inside the package can use generated fakes without an import cycle. There is no new flag; detection is by directory, so fakes written anywhere else come out exactly as before. A stale same-package fake that no longer compiles does not stop you regenerating it. (#378, fixes #103, #121, #210, #262, and #68 from 2016) - ๐
-testwrites the fake into the external test package,<package>_test, as a_test.gofile next to the tests that use it. It works for interfaces from other packages in your module, the standard library and third-party modules, so-test io.WriteCloserputsFakeWriteCloserin<package>_test, the package that tests<package>'s public API, and writes nothing anywhere else. @nkovacs proposed and prototyped this in #135 in 2019. Thanks Nikola. (#383, fixes #135) - ๐ The package clause of a fake follows whatever package already lives in the output directory, and is named after the directory only when there is nothing there yet. So
fakes/can holdpackage impl_fakes: add adoc.godeclaring it and generate. Existing fakes packages are unaffected, their files already match the directory. (#384, fixes #249) - A fake of an unexported interface generated into its own package is unexported too:
gadgetgetsfakeGadget, notFakeGadget.-fake-nameis left alone. (#386)
Flags on the -generate line are defaults
- ๐
-o,-header,-q,-testand the new-fake-name-templategiven alongside-generateapply to everycounterfeiter:generatedirective in the package. A directive's own flags still win.-fake-name-templateis atext/templateover{{.TargetName}}, so-generate -o fake -fake-name-template '{{.TargetName}}'puts every fake in afakepackage named after its interface, written once instead of-oand-fake-nameon every line. This is @matt-royal's design and fixture from #195, re-applied on the current tree. Thanks Matt. (#379, fixes #191)
โก๏ธ moar speed
-
Only the target package is type-checked from source now. Everything it imports is read from export data through the go build cache, instead of the whole dependency graph being type-checked on every run, stdlib included. On cloudfoundry/cli's actor/v7action (11 fakes) with a warm build cache:
- one
//go:generateline per fake: 4.7 seconds, was 11 - the same package on a single
-generatedirective: 1.0 second, was 1.4, on a third of the CPU - a single fake on its own: 0.48 seconds, was 1.1
- the repository benchmark: 130ms per uncached generate, was 600ms, allocating 7MB instead of 570MB
The generated fakes are byte-for-byte identical across the fixture corpus. (#380, related #120, #181)
- one
-
๐ Type errors in the target package that have nothing to do with the interface no longer stop generation: an import that can't be resolved in a sandboxed build, a broken file elsewhere in the package mid-refactor. A file that does not parse is still fatal. Otherwise generation fails only if the interface's own signatures use a type that could not be loaded, and the error names the method and quotes the load errors behind it. Based on @navijation's #183. Thanks Navneeth. (#380, fixes #182)
Fixes
- ๐ Generic fakes with
comparable, union or~Tconstraints compile. The assertion lives in a blank generic function now, so any constraint works, and the packages constraints come from are imported instead of guessed from the type string. (#378, fixes #365) - ๐ Reading
Invocations()on a function fake while another goroutine calls it could deadlock. Interface fakes got this fix in v6.11.3; function fakes were missed. (#387, related #41, #44) - ๐ Variadic arguments are recorded as a copy, like every other slice, so changing the slice after the call no longer changes what
ArgsForCallandInvocationsreport. (#387) - ๐
counterfeiter io.WriteCloser -prints to stdout, as the usage text says, instead of failing with "No such file/directory/package". (#383) - ๐ A fake generated into a directory whose name differs from its package (
go-fooholdingpackage foo) compiles. (#383) - ๐
generator.Cache,generator.CachedFileReaderandFake.Generateare safe to use from several goroutines, for anyone driving the generator as a library. The CLI never hit this. (#388)
๐ Docs
- The README is rewritten so it's a bit more approachable for someone new to the tool:
go get -tooland-generateas the recommended setup, a table of the defaults and how to change each, the common setups, the fake API, and the full-helpoutput, which a test keeps in sync with the tool. The help text was wrong about-pand had no entry for-q. (#385, fixes #102)
๐งน Housekeeping
- ๐ CI actions updated to current majors by @katsugtgz (#377)
- โฌ๏ธ dependency updates (gomega 1.43.0, x/tools 0.50.0, x/text 0.42.0)
- the test suite runs in parallel and CI is about 40% faster on Linux (#388)
New Contributors
- @katsugtgz made their first contribution in #377
Full Changelog: v6.12.2...v6.13.0