115 lines
3.6 KiB
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: @[])
|
|
#])
|