Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/cch123/supermonkey
Patch all Go functions for testing
https://github.com/cch123/supermonkey
Last synced: 6 days ago
JSON representation
Patch all Go functions for testing
- Host: GitHub
- URL: https://github.com/cch123/supermonkey
- Owner: cch123
- License: mit
- Created: 2020-09-03T11:48:09.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-12-03T19:24:28.000Z (about 1 year ago)
- Last Synced: 2024-12-29T14:19:19.918Z (13 days ago)
- Language: Go
- Homepage:
- Size: 78.1 KB
- Stars: 254
- Watchers: 4
- Forks: 17
- Open Issues: 10
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
- my-awesome - cch123/supermonkey - 12 star:0.3k fork:0.0k Patch all Go functions for testing (Go)
- go-awesome - SuperMonkey - Make private methods testable (Open source library / Test)
README
# SuperMonkey
![gopher](https://user-images.githubusercontent.com/29589055/102566226-0a23b700-411a-11eb-879e-8b58b6a1c8d6.png)
This lib is inspired by https://github.com/bouk/monkey, and uses some of the code
## Introduction
Patch all functions without limits, including which are unexported
**Warning** : please add -l to your gcflags or add `//go:noinline` to func which you want to patch.
## when running in tests
you should run this lib under a go mod project and provide the full project path
**Warning** : use `go test -ldflags="-s=false" -gcflags="-l"` to enable symbol table and disable inline.
```
2023/04/23 14:01:05 reading /root/tmp/go-build541175936/b001/exe/a: no symbol section
2023/04/23 14:01:05 reading /root/tmp/go-build541175936/b001/exe/a: no symbols
```
if you has this problem, just set `-ldflags="-s=false"`## when running not in tests
### patch private function
#### normal
```go
package mainimport (
"fmt"sm "github.com/cch123/supermonkey"
)func main() {
fmt.Println("original function output:")
heyHey()patchGuard := sm.Patch(heyHey, func() {
fmt.Println("please be polite")
})
fmt.Println("after patch, function output:")
heyHey()patchGuard.Unpatch()
fmt.Println("unpatch, then output:")
heyHey()
}//go:noinline
func heyHey() {
fmt.Println("fake")
}
```> go run -gcflags="-l" yourfile.go
#### full symbol name
```go
package mainimport (
"fmt"sm "github.com/cch123/supermonkey"
)func main() {
fmt.Println("original function output:")
heyHeyHey()patchGuard := sm.PatchByFullSymbolName("main.heyHeyHey", func() {
fmt.Println("please be polite")
})
fmt.Println("after patch, function output:")
heyHeyHey()patchGuard.Unpatch()
fmt.Println("unpatch, then output:")
heyHeyHey()
}//go:noinline
func heyHeyHey() {
fmt.Println("fake")
}
```> go run -gcflags="-l" yourfile.go
### patch private instance method
#### normal
```go
package mainimport (
"fmt"sm "github.com/cch123/supermonkey"
)type person struct{ name string }
//go:noinline
func (p *person) speak() {
fmt.Println("my name is ", p.name)
}func main() {
var p = person{"Lance"}
fmt.Println("original function output:")
p.speak()patchGuard := sm.Patch((*person).speak, func(*person) {
fmt.Println("we are all the same")
})
fmt.Println("after patch, function output:")
p.speak()patchGuard.Unpatch()
fmt.Println("unpatch, then output:")
p.speak()
}
```> go run -gcflags="-l" yourfile.go
#### full symbol name
```go
package mainimport (
"fmt"
"unsafe"sm "github.com/cch123/supermonkey"
)type person struct{ name string }
//go:noinline
func (p *person) speak() {
fmt.Println("my name is ", p.name)
}func main() {
var p = person{"Linda"}
fmt.Println("original function output:")
p.speak()patchGuard := sm.PatchByFullSymbolName("main.(*person).speak", func(ptr uintptr) {
p = (*person)(unsafe.Pointer(ptr))
fmt.Println(p.name, ", we are all the same")
})
fmt.Println("after patch, function output:")
p.speak()patchGuard.Unpatch()
fmt.Println("unpatch, then output:")
p.speak()
}
``````go
package mainimport (
"context"
"fmt"sm "github.com/cch123/supermonkey"
)type Bar struct {
Name string
}type Foo struct{}
func (*Foo) MyFunc(ctx context.Context) (*Bar, error) {
return &Bar{"Bar"}, nil
}func main() {
f := &Foo{}
fmt.Println("original function output:")
fmt.Println(f.MyFunc(nil))//patchGuard := sm.PatchByFullSymbolName("main.(*Foo).MyFunc", func(_ *Foo, ctx context.Context) (*Bar, error) {
patchGuard := sm.PatchByFullSymbolName("main.(*Foo).MyFunc", func(_ uintptr, ctx context.Context) (*Bar, error) {
return &Bar{"Not bar"}, nil
})fmt.Println("after patch, function output:")
fmt.Println(f.MyFunc(nil))patchGuard.Unpatch()
fmt.Println("unpatch, then output:")
fmt.Println(f.MyFunc(nil))
}
```> go run -gcflags="-l" yourfile.go
## Authors
[cch123](https://github.com/cch123)
[Mutated1994](https://github.com/Mutated1994)