11// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22// SPDX-License-Identifier: MIT-0
33
4- use std:: collections:: BTreeMap ;
4+ use std:: collections:: HashMap ;
55
66use anyhow:: { Result , anyhow, bail} ;
77use cel_interpreter:: Value as celValue;
@@ -12,9 +12,9 @@ use crate::constants::MAX_EXPRESSION_LENGTH;
1212use crate :: functions;
1313
1414pub fn execute_expressions (
15- fields : & BTreeMap < String , Value > ,
16- expressions : & BTreeMap < String , String > ,
17- ) -> Result < BTreeMap < String , Value > > {
15+ fields : & HashMap < String , Value > ,
16+ expressions : & HashMap < String , String > ,
17+ ) -> Result < HashMap < String , Value > > {
1818 if expressions. is_empty ( ) {
1919 return Ok ( fields. clone ( ) ) ;
2020 }
@@ -51,7 +51,8 @@ pub fn execute_expressions(
5151 context. add_function ( "date" , functions:: date) ;
5252 context. add_function ( "age" , functions:: age) ;
5353
54- let mut transformed: BTreeMap < String , Value > = BTreeMap :: new ( ) ;
54+ let mut transformed: HashMap < String , Value > =
55+ HashMap :: with_capacity ( fields. len ( ) + expressions. len ( ) ) ;
5556
5657 for ( field, decrypted_value) in fields {
5758 context
@@ -92,7 +93,7 @@ pub fn execute_expressions(
9293mod tests {
9394 use super :: * ;
9495 use proptest:: prelude:: * ;
95- use std:: collections:: BTreeMap ;
96+ use std:: collections:: HashMap ;
9697
9798 // **Feature: enclave-improvements, Property 5: Expression failure fallback**
9899 // **Validates: Requirements 8.2**
@@ -111,9 +112,9 @@ mod tests {
111112 /// Simulates the fallback behavior from main.rs:
112113 /// When execute_expressions returns Err, return the original fields unchanged.
113114 fn execute_with_fallback (
114- fields : & BTreeMap < String , Value > ,
115- expressions : & BTreeMap < String , String > ,
116- ) -> BTreeMap < String , Value > {
115+ fields : & HashMap < String , Value > ,
116+ expressions : & HashMap < String , String > ,
117+ ) -> HashMap < String , Value > {
117118 match execute_expressions ( fields, expressions) {
118119 Ok ( result) => result,
119120 Err ( _) => fields. clone ( ) ,
@@ -133,7 +134,7 @@ mod tests {
133134 invalid_expr_type in 0usize ..3
134135 ) {
135136 // Create original fields
136- let mut fields: BTreeMap <String , Value > = BTreeMap :: new( ) ;
137+ let mut fields: HashMap <String , Value > = HashMap :: new( ) ;
137138 fields. insert( field_name. clone( ) , Value :: String ( field_value. clone( ) ) ) ;
138139
139140 // Create an invalid expression that will fail to execute gracefully
@@ -144,7 +145,7 @@ mod tests {
144145 _ => "undefined_var.to_uppercase()" . to_string( ) ,
145146 } ;
146147
147- let mut expressions: BTreeMap <String , String > = BTreeMap :: new( ) ;
148+ let mut expressions: HashMap <String , String > = HashMap :: new( ) ;
148149 expressions. insert( "result" . to_string( ) , invalid_expression) ;
149150
150151 // Execute with fallback (simulating main.rs behavior)
@@ -173,7 +174,7 @@ mod tests {
173174 use std:: hash:: { Hash , Hasher } ;
174175
175176 // Generate deterministic field names and values based on seed
176- let mut fields: BTreeMap <String , Value > = BTreeMap :: new( ) ;
177+ let mut fields: HashMap <String , Value > = HashMap :: new( ) ;
177178 for i in 0 ..num_fields {
178179 let mut hasher = DefaultHasher :: new( ) ;
179180 ( field_seed, i) . hash( & mut hasher) ;
@@ -184,7 +185,7 @@ mod tests {
184185 }
185186
186187 // Create an expression that references an undefined variable
187- let mut expressions: BTreeMap <String , String > = BTreeMap :: new( ) ;
188+ let mut expressions: HashMap <String , String > = HashMap :: new( ) ;
188189 expressions. insert( "computed" . to_string( ) , "undefined_var.to_uppercase()" . to_string( ) ) ;
189190
190191 // Execute with fallback
@@ -212,10 +213,10 @@ mod tests {
212213 field_name in "[a-z][a-z0-9_]{0,10}" ,
213214 field_value in "[a-zA-Z0-9 ]{1,20}"
214215 ) {
215- let mut fields: BTreeMap <String , Value > = BTreeMap :: new( ) ;
216+ let mut fields: HashMap <String , Value > = HashMap :: new( ) ;
216217 fields. insert( field_name. clone( ) , Value :: String ( field_value. clone( ) ) ) ;
217218
218- let expressions: BTreeMap <String , String > = BTreeMap :: new( ) ;
219+ let expressions: HashMap <String , String > = HashMap :: new( ) ;
219220
220221 let result = execute_expressions( & fields, & expressions) . unwrap( ) ;
221222
@@ -233,11 +234,11 @@ mod tests {
233234 // Generate lowercase string to test to_uppercase
234235 field_value in "[a-z]{1,10}"
235236 ) {
236- let mut fields: BTreeMap <String , Value > = BTreeMap :: new( ) ;
237+ let mut fields: HashMap <String , Value > = HashMap :: new( ) ;
237238 fields. insert( field_name. clone( ) , Value :: String ( field_value. clone( ) ) ) ;
238239
239240 // Create expression to uppercase the field
240- let mut expressions: BTreeMap <String , String > = BTreeMap :: new( ) ;
241+ let mut expressions: HashMap <String , String > = HashMap :: new( ) ;
241242 expressions. insert( field_name. clone( ) , format!( "{}.to_uppercase()" , field_name) ) ;
242243
243244 let result = execute_expressions( & fields, & expressions) . unwrap( ) ;
@@ -253,67 +254,65 @@ mod tests {
253254
254255 #[ test]
255256 fn test_skip_expressions ( ) {
256- let expressions = BTreeMap :: new ( ) ;
257+ let expressions = HashMap :: new ( ) ;
257258
258- let expected: BTreeMap < String , Value > =
259- BTreeMap :: from ( [ ( "first_name" . to_string ( ) , "Bob" . into ( ) ) ] ) ;
259+ let expected: HashMap < String , Value > =
260+ HashMap :: from ( [ ( "first_name" . to_string ( ) , "Bob" . into ( ) ) ] ) ;
260261
261262 let actual = execute_expressions ( & expected, & expressions) . unwrap ( ) ;
262263 assert_eq ! ( actual, expected) ;
263264 }
264265
265266 #[ test]
266267 fn test_execute_transforms ( ) {
267- let expressions: BTreeMap < String , String > = BTreeMap :: from ( [ (
268+ let expressions: HashMap < String , String > = HashMap :: from ( [ (
268269 "first_name" . to_string ( ) ,
269270 "first_name.to_uppercase()" . to_string ( ) ,
270271 ) ] ) ;
271272
272- let fields: BTreeMap < String , Value > =
273- BTreeMap :: from ( [ ( "first_name" . to_string ( ) , "Bob" . into ( ) ) ] ) ;
273+ let fields: HashMap < String , Value > =
274+ HashMap :: from ( [ ( "first_name" . to_string ( ) , "Bob" . into ( ) ) ] ) ;
274275
275- let expected: BTreeMap < String , Value > =
276- BTreeMap :: from ( [ ( "first_name" . to_string ( ) , "BOB" . into ( ) ) ] ) ;
276+ let expected: HashMap < String , Value > =
277+ HashMap :: from ( [ ( "first_name" . to_string ( ) , "BOB" . into ( ) ) ] ) ;
277278
278279 let actual = execute_expressions ( & fields, & expressions) . unwrap ( ) ;
279280 assert_eq ! ( actual, expected) ;
280281 }
281282
282283 #[ test]
283284 fn test_base64 ( ) {
284- let expressions: BTreeMap < String , String > = BTreeMap :: from ( [ (
285+ let expressions: HashMap < String , String > = HashMap :: from ( [ (
285286 "first_name" . into ( ) ,
286287 "first_name.base64_encode().base64_decode()" . into ( ) ,
287288 ) ] ) ;
288289
289- let fields: BTreeMap < String , Value > = BTreeMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
290+ let fields: HashMap < String , Value > = HashMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
290291
291- let expected: BTreeMap < String , Value > =
292- BTreeMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
292+ let expected: HashMap < String , Value > = HashMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
293293
294294 let actual = execute_expressions ( & fields, & expressions) . unwrap ( ) ;
295295 assert_eq ! ( actual, expected) ;
296296 }
297297
298298 #[ test]
299299 fn test_hex ( ) {
300- let expressions: BTreeMap < String , String > = BTreeMap :: from ( [ (
300+ let expressions: HashMap < String , String > = HashMap :: from ( [ (
301301 "first_name" . into ( ) ,
302302 "first_name.hex_encode().hex_decode()" . into ( ) ,
303303 ) ] ) ;
304304
305- let fields: BTreeMap < String , Value > = BTreeMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
305+ let fields: HashMap < String , Value > = HashMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
306306
307- let expected: BTreeMap < String , Value > =
308- BTreeMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
307+ let expected: HashMap < String , Value > = HashMap :: from ( [ ( "first_name" . into ( ) , "Bob" . into ( ) ) ] ) ;
309308
310309 let actual = execute_expressions ( & fields, & expressions) . unwrap ( ) ;
311310 assert_eq ! ( actual, expected) ;
312311 }
313312
314313 #[ test]
315314 fn test_functions ( ) {
316- let expressions: BTreeMap < String , String > = BTreeMap :: from ( [
315+ let expressions: HashMap < String , String > = HashMap :: from ( [
317316 ( "is_empty" . into ( ) , "''.is_empty() == true" . into ( ) ) ,
318317 ( "to_lowercase" . into ( ) , "'Bob'.to_lowercase()" . into ( ) ) ,
319318 ( "to_uppercase" . into ( ) , "'Bob'.to_uppercase()" . into ( ) ) ,
@@ -327,43 +326,63 @@ mod tests {
327326 ( "date" . into ( ) , "date('1979-04-05')" . into ( ) ) ,
328327 ] ) ;
329328
330- let fields = BTreeMap :: default ( ) ;
331- let expected: BTreeMap < String , Value > =
332- BTreeMap :: from ( [
333- ( "is_empty" . into ( ) , true . into ( ) ) ,
334- ( "to_lowercase" . into ( ) , "bob" . into ( ) ) ,
335- ( "to_uppercase" . into ( ) , "BOB" . into ( ) ) ,
336- ( "sha256" . into ( ) , "cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961" . into ( ) ) ,
337- ( "sha384" . into ( ) , "b7808c5991933fa578a7d41a177b013f2f745a2c4fac90d1e8631a1ce21918dc5fee092a290a6443e47649989ec9871f" . into ( ) ) ,
338- ( "sha512" . into ( ) , "0c3e99453b4ae505617a3c9b6ce73fc3cd13ddc3b2e2237459710a57f8ec6d26d056db144ff7c71b00ed4e4c39716e9e2099c8076e604423dd74554d4db1e649" . into ( ) ) ,
339- ( "hex_encode" . into ( ) , "426f62" . into ( ) ) ,
340- ( "hex_decode" . into ( ) , "Bob" . into ( ) ) ,
341- ( "base64_encode" . into ( ) , "Qm9i" . into ( ) ) ,
342- ( "base64_decode" . into ( ) , "Bob" . into ( ) ) ,
343- ( "date" . into ( ) , "1979-04-05T00:00:00+00:00" . into ( ) ) ,
344- ] ) ;
345-
329+ let fields = HashMap :: default ( ) ;
330+ // Note: Using Vec for comparison since HashMap ordering is non-deterministic
346331 let actual = execute_expressions ( & fields, & expressions) . unwrap ( ) ;
347- assert_eq ! ( actual, expected) ;
332+
333+ assert_eq ! ( actual. get( "is_empty" ) , Some ( & Value :: Bool ( true ) ) ) ;
334+ assert_eq ! (
335+ actual. get( "to_lowercase" ) ,
336+ Some ( & Value :: String ( "bob" . into( ) ) )
337+ ) ;
338+ assert_eq ! (
339+ actual. get( "to_uppercase" ) ,
340+ Some ( & Value :: String ( "BOB" . into( ) ) )
341+ ) ;
342+ assert_eq ! (
343+ actual. get( "sha256" ) ,
344+ Some ( & Value :: String (
345+ "cd9fb1e148ccd8442e5aa74904cc73bf6fb54d1d54d333bd596aa9bb4bb4e961" . into( )
346+ ) )
347+ ) ;
348+ assert_eq ! ( actual. get( "sha384" ) , Some ( & Value :: String ( "b7808c5991933fa578a7d41a177b013f2f745a2c4fac90d1e8631a1ce21918dc5fee092a290a6443e47649989ec9871f" . into( ) ) ) ) ;
349+ assert_eq ! ( actual. get( "sha512" ) , Some ( & Value :: String ( "0c3e99453b4ae505617a3c9b6ce73fc3cd13ddc3b2e2237459710a57f8ec6d26d056db144ff7c71b00ed4e4c39716e9e2099c8076e604423dd74554d4db1e649" . into( ) ) ) ) ;
350+ assert_eq ! (
351+ actual. get( "hex_encode" ) ,
352+ Some ( & Value :: String ( "426f62" . into( ) ) )
353+ ) ;
354+ assert_eq ! ( actual. get( "hex_decode" ) , Some ( & Value :: String ( "Bob" . into( ) ) ) ) ;
355+ assert_eq ! (
356+ actual. get( "base64_encode" ) ,
357+ Some ( & Value :: String ( "Qm9i" . into( ) ) )
358+ ) ;
359+ assert_eq ! (
360+ actual. get( "base64_decode" ) ,
361+ Some ( & Value :: String ( "Bob" . into( ) ) )
362+ ) ;
363+ assert_eq ! (
364+ actual. get( "date" ) ,
365+ Some ( & Value :: String ( "1979-04-05T00:00:00+00:00" . into( ) ) )
366+ ) ;
348367 }
349368
350369 #[ test]
351370 fn test_complex ( ) {
352- let expressions: BTreeMap < String , String > =
353- BTreeMap :: from ( [ ( "age" . into ( ) , "date(birth_date).age()" . into ( ) ) ] ) ;
371+ let expressions: HashMap < String , String > =
372+ HashMap :: from ( [ ( "age" . into ( ) , "date(birth_date).age()" . into ( ) ) ] ) ;
354373
355- let fields: BTreeMap < String , Value > = BTreeMap :: from ( [
374+ let fields: HashMap < String , Value > = HashMap :: from ( [
356375 ( "first_name" . into ( ) , "Bob" . into ( ) ) ,
357376 ( "birth_date" . into ( ) , "1979-01-01" . into ( ) ) ,
358377 ] ) ;
359378
360- let expected: BTreeMap < String , Value > = BTreeMap :: from ( [
361- ( "first_name" . into ( ) , "Bob" . into ( ) ) ,
362- ( "birth_date" . into ( ) , "1979-01-01" . into ( ) ) ,
363- ( "age" . into ( ) , 46 . into ( ) ) ,
364- ] ) ;
365-
366379 let actual = execute_expressions ( & fields, & expressions) . unwrap ( ) ;
367- assert_eq ! ( actual, expected) ;
380+
381+ assert_eq ! ( actual. get( "first_name" ) , Some ( & Value :: String ( "Bob" . into( ) ) ) ) ;
382+ assert_eq ! (
383+ actual. get( "birth_date" ) ,
384+ Some ( & Value :: String ( "1979-01-01" . into( ) ) )
385+ ) ;
386+ assert_eq ! ( actual. get( "age" ) , Some ( & Value :: Number ( 46 . into( ) ) ) ) ;
368387 }
369388}
0 commit comments