From e6bda833096c256471f4e89ea83a1d22fa42900c Mon Sep 17 00:00:00 2001 From: Humza Shahid Date: Tue, 9 Dec 2025 11:42:30 +0000 Subject: [PATCH] begin adding tests for persistent-vector.sml, and add bug fix to 'PersistentVector.delete' in light of one of the tests. (We were decrementing by the wrong value previously, but I fixed it and added a comment of how we arrive at the value we want to decrement by --- fcore/persistent-vector.sml | 72 ++++++++++++++++++++++---------- shf-tests.mlb | 1 + test/persistent-vector-tests.sml | 55 ++++++++++++++++++++++++ test/test.sml | 14 +++---- 4 files changed, 114 insertions(+), 28 deletions(-) create mode 100644 test/persistent-vector-tests.sml diff --git a/fcore/persistent-vector.sml b/fcore/persistent-vector.sml index d5d038a..0fc0e2d 100644 --- a/fcore/persistent-vector.sml +++ b/fcore/persistent-vector.sml @@ -349,8 +349,16 @@ struct fun getMaxSize tree = case tree of - BRANCH (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) - | LEAF (_, sizes) => Vector.sub (sizes, Vector.length sizes - 1) + BRANCH (_, sizes) => + if Vector.length sizes = 0 then + 0 + else + Vector.sub (sizes, Vector.length sizes - 1) + | LEAF (_, sizes) => + if Vector.length sizes = 0 then + 0 + else + Vector.sub (sizes, Vector.length sizes - 1) fun splitLeft (offset, tree) = case tree of @@ -893,7 +901,7 @@ struct fun delete (start, length, tree) = let val finishIdx = start + length - val {start, finish} = startNextMatch (finishIdx, tree) + val {start, finish} = startNextMatch (start, tree) in if start = ~1 then (* nothing to delete *) @@ -902,26 +910,48 @@ struct let (* split left and right side *) val left = splitLeft (start, tree) - val left = root left - val right = splitRight (finishIdx, tree) - val right = root right - - (* calculate what the new index should be - * for the first match in the right tree, - * and decrement the right tree to reach this index - * if necessary. *) - val leftSize = getMaxSize left - val {start = rightStart, ...} = getFirstItem right - val rightStart = rightStart + leftSize - val difference = start - rightStart - val right = - if difference = 0 then - right - else - decrement (difference, right) in - join (left, right) + if isEmpty right then + root left + else + let + val left = root left + val right = root right + + (* calculate what the new index should be + * for the first match in the right tree, + * and decrement the right tree to reach this index + * if necessary. + * + * We calculate the index the right node should start at + * using this method: + * 1. We get the first match after finishIdx from the original * tree + * 2. We subtract this by the length provided to us, + * which tells us where the right node should start at. + * 3. We get the first item in the right node, + * and add the last item in the left node + * to get an absolute value. + * 4. We subtract the match from the original tree + * by the first item in the right node. + * This step gives us the difference: how much + * we need to decrement the right node by. + * *) + val {start = shouldBeStart, ...} = + startNextMatch (finishIdx, tree) + val shouldBeStart = shouldBeStart - length + + val leftSize = getMaxSize left + val {start = rightStart, ...} = getFirstItem right + val difference = rightStart - shouldBeStart + val right = + if difference = 0 then + right + else + decrement (difference, right) + in + join (left, right) + end end end diff --git a/shf-tests.mlb b/shf-tests.mlb index e6f423b..6fb2427 100644 --- a/shf-tests.mlb +++ b/shf-tests.mlb @@ -71,4 +71,5 @@ test/test-utils.sml test/normal-move.sml test/normal-delete.sml test/regression.sml +test/persistent-vector-tests.sml test/test.sml diff --git a/test/persistent-vector-tests.sml b/test/persistent-vector-tests.sml new file mode 100644 index 0000000..c16b311 --- /dev/null +++ b/test/persistent-vector-tests.sml @@ -0,0 +1,55 @@ +structure PersistentVectorTests = +struct + open Railroad + open Railroad.Test + + structure Pv = PersistentVector + + val appendTests = describe "PersistentVector.append" + [test "appends new values to end" (fn _ => + let + (* arrange *) + val pv = Pv.fromList [(1, 1), (3, 3)] + + (* act *) + val pv = Pv.append (5, 7, pv) + + (* assert *) + val outputList = Pv.toList pv + val expectedList = [(1, 1), (3, 3), (5, 7)] + in + Expect.isTrue (outputList = expectedList) + end)] + + fun printList lst = + let + val str = + List.map + (fn (start, finish) => + "(" ^ Int.toString start ^ ", " ^ Int.toString finish ^ ")") lst + val str = "[" ^ String.concatWith ", " str ^ "]\n" + in + print str + end + + val deleteTests = describe "PersistentVector.delete" + [test + "deletes last value correctly \ + \when only last value is in deletion range" + (fn _ => + let + (* arrange *) + val pv = Pv.fromList [(0, 0), (3, 3), (5, 5)] + + (* act *) + val pv = Pv.delete (5, 1, pv) + + (* assert *) + val outputList = Pv.toList pv + val expectedList = [(0, 0), (3, 3)] + in + Expect.isTrue (outputList = expectedList) + end)] + + val tests = [appendTests, deleteTests] +end diff --git a/test/test.sml b/test/test.sml index 416569a..2d5976d 100644 --- a/test/test.sml +++ b/test/test.sml @@ -5,13 +5,13 @@ struct fun main () = let - val tests = - List.concat - [ NormalMove.tests - , NormalDelete.tests - , Regression.tests - , RegexTests.tests - ] + val tests = List.concat + [ NormalMove.tests + , NormalDelete.tests + , Regression.tests + , RegexTests.tests + , PersistentVectorTests.tests + ] val tests = concat tests in runWithConfig [Configuration.PrintPassed false] tests