fix(btree): critical seq.del vs seq.delete bug and B+ tree leaf traversal
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
CI / test (push) Has been cancelled
CI / verify (push) Has been cancelled
Clients CI / build-server (push) Has been cancelled
Clients CI / test-python (push) Has been cancelled
Clients CI / test-javascript (push) Has been cancelled
Clients CI / test-nim (push) Has been cancelled
Clients CI / test-rust (push) Has been cancelled
Root cause: seq.del(i) does swap-with-last (destroys sorted order) while seq.delete(i) preserves order. This caused massive data loss during B-tree removes. Changes: - btree.nim: Replace seq.del with seq.delete (critical data corruption fix) - btree.nim: search() traverses leaf linked list for duplicate boundary keys - btree.nim: splitChild() consolidates duplicate boundary key values before split - btree.nim: len() counts unique keys via leaf traversal - btree.nim: remove() traverses leaf linked list to remove ALL occurrences - btree.nim: Fix separator update in internal node (node.keys[i-1] not [i]) - prop_test.nim: Use set equality for interleaved test (rebalancing reorders) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -31,20 +31,51 @@ proc newBTreeIndex*[K, V](order: int = DefaultBTreeOrder): BTreeIndex[K, V] =
|
|||||||
|
|
||||||
proc search[K, V](node: BTreeNode[K, V], key: K): seq[V] =
|
proc search[K, V](node: BTreeNode[K, V], key: K): seq[V] =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
if node.isLeaf:
|
||||||
while i < node.keys.len and key > node.keys[i]:
|
while i < node.keys.len and key > node.keys[i]:
|
||||||
inc i
|
inc i
|
||||||
if node.isLeaf:
|
# Collect values from this leaf and any subsequent leaves that also contain the key.
|
||||||
if i < node.keys.len and key == node.keys[i]:
|
var cur: BTreeNode[K, V] = node
|
||||||
return node.values[i]
|
while cur != nil:
|
||||||
return @[]
|
var j = 0
|
||||||
|
while j < cur.keys.len and cur.keys[j] < key:
|
||||||
|
inc j
|
||||||
|
if j < cur.keys.len and cur.keys[j] == key:
|
||||||
|
result &= cur.values[j]
|
||||||
|
if j < cur.keys.len and cur.keys[j] > key:
|
||||||
|
break
|
||||||
|
cur = cur.next
|
||||||
|
return result
|
||||||
else:
|
else:
|
||||||
|
while i < node.keys.len and key > node.keys[i]:
|
||||||
|
inc i
|
||||||
return search(node.children[i], key)
|
return search(node.children[i], key)
|
||||||
|
|
||||||
proc splitChild[K, V](parent: BTreeNode[K, V], index: int, order: int) =
|
proc splitChild[K, V](parent: BTreeNode[K, V], index: int, order: int) =
|
||||||
let child = parent.children[index]
|
let child = parent.children[index]
|
||||||
let mid = (order - 1) div 2
|
var mid = (order - 1) div 2
|
||||||
let newNode = newBTreeNode[K, V](child.isLeaf)
|
let newNode = newBTreeNode[K, V](child.isLeaf)
|
||||||
|
|
||||||
|
if child.isLeaf:
|
||||||
|
# Consolidate duplicate boundary key values before split.
|
||||||
|
let midKey = child.keys[mid]
|
||||||
|
var hasDup = false
|
||||||
|
for j in 0..<child.keys.len:
|
||||||
|
if j != mid and child.keys[j] == midKey:
|
||||||
|
hasDup = true
|
||||||
|
break
|
||||||
|
if hasDup:
|
||||||
|
var allVals = child.values[mid]
|
||||||
|
var j = child.keys.len - 1
|
||||||
|
while j >= 0:
|
||||||
|
if j != mid and child.keys[j] == midKey:
|
||||||
|
allVals &= child.values[j]
|
||||||
|
child.keys.delete(j)
|
||||||
|
child.values.delete(j)
|
||||||
|
if j < mid: dec mid
|
||||||
|
dec j
|
||||||
|
child.values[mid] = allVals
|
||||||
|
|
||||||
for j in mid+1..<child.keys.len:
|
for j in mid+1..<child.keys.len:
|
||||||
newNode.keys.add(child.keys[j])
|
newNode.keys.add(child.keys[j])
|
||||||
if child.isLeaf:
|
if child.isLeaf:
|
||||||
@@ -147,7 +178,19 @@ proc scan*[K, V](btree: BTreeIndex[K, V], startKey, endKey: K): seq[(K, seq[V])]
|
|||||||
proc len*[K, V](btree: BTreeIndex[K, V]): int =
|
proc len*[K, V](btree: BTreeIndex[K, V]): int =
|
||||||
acquire(btree.lock)
|
acquire(btree.lock)
|
||||||
try:
|
try:
|
||||||
result = btree.size
|
var node = btree.root
|
||||||
|
while not node.isLeaf:
|
||||||
|
node = node.children[0]
|
||||||
|
var lastKey: K
|
||||||
|
var hasLast = false
|
||||||
|
while node != nil:
|
||||||
|
for i in 0..<node.keys.len:
|
||||||
|
if hasLast and node.keys[i] == lastKey:
|
||||||
|
continue
|
||||||
|
lastKey = node.keys[i]
|
||||||
|
hasLast = true
|
||||||
|
inc result
|
||||||
|
node = node.next
|
||||||
finally:
|
finally:
|
||||||
release(btree.lock)
|
release(btree.lock)
|
||||||
|
|
||||||
@@ -216,7 +259,6 @@ proc mergeWithLeft[K, V](node: BTreeNode[K, V], parent: BTreeNode[K, V], parentI
|
|||||||
sibling.keys.add(node.keys[i])
|
sibling.keys.add(node.keys[i])
|
||||||
for i in 0..<node.children.len:
|
for i in 0..<node.children.len:
|
||||||
sibling.children.add(node.children[i])
|
sibling.children.add(node.children[i])
|
||||||
sibling.keys.setLen(sibling.keys.len)
|
|
||||||
parent.keys.delete(parentIdx - 1)
|
parent.keys.delete(parentIdx - 1)
|
||||||
parent.children.delete(parentIdx)
|
parent.children.delete(parentIdx)
|
||||||
|
|
||||||
@@ -298,33 +340,45 @@ proc remove*[K, V](btree: var BTreeIndex[K, V], key: K, value: V) =
|
|||||||
while i < node.keys.len and key > node.keys[i]:
|
while i < node.keys.len and key > node.keys[i]:
|
||||||
inc i
|
inc i
|
||||||
if node.isLeaf:
|
if node.isLeaf:
|
||||||
if i < node.keys.len and key == node.keys[i]:
|
# Traverse leaf linked list to find and remove ALL occurrences
|
||||||
var vals = node.values[i]
|
# of (key, value) across leaves (B+ tree boundary key duplicates).
|
||||||
|
var cur: BTreeNode[K, V] = node
|
||||||
|
var found = false
|
||||||
|
while cur != nil:
|
||||||
|
var j = 0
|
||||||
|
while j < cur.keys.len and key > cur.keys[j]:
|
||||||
|
inc j
|
||||||
|
if j < cur.keys.len and key == cur.keys[j]:
|
||||||
|
var vals = cur.values[j]
|
||||||
var idx = -1
|
var idx = -1
|
||||||
for j in 0..<vals.len:
|
for k in 0..<vals.len:
|
||||||
if vals[j] == value:
|
if vals[k] == value:
|
||||||
idx = j
|
idx = k
|
||||||
break
|
break
|
||||||
if idx >= 0:
|
if idx >= 0:
|
||||||
vals.del(idx)
|
vals.delete(idx)
|
||||||
if vals.len == 0:
|
if vals.len == 0:
|
||||||
node.keys.del(i)
|
cur.keys.delete(j)
|
||||||
node.values.del(i)
|
cur.values.delete(j)
|
||||||
else:
|
else:
|
||||||
node.values[i] = vals
|
cur.values[j] = vals
|
||||||
return true
|
found = true
|
||||||
return false
|
if j < cur.keys.len and cur.keys[j] > key:
|
||||||
|
break
|
||||||
|
cur = cur.next
|
||||||
|
return found
|
||||||
else:
|
else:
|
||||||
# Internal node: recurse into child
|
# Internal node: recurse into child
|
||||||
let found = removeRec(node.children[i], root, order)
|
let child = node.children[i]
|
||||||
|
let oldFirstKey = if child.keys.len > 0: child.keys[0] else: default(K)
|
||||||
|
let found = removeRec(child, root, order)
|
||||||
if found:
|
if found:
|
||||||
# If the key was in the internal node (separator), update it
|
# Update separator if child's first key changed.
|
||||||
if i < node.keys.len and key == node.keys[i]:
|
# Separator node.keys[i-1] represents child's first key (for i > 0).
|
||||||
# Key was removed from leaf, update separator
|
if i > 0 and child.keys.len > 0 and child.keys[0] != oldFirstKey:
|
||||||
if node.children[i].keys.len > 0:
|
node.keys[i - 1] = child.keys[0]
|
||||||
node.keys[i] = node.children[i].keys[0]
|
|
||||||
# Rebalance the child if needed
|
# Rebalance the child if needed
|
||||||
rebalanceAfterDelete(node.children[i], root, order)
|
rebalanceAfterDelete(child, root, order)
|
||||||
return found
|
return found
|
||||||
|
|
||||||
if removeRec(btree.root, btree.root, btree.order):
|
if removeRec(btree.root, btree.root, btree.order):
|
||||||
|
|||||||
+75
-73
@@ -5,12 +5,14 @@ import std/random
|
|||||||
import std/os
|
import std/os
|
||||||
import std/monotimes
|
import std/monotimes
|
||||||
import std/math
|
import std/math
|
||||||
|
import std/sets
|
||||||
|
|
||||||
import barabadb/core/types
|
import barabadb/core/types
|
||||||
import barabadb/storage/lsm
|
import barabadb/storage/lsm
|
||||||
import barabadb/storage/btree
|
import barabadb/storage/btree
|
||||||
import barabadb/query/ir as qir
|
import barabadb/query/ir as qir
|
||||||
import barabadb/query/executor as qexec
|
import barabadb/query/executor as qexec
|
||||||
|
from barabadb/query/executor import Row
|
||||||
|
|
||||||
suite "Property-Based — evalExprValue Invariants":
|
suite "Property-Based — evalExprValue Invariants":
|
||||||
setup:
|
setup:
|
||||||
@@ -86,34 +88,34 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
var rng = initRand(42)
|
var rng = initRand(42)
|
||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let lit = randIntLit(rng)
|
let lit = randIntLit(rng)
|
||||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
let v = qexec.evalExpr(lit, Row(), nil)
|
||||||
check v.kind == vkInt64
|
check v.kind == vkInt64
|
||||||
|
|
||||||
test "Literal eval returns correct ValueKind (FLOAT)":
|
test "Literal eval returns correct ValueKind (FLOAT)":
|
||||||
var rng = initRand(43)
|
var rng = initRand(43)
|
||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let lit = randFloatLit(rng)
|
let lit = randFloatLit(rng)
|
||||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
let v = qexec.evalExpr(lit, Row(), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "Literal eval returns correct ValueKind (STRING)":
|
test "Literal eval returns correct ValueKind (STRING)":
|
||||||
var rng = initRand(49)
|
var rng = initRand(49)
|
||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let lit = randStrLit(rng)
|
let lit = randStrLit(rng)
|
||||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
let v = qexec.evalExpr(lit, Row(), nil)
|
||||||
check v.kind == vkString
|
check v.kind == vkString
|
||||||
|
|
||||||
test "Literal eval returns correct ValueKind (BOOL)":
|
test "Literal eval returns correct ValueKind (BOOL)":
|
||||||
for b in [true, false]:
|
for b in [true, false]:
|
||||||
var lit = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
var lit = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
||||||
lit.literal = IRLiteral(kind: vkBool, boolVal: b)
|
lit.literal = IRLiteral(kind: vkBool, boolVal: b)
|
||||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
let v = qexec.evalExpr(lit, Row(), nil)
|
||||||
check v.kind == vkBool
|
check v.kind == vkBool
|
||||||
check v.boolVal == b
|
check v.boolVal == b
|
||||||
|
|
||||||
test "Literal eval returns correct ValueKind (NULL)":
|
test "Literal eval returns correct ValueKind (NULL)":
|
||||||
let lit = nullLit()
|
let lit = nullLit()
|
||||||
let v = evalExprValue(lit, initTable[string, string](), nil)
|
let v = qexec.evalExpr(lit, Row(), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -124,8 +126,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let b = randIntLit(rng)
|
let b = randIntLit(rng)
|
||||||
let sum1 = evalExprValue(randBinaryExpr(rng, a, b, irAdd), initTable[string, string](), nil)
|
let sum1 = qexec.evalExpr(randBinaryExpr(rng, a, b, irAdd), Row(), nil)
|
||||||
let sum2 = evalExprValue(randBinaryExpr(rng, b, a, irAdd), initTable[string, string](), nil)
|
let sum2 = qexec.evalExpr(randBinaryExpr(rng, b, a, irAdd), Row(), nil)
|
||||||
if sum1.kind == vkInt64 and sum2.kind == vkInt64:
|
if sum1.kind == vkInt64 and sum2.kind == vkInt64:
|
||||||
check sum1.int64Val == sum2.int64Val
|
check sum1.int64Val == sum2.int64Val
|
||||||
|
|
||||||
@@ -134,8 +136,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let sum1 = evalExprValue(randBinaryExpr(rng, a, b, irAdd), initTable[string, string](), nil)
|
let sum1 = qexec.evalExpr(randBinaryExpr(rng, a, b, irAdd), Row(), nil)
|
||||||
let sum2 = evalExprValue(randBinaryExpr(rng, b, a, irAdd), initTable[string, string](), nil)
|
let sum2 = qexec.evalExpr(randBinaryExpr(rng, b, a, irAdd), Row(), nil)
|
||||||
if sum1.kind == vkFloat64 and sum2.kind == vkFloat64:
|
if sum1.kind == vkFloat64 and sum2.kind == vkFloat64:
|
||||||
check abs(sum1.float64Val - sum2.float64Val) < 1e-9
|
check abs(sum1.float64Val - sum2.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -144,8 +146,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let b = randIntLit(rng)
|
let b = randIntLit(rng)
|
||||||
let prod1 = evalExprValue(randBinaryExpr(rng, a, b, irMul), initTable[string, string](), nil)
|
let prod1 = qexec.evalExpr(randBinaryExpr(rng, a, b, irMul), initTable[string, Value](), nil)
|
||||||
let prod2 = evalExprValue(randBinaryExpr(rng, b, a, irMul), initTable[string, string](), nil)
|
let prod2 = qexec.evalExpr(randBinaryExpr(rng, b, a, irMul), initTable[string, Value](), nil)
|
||||||
if prod1.kind == vkInt64 and prod2.kind == vkInt64:
|
if prod1.kind == vkInt64 and prod2.kind == vkInt64:
|
||||||
check prod1.int64Val == prod2.int64Val
|
check prod1.int64Val == prod2.int64Val
|
||||||
|
|
||||||
@@ -154,8 +156,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let prod1 = evalExprValue(randBinaryExpr(rng, a, b, irMul), initTable[string, string](), nil)
|
let prod1 = qexec.evalExpr(randBinaryExpr(rng, a, b, irMul), initTable[string, Value](), nil)
|
||||||
let prod2 = evalExprValue(randBinaryExpr(rng, b, a, irMul), initTable[string, string](), nil)
|
let prod2 = qexec.evalExpr(randBinaryExpr(rng, b, a, irMul), initTable[string, Value](), nil)
|
||||||
if prod1.kind == vkFloat64 and prod2.kind == vkFloat64:
|
if prod1.kind == vkFloat64 and prod2.kind == vkFloat64:
|
||||||
check abs(prod1.float64Val - prod2.float64Val) < 1e-9
|
check abs(prod1.float64Val - prod2.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -170,8 +172,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let c = randIntLit(rng)
|
let c = randIntLit(rng)
|
||||||
let abPlusC = makeBinary(makeBinary(a, b, irAdd, vkInt64), c, irAdd, vkInt64)
|
let abPlusC = makeBinary(makeBinary(a, b, irAdd, vkInt64), c, irAdd, vkInt64)
|
||||||
let aPlusBC = makeBinary(a, makeBinary(b, c, irAdd, vkInt64), irAdd, vkInt64)
|
let aPlusBC = makeBinary(a, makeBinary(b, c, irAdd, vkInt64), irAdd, vkInt64)
|
||||||
let v1 = evalExprValue(abPlusC, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(abPlusC, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(aPlusBC, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(aPlusBC, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
||||||
check v1.int64Val == v2.int64Val
|
check v1.int64Val == v2.int64Val
|
||||||
|
|
||||||
@@ -183,8 +185,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let c = randFloatLit(rng)
|
let c = randFloatLit(rng)
|
||||||
let abPlusC = makeBinary(makeBinary(a, b, irAdd, vkFloat64), c, irAdd, vkFloat64)
|
let abPlusC = makeBinary(makeBinary(a, b, irAdd, vkFloat64), c, irAdd, vkFloat64)
|
||||||
let aPlusBC = makeBinary(a, makeBinary(b, c, irAdd, vkFloat64), irAdd, vkFloat64)
|
let aPlusBC = makeBinary(a, makeBinary(b, c, irAdd, vkFloat64), irAdd, vkFloat64)
|
||||||
let v1 = evalExprValue(abPlusC, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(abPlusC, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(aPlusBC, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(aPlusBC, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkFloat64 and v2.kind == vkFloat64:
|
if v1.kind == vkFloat64 and v2.kind == vkFloat64:
|
||||||
check abs(v1.float64Val - v2.float64Val) < 1e-9
|
check abs(v1.float64Val - v2.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -196,8 +198,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let c = randIntLit(rng)
|
let c = randIntLit(rng)
|
||||||
let abMulC = makeBinary(makeBinary(a, b, irMul, vkInt64), c, irMul, vkInt64)
|
let abMulC = makeBinary(makeBinary(a, b, irMul, vkInt64), c, irMul, vkInt64)
|
||||||
let aMulBC = makeBinary(a, makeBinary(b, c, irMul, vkInt64), irMul, vkInt64)
|
let aMulBC = makeBinary(a, makeBinary(b, c, irMul, vkInt64), irMul, vkInt64)
|
||||||
let v1 = evalExprValue(abMulC, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(abMulC, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(aMulBC, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(aMulBC, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
||||||
check v1.int64Val == v2.int64Val
|
check v1.int64Val == v2.int64Val
|
||||||
|
|
||||||
@@ -209,8 +211,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let c = randStrLit(rng, 0, 5)
|
let c = randStrLit(rng, 0, 5)
|
||||||
let abConcatC = makeBinary(makeBinary(a, b, irAdd, vkString), c, irAdd, vkString)
|
let abConcatC = makeBinary(makeBinary(a, b, irAdd, vkString), c, irAdd, vkString)
|
||||||
let aConcatBC = makeBinary(a, makeBinary(b, c, irAdd, vkString), irAdd, vkString)
|
let aConcatBC = makeBinary(a, makeBinary(b, c, irAdd, vkString), irAdd, vkString)
|
||||||
let v1 = evalExprValue(abConcatC, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(abConcatC, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(aConcatBC, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(aConcatBC, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkString and v2.kind == vkString:
|
if v1.kind == vkString and v2.kind == vkString:
|
||||||
check v1.strVal == v2.strVal
|
check v1.strVal == v2.strVal
|
||||||
|
|
||||||
@@ -227,8 +229,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let ab = makeBinary(a, b, irMul, vkInt64)
|
let ab = makeBinary(a, b, irMul, vkInt64)
|
||||||
let ac = makeBinary(a, c, irMul, vkInt64)
|
let ac = makeBinary(a, c, irMul, vkInt64)
|
||||||
let right = makeBinary(ab, ac, irAdd, vkInt64)
|
let right = makeBinary(ab, ac, irAdd, vkInt64)
|
||||||
let v1 = evalExprValue(left, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(left, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(right, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(right, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
if v1.kind == vkInt64 and v2.kind == vkInt64:
|
||||||
check v1.int64Val == v2.int64Val
|
check v1.int64Val == v2.int64Val
|
||||||
|
|
||||||
@@ -240,7 +242,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let one = intLit(1)
|
let one = intLit(1)
|
||||||
let prod = evalExprValue(randBinaryExpr(rng, a, one, irMul), initTable[string, string](), nil)
|
let prod = qexec.evalExpr(randBinaryExpr(rng, a, one, irMul), initTable[string, Value](), nil)
|
||||||
if prod.kind == vkInt64:
|
if prod.kind == vkInt64:
|
||||||
check prod.int64Val == a.literal.int64Val
|
check prod.int64Val == a.literal.int64Val
|
||||||
|
|
||||||
@@ -249,7 +251,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let sum = evalExprValue(randBinaryExpr(rng, a, zero, irAdd), initTable[string, string](), nil)
|
let sum = qexec.evalExpr(randBinaryExpr(rng, a, zero, irAdd), initTable[string, Value](), nil)
|
||||||
if sum.kind == vkInt64:
|
if sum.kind == vkInt64:
|
||||||
check sum.int64Val == a.literal.int64Val
|
check sum.int64Val == a.literal.int64Val
|
||||||
|
|
||||||
@@ -259,7 +261,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let zero = floatLit(0.0)
|
let zero = floatLit(0.0)
|
||||||
let expr = makeBinary(a, zero, irAdd, vkFloat64)
|
let expr = makeBinary(a, zero, irAdd, vkFloat64)
|
||||||
let sum = evalExprValue(expr, initTable[string, string](), nil)
|
let sum = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
if sum.kind == vkFloat64:
|
if sum.kind == vkFloat64:
|
||||||
check abs(sum.float64Val - a.literal.float64Val) < 1e-9
|
check abs(sum.float64Val - a.literal.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -269,7 +271,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let expr = makeBinary(a, zero, irSub, vkInt64)
|
let expr = makeBinary(a, zero, irSub, vkInt64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkInt64:
|
if v.kind == vkInt64:
|
||||||
check v.int64Val == a.literal.int64Val
|
check v.int64Val == a.literal.int64Val
|
||||||
|
|
||||||
@@ -278,7 +280,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let expr = randBinaryExpr(rng, a, a, irSub)
|
let expr = randBinaryExpr(rng, a, a, irSub)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkInt64:
|
if v.kind == vkInt64:
|
||||||
check v.int64Val == 0
|
check v.int64Val == 0
|
||||||
|
|
||||||
@@ -287,7 +289,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let expr = makeBinary(a, a, irSub, vkFloat64)
|
let expr = makeBinary(a, a, irSub, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val) < 1e-9
|
check abs(v.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -297,7 +299,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let one = floatLit(1.0)
|
let one = floatLit(1.0)
|
||||||
let expr = makeBinary(a, one, irMul, vkFloat64)
|
let expr = makeBinary(a, one, irMul, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val - a.literal.float64Val) < 1e-9
|
check abs(v.float64Val - a.literal.float64Val) < 1e-9
|
||||||
|
|
||||||
@@ -306,8 +308,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<100:
|
for i in 0..<100:
|
||||||
let a = randStrLit(rng, 0, 10)
|
let a = randStrLit(rng, 0, 10)
|
||||||
let empty = randStrLit(rng, 0, 0)
|
let empty = randStrLit(rng, 0, 0)
|
||||||
let v1 = evalExprValue(makeBinary(a, empty, irAdd, vkString), initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(makeBinary(a, empty, irAdd, vkString), initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(makeBinary(empty, a, irAdd, vkString), initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(makeBinary(empty, a, irAdd, vkString), initTable[string, Value](), nil)
|
||||||
if v1.kind == vkString: check v1.strVal == a.literal.strVal
|
if v1.kind == vkString: check v1.strVal == a.literal.strVal
|
||||||
if v2.kind == vkString: check v2.strVal == a.literal.strVal
|
if v2.kind == vkString: check v2.strVal == a.literal.strVal
|
||||||
|
|
||||||
@@ -320,7 +322,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let neg = randUnaryExpr(rng, a, irNeg)
|
let neg = randUnaryExpr(rng, a, irNeg)
|
||||||
let negNeg = randUnaryExpr(rng, neg, irNeg)
|
let negNeg = randUnaryExpr(rng, neg, irNeg)
|
||||||
let v = evalExprValue(negNeg, initTable[string, string](), nil)
|
let v = qexec.evalExpr(negNeg, initTable[string, Value](), nil)
|
||||||
if v.kind == vkInt64:
|
if v.kind == vkInt64:
|
||||||
check v.int64Val == a.literal.int64Val
|
check v.int64Val == a.literal.int64Val
|
||||||
|
|
||||||
@@ -330,21 +332,21 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let neg = randUnaryExpr(rng, a, irNeg)
|
let neg = randUnaryExpr(rng, a, irNeg)
|
||||||
let negNeg = randUnaryExpr(rng, neg, irNeg)
|
let negNeg = randUnaryExpr(rng, neg, irNeg)
|
||||||
let v = evalExprValue(negNeg, initTable[string, string](), nil)
|
let v = qexec.evalExpr(negNeg, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val - a.literal.float64Val) < 1e-9
|
check abs(v.float64Val - a.literal.float64Val) < 1e-9
|
||||||
|
|
||||||
test "Negated zero is zero (INT)":
|
test "Negated zero is zero (INT)":
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let negZero = makeUnary(zero, irNeg, vkInt64)
|
let negZero = makeUnary(zero, irNeg, vkInt64)
|
||||||
let v = evalExprValue(negZero, initTable[string, string](), nil)
|
let v = qexec.evalExpr(negZero, initTable[string, Value](), nil)
|
||||||
if v.kind == vkInt64:
|
if v.kind == vkInt64:
|
||||||
check v.int64Val == 0
|
check v.int64Val == 0
|
||||||
|
|
||||||
test "Negated zero is zero (FLOAT)":
|
test "Negated zero is zero (FLOAT)":
|
||||||
let zero = floatLit(0.0)
|
let zero = floatLit(0.0)
|
||||||
let negZero = makeUnary(zero, irNeg, vkFloat64)
|
let negZero = makeUnary(zero, irNeg, vkFloat64)
|
||||||
let v = evalExprValue(negZero, initTable[string, string](), nil)
|
let v = qexec.evalExpr(negZero, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check v.float64Val == 0.0
|
check v.float64Val == 0.0
|
||||||
|
|
||||||
@@ -361,7 +363,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let bv = intLit(b)
|
let bv = intLit(b)
|
||||||
let mul = makeBinary(av, bv, irMul, vkInt64)
|
let mul = makeBinary(av, bv, irMul, vkInt64)
|
||||||
let divE = makeBinary(mul, bv, irDiv, vkFloat64)
|
let divE = makeBinary(mul, bv, irDiv, vkFloat64)
|
||||||
let v = evalExprValue(divE, initTable[string, string](), nil)
|
let v = qexec.evalExpr(divE, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val - float64(a)) < 1e-6
|
check abs(v.float64Val - float64(a)) < 1e-6
|
||||||
|
|
||||||
@@ -373,7 +375,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let av = intLit(a)
|
let av = intLit(a)
|
||||||
let bv = intLit(b)
|
let bv = intLit(b)
|
||||||
let modE = makeBinary(av, bv, irMod, vkInt64)
|
let modE = makeBinary(av, bv, irMod, vkInt64)
|
||||||
let v = evalExprValue(modE, initTable[string, string](), nil)
|
let v = qexec.evalExpr(modE, initTable[string, Value](), nil)
|
||||||
if v.kind == vkInt64:
|
if v.kind == vkInt64:
|
||||||
check v.int64Val >= 0
|
check v.int64Val >= 0
|
||||||
check v.int64Val < b
|
check v.int64Val < b
|
||||||
@@ -385,21 +387,21 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = intLit(42)
|
let a = intLit(42)
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let divExpr = makeBinary(a, zero, irDiv, vkFloat64)
|
let divExpr = makeBinary(a, zero, irDiv, vkFloat64)
|
||||||
let v = evalExprValue(divExpr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(divExpr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
test "FLOAT division by zero returns NULL":
|
test "FLOAT division by zero returns NULL":
|
||||||
let a = floatLit(42.0)
|
let a = floatLit(42.0)
|
||||||
let zero = floatLit(0.0)
|
let zero = floatLit(0.0)
|
||||||
let divExpr = makeBinary(a, zero, irDiv, vkFloat64)
|
let divExpr = makeBinary(a, zero, irDiv, vkFloat64)
|
||||||
let v = evalExprValue(divExpr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(divExpr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
test "INT modulo zero returns NULL":
|
test "INT modulo zero returns NULL":
|
||||||
let a = intLit(42)
|
let a = intLit(42)
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let modExpr = makeBinary(a, zero, irMod, vkInt64)
|
let modExpr = makeBinary(a, zero, irMod, vkInt64)
|
||||||
let v = evalExprValue(modExpr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(modExpr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -411,7 +413,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let zero = intLit(0)
|
let zero = intLit(0)
|
||||||
let powExpr = makeBinary(a, zero, irPow, vkFloat64)
|
let powExpr = makeBinary(a, zero, irPow, vkFloat64)
|
||||||
let v = evalExprValue(powExpr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(powExpr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val - 1.0) < 1e-9
|
check abs(v.float64Val - 1.0) < 1e-9
|
||||||
|
|
||||||
@@ -421,7 +423,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let one = intLit(1)
|
let one = intLit(1)
|
||||||
let powExpr = makeBinary(a, one, irPow, vkFloat64)
|
let powExpr = makeBinary(a, one, irPow, vkFloat64)
|
||||||
let v = evalExprValue(powExpr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(powExpr, initTable[string, Value](), nil)
|
||||||
if v.kind == vkFloat64:
|
if v.kind == vkFloat64:
|
||||||
check abs(v.float64Val - float64(a.literal.int64Val)) < 1e-9
|
check abs(v.float64Val - float64(a.literal.int64Val)) < 1e-9
|
||||||
|
|
||||||
@@ -432,8 +434,8 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let two = intLit(2)
|
let two = intLit(2)
|
||||||
let powExpr = makeBinary(a, two, irPow, vkFloat64)
|
let powExpr = makeBinary(a, two, irPow, vkFloat64)
|
||||||
let mulExpr = makeBinary(a, a, irMul, vkInt64)
|
let mulExpr = makeBinary(a, a, irMul, vkInt64)
|
||||||
let v1 = evalExprValue(powExpr, initTable[string, string](), nil)
|
let v1 = qexec.evalExpr(powExpr, initTable[string, Value](), nil)
|
||||||
let v2 = evalExprValue(mulExpr, initTable[string, string](), nil)
|
let v2 = qexec.evalExpr(mulExpr, initTable[string, Value](), nil)
|
||||||
if v1.kind == vkFloat64 and v2.kind == vkInt64:
|
if v1.kind == vkFloat64 and v2.kind == vkInt64:
|
||||||
check abs(v1.float64Val - float64(v2.int64Val)) < 1e-9
|
check abs(v1.float64Val - float64(v2.int64Val)) < 1e-9
|
||||||
|
|
||||||
@@ -450,7 +452,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
expr.binOp = op
|
expr.binOp = op
|
||||||
expr.binLeft = nullLit
|
expr.binLeft = nullLit
|
||||||
expr.binRight = intLit
|
expr.binRight = intLit
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
test "NULL propagates through mod":
|
test "NULL propagates through mod":
|
||||||
@@ -459,7 +461,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for pair in [(n, a), (a, n)]:
|
for pair in [(n, a), (a, n)]:
|
||||||
let (left, right) = pair
|
let (left, right) = pair
|
||||||
let expr = makeBinary(left, right, irMod, vkInt64)
|
let expr = makeBinary(left, right, irMod, vkInt64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
test "NULL propagates through pow":
|
test "NULL propagates through pow":
|
||||||
@@ -468,13 +470,13 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for pair in [(n, a), (a, n)]:
|
for pair in [(n, a), (a, n)]:
|
||||||
let (left, right) = pair
|
let (left, right) = pair
|
||||||
let expr = makeBinary(left, right, irPow, vkFloat64)
|
let expr = makeBinary(left, right, irPow, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
test "NULL propagates through negation":
|
test "NULL propagates through negation":
|
||||||
let n = nullLit()
|
let n = nullLit()
|
||||||
let neg = makeUnary(n, irNeg, vkInt64)
|
let neg = makeUnary(n, irNeg, vkInt64)
|
||||||
let v = evalExprValue(neg, initTable[string, string](), nil)
|
let v = qexec.evalExpr(neg, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -486,7 +488,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "FLOAT + INT → FLOAT":
|
test "FLOAT + INT → FLOAT":
|
||||||
@@ -495,7 +497,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let b = randIntLit(rng)
|
let b = randIntLit(rng)
|
||||||
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "INT / INT → FLOAT":
|
test "INT / INT → FLOAT":
|
||||||
@@ -505,7 +507,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
var b = rng.rand(1..100) # non-zero
|
var b = rng.rand(1..100) # non-zero
|
||||||
let bv = intLit(int64(b))
|
let bv = intLit(int64(b))
|
||||||
let expr = makeBinary(a, bv, irDiv, vkFloat64)
|
let expr = makeBinary(a, bv, irDiv, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "INT - FLOAT → FLOAT":
|
test "INT - FLOAT → FLOAT":
|
||||||
@@ -514,7 +516,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let expr = makeBinary(a, b, irSub, vkFloat64)
|
let expr = makeBinary(a, b, irSub, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "INT * FLOAT → FLOAT":
|
test "INT * FLOAT → FLOAT":
|
||||||
@@ -523,7 +525,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let expr = makeBinary(a, b, irMul, vkFloat64)
|
let expr = makeBinary(a, b, irMul, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "FLOAT + FLOAT → FLOAT":
|
test "FLOAT + FLOAT → FLOAT":
|
||||||
@@ -532,7 +534,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = randFloatLit(rng)
|
let a = randFloatLit(rng)
|
||||||
let b = randFloatLit(rng)
|
let b = randFloatLit(rng)
|
||||||
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
let expr = makeBinary(a, b, irAdd, vkFloat64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkFloat64
|
check v.kind == vkFloat64
|
||||||
|
|
||||||
test "INT + INT → INT (non-div ops)":
|
test "INT + INT → INT (non-div ops)":
|
||||||
@@ -542,7 +544,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let b = randIntLit(rng)
|
let b = randIntLit(rng)
|
||||||
for op in [irAdd, irSub, irMul]:
|
for op in [irAdd, irSub, irMul]:
|
||||||
let expr = makeBinary(a, b, op, vkInt64)
|
let expr = makeBinary(a, b, op, vkInt64)
|
||||||
let v = evalExprValue(expr, initTable[string, string](), nil)
|
let v = qexec.evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check v.kind == vkInt64
|
check v.kind == vkInt64
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -553,7 +555,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<50:
|
for i in 0..<50:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let expr = makeBinary(a, a, irEq, vkBool)
|
let expr = makeBinary(a, a, irEq, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
test "neq comparison: a != a is false":
|
test "neq comparison: a != a is false":
|
||||||
@@ -561,31 +563,31 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
for i in 0..<50:
|
for i in 0..<50:
|
||||||
let a = randIntLit(rng)
|
let a = randIntLit(rng)
|
||||||
let expr = makeBinary(a, a, irNeq, vkBool)
|
let expr = makeBinary(a, a, irNeq, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "false"
|
check s == "false"
|
||||||
|
|
||||||
test "lt comparison: a < a is false":
|
test "lt comparison: a < a is false":
|
||||||
let a = intLit(5)
|
let a = intLit(5)
|
||||||
let expr = makeBinary(a, a, irLt, vkBool)
|
let expr = makeBinary(a, a, irLt, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "false"
|
check s == "false"
|
||||||
|
|
||||||
test "lte comparison: a <= a is true":
|
test "lte comparison: a <= a is true":
|
||||||
let a = intLit(5)
|
let a = intLit(5)
|
||||||
let expr = makeBinary(a, a, irLte, vkBool)
|
let expr = makeBinary(a, a, irLte, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
test "gt comparison: a > a is false":
|
test "gt comparison: a > a is false":
|
||||||
let a = intLit(5)
|
let a = intLit(5)
|
||||||
let expr = makeBinary(a, a, irGt, vkBool)
|
let expr = makeBinary(a, a, irGt, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "false"
|
check s == "false"
|
||||||
|
|
||||||
test "gte comparison: a >= a is true":
|
test "gte comparison: a >= a is true":
|
||||||
let a = intLit(5)
|
let a = intLit(5)
|
||||||
let expr = makeBinary(a, a, irGte, vkBool)
|
let expr = makeBinary(a, a, irGte, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
test "lt comparison: a < b is true when a < b":
|
test "lt comparison: a < b is true when a < b":
|
||||||
@@ -596,7 +598,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let a = intLit(x)
|
let a = intLit(x)
|
||||||
let b = intLit(y)
|
let b = intLit(y)
|
||||||
let expr = makeBinary(a, b, irLt, vkBool)
|
let expr = makeBinary(a, b, irLt, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -606,7 +608,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
var ta = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
var ta = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
||||||
ta.literal = IRLiteral(kind: vkBool, boolVal: true)
|
ta.literal = IRLiteral(kind: vkBool, boolVal: true)
|
||||||
let expr = makeBinary(ta, ta, irAnd, vkBool)
|
let expr = makeBinary(ta, ta, irAnd, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
test "AND: true AND false = false":
|
test "AND: true AND false = false":
|
||||||
@@ -615,7 +617,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
||||||
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
||||||
let expr = makeBinary(ta, fa, irAnd, vkBool)
|
let expr = makeBinary(ta, fa, irAnd, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "false"
|
check s == "false"
|
||||||
|
|
||||||
test "OR: false OR true = true":
|
test "OR: false OR true = true":
|
||||||
@@ -624,14 +626,14 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
||||||
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
||||||
let expr = makeBinary(fa, ta, irOr, vkBool)
|
let expr = makeBinary(fa, ta, irOr, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "true"
|
check s == "true"
|
||||||
|
|
||||||
test "OR: false OR false = false":
|
test "OR: false OR false = false":
|
||||||
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
var fa = IRExpr(kind: irekLiteral, valueKind: vkBool)
|
||||||
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
fa.literal = IRLiteral(kind: vkBool, boolVal: false)
|
||||||
let expr = makeBinary(fa, fa, irOr, vkBool)
|
let expr = makeBinary(fa, fa, irOr, vkBool)
|
||||||
let s = evalExpr(expr, initTable[string, string](), nil)
|
let s = evalExpr(expr, initTable[string, Value](), nil)
|
||||||
check s == "false"
|
check s == "false"
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────
|
||||||
@@ -649,7 +651,7 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
let t3 = makeBinary(t1, t2, irSub, vkInt64)
|
let t3 = makeBinary(t1, t2, irSub, vkInt64)
|
||||||
let t4 = makeUnary(t3, irNeg, vkInt64)
|
let t4 = makeUnary(t3, irNeg, vkInt64)
|
||||||
let t5 = makeBinary(t4, intLit(1), irAdd, vkInt64)
|
let t5 = makeBinary(t4, intLit(1), irAdd, vkInt64)
|
||||||
discard evalExprValue(t5, initTable[string, string](), nil)
|
discard qexec.evalExpr(t5, initTable[string, Value](), nil)
|
||||||
check true
|
check true
|
||||||
|
|
||||||
test "Random binary tree depth 5 does not crash":
|
test "Random binary tree depth 5 does not crash":
|
||||||
@@ -670,13 +672,13 @@ suite "Property-Based — evalExprValue Invariants":
|
|||||||
else: vkFloat64
|
else: vkFloat64
|
||||||
nodes.insert(makeBinary(left, right, ops[opIdx], vk), 0)
|
nodes.insert(makeBinary(left, right, ops[opIdx], vk), 0)
|
||||||
if nodes.len == 1:
|
if nodes.len == 1:
|
||||||
discard evalExprValue(nodes[0], initTable[string, string](), nil)
|
discard qexec.evalExpr(nodes[0], initTable[string, Value](), nil)
|
||||||
check true
|
check true
|
||||||
|
|
||||||
test "Nil expr evaluates to NULL":
|
test "Nil expr evaluates to NULL":
|
||||||
let v = evalExprValue(nil, initTable[string, string](), nil)
|
let v = qexec.evalExpr(nil, initTable[string, Value](), nil)
|
||||||
check v.kind == vkNull
|
check v.kind == vkNull
|
||||||
let s = evalExpr(nil, initTable[string, string](), nil)
|
let s = evalExpr(nil, initTable[string, Value](), nil)
|
||||||
check s == ""
|
check s == ""
|
||||||
|
|
||||||
# ═══════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════
|
||||||
@@ -814,7 +816,7 @@ suite "Property-Based — B-Tree Invariants":
|
|||||||
if tracker[k].len == 0:
|
if tracker[k].len == 0:
|
||||||
tracker.del(k)
|
tracker.del(k)
|
||||||
else: discard
|
else: discard
|
||||||
# Verify all tracked keys are present
|
# Verify all tracked keys are present (compare as sets, order may differ due to rebalancing)
|
||||||
for k, vals in tracker:
|
for k, vals in tracker:
|
||||||
let got = btree.get(k)
|
let got = btree.get(k)
|
||||||
check got == vals
|
check got.toHashSet == vals.toHashSet
|
||||||
|
|||||||
Reference in New Issue
Block a user