nim-drchaos/examples/fuzz_graph.nim

115 lines
3.6 KiB
Nim

# Good seed to try out: -seed=4013847822
when defined(runFuzzTests):
const
MaxNodes = 8 # User defined, statically limits number of nodes.
MaxEdges = 2 # Limits number of edges
type
NodeIdx = distinct int
proc `$`(x: NodeIdx): string {.borrow.}
proc `==`(a, b: NodeIdx): bool {.borrow.}
else:
type
NodeIdx = int
type
Graph*[T] = object
nodes: seq[Node[T]]
Node[T] = object
data: T
edges: seq[NodeIdx]
proc `[]`*[T](x: Graph[T]; idx: Natural): lent T {.inline.} = x.nodes[idx].data
proc `[]`*[T](x: var Graph[T]; idx: Natural): var T {.inline.} = x.nodes[idx].data
proc addNode*[T](x: var Graph[T]; data: sink T) {.nodestroy.} =
x.nodes.add Node[T](data: data, edges: @[])
proc deleteNode*[T](x: var Graph[T]; idx: Natural) =
if idx < x.nodes.len:
x.nodes.delete(idx)
for n in x.nodes.mitems:
if (let position = n.edges.find(idx.NodeIdx); position != -1):
n.edges.delete(position)
proc addEdge*[T](x: var Graph[T]; `from`, to: Natural) =
if `from` < x.nodes.len and to < x.nodes.len:
x.nodes[`from`].edges.add(to.NodeIdx)
proc deleteEdge*[T](x: var Graph[T]; `from`, to: Natural) =
if `from` < x.nodes.len and to < x.nodes.len:
template fromNode: untyped = x.nodes[`from`]
if (let toNodeIdx = fromNode.edges.find(to.NodeIdx); toNodeIdx != -1):
template toNode: untyped = fromNode.edges[toNodeIdx]
fromNode.edges.delete(toNodeIdx)
#x.deleteNode(toNode.int) #sneaky bug?
when defined(runFuzzTests) and isMainModule:
import std/random, drchaos/[mutator, common]
{.experimental: "strictFuncs".}
proc mutate(value: var NodeIdx; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
repeatMutate(mutateEnum(value.int, MaxNodes, r).NodeIdx)
proc mutate[T](value: var seq[Node[T]]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
repeatMutateInplace(mutateSeq(value, tmp, MaxNodes, sizeIncreaseHint, r))
proc mutate(value: var seq[NodeIdx]; sizeIncreaseHint: int; enforceChanges: bool; r: var Rand) =
repeatMutateInplace(mutateSeq(value, tmp, MaxEdges, sizeIncreaseHint, r))
#proc postProcess[T: SomeNumber](x: var seq[Node[T]]; r: var Rand) =
#if x.len >= 8:
#x[0].data = 63
#x[1].data = 3
#x[2].data = -56
#x[3].data = 100
#x[4].data = -100
#x[5].data = -78
#x[6].data = 46
#x[7].data = 120
func fuzzTarget(x: Graph[int8]) =
when defined(dumpFuzzInput): debugEcho(x)
if x.nodes.len == 8 and
x.nodes[0].data == 63 and
x.nodes[1].data == 3 and
x.nodes[2].data == -56 and
x.nodes[3].data == 100 and
x.nodes[4].data == -100 and
x.nodes[5].data == -78 and
x.nodes[6].data == 46 and
x.nodes[7].data == 120 and
x.nodes[0].edges.len == 2 and
x.nodes[0].edges[0] == 1.NodeIdx and
x.nodes[0].edges[1] == 2.NodeIdx and
x.nodes[1].edges.len == 2 and
x.nodes[1].edges[0] == 3.NodeIdx and
x.nodes[1].edges[1] == 4.NodeIdx and
x.nodes[2].edges.len == 2 and
x.nodes[2].edges[0] == 5.NodeIdx and
x.nodes[2].edges[1] == 6.NodeIdx and
x.nodes[3].edges.len == 1 and
x.nodes[3].edges[0] == 7.NodeIdx and
x.nodes[4].edges.len == 0 and
x.nodes[5].edges.len == 0 and
x.nodes[6].edges.len == 0 and
x.nodes[7].edges.len == 0:
doAssert false
defaultMutator(fuzzTarget)
#(nodes: @[
#(data: 63, edges: @[1, 2]),
#(data: 3, edges: @[3, 4]),
#(data: -56, edges: @[5, 6]),
#(data: 100, edges: @[7]),
#(data: -100, edges: @[]),
#(data: -78, edges: @[]),
#(data: 46, edges: @[]),
#(data: 120, edges: @[])
#])