From 6501a611ba1c26c5d84de0ce2dd9189008962948 Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Tue, 27 Aug 2024 18:52:53 +0200 Subject: [PATCH] Add simple mocking mechanism. --- tests/utils/mock.nim | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/utils/mock.nim diff --git a/tests/utils/mock.nim b/tests/utils/mock.nim new file mode 100644 index 000000000..d090ff18a --- /dev/null +++ b/tests/utils/mock.nim @@ -0,0 +1,48 @@ +# Sourced from https://forum.nim-lang.org/t/9255#60617 + +import posix + +type Instr {.union.} = object + bytes: array[8, byte] + value: uint64 + +proc mockImpl*(target, replacement: pointer) = + # YOLO who needs alignment + #doAssert (cast[ByteAddress](target) and ByteAddress(0x07)) == 0 + var page = cast[pointer](cast[ByteAddress](target) and (not 0xfff)) + doAssert mprotect(page, 4096, PROT_WRITE or PROT_EXEC) == 0 + let rel = cast[ByteAddress](replacement) - cast[ByteAddress](target) - 5 + var instr = Instr( + bytes: [ + 0xe9.byte, + (rel shr 0).byte, + (rel shr 8).byte, + (rel shr 16).byte, + (rel shr 24).byte, + 0, + 0, + 0, + ] + ) + cast[ptr uint64](target)[] = instr.value + doAssert mprotect(page, 4096, PROT_EXEC) == 0 + +# Note: Requires manual cleanup +# Usage Example: +# proc helloWorld(): string = +# "Hello, World!" +# +# echo helloWorld() # "Hello, World!" +# +# let backup = helloWorld +# mock(helloWorld): +# proc mockedHellWorld(): string = +# "Mocked Hello, World!" +# mockedHellWorld +# +# echo helloWorld() # "Mocked Hello, World!" +# +# mock(helloWorld): +# backup +template mock*(target, replacement: untyped): untyped = + mockImpl(cast[pointer](target), cast[pointer](replacement))