{"id":45345878,"url":"https://github.com/xakep666/monkey","last_synced_at":"2026-02-21T11:30:43.531Z","repository":{"id":42486692,"uuid":"453642450","full_name":"xakep666/monkey","owner":"xakep666","description":"Library for monkey-patching functions in Go","archived":false,"fork":false,"pushed_at":"2022-04-03T14:29:09.000Z","size":35,"stargazers_count":24,"open_issues_count":2,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-06-19T11:37:55.408Z","etag":null,"topics":["go","monkey-patching"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xakep666.png","metadata":{"files":{"readme":"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}},"created_at":"2022-01-30T09:54:47.000Z","updated_at":"2023-09-08T18:31:07.000Z","dependencies_parsed_at":"2022-09-06T01:50:18.708Z","dependency_job_id":null,"html_url":"https://github.com/xakep666/monkey","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/xakep666/monkey","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xakep666%2Fmonkey","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xakep666%2Fmonkey/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xakep666%2Fmonkey/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xakep666%2Fmonkey/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xakep666","download_url":"https://codeload.github.com/xakep666/monkey/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xakep666%2Fmonkey/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29679772,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T11:29:27.227Z","status":"ssl_error","status_checked_at":"2026-02-21T11:29:20.292Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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","monkey-patching"],"created_at":"2026-02-21T11:30:42.569Z","updated_at":"2026-02-21T11:30:43.524Z","avatar_url":"https://github.com/xakep666.png","language":"Go","readme":"Monkey\n========\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/xakep666/monkey.svg)](https://pkg.go.dev/github.com/xakep666/monkey)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Go Test](https://github.com/xakep666/monkey/actions/workflows/testing.yml/badge.svg)](https://github.com/xakep666/monkey/actions/workflows/testing.yml)\n\n\"Monkey\" is a library for monkey-patching functions. \nThis may be useful to get determined test result with functions that have side effect (like `time.Now()`).\n\n# Why does this library exist?\n\nEarlier I found library [github.com/bouk/monkey](https://github.com/bouk/monkey) with same name and functionality and sometimes used it in tests.\nBut this library was unstable, and currently it's archived. So I decided to create new one with different approach.\n\n# Usage\n\nMonkey-patching `time.Now()` in tests:\n```go\npackage sometest\n\nimport (\n\t\"testing\"\n\t\"time\"\n\t\n\t\"github.com/xakep666/monkey\"\n)\n\nfunc init() {\n\tmonkey.NewPatcher().\n\t\tApply(func(patcher *monkey.Patcher) {\n\t\t\tmonkey.RegisterReplacement(patcher, time.Now, func() time.Time {\n\t\t\t\treturn time.Date(1980, 1, 2, 3, 4, 5, 6, time.UTC)\n\t\t\t})\n\t\t}).\n\t\tMustPatchAndExec()\n}\n\nfunc TestTime(t *testing.T) {\n\tif now := time.Now(); !now.Equal(time.Date(1980, 1, 2, 3, 4, 5, 6, time.UTC)) {\n\t\tt.Errorf(\"Time not patched, returned: %s\", now)\n\t}\n}\n```\n\nMore examples can be found [here](example/main.go).\n\n# How does it work\n\n* Developer register own replacements for specified functions.\n* Some checks performed i.e. for cyclic replacements.\n* Current executable copied to temporary directory. Further operations will be performed with new temporary executable.\n* Unconditional jump instructions inserted at the beginning of specified functions.\n* New patched binary executed.\n\nTo prevent recursive self-(re)start this library adds special environment variable when it starts patched binary.\n\n# Comparison with `github.com/bouk/monkey`\n\nUnlike mentioned library this performs patching _before_ binary execution. This results in major advantages but\nhas same disadvantages.\n\nAdvantages:\n* No `unsafe` imported.\n* No `mprotect`-like system calls. Some systems refused to set writeable and executable flag on pages.\n* Process memory (executable code) not modified in runtime.\n* No data-races during patch and call processes. It follows from the previous paragraph.\n\nDisadvantages:\n* Disk activity (writing to temporary folder).\n* Impossible to \"unpatch\" or somehow call original version of function.\n* Sometimes may fail to locate address of function inside executable.\n\nHere is some points why patch may fail:\n* OS temp directory not available for writing or binaries executing.\n* Unsupported architecture. This library contains binary opcodes of unconditional jump instructions for different architectures.\n* Target function inlined by compiler. To avoid this use `//go:noinline` pragma or `-gcflags=-l` compiler flag.\n* Attempt to patch interface method. But sometimes it may work (see example).\n* Missing symbol table and/or PC-Line table needed to locate function address in executable by name. I've seen this only on Windows with under such circumstances:\n  * `go test` without `-o`\n  * `go run`\n  * `go build` with `-ldflags=-s`\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxakep666%2Fmonkey","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxakep666%2Fmonkey","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxakep666%2Fmonkey/lists"}