@@ -411,6 +411,236 @@ await VerifyOpenApiDocument(builder, document =>
411411 } ) ;
412412 }
413413
414+ [ Fact ]
415+ public async Task GetOpenApiSchema_Base64StringAttribute_StringProperties ( )
416+ {
417+ var builder = CreateBuilder ( ) ;
418+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
419+
420+ await VerifyOpenApiDocument ( builder , document =>
421+ {
422+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
423+ var nonNullable = schema . Properties [ "base64StringValue" ] ;
424+ var nullable = schema . Properties [ "nullableBase64StringValue" ] ;
425+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
426+ Assert . Equal ( "byte" , nonNullable . Format ) ;
427+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
428+ Assert . Equal ( "byte" , nullable . Format ) ;
429+ } ) ;
430+ }
431+
432+ [ Fact ]
433+ public async Task GetOpenApiSchema_RangeAttribute_IntProperties ( )
434+ {
435+ var builder = CreateBuilder ( ) ;
436+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
437+
438+ await VerifyOpenApiDocument ( builder , document =>
439+ {
440+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
441+ var nonNullable = schema . Properties [ "rangeIntValue" ] ;
442+ var nullable = schema . Properties [ "nullableRangeIntValue" ] ;
443+ Assert . Equal ( JsonSchemaType . Integer , nonNullable . Type ) ;
444+ Assert . Equal ( "int32" , nonNullable . Format ) ;
445+ Assert . Equal ( "1" , nonNullable . Minimum ) ;
446+ Assert . Equal ( "100" , nonNullable . Maximum ) ;
447+ Assert . Equal ( JsonSchemaType . Integer | JsonSchemaType . Null , nullable . Type ) ;
448+ Assert . Equal ( "int32" , nullable . Format ) ;
449+ Assert . Equal ( "1" , nullable . Minimum ) ;
450+ Assert . Equal ( "100" , nullable . Maximum ) ;
451+ } ) ;
452+ }
453+
454+ [ Fact ]
455+ public async Task GetOpenApiSchema_RangeAttribute_DoubleProperties ( )
456+ {
457+ var builder = CreateBuilder ( ) ;
458+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
459+
460+ await VerifyOpenApiDocument ( builder , document =>
461+ {
462+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
463+ var nonNullable = schema . Properties [ "rangeDoubleValue" ] ;
464+ var nullable = schema . Properties [ "nullableRangeDoubleValue" ] ;
465+ Assert . Equal ( JsonSchemaType . Number , nonNullable . Type ) ;
466+ Assert . Equal ( "double" , nonNullable . Format ) ;
467+ Assert . Equal ( "0.1" , nonNullable . Minimum as string ) ;
468+ Assert . Equal ( "99.9" , nonNullable . Maximum as string ) ;
469+ Assert . Equal ( JsonSchemaType . Number | JsonSchemaType . Null , nullable . Type ) ;
470+ Assert . Equal ( "double" , nullable . Format ) ;
471+ Assert . Equal ( "0.1" , nullable . Minimum as string ) ;
472+ Assert . Equal ( "99.9" , nullable . Maximum as string ) ;
473+ } ) ;
474+ }
475+
476+ [ Fact ]
477+ public async Task GetOpenApiSchema_RegularExpressionAttribute_StringProperties ( )
478+ {
479+ var builder = CreateBuilder ( ) ;
480+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
481+
482+ await VerifyOpenApiDocument ( builder , document =>
483+ {
484+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
485+ var nonNullable = schema . Properties [ "regexStringValue" ] ;
486+ var nullable = schema . Properties [ "nullableRegexStringValue" ] ;
487+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
488+ Assert . Equal ( "^[A-Z]{3}$" , nonNullable . Pattern ) ;
489+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
490+ Assert . Equal ( "^[A-Z]{3}$" , nullable . Pattern ) ;
491+ } ) ;
492+ }
493+
494+ [ Fact ]
495+ public async Task GetOpenApiSchema_MaxLengthAttribute_StringProperties ( )
496+ {
497+ var builder = CreateBuilder ( ) ;
498+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
499+
500+ await VerifyOpenApiDocument ( builder , document =>
501+ {
502+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
503+ var nonNullable = schema . Properties [ "maxLengthStringValue" ] ;
504+ var nullable = schema . Properties [ "nullableMaxLengthStringValue" ] ;
505+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
506+ Assert . Equal ( 10 , nonNullable . MaxLength ) ;
507+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
508+ Assert . Equal ( 10 , nullable . MaxLength ) ;
509+ } ) ;
510+ }
511+
512+ [ Fact ]
513+ public async Task GetOpenApiSchema_MaxLengthAttribute_ArrayProperties ( )
514+ {
515+ var builder = CreateBuilder ( ) ;
516+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
517+
518+ await VerifyOpenApiDocument ( builder , document =>
519+ {
520+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
521+ var nonNullable = schema . Properties [ "maxLengthArrayValue" ] ;
522+ var nullable = schema . Properties [ "nullableMaxLengthArrayValue" ] ;
523+ Assert . Equal ( JsonSchemaType . Array , nonNullable . Type ) ;
524+ Assert . Equal ( 5 , nonNullable . MaxItems ) ;
525+ Assert . Equal ( JsonSchemaType . Array | JsonSchemaType . Null , nullable . Type ) ;
526+ Assert . Equal ( 5 , nullable . MaxItems ) ;
527+ } ) ;
528+ }
529+
530+ [ Fact ]
531+ public async Task GetOpenApiSchema_MinLengthAttribute_StringProperties ( )
532+ {
533+ var builder = CreateBuilder ( ) ;
534+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
535+
536+ await VerifyOpenApiDocument ( builder , document =>
537+ {
538+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
539+ var nonNullable = schema . Properties [ "minLengthStringValue" ] ;
540+ var nullable = schema . Properties [ "nullableMinLengthStringValue" ] ;
541+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
542+ Assert . Equal ( 3 , nonNullable . MinLength ) ;
543+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
544+ Assert . Equal ( 3 , nullable . MinLength ) ;
545+ } ) ;
546+ }
547+
548+ [ Fact ]
549+ public async Task GetOpenApiSchema_MinLengthAttribute_ArrayProperties ( )
550+ {
551+ var builder = CreateBuilder ( ) ;
552+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
553+
554+ await VerifyOpenApiDocument ( builder , document =>
555+ {
556+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
557+ var nonNullable = schema . Properties [ "minLengthArrayValue" ] ;
558+ var nullable = schema . Properties [ "nullableMinLengthArrayValue" ] ;
559+ Assert . Equal ( JsonSchemaType . Array , nonNullable . Type ) ;
560+ Assert . Equal ( 2 , nonNullable . MinItems ) ;
561+ Assert . Equal ( JsonSchemaType . Array | JsonSchemaType . Null , nullable . Type ) ;
562+ Assert . Equal ( 2 , nullable . MinItems ) ;
563+ } ) ;
564+ }
565+
566+ [ Fact ]
567+ public async Task GetOpenApiSchema_LengthAttribute_StringProperties ( )
568+ {
569+ var builder = CreateBuilder ( ) ;
570+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
571+
572+ await VerifyOpenApiDocument ( builder , document =>
573+ {
574+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
575+ var nonNullable = schema . Properties [ "lengthStringValue" ] ;
576+ var nullable = schema . Properties [ "nullableLengthStringValue" ] ;
577+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
578+ Assert . Equal ( 2 , nonNullable . MinLength ) ;
579+ Assert . Equal ( 8 , nonNullable . MaxLength ) ;
580+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
581+ Assert . Equal ( 2 , nullable . MinLength ) ;
582+ Assert . Equal ( 8 , nullable . MaxLength ) ;
583+ } ) ;
584+ }
585+
586+ [ Fact ]
587+ public async Task GetOpenApiSchema_LengthAttribute_ArrayProperties ( )
588+ {
589+ var builder = CreateBuilder ( ) ;
590+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
591+
592+ await VerifyOpenApiDocument ( builder , document =>
593+ {
594+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
595+ var nonNullable = schema . Properties [ "lengthArrayValue" ] ;
596+ var nullable = schema . Properties [ "nullableLengthArrayValue" ] ;
597+ Assert . Equal ( JsonSchemaType . Array , nonNullable . Type ) ;
598+ Assert . Equal ( 1 , nonNullable . MinItems ) ;
599+ Assert . Equal ( 4 , nonNullable . MaxItems ) ;
600+ Assert . Equal ( JsonSchemaType . Array | JsonSchemaType . Null , nullable . Type ) ;
601+ Assert . Equal ( 1 , nullable . MinItems ) ;
602+ Assert . Equal ( 4 , nullable . MaxItems ) ;
603+ } ) ;
604+ }
605+
606+ [ Fact ]
607+ public async Task GetOpenApiSchema_UrlAttribute_StringProperties ( )
608+ {
609+ var builder = CreateBuilder ( ) ;
610+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
611+
612+ await VerifyOpenApiDocument ( builder , document =>
613+ {
614+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
615+ var nonNullable = schema . Properties [ "urlStringValue" ] ;
616+ var nullable = schema . Properties [ "nullableUrlStringValue" ] ;
617+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
618+ Assert . Equal ( "uri" , nonNullable . Format ) ;
619+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
620+ Assert . Equal ( "uri" , nullable . Format ) ;
621+ } ) ;
622+ }
623+
624+ [ Fact ]
625+ public async Task GetOpenApiSchema_StringLengthAttribute_StringProperties ( )
626+ {
627+ var builder = CreateBuilder ( ) ;
628+ builder . MapPost ( "/api" , ( PropertiesWithDataAnnotations model ) => { } ) ;
629+
630+ await VerifyOpenApiDocument ( builder , document =>
631+ {
632+ var schema = document . Paths [ "/api" ] . Operations [ HttpMethod . Post ] . RequestBody . Content . First ( ) . Value . Schema ;
633+ var nonNullable = schema . Properties [ "stringLengthValue" ] ;
634+ var nullable = schema . Properties [ "nullableStringLengthValue" ] ;
635+ Assert . Equal ( JsonSchemaType . String , nonNullable . Type ) ;
636+ Assert . Equal ( 5 , nonNullable . MinLength ) ;
637+ Assert . Equal ( 20 , nonNullable . MaxLength ) ;
638+ Assert . Equal ( JsonSchemaType . String | JsonSchemaType . Null , nullable . Type ) ;
639+ Assert . Equal ( 5 , nullable . MinLength ) ;
640+ Assert . Equal ( 20 , nullable . MaxLength ) ;
641+ } ) ;
642+ }
643+
414644#nullable enable
415645 private class NullablePropertiesTestModel
416646 {
@@ -452,5 +682,72 @@ private class NullablePropertiesWithValidationModel
452682 [ Description ( "A description field" ) ]
453683 public string ? NullableDescription { get ; set ; }
454684 }
685+
686+ private class PropertiesWithDataAnnotations
687+ {
688+ // Base64StringAttribute
689+ [ Base64String ]
690+ public string Base64StringValue { get ; set ; } = string . Empty ;
691+ [ Base64String ]
692+ public string ? NullableBase64StringValue { get ; set ; }
693+
694+ // RangeAttribute
695+ [ Range ( 1 , 100 ) ]
696+ public int RangeIntValue { get ; set ; } = 0 ;
697+ [ Range ( 1 , 100 ) ]
698+ public int ? NullableRangeIntValue { get ; set ; }
699+ [ Range ( 0.1 , 99.9 ) ]
700+ public double RangeDoubleValue { get ; set ; } = 0.0 ;
701+ [ Range ( 0.1 , 99.9 ) ]
702+ public double ? NullableRangeDoubleValue { get ; set ; }
703+
704+ // RegularExpressionAttribute
705+ [ RegularExpression ( @"^[A-Z]{3}$" ) ]
706+ public string RegexStringValue { get ; set ; } = string . Empty ;
707+ [ RegularExpression ( @"^[A-Z]{3}$" ) ]
708+ public string ? NullableRegexStringValue { get ; set ; }
709+
710+ // MaxLengthAttribute
711+ [ MaxLength ( 10 ) ]
712+ public string MaxLengthStringValue { get ; set ; } = string . Empty ;
713+ [ MaxLength ( 10 ) ]
714+ public string ? NullableMaxLengthStringValue { get ; set ; }
715+ [ MaxLength ( 5 ) ]
716+ public int [ ] MaxLengthArrayValue { get ; set ; } = [ ] ;
717+ [ MaxLength ( 5 ) ]
718+ public int [ ] ? NullableMaxLengthArrayValue { get ; set ; }
719+
720+ // MinLengthAttribute
721+ [ MinLength ( 3 ) ]
722+ public string MinLengthStringValue { get ; set ; } = string . Empty ;
723+ [ MinLength ( 3 ) ]
724+ public string ? NullableMinLengthStringValue { get ; set ; }
725+ [ MinLength ( 2 ) ]
726+ public int [ ] MinLengthArrayValue { get ; set ; } = [ ] ;
727+ [ MinLength ( 2 ) ]
728+ public int [ ] ? NullableMinLengthArrayValue { get ; set ; }
729+
730+ // LengthAttribute (custom, if available)
731+ [ Length ( 2 , 8 ) ]
732+ public string LengthStringValue { get ; set ; } = string . Empty ;
733+ [ Length ( 2 , 8 ) ]
734+ public string ? NullableLengthStringValue { get ; set ; }
735+ [ Length ( 1 , 4 ) ]
736+ public int [ ] LengthArrayValue { get ; set ; } = [ ] ;
737+ [ Length ( 1 , 4 ) ]
738+ public int [ ] ? NullableLengthArrayValue { get ; set ; }
739+
740+ // UrlAttribute
741+ [ Url ]
742+ public string UrlStringValue { get ; set ; } = string . Empty ;
743+ [ Url ]
744+ public string ? NullableUrlStringValue { get ; set ; }
745+
746+ // StringLengthAttribute
747+ [ StringLength ( 20 , MinimumLength = 5 ) ]
748+ public string StringLengthValue { get ; set ; } = string . Empty ;
749+ [ StringLength ( 20 , MinimumLength = 5 ) ]
750+ public string ? NullableStringLengthValue { get ; set ; }
751+ }
455752#nullable restore
456753}
0 commit comments