@@ -612,18 +612,39 @@ func TestOpenAPI(t *testing.T) {
612
612
}
613
613
}
614
614
615
+ type IntNot3 int
616
+
617
+ func (i IntNot3 ) Resolve (ctx huma.Context , prefix * huma.PathBuffer ) []error {
618
+ if i != 0 && i % 3 == 0 {
619
+ return []error {& huma.ErrorDetail {
620
+ Location : prefix .String (),
621
+ Message : "Value cannot be a multiple of three" ,
622
+ Value : i ,
623
+ }}
624
+ }
625
+ return nil
626
+ }
627
+
628
+ var _ huma.ResolverWithPath = (* IntNot3 )(nil )
629
+
615
630
type ExhaustiveErrorsInputBody struct {
616
- Name string `json:"name" maxLength:"10"`
617
- Count int `json:"count" minimum:"1"`
631
+ Name string `json:"name" maxLength:"10"`
632
+ Count IntNot3 `json:"count" minimum:"1"`
633
+
634
+ // Having a pointer which is never loaded should not cause
635
+ // the tests to fail when running resolvers.
636
+ Ptr * IntNot3 `json:"ptr,omitempty" minimum:"1"`
618
637
}
619
638
620
639
func (b * ExhaustiveErrorsInputBody ) Resolve (ctx huma.Context ) []error {
621
640
return []error {fmt .Errorf ("body resolver error" )}
622
641
}
623
642
624
643
type ExhaustiveErrorsInput struct {
625
- ID string `path:"id" maxLength:"5"`
626
- Body ExhaustiveErrorsInputBody `json:"body"`
644
+ ID IntNot3 `path:"id" maximum:"10"`
645
+ Query IntNot3 `query:"query"`
646
+ Header IntNot3 `header:"header"`
647
+ Body ExhaustiveErrorsInputBody `json:"body"`
627
648
}
628
649
629
650
func (i * ExhaustiveErrorsInput ) Resolve (ctx huma.Context ) []error {
@@ -634,21 +655,21 @@ func (i *ExhaustiveErrorsInput) Resolve(ctx huma.Context) []error {
634
655
}}
635
656
}
636
657
637
- type ExhaustiveErrorsOutput struct {
638
- }
658
+ var _ huma.Resolver = (* ExhaustiveErrorsInput )(nil )
639
659
640
660
func TestExhaustiveErrors (t * testing.T ) {
641
661
r , app := humatest .New (t , huma .DefaultConfig ("Test API" , "1.0.0" ))
642
662
huma .Register (app , huma.Operation {
643
663
OperationID : "test" ,
644
664
Method : http .MethodPut ,
645
665
Path : "/errors/{id}" ,
646
- }, func (ctx context.Context , input * ExhaustiveErrorsInput ) (* ExhaustiveErrorsOutput , error ) {
647
- return & ExhaustiveErrorsOutput {} , nil
666
+ }, func (ctx context.Context , input * ExhaustiveErrorsInput ) (* struct {} , error ) {
667
+ return nil , nil
648
668
})
649
669
650
- req , _ := http .NewRequest (http .MethodPut , "/errors/123456 " , strings .NewReader (`{"name": "12345678901", "count": 0 }` ))
670
+ req , _ := http .NewRequest (http .MethodPut , "/errors/15?query=3 " , strings .NewReader (`{"name": "12345678901", "count": -6 }` ))
651
671
req .Header .Set ("Content-Type" , "application/json" )
672
+ req .Header .Set ("Header" , "3" )
652
673
w := httptest .NewRecorder ()
653
674
r .ServeHTTP (w , req )
654
675
assert .Equal (t , http .StatusUnprocessableEntity , w .Code )
@@ -659,23 +680,39 @@ func TestExhaustiveErrors(t *testing.T) {
659
680
"detail": "validation failed",
660
681
"errors": [
661
682
{
662
- "message": "expected length <= 5 ",
683
+ "message": "expected number <= 10 ",
663
684
"location": "path.id",
664
- "value": "123456"
685
+ "value": 15
665
686
}, {
666
687
"message": "expected length <= 10",
667
688
"location": "body.name",
668
689
"value": "12345678901"
669
690
}, {
670
691
"message": "expected number >= 1",
671
692
"location": "body.count",
672
- "value": 0
693
+ "value": -6
673
694
}, {
674
695
"message": "input resolver error",
675
696
"location": "path.id",
676
- "value": "123456"
697
+ "value": 15
698
+ }, {
699
+ "message": "Value cannot be a multiple of three",
700
+ "location": "path.id",
701
+ "value": 15
702
+ }, {
703
+ "message": "Value cannot be a multiple of three",
704
+ "location": "query.query",
705
+ "value": 3
706
+ }, {
707
+ "message": "Value cannot be a multiple of three",
708
+ "location": "header.header",
709
+ "value": 3
677
710
}, {
678
711
"message": "body resolver error"
712
+ }, {
713
+ "message": "Value cannot be a multiple of three",
714
+ "location": "body.count",
715
+ "value": -6
679
716
}
680
717
]
681
718
}` , w .Body .String ())
@@ -745,6 +782,44 @@ func TestResolverCustomStatus(t *testing.T) {
745
782
assert .Contains (t , w .Body .String (), "nope" )
746
783
}
747
784
785
+ func TestParamPointerPanics (t * testing.T ) {
786
+ // For now we don't support these, so we panic rather than have subtle
787
+ // bugs that are hard to track down.
788
+ _ , app := humatest .New (t , huma .DefaultConfig ("Test API" , "1.0.0" ))
789
+
790
+ assert .Panics (t , func () {
791
+ huma .Register (app , huma.Operation {
792
+ OperationID : "bug" ,
793
+ Method : http .MethodGet ,
794
+ Path : "/bug" ,
795
+ }, func (ctx context.Context , input * struct {
796
+ Param * string `query:"param"`
797
+ }) (* struct {}, error ) {
798
+ return nil , nil
799
+ })
800
+ })
801
+ }
802
+
803
+ func TestPointerDefaultPanics (t * testing.T ) {
804
+ // For now we don't support these, so we panic rather than have subtle
805
+ // bugs that are hard to track down.
806
+ _ , app := humatest .New (t , huma .DefaultConfig ("Test API" , "1.0.0" ))
807
+
808
+ assert .Panics (t , func () {
809
+ huma .Register (app , huma.Operation {
810
+ OperationID : "bug" ,
811
+ Method : http .MethodGet ,
812
+ Path : "/bug" ,
813
+ }, func (ctx context.Context , input * struct {
814
+ Body struct {
815
+ Value * string `json:"value,omitempty" default:"foo"`
816
+ }
817
+ }) (* struct {}, error ) {
818
+ return nil , nil
819
+ })
820
+ })
821
+ }
822
+
748
823
func BenchmarkSecondDecode (b * testing.B ) {
749
824
type MediumSized struct {
750
825
ID int `json:"id"`
0 commit comments