@@ -35,6 +35,7 @@ public class ResponseMapperTests
3535 private static JsonDocument _mappingJson ;
3636 private static JsonDocument _propertyAliasesJson ;
3737 private static Dictionary < string , Dictionary < string , string > > _propertyAliases ;
38+ private static List < S3Grant > _s3Grants ;
3839
3940 [ ClassInitialize ]
4041 public static void ClassInitialize ( TestContext context )
@@ -214,6 +215,231 @@ public void MapPutObjectResponse_AllMappedProperties_WorkCorrectly()
214215 }
215216 }
216217
218+ [ TestMethod ]
219+ [ TestCategory ( "S3" ) ]
220+ public void MapUploadRequest_PutObjectRequest_AllMappedProperties_WorkCorrectly ( )
221+ {
222+ // Get the expected mappings from JSON
223+ var putObjectMappings = _mappingJson . RootElement
224+ . GetProperty ( "Conversion" )
225+ . GetProperty ( "UploadRequest" )
226+ . GetProperty ( "PutObjectRequest" )
227+ . EnumerateArray ( )
228+ . Select ( prop => prop . GetString ( ) )
229+ . ToList ( ) ;
230+
231+ // Create source object with dynamically generated test data
232+ var sourceRequest = new TransferUtilityUploadRequest ( ) ;
233+ var sourceType = typeof ( TransferUtilityUploadRequest ) ;
234+ var testDataValues = new Dictionary < string , object > ( ) ;
235+
236+ // Generate test data for each mapped property
237+ foreach ( var propertyName in putObjectMappings )
238+ {
239+ // Resolve alias to actual property name
240+ var resolvedPropertyName = ResolvePropertyName ( propertyName , sourceType . Name ) ;
241+ var sourceProperty = sourceType . GetProperty ( resolvedPropertyName ) ;
242+ if ( sourceProperty ? . CanWrite == true )
243+ {
244+ var testValue = GenerateTestValue ( sourceProperty . PropertyType , propertyName ) ;
245+ sourceProperty . SetValue ( sourceRequest , testValue ) ;
246+ testDataValues [ propertyName ] = testValue ;
247+ }
248+ }
249+
250+ var simpleUploadCommand = new SimpleUploadCommand ( null , null , sourceRequest ) ;
251+
252+ // Map the response
253+ var mappedRequest = simpleUploadCommand . ConstructRequest ( ) ;
254+ Assert . IsNotNull ( mappedRequest , "Mapped request should not be null" ) ;
255+
256+ // Verify all mapped properties using reflection
257+ var targetType = typeof ( PutObjectRequest ) ;
258+ var failedAssertions = new List < string > ( ) ;
259+
260+ foreach ( var propertyName in putObjectMappings )
261+ {
262+ // Resolve alias to actual property name for reflection lookups
263+ var resolvedPropertyName = ResolvePropertyName ( propertyName , sourceType . Name ) ;
264+ var sourceProperty = sourceType . GetProperty ( resolvedPropertyName ) ;
265+ var targetProperty = targetType . GetProperty ( resolvedPropertyName ) ;
266+
267+ if ( sourceProperty == null )
268+ {
269+ failedAssertions . Add ( $ "Source property '{ propertyName } ' (resolved to: { resolvedPropertyName } ) not found in PutObjectResponse") ;
270+ continue ;
271+ }
272+
273+ if ( targetProperty == null )
274+ {
275+ failedAssertions . Add ( $ "Target property '{ propertyName } ' (resolved to: { resolvedPropertyName } ) not found in TransferUtilityUploadResponse") ;
276+ continue ;
277+ }
278+
279+ var sourceValue = sourceProperty . GetValue ( sourceRequest ) ;
280+ var targetValue = targetProperty . GetValue ( mappedRequest ) ;
281+
282+ // Special handling for complex object comparisons
283+ if ( ! AreValuesEqual ( sourceValue , targetValue ) )
284+ {
285+ failedAssertions . Add ( $ "{ propertyName } : Expected '{ sourceValue ?? "null" } ', got '{ targetValue ?? "null" } '") ;
286+ }
287+ }
288+
289+ // Report any failures
290+ if ( failedAssertions . Any ( ) )
291+ {
292+ Assert . Fail ( $ "Property mapping failures:\n { string . Join ( "\n " , failedAssertions ) } ") ;
293+ }
294+ }
295+
296+ [ TestMethod ]
297+ [ TestCategory ( "S3" ) ]
298+ public void MapUploadRequest_CreateMultipartRequest_AllMappedProperties_WorkCorrectly ( )
299+ {
300+ // Get the expected mappings from JSON
301+ var createMultipartRequestMappings = _mappingJson . RootElement
302+ . GetProperty ( "Conversion" )
303+ . GetProperty ( "UploadRequest" )
304+ . GetProperty ( "CreateMultipartRequest" )
305+ . EnumerateArray ( )
306+ . Select ( prop => prop . GetString ( ) )
307+ . ToList ( ) ;
308+
309+ // Create source object with dynamically generated test data
310+ var sourceRequest = new TransferUtilityUploadRequest ( ) ;
311+ var sourceType = typeof ( TransferUtilityUploadRequest ) ;
312+ var testDataValues = new Dictionary < string , object > ( ) ;
313+
314+ // Generate test data for each mapped property
315+ foreach ( var propertyName in createMultipartRequestMappings )
316+ {
317+ // Resolve alias to actual property name
318+ var resolvedPropertyName = ResolvePropertyName ( propertyName , sourceType . Name ) ;
319+ var sourceProperty = sourceType . GetProperty ( resolvedPropertyName ) ;
320+ if ( sourceProperty ? . CanWrite == true )
321+ {
322+ var testValue = GenerateTestValue ( sourceProperty . PropertyType , propertyName ) ;
323+ sourceProperty . SetValue ( sourceRequest , testValue ) ;
324+ testDataValues [ propertyName ] = testValue ;
325+ }
326+ }
327+
328+ // Add inherited properties for comprehensive testing
329+ sourceRequest . InputStream = new MemoryStream ( 1024 ) ;
330+
331+ var multipartUploadCommand = new MultipartUploadCommand ( null , null , sourceRequest ) ;
332+
333+ // Map the response
334+ var mappedRequest = multipartUploadCommand . ConstructInitiateMultipartUploadRequest ( ) ;
335+ Assert . IsNotNull ( mappedRequest , "Mapped request should not be null" ) ;
336+
337+ // Verify all mapped properties using reflection
338+ var targetType = typeof ( InitiateMultipartUploadRequest ) ;
339+ var failedAssertions = new List < string > ( ) ;
340+
341+ foreach ( var propertyName in createMultipartRequestMappings )
342+ {
343+ // Resolve alias to actual property name for reflection lookups
344+ var resolvedSourcePropertyName = ResolvePropertyName ( propertyName , sourceType . Name ) ;
345+ var resolvedTargetPropertyName = ResolvePropertyName ( propertyName , targetType . Name ) ;
346+ var sourceProperty = sourceType . GetProperty ( resolvedSourcePropertyName ) ;
347+ var targetProperty = targetType . GetProperty ( resolvedTargetPropertyName ) ;
348+
349+ object sourceValue = null ;
350+
351+ if ( sourceProperty != null )
352+ {
353+ // Property found directly on source type
354+ sourceValue = sourceProperty . GetValue ( sourceRequest ) ;
355+ }
356+ else
357+ {
358+ // Check if source type has a Headers property of type HeadersCollection
359+ var sourceHeadersProperty = sourceType . GetProperty ( "Headers" ) ;
360+ if ( sourceHeadersProperty != null && typeof ( HeadersCollection ) . IsAssignableFrom ( sourceHeadersProperty . PropertyType ) )
361+ {
362+ var sourceHeadersCollection = sourceHeadersProperty . GetValue ( sourceRequest ) as HeadersCollection ;
363+ if ( sourceHeadersCollection != null )
364+ {
365+ var sourceHeadersCollectionProperty = typeof ( HeadersCollection ) . GetProperty ( resolvedSourcePropertyName ) ;
366+ if ( sourceHeadersCollectionProperty != null )
367+ {
368+ sourceValue = sourceHeadersCollectionProperty . GetValue ( sourceHeadersCollection ) ;
369+ }
370+ else
371+ {
372+ failedAssertions . Add ( $ "Source property '{ propertyName } ' (resolved to: { resolvedSourcePropertyName } ) not found in TransferUtilityUploadRequest or HeadersCollection") ;
373+ continue ;
374+ }
375+ }
376+ else
377+ {
378+ failedAssertions . Add ( $ "Source Headers collection is null in TransferUtilityUploadRequest") ;
379+ continue ;
380+ }
381+ }
382+ else
383+ {
384+ failedAssertions . Add ( $ "Source property '{ propertyName } ' (resolved to: { resolvedSourcePropertyName } ) not found in TransferUtilityUploadRequest") ;
385+ continue ;
386+ }
387+ }
388+
389+ object targetValue = null ;
390+
391+ if ( targetProperty != null )
392+ {
393+ // Property found directly on target type
394+ targetValue = targetProperty . GetValue ( mappedRequest ) ;
395+ }
396+ else
397+ {
398+ // Check if target type has a Headers property of type HeadersCollection
399+ var headersProperty = targetType . GetProperty ( "Headers" ) ;
400+ if ( headersProperty != null && typeof ( HeadersCollection ) . IsAssignableFrom ( headersProperty . PropertyType ) )
401+ {
402+ var headersCollection = headersProperty . GetValue ( mappedRequest ) as HeadersCollection ;
403+ if ( headersCollection != null )
404+ {
405+ var headersCollectionProperty = typeof ( HeadersCollection ) . GetProperty ( resolvedTargetPropertyName ) ;
406+ if ( headersCollectionProperty != null )
407+ {
408+ targetValue = headersCollectionProperty . GetValue ( headersCollection ) ;
409+ }
410+ else
411+ {
412+ failedAssertions . Add ( $ "Target property '{ propertyName } ' (resolved to: { resolvedTargetPropertyName } ) not found in InitiateMultipartUploadRequest or HeadersCollection") ;
413+ continue ;
414+ }
415+ }
416+ else
417+ {
418+ failedAssertions . Add ( $ "Headers collection is null in InitiateMultipartUploadRequest") ;
419+ continue ;
420+ }
421+ }
422+ else
423+ {
424+ failedAssertions . Add ( $ "Target property '{ propertyName } ' (resolved to: { resolvedTargetPropertyName } ) not found in InitiateMultipartUploadRequest") ;
425+ continue ;
426+ }
427+ }
428+
429+ // Special handling for complex object comparisons
430+ if ( ! AreValuesEqual ( sourceValue , targetValue ) )
431+ {
432+ failedAssertions . Add ( $ "{ propertyName } : Expected '{ sourceValue ?? "null" } ', got '{ targetValue ?? "null" } '") ;
433+ }
434+ }
435+
436+ // Report any failures
437+ if ( failedAssertions . Any ( ) )
438+ {
439+ Assert . Fail ( $ "Property mapping failures:\n { string . Join ( "\n " , failedAssertions ) } ") ;
440+ }
441+ }
442+
217443 [ TestMethod ]
218444 [ TestCategory ( "S3" ) ]
219445 public void MapPutObjectResponse_NullValues_HandledCorrectly ( )
@@ -439,6 +665,36 @@ private static object GenerateTestValue(Type propertyType, string propertyName)
439665 return 1024 ;
440666 }
441667
668+ if ( propertyType == typeof ( List < S3Grant > ) )
669+ {
670+ if ( _s3Grants is null )
671+ {
672+ _s3Grants = new List < S3Grant > { new S3Grant { Grantee = new S3Grantee { DisplayName = "test-s3grantee" } } } ;
673+ }
674+
675+ return _s3Grants ;
676+ }
677+
678+ if ( propertyType == typeof ( MetadataCollection ) )
679+ {
680+ var metadataCollection = new MetadataCollection ( ) ;
681+ metadataCollection . Add ( "x-amz-meta-testkey" , "testvalue" ) ;
682+ return metadataCollection ;
683+ }
684+
685+ if ( propertyType == typeof ( DateTime ) )
686+ {
687+ return DateTime . UtcNow ;
688+ }
689+
690+ if ( propertyType == typeof ( List < Tag > ) )
691+ {
692+ return new List < Tag >
693+ {
694+ new Tag { Key = "test-key" , Value = "test-value" }
695+ } ;
696+ }
697+
442698 // For unknown types, throw an exception instead of returning null
443699 // If we've reached this point it means there is an unhandled scenario/missing mapping in our test code that we need to handle.
444700 throw new NotSupportedException (
0 commit comments