monkey

package
v2.0.0-alpha.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 25, 2022 License: MIT Imports: 14 Imported by: 0

README

This package is a fork of https://github.com/bouk/monkey.

As you may expect, this package is unsafe and fragile and probably crash you program, it is only recommended for testing usage.

Notes

  1. Monkey sometimes fails to patch a function if inlining is enabled. Try running your tests with inlining disabled, for example: -gcflags=-l (below go1.10) or -gcflags=all=-l (go1.10 and above). The same command line argument can also be used for build.
  2. Monkey won't work on some security-oriented operating system that don't allow memory pages to be both write and execute at the same time. With the current approach there's not really a reliable fix for this.
  3. Monkey is super unsafe, be sure you know what you are doing.

References

  1. https://github.com/bouk/monkey
  2. https://github.com/brahma-adshonor/gohook
  3. https://www.cnblogs.com/catch/p/10973611.html
  4. https://onedrive.live.com/View.aspx?resid=7804A3BDAEB13A9F!58083&authkey=!AKVlLS9s9KYh07s

Documentation

Overview

Example
beforePatch := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
fmt.Printf("original: %v\n", beforePatch)

patch := PatchFunc(MyTimeFunc, func(year, month, day, hour, min, sec, nsec int) time.Time {
	return time.Date(2001, 1, 1, 1, 1, 1, 1, time.UTC)
})
duringPatch := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
fmt.Printf("patched: %v\n", duringPatch)

patch.Delete()
unpatched := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
fmt.Printf("unpatched: %v\n", unpatched)

fmt.Printf("before AutoUnpatch\n")

AutoUnpatch(func() {
	tmp := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, before mock: %v\n", tmp)

	// We can use `Return` to return specified values.
	Mock().Target(MyTimeFunc).
		Return(time.Date(2001, time.January, 1, 1, 1, 1, 1, time.UTC)).
		Build()
	tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, after mock: %v\n", tmp)

	var innerFunc = func(year, month, day, hour, min, sec, nsec int) time.Time {
		return time.Date(2002, time.February, 2, 2, 2, 2, 2, time.UTC)
	}

	AutoUnpatch(func() {
		tmp := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
		fmt.Printf("inner AutoUnpatch, before mock: %v\n", tmp)

		// We can also use `To` to specify a replacement function.
		Mock().Target(MyTimeFunc).To(innerFunc).Build()
		tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
		fmt.Printf("inner AutoUnpatch, after mock: %v\n", tmp)
	})

	tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, after inner: %v\n", tmp)

	// In AutoUnpatch, we can also use the Patch* functions.

	// Static function works.
	PatchFunc(MyTimeFunc, mock333)
	tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, after inner mock333: %v\n", tmp)

	// Closure also works.
	var fakeTime = time.Date(2004, time.April, 4, 4, 4, 4, 4, time.UTC)
	var mock444 = func(year, month, day, hour, min, sec, nsec int) time.Time {
		return fakeTime
	}
	PatchFunc(MyTimeFunc, mock444)
	tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, after inner mock444: %v\n", tmp)

	// We can also patch a function by name.
	Mock().ByName("github.com/jxskiss/gopkg/v2/monkey.MyTimeFunc",
		(func(year, month, day, hour, min, sec, nsec int) time.Time)(nil)).
		Return(time.Date(2005, time.May, 5, 5, 5, 5, 5, time.UTC)).
		Build()
	tmp = MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
	fmt.Printf("with AutoUnpatch, ByName: %v\n", tmp)
})

afterAutoUnpatch := MyTimeFunc(2021, 2, 3, 4, 5, 6, 7)
fmt.Printf("after AutoUnpatch: %v\n", afterAutoUnpatch)
Output:

original: 2021-02-03 04:05:06.000000007 +0000 UTC
patched: 2001-01-01 01:01:01.000000001 +0000 UTC
unpatched: 2021-02-03 04:05:06.000000007 +0000 UTC
before AutoUnpatch
with AutoUnpatch, before mock: 2021-02-03 04:05:06.000000007 +0000 UTC
with AutoUnpatch, after mock: 2001-01-01 01:01:01.000000001 +0000 UTC
inner AutoUnpatch, before mock: 2001-01-01 01:01:01.000000001 +0000 UTC
inner AutoUnpatch, after mock: 2002-02-02 02:02:02.000000002 +0000 UTC
with AutoUnpatch, after inner: 2001-01-01 01:01:01.000000001 +0000 UTC
with AutoUnpatch, after inner mock333: 2003-03-03 03:03:03.000000003 +0000 UTC
with AutoUnpatch, after inner mock444: 2004-04-04 04:04:04.000000004 +0000 UTC
with AutoUnpatch, ByName: 2005-05-05 05:05:05.000000005 +0000 UTC
after AutoUnpatch: 2021-02-03 04:05:06.000000007 +0000 UTC

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AutoUnpatch

