@@ -127,16 +127,20 @@ public async Task SendsCorrectPayloadWithPersonProperties()
127127 container . FakeTimeProvider . SetUtcNow ( new DateTimeOffset ( 2024 , 1 , 21 , 19 , 08 , 23 , TimeSpan . Zero ) ) ;
128128 var requestHandler = container . FakeHttpMessageHandler . AddCaptureResponse ( ) ;
129129 var client = container . Activate < PostHogClient > ( ) ;
130+ var personPropertiesToSet = new Dictionary < string , object > { [ "age" ] = 36 } ;
131+ var personPropertiesToSetOnce = new Dictionary < string , object > { [ "join_date" ] = "2024-01-21" } ;
130132
131133 var result = await client . IdentifyAsync (
132134 distinctId : "some-distinct-id" ,
133135 email : "wildling-lover@example.com" ,
134136 name : "Jon Snow" ,
135- personPropertiesToSet : new ( ) { [ "age" ] = 36 } ,
136- personPropertiesToSetOnce : new ( ) { [ "join_date" ] = "2024-01-21" } ,
137+ personPropertiesToSet ,
138+ personPropertiesToSetOnce ,
137139 CancellationToken . None ) ;
138140
139141 Assert . Equal ( 1 , result . Status ) ;
142+ Assert . Equal ( new Dictionary < string , object > { [ "age" ] = 36 } , personPropertiesToSet ) ;
143+ Assert . Equal ( new Dictionary < string , object > { [ "join_date" ] = "2024-01-21" } , personPropertiesToSetOnce ) ;
140144 var received = requestHandler . GetReceivedRequestBody ( indented : true ) ;
141145 Assert . Equal ( $$ """
142146 {
@@ -245,7 +249,7 @@ public async Task SendsCorrectPayload()
245249 }
246250
247251 [ Fact ]
248- public async Task CancellationTokenOverloadOverwritesNameProperty ( )
252+ public async Task CancellationTokenOverloadDoesNotOverwriteInputNameProperty ( )
249253 {
250254 var container = new TestContainer ( ) ;
251255 var requestHandler = container . FakeHttpMessageHandler . AddCaptureResponse ( ) ;
@@ -264,7 +268,7 @@ public async Task CancellationTokenOverloadOverwritesNameProperty()
264268 CancellationToken . None ) ;
265269
266270 Assert . Equal ( 1 , result . Status ) ;
267- Assert . Equal ( "PostHog " , properties [ "name" ] ) ;
271+ Assert . Equal ( "Old Name " , properties [ "name" ] ) ;
268272 using var document = JsonDocument . Parse ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
269273 var root = document . RootElement ;
270274 var groupSet = root . GetProperty ( "properties" ) . GetProperty ( "$group_set" ) ;
@@ -274,7 +278,7 @@ public async Task CancellationTokenOverloadOverwritesNameProperty()
274278 }
275279
276280 [ Fact ]
277- public async Task DistinctIdCancellationTokenOverloadOverwritesNameProperty ( )
281+ public async Task DistinctIdCancellationTokenOverloadDoesNotOverwriteInputNameProperty ( )
278282 {
279283 var container = new TestContainer ( ) ;
280284 var requestHandler = container . FakeHttpMessageHandler . AddCaptureResponse ( ) ;
@@ -294,7 +298,7 @@ public async Task DistinctIdCancellationTokenOverloadOverwritesNameProperty()
294298 CancellationToken . None ) ;
295299
296300 Assert . Equal ( 1 , result . Status ) ;
297- Assert . Equal ( "PostHog " , properties [ "name" ] ) ;
301+ Assert . Equal ( "Old Name " , properties [ "name" ] ) ;
298302 using var document = JsonDocument . Parse ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
299303 var root = document . RootElement ;
300304 var groupSet = root . GetProperty ( "properties" ) . GetProperty ( "$group_set" ) ;
@@ -415,6 +419,34 @@ static JsonElement GetOnlyBatchItem(FakeHttpMessageHandler.RequestHandler batchH
415419
416420public class TheCaptureMethod
417421{
422+ [ Fact ]
423+ public async Task DoesNotMutateOrRetainProvidedProperties ( )
424+ {
425+ var container = new TestContainer ( services => services . Configure < PostHogOptions > ( options =>
426+ {
427+ options . SuperProperties [ "super" ] = "property" ;
428+ } ) ) ;
429+ var requestHandler = container . FakeHttpMessageHandler . AddBatchResponse ( ) ;
430+ var client = container . Activate < PostHogClient > ( ) ;
431+ var timestamp = new DateTimeOffset ( 2024 , 1 , 21 , 19 , 8 , 23 , TimeSpan . Zero ) ;
432+ var properties = new Dictionary < string , object > { [ "source" ] = "before" } ;
433+ var groups = new GroupCollection { new Group ( "company" , "acme" ) } ;
434+
435+ Assert . True ( client . Capture ( "test-user" , "test-event" , properties , groups , flags : null , timestamp ) ) ;
436+ Assert . Equal ( new Dictionary < string , object > { [ "source" ] = "before" } , properties ) ;
437+
438+ properties [ "source" ] = "after" ;
439+ await client . FlushAsync ( ) ;
440+
441+ using var document = JsonDocument . Parse ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
442+ var capturedProperties = document . RootElement . GetProperty ( "batch" ) [ 0 ] . GetProperty ( "properties" ) ;
443+ Assert . Equal ( "before" , capturedProperties . GetProperty ( "source" ) . GetString ( ) ) ;
444+ Assert . Equal ( "property" , capturedProperties . GetProperty ( "super" ) . GetString ( ) ) ;
445+ Assert . Equal ( "acme" , capturedProperties . GetProperty ( "$groups" ) . GetProperty ( "company" ) . GetString ( ) ) ;
446+ Assert . True ( capturedProperties . GetProperty ( "$is_server" ) . GetBoolean ( ) ) ;
447+ Assert . Equal ( timestamp , capturedProperties . GetProperty ( "timestamp" ) . GetDateTimeOffset ( ) ) ;
448+ }
449+
418450 [ Fact ]
419451 public async Task BeforeSendCanModifyFullyEnrichedEventBeforeUpload ( )
420452 {
@@ -436,13 +468,13 @@ public async Task BeforeSendCanModifyFullyEnrichedEventBeforeUpload()
436468 } ) ) ;
437469 var requestHandler = container . FakeHttpMessageHandler . AddBatchResponse ( ) ;
438470 var client = container . Activate < PostHogClient > ( ) ;
471+ var inputProperties = new Dictionary < string , object > { [ "secret" ] = "remove-me" } ;
439472
440- client . Capture (
441- "test-user" ,
442- "before-send-event" ,
443- new Dictionary < string , object > { [ "secret" ] = "remove-me" } ) ;
473+ client . Capture ( "test-user" , "before-send-event" , inputProperties ) ;
444474 await client . FlushAsync ( ) ;
445475
476+ Assert . Equal ( "remove-me" , inputProperties [ "secret" ] ) ;
477+
446478 using var document = JsonDocument . Parse ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
447479 var properties = document . RootElement
448480 . GetProperty ( "batch" ) [ 0 ]
@@ -1183,6 +1215,27 @@ public async Task CaptureDefaultsToNotSendingFeatureFlagsEvenWhenLocalEvaluation
11831215
11841216public class TheCaptureExceptionMethod
11851217{
1218+ [ Fact ]
1219+ public async Task DoesNotMutateProvidedProperties ( )
1220+ {
1221+ var ( _, requestHandler , client ) = CreateClient ( ) ;
1222+ var properties = new Dictionary < string , object > { [ "source" ] = "test" } ;
1223+
1224+ Assert . True ( client . CaptureException (
1225+ new InvalidOperationException ( "boom" ) ,
1226+ "some-distinct-id" ,
1227+ properties ,
1228+ groups : null ,
1229+ flags : null ,
1230+ timestamp : DateTimeOffset . UtcNow ) ) ;
1231+ Assert . Equal ( new Dictionary < string , object > { [ "source" ] = "test" } , properties ) ;
1232+
1233+ await client . FlushAsync ( ) ;
1234+ var ( _, _, capturedProperties ) = ParseSingleEvent ( requestHandler . GetReceivedRequestBody ( indented : false ) ) ;
1235+ Assert . Equal ( "test" , capturedProperties . GetProperty ( "source" ) . GetString ( ) ) ;
1236+ Assert . Equal ( "System.InvalidOperationException" , capturedProperties . GetProperty ( "$exception_type" ) . GetString ( ) ) ;
1237+ }
1238+
11861239 [ Fact ]
11871240 public async Task CaptureExceptionWithDivideByZeroException ( ) // based on PostHog/posthog-python test_exception_capture
11881241 {
0 commit comments