
    iMC              	         d Z ddlmZ ddlZddlmc mZ ddl	Z	e	j                  j                  dd       ddlZddlZddlmZmZ ddlmZmZmZmZmZ  eddd	d
ddej,                        ZdZd[dZd Zd Zd Zd Zd Zd Zd Zd Z d Z!d Z"d Z#d Z$d Z%d Z&d Z'd Z(d Z)d Z*d  Z+d! Z,d" Z-d# Z.d$ Z/d% Z0d& Z1d' Z2d( Z3d) Z4d* Z5d+ Z6d, Z7d- Z8d. Z9d/ Z:d0 Z;e<d1k(  rddl=Z=da>da?d\d2Z@ e@d3e        e@d4e        e@d5e        e@d6e        e@d7e        e@d8e        e@d9e        e@d:e         e@d;e!        e@d<e"        e@d=e#        e@d>e$        e@d?e%        e@d@e&        e@dAe'        e@dBe(        e@dCe)        e@dDe*        e@dEe+        e@dFe,        e@dGe-        e@dHe.        e@dIe/        e@dJe0        e@dKe1        e@dLe2        e@dMe3        e@dNe4        e@dOe5        e@dPe6        e@dQe7        e@dRe8        e@dSe9        e@dTe:        e@dUe;        eAdVt~         dWt|         dX       t~        t|        k(  r	 eAdY       y e	j                  d       yy)]u  
Tests for Story 6.01 (Track B): StateDelta — RFC 6902 JSON Patch Proposal

Black Box tests (BB): verify the public contract from the outside —
    correct state transformation, immutability, error types.
White Box tests (WB): verify internal logic — validate_patch rules,
    specific op behaviors, path parsing, sentinel internals.

Story: 6.01
File under test: core/coherence/state_delta.py
    )annotationsNz/mnt/e/genesis-system)datetimetimezone)
StateDeltaPatchConflictErrorvalidate_patchapply_patch	VALID_OPSi           )tzinfo   c                *    t        dd|| t              S )N	agent-001sess-abc)agent_id
session_idversion_at_readpatchsubmitted_at)r   _NOWr   versions     6/mnt/e/genesis-system/tests/track_b/test_story_6_01.py_make_deltar   ,   s         c                 4   ddd} ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}y)u^   BB1: Valid patch {"op": "replace", "path": "/name", "value": "new"} applied → state updated.oldr   )namecountreplacez/namenewoppathvaluer    ==z%(py1)s == %(py4)spy1py4assert %(py6)spy6Nr!   r	   
@pytest_ar_call_reprcompare	_safereprAssertionError_format_explanationstater   result@py_assert0@py_assert3@py_assert2@py_format5@py_format7s           r   !test_bb1_replace_op_updates_stater>   ;   s    Q'Ew?@E&F&>"U">U"""">U""">"""U"""""""'?a?a?a?ar   c                 X   ddi} ddddg}t        j                  t              5 }t        | |       ddd       j                  }|j
                  }d}||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y# 1 sw Y   oxY w)u[   BB2: op: "test" with wrong value → PatchConflictError raised with path, expected, actual.statusactivetest/statusinactiver$   Nr(   z,%(py2)s
{%(py2)s = %(py0)s.path
} == %(py5)serrpy0py2py5assert %(py7)spy7z0%(py2)s
{%(py2)s = %(py0)s.expected
} == %(py5)sz.%(py2)s
{%(py2)s = %(py0)s.actual
} == %(py5)s)pytestraisesr   r	   r'   r&   r1   r2   @py_builtinslocals_should_repr_global_namer3   r4   r5   expectedactual)	r7   r   exc_inforF   @py_assert1@py_assert4r:   @py_format6@py_format8s	            r   8test_bb2_test_op_wrong_value_raises_patch_conflict_errorr[   D   s   x EI
CDE	)	* "hE5!"
..C88 y 8y    8y      3   3   8   y       <<%:%<:%%%%<:%%%%%%3%%%3%%%<%%%:%%%%%%%::!!:!!!!:!!!!!!3!!!3!!!:!!!!!!!!!!" "s   JJ)c                     t               } t        j                  t              5  d| _        ddd       y# 1 sw Y   yxY w)uj   BB3: frozen=True → attempt to set agent_id raises FrozenInstanceError (dataclasses.FrozenInstanceError).modifiedN)r   rO   rP   	Exceptionr   )deltas    r   6test_bb3_frozen_dataclass_raises_frozen_instance_errorr`   P   s1    ME	y	! $#$ $ $s   5>c                    ddd} t        j                  |       }ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j
                  |      t        j
                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}| |k(  }	|	st        j                  d	|	fd| |f      dt        j                         v st        j                  |       rt        j
                  |       nddt        j                         v st        j                  |      rt        j
                  |      nddz  }
dd|
iz  }t        t        j                  |            d}	y)z;BB4: apply_patch returns NEW dict, original is not mutated.r   r   )xyr"   /xc   r$   rb   r(   r*   r+   r.   r/   Nz%(py0)s == %(py2)soriginaloriginal_copyrH   rI   assert %(py4)sr-   )copydeepcopyr	   r1   r2   r3   r4   r5   rQ   rR   rS   )rg   rh   r   r8   r9   r:   r;   r<   r=   rW   @py_format3s              r   8test_bb4_apply_patch_returns_new_dict_original_unchangedrn   W   s    QHMM(+Mtb9:E5)F#;";";";"}$$$$8}$$$$$$8$$$8$$$$$$}$$$}$$$$$$$r   c                 2   ddi} ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }dd|iz  }t	        t        j
                  |            dx}x}}|d   }d}||k(  }|slt        j                  d|fd	||f      t        j                  |      t        j                  |      d
z  }dd|iz  }t	        t        j
                  |            dx}x}}y)z@BB5: "add" op on a new key creates the key with the given value.existingyesaddz
/new_fieldcreatedr$   	new_fieldr(   r*   r+   r.   r/   Nr0   r6   s           r   test_bb5_add_creates_new_keyru   a   s    E<)DEE&F++)+)++++)++++++)+++++++*&&&&&&&&&&&&&&&&&&&r   c                    ddi} ddddg}t        | |      }|| k(  }|st        j                  d|fd|| f      dt        j                         v st        j
                  |      rt        j                  |      ndd	t        j                         v st        j
                  |       rt        j                  |       nd	d
z  }dd|iz  }t        t        j                  |            d}y)uL   BB6: op: "test" with correct value → no exception raised, state unchanged.r@   rA   rB   rC   r$   r(   rf   r8   r7   ri   rj   r-   N)	r	   r1   r2   rQ   rR   rS   r3   r4   r5   )r7   r   r8   rW   rm   r<   s         r   %test_bb6_test_op_correct_value_passesrw   j   s    x EIABE&FU?6U66UUr   c                 |   ddd} dddg}t        | |      }d}||v}|st        j                  d|fd	||f      t        j                  |      d
t	        j
                         v st        j                  |      rt        j                  |      nd
dz  }dd|iz  }t        t        j                  |            dx}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}y)z4BB7: "remove" op deletes an existing key from state.rq   bye)keep	delete_meremovez
/delete_mer%   r&   r{   not inz%(py1)s not in %(py3)sr8   r,   py3assert %(py5)srJ   Nrz   r(   r*   r+   r.   r/   )	r	   r1   r2   r3   rQ   rR   rS   r4   r5   )
r7   r   r8   r9   r;   @py_format4rY   r:   r<   r=   s
             r   test_bb7_remove_op_deletes_keyr   r   s    /El34E&F$;f$$$$;f$$$;$$$$$$f$$$f$$$$$$$&>"U">U"""">U""">"""U"""""""r   c                    ddi} ddddg}t        t        |            }|j                  |       }t        | |      }||k(  }|st	        j
                  d|fd	||f      d
t        j                         v st	        j                  |      rt	        j                  |      nd
dt        j                         v st	        j                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            d}y)zRBB8: StateDelta.apply_to() gives same result as apply_patch() with the same state.val
   r"   z/val*   r$   r   r(   rf   result_methodresult_funcri   rj   r-   N)r   tupleapply_tor	   r1   r2   rQ   rR   rS   r3   r4   r5   )r7   
patch_listr_   r   r   rW   rm   r<   s           r   8test_bb8_apply_to_convenience_method_matches_apply_patchr   {   s    BKE"FR@AJeJ/0ENN5)MeZ0KK''''=K''''''='''=''''''K'''K'''''''r   c                 F   ddddiii} ddddg}t        | |      }|d   d   d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}y)z1BB9: Nested path like "/a/b/c" works for replace.abcr   r"   z/a/b/cr#   r$   r(   r*   r+   r.   r/   Nr0   r6   s           r   test_bb9_nested_path_replacer      s    3e%&Ex%@AE&F#;sC )E) E)))) E))) )))E)))))))r   c                 <   ddi} ddddddddg}t        | |      }|d	   }d}||k(  }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}y)u9   BB10: Multiple ops applied in order — add then replace.rb   r   rr   /yr   r$   r"      rc   r(   r*   r+   r.   r/   Nr0   r6   s           r   )test_bb10_multi_op_patch_applied_in_orderr      s    !HEdR0$4E &F#;";";";"r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)uH   WB1: validate_patch rejects unknown op type "destroy" → returns False.destroyrd   r}   Fisz0%(py3)s
{%(py3)s = %(py0)s(%(py1)s)
} is %(py6)sr   r   rH   r,   r   r/   assert %(py8)spy8N	r   r1   r2   rQ   rR   rS   r3   r4   r5   r   r;   @py_assert5rX   r=   @py_format9s         r   *test_wb1_validate_patch_rejects_unknown_opr      s    t,-E% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)uG   WB2: validate_patch rejects op dict missing "op" key → returns False.rd   r   )r&   r'   Fr   r   r   r   r   r   r   Nr   r   s         r   .test_wb2_validate_patch_rejects_missing_op_keyr      s    Q'(E% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c            	     Z   ddddddddddddd	dd
dddd
ddddg} | D ]  }|g}t        |      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |      t        j                  |      t        j                  |      dz  }t        j                  d|d          dz   d|iz  }t        t        j                  |            dx}x}x}}	 y)uF   WB3: validate_patch accepts all 6 valid ops → returns True for each.rr   rd   r   r$   r|   r}   r"   mover   r%   r&   fromrk   z/zrB   Tr   z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)sr   rH   rI   r-   rL   zExpected True for op: r%   z
>assert %(py9)spy9N)
r   r1   r2   rQ   rR   rS   r3   _format_assertmsgr4   r5   )ops_with_required_fieldsop_dictrW   r:   @py_assert6r   rZ   @py_format10s           r   1test_wb3_validate_patch_accepts_all_six_valid_opsr      s     dQ/&$3tT2tT2ta0  , [&iZ~i(ZDZ(D0ZZZ(DZZZZZZ~ZZZ~ZZZiZZZ(ZZZDZZZ4J7SW=/2ZZZZZZZZ[r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)zBWB4: validate_patch returns False if "move" op missing "from" key.r   /destr}   Fr   r   r   r   r   r   r   Nr   r   s         r   .test_wb4_validate_patch_requires_from_for_mover          G,-E% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)zBWB5: validate_patch returns False if "copy" op missing "from" key.rk   r   r}   Fr   r   r   r   r   r   r   Nr   r   s         r   .test_wb5_validate_patch_requires_from_for_copyr      r   r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)zBWB6: validate_patch returns False if "add" op missing "value" key.rr   rd   r}   Fr   r   r   r   r   r   r   Nr   r   s         r   .test_wb6_validate_patch_requires_value_for_addr      s    4()E% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c                 .   dddg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}}y)zCWB7: validate_patch returns False if "test" op missing "value" key.rB   rd   r}   Fr   r   r   r   r   r   r   Nr   r   s         r   /test_wb7_validate_patch_requires_value_for_testr      s    D)*E% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c                     ddi} dddg}t        j                  t              5  t        | |       ddd       y# 1 sw Y   yxY w)u<   WB5 (test plan): "remove" on non-existent path → KeyError.r   r   r|   z/nonexistentr}   NrO   rP   KeyErrorr	   r7   r   s     r   *test_wb8_remove_on_nonexistent_path_raisesr      sC    !HEn56E	x	  "E5!" " "s	   :Ac                 p   dddd} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx} x}x}}d} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx} x}x}}d} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx} x}x}}y)z8WB: validate_patch returns False if patch is not a list.rr   rd   r   r$   Fr   r   r   r   assert %(py9)sr   Nz
not a listr   rW   r:   r   r   rZ   r   s         r   (test_wb9_validate_patch_rejects_non_listr      s   !&qAK>ABKeKBeKKKKBeKKKKKK>KKK>KKKAKKKBKKKeKKKKKKK&0>,'050'50000'5000000>000>000,000'00050000000(>$(5(5((((5((((((>(((>((($((((((5(((((((r   c                 (   dg} t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               nddt        j                         v st        j
                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}y
)z>WB: validate_patch returns False if any element is not a dict.zadd /x 1Fr   r   r   r   r   r   r   Nr   r   s         r   2test_wb10_validate_patch_rejects_non_dict_elementsr      s    LE% )E) E)))) E))))))>)))>))))))%)))%))) )))E)))))))r   c                 (   t        ddd      } | j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}| j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}| j                  }d}||k(  }|st        j                  d|fd||f      dt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      t        j                  |      dz  }dd	|iz  }t        t        j                  |            d
x}x}}d}t        |       }||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d
x}x}}d}t        |       }||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d
x}x}}d}t        |       }||v }|st        j                  d|fd||f      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      dz  }	dd|	iz  }
t        t        j                  |
            d
x}x}}y
)z=WB: PatchConflictError has path, expected, actual attributes.rd   expected_val
actual_valr(   rE   rF   rG   rK   rL   NrM   rN   )in)z0%(py1)s in %(py6)s
{%(py6)s = %(py3)s(%(py4)s)
}str)r,   r   r-   r/   r   r   )r   r&   r1   r2   rQ   rR   rS   r3   r4   r5   rT   rU   r   )rF   rW   rX   r:   rY   rZ   r9   r   r;   r=   r   s              r   )test_wb11_patch_conflict_error_attributesr      s   
T><
@C88t8t8t338t<<)>)<>))))<>))))))3)))3)))<)))>)))))))::%%:%%%%:%%%%%%3%%%3%%%:%%%%%%%%%%3s84848433ss8%SX%>X%%%%>X%%%>%%%%%%S%%%S%%%%%%%%%%%%X%%%%%%%#3s8#<8####<8###<######3###3######s###s###8#######r   c                 t   h d} t         | k(  }|st        j                  d|fdt         | f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       dz  }dd|iz  }t        t        j                  |            dx}} y)	z9WB: VALID_OPS contains exactly the 6 RFC 6902 operations.>   rr   rk   r   rB   r|   r"   r(   )z%(py0)s == %(py3)sr
   )rH   r   r   rJ   N)	r
   r1   r2   rQ   rR   rS   r3   r4   r5   )r;   rW   r   rY   s       r   ,test_wb12_valid_ops_set_contains_exactly_sixr      s^    LL9LLLLL9LLLLLLL9LLL9LLLLLLLLLLLr   c                 p   t        dddfd      } | j                  }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |       rt        j                  |       nd	t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |       rt        j                  |       nd	t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}| j                  }d}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |       rt        j                  |       nd	t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}| j                  }dddf}||k(  }|st        j                  d|fd||f      d	t	        j
                         v st        j                  |       rt        j                  |       nd	t        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}| j                  }|t        k(  }|st        j                  d|fd|t        f      d	t	        j
                         v st        j                  |       rt        j                  |       nd	t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            dx}}y)z>WB: All StateDelta fields are accessible on a frozen instance.r|   rd   r}      r   r   r(   )z0%(py2)s
{%(py2)s = %(py0)s.agent_id
} == %(py5)sr_   rG   rK   rL   Nr   )z2%(py2)s
{%(py2)s = %(py0)s.session_id
} == %(py5)s)z7%(py2)s
{%(py2)s = %(py0)s.version_at_read
} == %(py5)s)z-%(py2)s
{%(py2)s = %(py0)s.patch
} == %(py5)s)z4%(py2)s
{%(py2)s = %(py0)s.submitted_at
} == %(py4)sr   )rH   rI   r-   r.   r/   )r   r   r1   r2   rQ   rR   rS   r3   r4   r5   r   r   r   r   r   )r_   rW   rX   r:   rY   rZ   r<   r=   s           r   ,test_wb13_frozen_dataclass_fields_accessibler      s`   h=?KE>>([(>[((((>[((((((5(((5(((>((([((((((()z)z))))z))))))5)))5))))))z)))))))  %A% A%%%% A%%%%%%5%%%5%%% %%%A%%%%%%%;;;(D9;;;;;;;;;;;;;;;;5;;;5;;;;;;;;;;;;;;;%%%%%%%%%%%5%%%5%%%%%%%%%%%%%%%%%%%r   c                    t        ddddf      } | j                  }t        |t              }|sddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |       rt        j                  |       ndt        j                  |      d	t	        j
                         v st        j                  t              rt        j                  t              nd	t        j                  |      d
z  }t        t        j                  |            dx}}y)zLWB: StateDelta.patch is a tuple (frozen dataclass requires hashable fields).rr   z/kr   r$   r   zPassert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.patch
}, %(py4)s)
}
isinstancer_   r   )rH   r,   r   r-   r/   N)r   r   r   r   rQ   rR   r1   rS   r3   r4   r5   )r_   r;   r   r=   s       r   !test_wb14_patch_is_tuple_not_listr      s    eTAFHIEkk):k5)))))))):))):))))))e)))e)))k))))))5)))5))))))))))r   c                 ~   ddd} ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}d}||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j                  |      rt        j                  |      nddz  }dd|iz  }	t	        t        j
                  |	            dx}}y)z@WB: 'move' removes from source path and sets value at dest path.value_to_moveN)srcdestr   r   /srcr   r   r(   r*   r+   r.   r/   r   r~   r   r8   r   r   rJ   )	r	   r1   r2   r3   r4   r5   rQ   rR   rS   )
r7   r   r8   r9   r:   r;   r<   r=   r   rY   s
             r   *test_wb15_move_op_removes_source_adds_destr     s    #T2EGV<=E&F&>,_,>_,,,,>_,,,>,,,_,,,,,,,555r   c                 2   ddi} ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t	        t        j
                  |            dx}x}}|d   }d}||k(  }|slt        j                  d|fd||f      t        j                  |      t        j                  |      d	z  }d
d|iz  }t	        t        j
                  |            dx}x}}y)z2WB: 'copy' copies from source without removing it.r   rg   rk   r   r   r   r(   r*   r+   r.   r/   Nr   r0   r6   s           r   (test_wb16_copy_op_does_not_remove_sourcer     s    JEGV<=E&F%=&J&=J&&&&=J&&&=&&&J&&&&&&&&>'Z'>Z''''>Z'''>'''Z'''''''r   c                 r   ddg dii} ddddg}t        | |      }|d   d   j                  d	       | d   d   }g d}||k(  }|slt        j                  d
|fd||f      t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uX   WB: 'copy' op performs a deep copy — mutating the result's copy doesn't affect source.r   nested)r   r      rk   r   r   r   r   re   r(   r*   r+   r.   r/   N)r	   appendr1   r2   r3   r4   r5   r6   s           r   test_wb17_copy_op_is_deep_copyr     s    Xy)*EGV<=E&F
6N8##B'<!.Y.!Y....!Y...!...Y.......r   c                     ddi} ddddg}t        j                  t              5  t        | |       ddd       y# 1 sw Y   yxY w)z@WB: 'replace' on non-existent path raises KeyError (must exist).r   r   r"   z/does_not_existre   r$   Nr   r   s     r   ,test_wb18_replace_on_nonexistent_path_raisesr      sF    !HE'82FGE	x	  "E5!" " "s	   ;Ac                    g } t        |       }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  t               rt        j                  t               ndt        j                  |       t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx} x}x}}y)	zMWB: validate_patch returns True for an empty patch (no-op is valid RFC 6902).Tr   r   r   r   r   r   Nr   r   s         r   +test_wb19_validate_patch_accepts_empty_listr   (  s    %>"%%%%%%%%%%%%>%%%>%%%"%%%%%%%%%%%%%r   c                 Z   ddd} ddddg}t        | |      }|d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}ddddg}t        | |      }	|	d   }d}||k(  }|slt        j                  d	|fd
||f      t        j                  |      t        j                  |      dz  }dd|iz  }t	        t        j
                  |            dx}x}}y)u;   WB: RFC 6901 tilde escaping — ~1 means '/', ~0 means '~'.	slash_key	tilde_key)a/bc~dr"   z/a~1bupdatedr$   r   r(   r*   r+   r.   r/   Nz/c~0dupdated_tilder   r0   )
r7   patch_slashr8   r9   r:   r;   r<   r=   patch_tilderesult2s
             r   !test_wb20_tilde_escaping_in_pathsr   -  s    4E#WyIJK,F%=%I%=I%%%%=I%%%=%%%I%%%%%%% $WOPK%-G5>,_,>_,,,,>_,,,>,,,_,,,,,,,r   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)z9Package level: StateDelta importable from core.coherence.r   )r   r   z%(py0)s is %(py2)sSDr   ri   rj   r-   N)
core.coherencer   r1   r2   rQ   rR   rS   r3   r4   r5   )r   rW   rm   r<   s       r    test_package_exports_state_deltar   @  sm    /222r   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)zAPackage level: PatchConflictError importable from core.coherence.r   )r   r   r   PCEr   ri   rj   r-   N)
r   r   r1   r2   rQ   rR   rS   r3   r4   r5   )r   rW   rm   r<   s       r   )test_package_exports_patch_conflict_errorr   F  sq    8$$$$$3$$$$$$$3$$$3$$$$$$$$$$$$$$$$$$r   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)z=Package level: validate_patch importable from core.coherence.r   )r   r   r   vpr   ri   rj   r-   N)
r   r   r1   r2   rQ   rR   rS   r3   r4   r5   )r   rW   rm   r<   s       r   #test_package_exports_validate_patchr   L  sm    3222r   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)z:Package level: apply_patch importable from core.coherence.r   )r	   r   r   apr	   ri   rj   r-   N)
r   r	   r1   r2   rQ   rR   rS   r3   r4   r5   )r  rW   rm   r<   s       r    test_package_exports_apply_patchr  R  sm    0222r   c                    ddl m}  | t        u }|st        j                  d|fd| t        f      dt	        j
                         v st        j                  |       rt        j                  |       nddt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd	|iz  }t        t        j                  |            d
}y
)z8Package level: VALID_OPS importable from core.coherence.r   )r
   r   r   vor
   ri   rj   r-   N)
r   r
   r1   r2   rQ   rR   rS   r3   r4   r5   )r  rW   rm   r<   s       r   test_package_exports_valid_opsr  X  sl    .?222r   __main__c                    t         dz  a 	  |        t        d|         t        dz  ay # t        $ r/}t        d|  d|        t	        j
                          Y d }~y d }~ww xY w)Nr   z	  [PASS] z	  [FAIL] z: )	tests_runprinttests_passedr^   	traceback	print_exc)r    fnexcs      r   _runr  h  sb    Q		"DIdV$%AL 	"IdV2cU+,!!	"s   * 	A"%AA"zBB1: replace op updates stateu/   BB2: test op wrong value → PatchConflictErrorz(BB3: frozen dataclass raises on mutationz!BB4: apply_patch returns new dictzBB5: add creates new keyz!BB6: test op correct value passeszBB7: remove op deletes keyz BB8: apply_to convenience methodzBB9: nested path replacezBB10: multi-op patch in orderz&WB1: validate_patch rejects unknown opz*WB2: validate_patch rejects missing op keyz%WB3: validate_patch accepts all 6 opsz,WB4: validate_patch requires 'from' for movez,WB5: validate_patch requires 'from' for copyz,WB6: validate_patch requires 'value' for addz-WB7: validate_patch requires 'value' for testz&WB8: remove on nonexistent path raisesz$WB9: validate_patch rejects non-listz.WB10: validate_patch rejects non-dict elementsz#WB11: PatchConflictError attributesz!WB12: VALID_OPS has exactly 6 opsz(WB13: frozen dataclass fields accessiblezWB14: patch is tuple not listz$WB15: move removes source, adds destz!WB16: copy does not remove sourcezWB17: copy is deep copyz#WB18: replace on nonexistent raiseszWB19: empty patch is validzWB20: tilde escaping in pathszPKG: StateDelta exportzPKG: PatchConflictError exportzPKG: validate_patch exportzPKG: apply_patch exportzPKG: VALID_OPS export
/z tests passedz(ALL TESTS PASSED -- Story 6.01 (Track B)) r   )r   r   r   intreturnr   )r    r   )C__doc__
__future__r   builtinsrQ   _pytest.assertion.rewrite	assertionrewriter1   sysr&   insertrk   rO   r   r   core.coherence.state_deltar   r   r   r	   r
   utcr   r   r>   r[   r`   rn   ru   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  __name__r  r  r
  r  r	  exitr  r   r   <module>r!     s  
 #   
 * +   '  aRAhll; 	"$%'#(* **[****")*$M
&*(/"&
-&%  zIL	" 		(*KL	:<tu	35kl	,.fg	#%AB	,.ST	%'EF	+-ef	#%AB	(*ST 		13]^	57ef	02cd	79gh	79gh	79gh	8:ij	13]^	/1YZ	9;mn	.0YZ	,.Z[	35ab	(*KL	/1[\	,.VW	"$BC	.0\]	%'RS	(*KL 		!#CD	)+TU	%'JK	"$DE	 "@A	B|nAi[
67y 89} r   