From 9e0a9905bd84c102837483a49875f16068ed0d87 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 8 Sep 2026 08:33:42 +0000 Subject: [PATCH] :bug: Add bounds checking to remove-interaction to prevent crashes The remove-interaction function used subvec without validating that the index was within bounds, causing 'Index out of bounds' errors when removing multiple interactions in rapid succession. Add bounds validation to return the unchanged interactions vector when an invalid index is provided. This prevents crashes while maintaining data integrity and idempotent behavior. Closes #11546 AI-assisted-by: qwen3.7-plus --- .../app/common/types/shape/interactions.cljc | 6 ++-- .../types/shape_interactions_test.cljc | 31 +++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/common/src/app/common/types/shape/interactions.cljc b/common/src/app/common/types/shape/interactions.cljc index 6b06b68897..dfb764d05d 100644 --- a/common/src/app/common/types/shape/interactions.cljc +++ b/common/src/app/common/types/shape/interactions.cljc @@ -714,8 +714,10 @@ (defn remove-interaction [interactions index] (let [interactions (or interactions [])] - (into (subvec interactions 0 index) - (subvec interactions (inc index))))) + (if (and (>= index 0) (< index (count interactions))) + (into (subvec interactions 0 index) + (subvec interactions (inc index))) + interactions))) (defn update-interaction [interactions index update-fn] diff --git a/common/test/common_tests/types/shape_interactions_test.cljc b/common/test/common_tests/types/shape_interactions_test.cljc index da056ae136..c86c4cffc9 100644 --- a/common/test/common_tests/types/shape_interactions_test.cljc +++ b/common/test/common_tests/types/shape_interactions_test.cljc @@ -861,6 +861,37 @@ (t/is (= (:action-type (last new-interactions)) :open-url)))))) +(t/deftest remove-interaction-bounds-check + (let [i1 (ctsi/set-action-type ctsi/default-interaction :open-overlay) + i2 (ctsi/set-action-type ctsi/default-interaction :close-overlay) + i3 (ctsi/set-action-type ctsi/default-interaction :prev-screen) + interactions [i1 i2 i3]] + + (t/testing "Remove interaction with valid index" + (let [new-interactions (ctsi/remove-interaction interactions 1)] + (t/is (= 2 (count new-interactions))) + (t/is (= :open-overlay (:action-type (first new-interactions)))) + (t/is (= :prev-screen (:action-type (second new-interactions)))))) + + (t/testing "Remove interaction with index out of bounds (too high)" + (let [new-interactions (ctsi/remove-interaction interactions 10)] + (t/is (= 3 (count new-interactions))) + (t/is (= interactions new-interactions)))) + + (t/testing "Remove interaction with negative index" + (let [new-interactions (ctsi/remove-interaction interactions -1)] + (t/is (= 3 (count new-interactions))) + (t/is (= interactions new-interactions)))) + + (t/testing "Remove interaction from empty vector" + (let [new-interactions (ctsi/remove-interaction [] 0)] + (t/is (= 0 (count new-interactions))))) + + (t/testing "Remove interaction from nil" + (let [new-interactions (ctsi/remove-interaction nil 0)] + (t/is (= 0 (count new-interactions))))))) + + (t/deftest remap-interactions (let [frame1 (cts/setup-shape {:type :frame}) frame2 (cts/setup-shape {:type :frame})