{"id":36491893,"url":"https://github.com/qrdl/testaroli","last_synced_at":"2026-02-14T09:10:07.742Z","repository":{"id":217090056,"uuid":"743064661","full_name":"qrdl/testaroli","owner":"qrdl","description":"Monkey patching unit testing utility for Go","archived":false,"fork":false,"pushed_at":"2026-02-07T20:10:53.000Z","size":134,"stargazers_count":24,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-08T04:32:43.870Z","etag":null,"topics":["go","golang","golang-package","monkey-patching","unit-testing"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/qrdl.png","metadata":{"files":{"readme":"docs/README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-01-14T07:59:13.000Z","updated_at":"2026-02-07T19:50:49.000Z","dependencies_parsed_at":"2024-04-18T08:31:12.973Z","dependency_job_id":"8463e8c3-b042-4b37-ab3f-f9b232c8291b","html_url":"https://github.com/qrdl/testaroli","commit_stats":null,"previous_names":["qrdl/testaroli"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/qrdl/testaroli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qrdl%2Ftestaroli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qrdl%2Ftestaroli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qrdl%2Ftestaroli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qrdl%2Ftestaroli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/qrdl","download_url":"https://codeload.github.com/qrdl/testaroli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/qrdl%2Ftestaroli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29441285,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-14T07:24:13.446Z","status":"ssl_error","status_checked_at":"2026-02-14T07:23:58.969Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","golang","golang-package","monkey-patching","unit-testing"],"created_at":"2026-01-12T01:56:40.357Z","updated_at":"2026-02-14T09:10:07.735Z","avatar_url":"https://github.com/qrdl.png","language":"Go","readme":"# testaroli\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/qrdl/testaroli.svg)](https://pkg.go.dev/github.com/qrdl/testaroli)\n[![Go Report Card](https://goreportcard.com/badge/github.com/qrdl/testaroli)](https://goreportcard.com/report/github.com/qrdl/testaroli)\n[![Tests](https://github.com/qrdl/testaroli/actions/workflows/go.yml/badge.svg?query=branch%3Amain)](https://github.com/qrdl/testaroli/actions/workflows/go.yml?query=branch%3Amain)\n[![CodeQL](https://github.com/qrdl/testaroli/workflows/CodeQL/badge.svg?query=branch%3Amain)](https://github.com/qrdl/testaroli/actions/workflows/github-code-scanning/codeql?query=branch%3Amain)\n[![codecov](https://codecov.io/github/qrdl/testaroli/graph/badge.svg)](https://codecov.io/github/qrdl/testaroli)\n[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fqrdl%2Ftestaroli.svg?type=small)](https://app.fossa.io/projects/git%2Bgithub.com%2Fqrdl%2Ftestaroli?ref=badge_small)\n\nPackage `testaroli` provides runtime function and method overriding for Go unit tests through binary patching. This enables testing of error paths and exceptional conditions without requiring dependency injection or interface wrappers.\n\nThis is a testing utility only. It modifies executable code at runtime and must not be used in production.\n\n## Use Cases\n\n`Testaroli` addresses several testing challenges in Go:\n\n- Testing error handling when external dependencies fail (network, filesystem, database)\n- Exercising exceptional code paths that are hard to trigger naturally\n- Testing functions that call standard library or third-party code directly\n- Isolating units under test from their dependencies without modifying production code\n- Testing legacy codebases where adding dependency injection would require extensive refactoring\n- Reducing test fragility - changes to internal implementations (like SQL queries or API calls) don't require updating mocks in every affected test\n\nAs a practical demonstration, `testaroli`'s own test suite uses itself to test exceptional code paths, achieving 99%+ test coverage.\n\n## How It Works\n\n`Testaroli` operates by:\n1. Saving the original function prologue (first bytes of machine code)\n2. Overwriting the function entry point with a jump to the mock implementation\n3. Temporarily modifying memory page protections to allow code modification\n4. Restoring the original prologue after the specified number of calls\n\nThis approach requires platform-specific implementations for memory protection APIs (mprotect on Unix, VirtualProtect on Windows) and CPU architecture-specific instruction handling (x86-64, ARM64).\n\nNote that macOS requires additional complexity due to security restrictions. See [macOS.md](macOS.md) for implementation details.\n\n## Platforms supported\n\n`Testaroli` modifies the actual executable at runtime, therefore is OS and CPU architecture-specific.\n\nOS/arch combinations:\n\n|         | x86-64 | ARM64  |\n|---------|:------:|:------:|\n| Linux   | ✅     | ✅     |\n| Windows | ✅     | ✅[^1] |\n| macOS   | ✅     | ✅     |\n| BSD[^2] | ✅     | ✅     |\n\n[^1]: I could only get it working using [MSYS CLANGARM64](https://www.msys2.org/docs/arm64/) shell, see [this issue](https://github.com/qrdl/testaroli/issues/44) for more details.\n\n[^2]: This package was tested on FreeBSD but it should work on other BSD flavours (NetBSD, OpenBSD and DragonFly BSD) as well.\n\n## Command line options\n\nIt is recommended to switch off compiler optimisations and disable function inlining using `-gcflags=\"all=-N -l\"` CLI option when running tests, like this:\n\n`go test -gcflags=\"all=-N -l\" ./...`\n\nIf you plan to run tests from VS Code, add `\"go.testFlags\": [ \"-gcflags\", \"all=-N -l\" ]` to [settings.json](https://code.visualstudio.com/docs/getstarted/settings#_settings-json-file) file.\n\nTypical use:\n```go\nimport . \"github.com/qrdl/testaroli\"\n\n// Test function foo() which calls bar() internally.\nfunc foo() error {\n    ...\n    if err := bar(42); err != nil {\n        return err\n    }\n    ...\n}\n\nfunc bar(baz int) error {\n    ...\n}\n\nfunc TestBarFailing(t *testing.T) {\n    // Override bar() to verify it receives the correct\n    // argument and returns a predefined result.\n    Override(TestingContext(t), bar, Once, func(a int) error {\n        Expectation().CheckArgs(a)  // \u003c-- arg value checked here\n        return ErrInvalid\n    })(42) // \u003c-- expected argument value\n\n    err := foo()\n    if !errors.Is(err, ErrInvalid) {\n        t.Errorf(\"unexpected %v\", err)\n    }\n    if err = ExpectationsWereMet(); err != nil {\n        t.Error(err)\n    }\n}\n```\n\nIt is also possible to override functions and methods in other packages, including ones from standard library, as in the example below. Note that method receiver becomes the\nfirst argument of the mock function.\n\n```go\nfunc TestFoo(t *testing.T) {\n    Override(TestingContext(t), (*os.File).Read, Once, func(f *os.File, b []byte) (n int, err error) {\n        Expectation()\n        copy(b, []byte(\"foo\"))\n        return 3, nil\n    })\n\n    f, _ := os.Open(\"test.file\")\n    defer f.Close()\n    buf := make([]byte, 3)\n    n, _ := f.Read(buf)\n    if n != 3 || string(buf) != \"foo\" {\n        t.Errorf(\"unexpected file content %s\", string(buf))\n    }\n    if err = ExpectationsWereMet(); err != nil {\n        t.Error(err)\n    }\n}\n```\nSee more advanced usage examples in [examples](../examples) directory. For detailed documentation see [Go reference](https://pkg.go.dev/github.com/qrdl/testaroli).\n\n## Troubleshooting\n\nHaving issues? Check the [Troubleshooting Guide](troubleshooting.md) for solutions to common problems.\n\n## For AI Assistants\n\nThis repository includes machine-readable documentation to help AI coding assistants generate testaroli overrides:\n\n- **[SKILLS.md](../SKILLS.md)** - Comprehensive function override generation patterns and step-by-step instructions\n- **[AGENTS.md](../AGENTS.md)** - Project architecture, design patterns, and technical implementation details\n- **[skill.yaml](../skill.yaml)** - Structured metadata for skill discovery and AI integration\n\nAI assistants can reference these files to:\n- Generate proper testaroli override code following established patterns\n- Understand the library architecture and capabilities\n- Suggest appropriate override strategies for different testing scenarios\n- Validate argument expectations and track mock calls correctly\n\nDevelopers can also use SKILLS.md as a quick reference guide with copy-paste patterns for common testing scenarios.\n\n## Limitations\n\n### Generic Functions\n\nOverride generic functions by using function references instead of direct calls. The [Generic Functions Guide](generics.md) shows complete patterns and examples for working with generics.\n\n### Interface Methods\n\nInterface methods must be overridden at the concrete type level, not the interface level. Override the type method that implements the interface instead. See the [Interface Methods Guide](interfaces.md) for patterns and examples.\n\n### Other Constraints\n\n- **Testing only** - Never use testaroli in production code\n- **Compiler flags required** - Must use `-gcflags=\"all=-N -l\"` to disable optimizations and inlining\n- **Platform-specific** - Only works on supported OS/architecture combinations (see table above)\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqrdl%2Ftestaroli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqrdl%2Ftestaroli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqrdl%2Ftestaroli/lists"}