Skip to content

Commit 13a3050

Browse files
committed
fix: Error on circular references
1 parent 38fa5ba commit 13a3050

File tree

6 files changed

+132
-8
lines changed

6 files changed

+132
-8
lines changed

README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,4 @@ bpm install
5858
- error on invalid references (`type=object` in virtual object metadata, when it is referencing an array)
5959
- ensure error (for set primarily) if the virtual object references a variable that does not exist
6060
- "queried for X, but found existing object": print object in error (same with indexed arrays)
61-
- support `--pass-by-value`
62-
- check for circular references
63-
- --reply-with-ref --reply-with-value
64-
- meta: 'unset REPLY' potential conflict with set -u
61+
--reply-with-value

pkg/lib/traverse-get.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ bash_object.traverse-get() {
7070
stdtrace.log 2 "BLOCK: OBJECT/ARRAY"
7171
fi
7272

73+
local old_current_object_name="$current_object_name"
74+
7375
virtual_item="${key_value#??}"
7476
bash_object.parse_virtual_object "$virtual_item"
7577
local current_object_name="$REPLY1"
@@ -104,6 +106,12 @@ bash_object.traverse-get() {
104106
# return
105107
# ;;
106108
# esac
109+
110+
# Ensure no circular references (WET)
111+
if [ "$old_current_object_name" = "$current_object_name" ]; then
112+
bash_object.util.die 'ERROR_SELF_REFERENCE' "Virtual object '$current_object_name' cannot reference itself"
113+
return
114+
fi
107115
elif ((i+1 == ${#REPLIES[@]})); then
108116
if [ -n "${VERIFY_BASH_OBJECT+x}" ]; then
109117
# Ensure the 'final_value' is the same type as specified by the user
@@ -140,6 +148,12 @@ bash_object.traverse-get() {
140148
esac
141149
fi
142150

151+
# Ensure no circular references (WET)
152+
if [ "$old_current_object_name" = "$current_object_name" ]; then
153+
bash_object.util.die 'ERROR_SELF_REFERENCE' "Virtual object '$current_object_name' cannot reference itself"
154+
return
155+
fi
156+
143157
# We are last element of query, return the object
144158
if [ "$final_value_type" = object ]; then
145159
case "$vmd_dtype" in

pkg/lib/traverse-set.sh

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,7 @@ bash_object.traverse-set() {
139139
if ((i+1 < ${#REPLIES[@]})); then
140140
bash_object.util.die 'ERROR_NOT_FOUND' "Key or index '$key' (filter index '$i') does not exist"
141141
return
142-
# If we are at the last element in the query, and it doesn't
143-
# exist, create it
142+
# If we are at the last element in the query, and it doesn't exist, create it
144143
elif ((i+1 == ${#REPLIES[@]})); then
145144
if [ "$final_value_type" = object ]; then
146145
# TODO: test this
@@ -227,6 +226,8 @@ bash_object.traverse-set() {
227226
stdtrace.log 2 "BLOCK: OBJECT/ARRAY"
228227
fi
229228

229+
local old_current_object_name="$current_object_name"
230+
230231
virtual_item="${key_value#??}"
231232
bash_object.parse_virtual_object "$virtual_item"
232233
local current_object_name="$REPLY1"
@@ -236,7 +237,20 @@ bash_object.traverse-set() {
236237
if ((i+1 < ${#REPLIES[@]})); then
237238
# TODO: test these internal invalid errors (error when type=array references object, etc.)?
238239
:
240+
241+
# Ensure no circular references (WET)
242+
if [ "$old_current_object_name" = "$current_object_name" ]; then
243+
bash_object.util.die 'ERROR_SELF_REFERENCE' "Virtual object '$current_object_name' cannot reference itself"
244+
return
245+
fi
239246
elif ((i+1 == ${#REPLIES[@]})); then
247+
# Ensure no circular references (WET)
248+
if [ "$old_current_object_name" = "$current_object_name" ]; then
249+
bash_object.util.die 'ERROR_SELF_REFERENCE' "Virtual object '$current_object_name' cannot reference itself"
250+
return
251+
fi
252+
253+
# We are last element of query, but do not set the object there is one that already exists
240254
if [ "$final_value_type" = object ]; then
241255
case "$vmd_dtype" in
242256
object) :;;
@@ -293,10 +307,10 @@ bash_object.traverse-set() {
293307
return
294308
elif ((i+1 == ${#REPLIES[@]})); then
295309
if [ "$final_value_type" = object ]; then
296-
bash_object.util.die 'ERROR_ARGUMENTS_INCORRECT_TYPE' 'Assigning an object, but found existing string'
310+
bash_object.util.die 'ERROR_ARGUMENTS_INCORRECT_TYPE' "Assigning an $final_value_type, but found existing string"
297311
return
298312
elif [ "$final_value_type" = array ]; then
299-
bash_object.util.die 'ERROR_ARGUMENTS_INCORRECT_TYPE' 'Assigning an array, but found existing string'
313+
bash_object.util.die 'ERROR_ARGUMENTS_INCORRECT_TYPE' "Assigning an $final_value_type, but found existing string"
300314
return
301315
elif [ "$final_value_type" = string ]; then
302316
local -n string_to_copy_from="$final_value"

pkg/lib/util/ensure.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ bash_object.ensure.variable_does_exist() {
2020
fi
2121
}
2222

23+
# TODO
2324
# @description Test if the variable already exists. Note that the variable _must_ be sanitized before using this function
2425
bash_object.ensure.variable_does_not_exist() {
2526
local variable_name="$1"

pkg/lib/util/util.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
declare -gA ERRORS_BASH_OBJECT=(
55
[ERROR_NOT_FOUND]=
66
[ERROR_INTERNAL]=
7+
[ERROR_SELF_REFERENCE]="A virtual object cannot reference itself"
78

89
[ERROR_ARGUMENTS_INVALID]="Wrong number, empty, or missing required arguments to function"
910
[ERROR_ARGUMENTS_INVALID_TYPE]="The type of the final value specified by the user is neither 'object', 'array', nor 'string'"

tests/error-circular-reference.bats

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env bats
2+
3+
load './util/init.sh'
4+
5+
# get
6+
@test "get-object stops on circular reference" {
7+
declare -A SUB_OBJECT=([nested]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
8+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
9+
10+
run bobject get-object OBJECT '.my_key.nested'
11+
12+
assert_failure
13+
assert_line -p "ERROR_SELF_REFERENCE"
14+
assert_line -p "Virtual object 'SUB_OBJECT' cannot reference itself"
15+
}
16+
17+
@test "get-object stops on circular reference 2" {
18+
declare -A SUB_OBJECT=([nested]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
19+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
20+
21+
run bobject get-object OBJECT '.my_key.nested.nested'
22+
23+
assert_failure
24+
assert_line -p "ERROR_SELF_REFERENCE"
25+
assert_line -p "Virtual object 'SUB_OBJECT' cannot reference itself"
26+
}
27+
28+
@test "get-array stops on circular reference" {
29+
declare -a SUB_ARRAY=([nested]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
30+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
31+
32+
run bobject get-array OBJECT '.my_key.nested'
33+
34+
assert_failure
35+
assert_line -p "ERROR_SELF_REFERENCE"
36+
assert_line -p "Virtual object 'SUB_ARRAY' cannot reference itself"
37+
}
38+
39+
@test "get-array stops on circular reference 2" {
40+
declare -a SUB_ARRAY=([nested]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
41+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
42+
43+
run bobject get-array OBJECT '.my_key.nested.nested'
44+
45+
assert_failure
46+
assert_line -p "ERROR_SELF_REFERENCE"
47+
assert_line -p "Virtual object 'SUB_ARRAY' cannot reference itself"
48+
}
49+
50+
# set
51+
@test "set-object stops on circular reference" {
52+
declare -A SUB_OBJECT=([nested]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
53+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
54+
declare -A obj=()
55+
56+
run bobject set-object OBJECT --pass-by-ref '.my_key.nested' obj
57+
58+
assert_failure
59+
assert_line -p "ERROR_SELF_REFERENCE"
60+
assert_line -p "Virtual object 'SUB_OBJECT' cannot reference itself"
61+
}
62+
63+
@test "set-object stops on circular reference 2" {
64+
declare -A SUB_OBJECT=([nested]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
65+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=object;&SUB_OBJECT')
66+
declare -A obj=()
67+
68+
run bobject set-object OBJECT --pass-by-ref '.my_key.nested.gone' obj
69+
70+
assert_failure
71+
assert_line -p "ERROR_SELF_REFERENCE"
72+
assert_line -p "Virtual object 'SUB_OBJECT' cannot reference itself"
73+
}
74+
75+
@test "set-array stops on circular reference" {
76+
declare -a SUB_ARRAY=([nested]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
77+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
78+
declare -a arr=()
79+
80+
run bobject set-array OBJECT --pass-by-ref '.my_key.nested' arr
81+
82+
assert_failure
83+
assert_line -p "ERROR_SELF_REFERENCE"
84+
assert_line -p "Virtual object 'SUB_ARRAY' cannot reference itself"
85+
}
86+
87+
@test "set-array stops on circular reference 2" {
88+
declare -a SUB_ARRAY=([nested]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
89+
declare -A OBJECT=([my_key]=$'\x1C\x1Dtype=array;&SUB_ARRAY')
90+
declare -a arr=()
91+
92+
run bobject set-array OBJECT --pass-by-ref '.my_key.nested.gone' arr
93+
94+
assert_failure
95+
assert_line -p "ERROR_SELF_REFERENCE"
96+
assert_line -p "Virtual object 'SUB_ARRAY' cannot reference itself"
97+
}

0 commit comments

Comments
 (0)