func AutoUnpatch(f func())

AutoUnpatch encapsulates a function with a context, which automatically unpatch all patches applied within function f.

func Mock

func Mock() *mock

Mock returns a mock object which helps to do mocking.

Types

type Patch

type Patch struct {
	// contains filtered or unexported fields
}

Patch holds the patch data of a patch target and its replacement.

func PatchByName

func PatchByName(name string, repl interface{}) *Patch

PatchByName replaces a function with replacement by it's name. TargetName should be the fully-qualified name of the target function or method. If the target cannot be found or the replacement type does not match, it panics.

func PatchFunc

func PatchFunc(target, repl interface{}) *Patch

PatchFunc replaces a function with replacement. If target or replacement is not a function or their types do not match, it panics.

func PatchMethod

func PatchMethod(target interface{}, method string, repl interface{}) *Patch

PatchMethod replaces a target's method with replacement. Replacement should expect the receiver (of type target) as the first argument. If the method cannot be found or the replacement type does not match, it panics.

func PatchVar

func PatchVar(targetAddr, repl interface{}) *Patch

PatchVar replaces target's value with replacement. If type of target and repl does not match, it panics.

Example
var someVar = 1234
fmt.Printf("original: %v\n", someVar)

patch := PatchVar(&someVar, 2345)
fmt.Printf("patched: %v\n", someVar)

patch.Delete()
fmt.Printf("unpatched: %v\n", someVar)

fmt.Printf("before AutoUnpatch\n")

AutoUnpatch(func() {
	fmt.Printf("with AutoUnpatch, before patch: %v\n", someVar)

	PatchVar(&someVar, 3456)
	fmt.Printf("with AutoUnpatch, after patch: %v\n", someVar)

	AutoUnpatch(func() {
		fmt.Printf("inner AutoUnpatch, before patch: %v\n", someVar)

		PatchVar(&someVar, 4567)
		fmt.Printf("inner AutoUnpatch, after patch: %v\n", someVar)
	})

	fmt.Printf("with AutoUnpatch, after inner: %v\n", someVar)

	// Patch again.
	PatchVar(&someVar, 5678)
	fmt.Printf("with AutoUnpatch, patch again: %v\n", someVar)
})

fmt.Printf("after AutoUnpatch: %v\n", someVar)
Output:

original: 1234
patched: 2345
unpatched: 1234
before AutoUnpatch
with AutoUnpatch, before patch: 1234
with AutoUnpatch, after patch: 3456
inner AutoUnpatch, before patch: 3456
inner AutoUnpatch, after patch: 4567
with AutoUnpatch, after inner: 3456
with AutoUnpatch, patch again: 5678
after AutoUnpatch: 1234

func (*Patch) Delete

func (p *Patch) Delete()

Delete resets target to the state before applying the patch.

func (*Patch) Origin

func (p *Patch) Origin() interface{}

Origin returns the original target. For a function, it returns a function which runs the original code. For a variable, it returns the original value of the target variable.

Example
var someVar = 1234

AutoUnpatch(func() {
	fmt.Printf("before patch, testpkg.A: %v\n", testpkg.A())
	fmt.Printf("before patch, someVar: %v\n", someVar)

	patch1 := Mock().Target(testpkg.A).Return("ExamplePatch_Origin").Build()
	patch2 := PatchVar(&someVar, 5678)

	fmt.Printf("after patch, testpkg.A: %v\n", testpkg.A())
	fmt.Printf("after patch, someVar: %v\n", someVar)

	fmt.Printf("after patch, original testpkg.A: %v\n",
		patch1.Origin().(func() string)())
	fmt.Printf("after patch, original someVar: %v\n", patch2.Origin())
})
Output:

before patch, testpkg.A: testpkg.a
before patch, someVar: 1234
after patch, testpkg.A: ExamplePatch_Origin
after patch, someVar: 5678
after patch, original testpkg.A: testpkg.a
after patch, original someVar: 1234

func (*Patch) Patch

func (p *Patch) Patch()

Patch applies the patch.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL