@@ -2196,7 +2196,7 @@ public void Position_TryGetSnapshot_NoSnapshot_ReturnsFalse()
21962196 }
21972197
21982198 [ TestMethod ]
2199- public void Position_Process_ReturnsSameReference ( )
2199+ public void Position_Process_ReturnsCopy ( )
22002200 {
22012201 var holder = new PositionSnapshotHolder ( ) ;
22022202 var msg1 = new PositionChangeMessage
@@ -2219,8 +2219,13 @@ public void Position_Process_ReturnsSameReference()
22192219
22202220 var result2 = holder . Process ( msg2 ) ;
22212221
2222- // Must return same reference
2223- result1 . AssertSame ( result2 ) ;
2222+ // Must return different references (copies)
2223+ result1 . AssertNotSame ( result2 ) ;
2224+
2225+ // result1 has state from first Process call
2226+ result1 . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 100m ) ;
2227+ // result2 has updated state
2228+ result2 . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 150m ) ;
22242229 }
22252230
22262231 [ TestMethod ]
@@ -2237,9 +2242,7 @@ public void Position_Process_UpdatesExistingSnapshot()
22372242 . TryAdd ( PositionChangeTypes . CurrentValue , 100m )
22382243 . TryAdd ( PositionChangeTypes . AveragePrice , 50m ) ;
22392244
2240- var snapshot = holder . Process ( msg1 ) ;
2241- snapshot . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 100m ) ;
2242- snapshot . Changes [ PositionChangeTypes . AveragePrice ] . AssertEqual ( 50m ) ;
2245+ holder . Process ( msg1 ) ;
22432246
22442247 var msg2 = new PositionChangeMessage
22452248 {
@@ -2250,9 +2253,9 @@ public void Position_Process_UpdatesExistingSnapshot()
22502253 . TryAdd ( PositionChangeTypes . CurrentValue , 150m )
22512254 . TryAdd ( PositionChangeTypes . UnrealizedPnL , 25m ) ;
22522255
2253- holder . Process ( msg2 ) ;
2256+ var snapshot = holder . Process ( msg2 ) ;
22542257
2255- // Same snapshot should be updated
2258+ // Returned copy should have merged state
22562259 snapshot . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 150m ) ;
22572260 snapshot . Changes [ PositionChangeTypes . AveragePrice ] . AssertEqual ( 50m ) ; // unchanged
22582261 snapshot . Changes [ PositionChangeTypes . UnrealizedPnL ] . AssertEqual ( 25m ) ; // new field
@@ -2472,7 +2475,7 @@ public void Position_KeyIsCaseInsensitive()
24722475 }
24732476 . TryAdd ( PositionChangeTypes . CurrentValue , 100m ) ;
24742477
2475- var snap1 = holder . Process ( msg1 ) ;
2478+ holder . Process ( msg1 ) ;
24762479
24772480 var msg2 = new PositionChangeMessage
24782481 {
@@ -2486,9 +2489,12 @@ public void Position_KeyIsCaseInsensitive()
24862489
24872490 var snap2 = holder . Process ( msg2 ) ;
24882491
2489- // Should be same reference due to case-insensitive key
2490- snap1 . AssertSame ( snap2 ) ;
2491- snap1 . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 200m ) ;
2492+ // Case-insensitive key — same internal snapshot updated, returned as copy
2493+ snap2 . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 200m ) ;
2494+
2495+ // Verify via TryGetSnapshot — should also return 200
2496+ holder . TryGetSnapshot ( msg1 , out var retrieved ) ;
2497+ retrieved . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 200m ) ;
24922498 }
24932499
24942500 #endregion
@@ -2774,10 +2780,10 @@ public void Order_TryGetSnapshot_ReturnsCopy()
27742780 }
27752781
27762782 /// <summary>
2777- /// BUG #3: Position holder also returns live reference.
2783+ /// Position TryGetSnapshot must return a copy, not the internal reference.
27782784 /// </summary>
27792785 [ TestMethod ]
2780- public void Position_LiveReference_CanBeMutatedExternally_Bug ( )
2786+ public void Position_TryGetSnapshot_ReturnsCopy ( )
27812787 {
27822788 var holder = new PositionSnapshotHolder ( ) ;
27832789
@@ -2789,23 +2795,44 @@ public void Position_LiveReference_CanBeMutatedExternally_Bug()
27892795 }
27902796 . TryAdd ( PositionChangeTypes . CurrentValue , 100m ) ;
27912797
2792- var snapshot = holder . Process ( msg1 ) ;
2798+ holder . Process ( msg1 ) ;
27932799
2794- // Get snapshot via TryGetSnapshot
2795- holder . TryGetSnapshot ( msg1 , out var retrieved ) ;
2800+ // Get snapshot twice
2801+ holder . TryGetSnapshot ( msg1 , out var snap1 ) ;
2802+ holder . TryGetSnapshot ( msg1 , out var snap2 ) ;
2803+
2804+ // Should be different references (copies)
2805+ snap1 . AssertNotSame ( snap2 ) ;
27962806
2797- // BUG: Same reference returned
2798- snapshot . AssertSame ( retrieved ) ;
2807+ // But with same data
2808+ snap1 . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( snap2 . Changes [ PositionChangeTypes . CurrentValue ] ) ;
2809+ }
27992810
2800- // External code can mutate the internal state!
2801- retrieved . Changes [ PositionChangeTypes . CurrentValue ] = 999m ;
2811+ /// <summary>
2812+ /// Position Process must return a copy, not the internal reference.
2813+ /// External mutation must not affect internal state.
2814+ /// </summary>
2815+ [ TestMethod ]
2816+ public void Position_Process_ReturnsCopy_IsolatedFromInternal ( )
2817+ {
2818+ var holder = new PositionSnapshotHolder ( ) ;
28022819
2803- // This affects the internal snapshot
2804- holder . TryGetSnapshot ( msg1 , out var afterMutation ) ;
2805- afterMutation . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 999m ) ;
2820+ var msg1 = new PositionChangeMessage
2821+ {
2822+ PortfolioName = "Portfolio1" ,
2823+ SecurityId = _secId1 ,
2824+ ServerTime = _now ,
2825+ }
2826+ . TryAdd ( PositionChangeTypes . CurrentValue , 100m ) ;
28062827
2807- // Original 'snapshot' variable is also affected (same reference)
2808- snapshot . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 999m ) ;
2828+ var snapshot = holder . Process ( msg1 ) ;
2829+
2830+ // Mutate the returned copy
2831+ snapshot . Changes [ PositionChangeTypes . CurrentValue ] = 999m ;
2832+
2833+ // Internal state must NOT be affected
2834+ holder . TryGetSnapshot ( msg1 , out var afterMutation ) ;
2835+ afterMutation . Changes [ PositionChangeTypes . CurrentValue ] . AssertEqual ( 100m ) ;
28092836 }
28102837
28112838 /// <summary>
0 commit comments