@@ -251,12 +251,6 @@ mod tests {
251251 assert_eq ! ( s. to_lowercase( ) , output. to_lowercase( ) ) ;
252252 }
253253
254- fn semantic_policy_rtt ( s : & str ) {
255- let sem = SemanticPol :: from_str ( s) . unwrap ( ) ;
256- let output = sem. normalized ( ) . to_string ( ) ;
257- assert_eq ! ( s. to_lowercase( ) , output. to_lowercase( ) ) ;
258- }
259-
260254 #[ test]
261255 fn test_timelock_validity ( ) {
262256 // only height
@@ -279,17 +273,53 @@ mod tests {
279273 concrete_policy_rtt ( "or(99@pk(X),1@pk(Y))" ) ;
280274 concrete_policy_rtt ( "and(pk(X),or(99@pk(Y),1@older(12960)))" ) ;
281275
282- semantic_policy_rtt ( "pk()" ) ;
283- semantic_policy_rtt ( "or(pk(X),pk(Y))" ) ;
284- semantic_policy_rtt ( "and(pk(X),pk(Y))" ) ;
285-
286276 //fuzzer crashes
287277 assert ! ( ConcretePol :: from_str( "thresh()" ) . is_err( ) ) ;
288278 assert ! ( SemanticPol :: from_str( "thresh(0)" ) . is_err( ) ) ;
289279 assert ! ( SemanticPol :: from_str( "thresh()" ) . is_err( ) ) ;
290280 concrete_policy_rtt ( "ripemd160()" ) ;
291281 }
292282
283+ #[ test]
284+ fn semantic_display_uses_mathematical_notation ( ) {
285+ let pol = SemanticPol :: from_str ( "and(pk(A),pk(B))" ) . unwrap ( ) ;
286+ assert_eq ! ( pol. normalized( ) . to_string( ) , "(pk(A) ∧ pk(B))" ) ;
287+
288+ let pol = SemanticPol :: from_str ( "or(pk(A),pk(B))" ) . unwrap ( ) ;
289+ assert_eq ! ( pol. normalized( ) . to_string( ) , "(pk(A) ∨ pk(B))" ) ;
290+
291+ let pol = SemanticPol :: from_str ( "thresh(2,pk(A),pk(B),pk(C))" ) . unwrap ( ) ;
292+ assert_eq ! ( pol. normalized( ) . to_string( ) , "#{pk(A), pk(B), pk(C)} = 2" ) ;
293+ }
294+
295+ #[ test]
296+ fn semantic_display_roundtrips_via_from_str ( ) {
297+ // from_str must accept the mathematical Display output so that
298+ // `Display` and `FromStr` round-trip (a property serde relies on).
299+ for s in [
300+ "pk(A)" ,
301+ "and(pk(A),pk(B))" ,
302+ "or(pk(A),pk(B))" ,
303+ "thresh(2,pk(A),pk(B),pk(C))" ,
304+ "and(pk(A),or(pk(B),pk(C)))" ,
305+ "thresh(2,pk(A),and(pk(B),pk(C)),pk(D))" ,
306+ ] {
307+ let pol = SemanticPol :: from_str ( s) . unwrap ( ) . normalized ( ) ;
308+ let displayed = pol. to_string ( ) ;
309+ let reparsed = SemanticPol :: from_str ( & displayed) . unwrap ( ) . normalized ( ) ;
310+ assert_eq ! ( pol, reparsed, "round-trip failed for {}" , s) ;
311+ }
312+
313+ // Parser must also accept direct mathematical-form input.
314+ let math = "(pk(A) ∧ (pk(B) ∨ pk(C)))" ;
315+ let fncall = "and(pk(A),or(pk(B),pk(C)))" ;
316+ assert_eq ! ( SemanticPol :: from_str( math) . unwrap( ) , SemanticPol :: from_str( fncall) . unwrap( ) , ) ;
317+
318+ let math = "#{pk(A), pk(B), pk(C)} = 2" ;
319+ let fncall = "thresh(2,pk(A),pk(B),pk(C))" ;
320+ assert_eq ! ( SemanticPol :: from_str( math) . unwrap( ) , SemanticPol :: from_str( fncall) . unwrap( ) , ) ;
321+ }
322+
293323 #[ test]
294324 fn compile_invalid ( ) {
295325 // Since the root Error does not support Eq type, we have to
0 commit comments