@@ -625,6 +625,219 @@ func TestParseNestedCategorization(t *testing.T) {
625625 }
626626}
627627
628+ func TestControlSchemaPropertyResolved (t * testing.T ) {
629+ uiSchema := []byte (`{
630+ "type": "Control",
631+ "scope": "#/properties/name"
632+ }` )
633+ schema := []byte (`{
634+ "type": "object",
635+ "required": ["name"],
636+ "properties": {
637+ "name": {
638+ "type": "string",
639+ "minLength": 2,
640+ "maxLength": 50
641+ }
642+ }
643+ }` )
644+
645+ result , err := Parse (uiSchema , schema )
646+ require .NoError (t , err )
647+
648+ control , ok := result .UISchema .(* Control )
649+ require .True (t , ok )
650+ require .NotNil (t , control .SchemaProperty , "Expected SchemaProperty to be resolved" )
651+
652+ assert .Equal (t , "string" , control .SchemaProperty .Type )
653+ assert .Equal (t , 2 , * control .SchemaProperty .MinLength )
654+ assert .Equal (t , 50 , * control .SchemaProperty .MaxLength )
655+ assert .True (t , control .SchemaProperty .Required )
656+ }
657+
658+ func TestControlSchemaPropertyEnum (t * testing.T ) {
659+ uiSchema := []byte (`{
660+ "type": "Control",
661+ "scope": "#/properties/title"
662+ }` )
663+ schema := []byte (`{
664+ "type": "object",
665+ "properties": {
666+ "title": {
667+ "type": "string",
668+ "enum": ["Mr", "Mrs", "Miss", "Ms"]
669+ }
670+ }
671+ }` )
672+
673+ result , err := Parse (uiSchema , schema )
674+ require .NoError (t , err )
675+
676+ control := result .UISchema .(* Control )
677+ require .NotNil (t , control .SchemaProperty )
678+
679+ assert .Equal (t , "string" , control .SchemaProperty .Type )
680+ assert .Equal (t , []any {"Mr" , "Mrs" , "Miss" , "Ms" }, control .SchemaProperty .Enum )
681+ assert .False (t , control .SchemaProperty .Required )
682+ }
683+
684+ func TestControlSchemaPropertyBoolean (t * testing.T ) {
685+ uiSchema := []byte (`{
686+ "type": "Control",
687+ "scope": "#/properties/acceptTerms"
688+ }` )
689+ schema := []byte (`{
690+ "type": "object",
691+ "properties": {
692+ "acceptTerms": {
693+ "type": "boolean",
694+ "default": false,
695+ "const": true
696+ }
697+ }
698+ }` )
699+
700+ result , err := Parse (uiSchema , schema )
701+ require .NoError (t , err )
702+
703+ control := result .UISchema .(* Control )
704+ require .NotNil (t , control .SchemaProperty )
705+
706+ assert .Equal (t , "boolean" , control .SchemaProperty .Type )
707+ assert .Equal (t , false , control .SchemaProperty .Default )
708+ assert .Equal (t , true , control .SchemaProperty .Const )
709+ }
710+
711+ func TestControlSchemaPropertyNestedScope (t * testing.T ) {
712+ uiSchema := []byte (`{
713+ "type": "Control",
714+ "scope": "#/properties/personalDetails/properties/address/properties/postcode"
715+ }` )
716+ schema := []byte (`{
717+ "type": "object",
718+ "properties": {
719+ "personalDetails": {
720+ "type": "object",
721+ "properties": {
722+ "address": {
723+ "type": "object",
724+ "required": ["postcode"],
725+ "properties": {
726+ "postcode": {
727+ "type": "string",
728+ "pattern": "^[A-Z]{1,2}[0-9][0-9A-Z]?\\s?[0-9][A-Z]{2}$"
729+ }
730+ }
731+ }
732+ }
733+ }
734+ }
735+ }` )
736+
737+ result , err := Parse (uiSchema , schema )
738+ require .NoError (t , err )
739+
740+ control := result .UISchema .(* Control )
741+ require .NotNil (t , control .SchemaProperty )
742+
743+ assert .Equal (t , "string" , control .SchemaProperty .Type )
744+ assert .Equal (t , `^[A-Z]{1,2}[0-9][0-9A-Z]?\s?[0-9][A-Z]{2}$` , control .SchemaProperty .Pattern )
745+ assert .True (t , control .SchemaProperty .Required )
746+ }
747+
748+ func TestControlSchemaPropertyNilSchema (t * testing.T ) {
749+ uiSchema := []byte (`{
750+ "type": "Control",
751+ "scope": "#/properties/name"
752+ }` )
753+
754+ result , err := Parse (uiSchema , nil )
755+ require .NoError (t , err )
756+
757+ control := result .UISchema .(* Control )
758+ assert .Nil (t , control .SchemaProperty )
759+ }
760+
761+ func TestControlSchemaPropertyUnresolvableScope (t * testing.T ) {
762+ uiSchema := []byte (`{
763+ "type": "Control",
764+ "scope": "#/properties/nonexistent/properties/field"
765+ }` )
766+ schema := []byte (`{
767+ "type": "object",
768+ "properties": {
769+ "name": { "type": "string" }
770+ }
771+ }` )
772+
773+ result , err := Parse (uiSchema , schema )
774+ require .NoError (t , err )
775+
776+ control := result .UISchema .(* Control )
777+ assert .Nil (t , control .SchemaProperty )
778+ }
779+
780+ func TestControlSchemaPropertyWithFormat (t * testing.T ) {
781+ uiSchema := []byte (`{
782+ "type": "Control",
783+ "scope": "#/properties/email"
784+ }` )
785+ schema := []byte (`{
786+ "type": "object",
787+ "properties": {
788+ "email": {
789+ "type": "string",
790+ "format": "email"
791+ }
792+ }
793+ }` )
794+
795+ result , err := Parse (uiSchema , schema )
796+ require .NoError (t , err )
797+
798+ control := result .UISchema .(* Control )
799+ require .NotNil (t , control .SchemaProperty )
800+
801+ assert .Equal (t , "string" , control .SchemaProperty .Type )
802+ assert .Equal (t , "email" , control .SchemaProperty .Format )
803+ }
804+
805+ func TestLayoutWithMultipleControlsSchemaResolved (t * testing.T ) {
806+ uiSchema := []byte (`{
807+ "type": "VerticalLayout",
808+ "elements": [
809+ { "type": "Control", "scope": "#/properties/name" },
810+ { "type": "Control", "scope": "#/properties/age" }
811+ ]
812+ }` )
813+ schema := []byte (`{
814+ "type": "object",
815+ "required": ["name"],
816+ "properties": {
817+ "name": { "type": "string" },
818+ "age": { "type": "integer", "minimum": 0, "maximum": 150 }
819+ }
820+ }` )
821+
822+ result , err := Parse (uiSchema , schema )
823+ require .NoError (t , err )
824+
825+ layout := result .UISchema .(* VerticalLayout )
826+ require .Len (t , layout .Elements , 2 )
827+
828+ nameCtrl := layout .Elements [0 ].(* Control )
829+ require .NotNil (t , nameCtrl .SchemaProperty )
830+ assert .Equal (t , "string" , nameCtrl .SchemaProperty .Type )
831+ assert .True (t , nameCtrl .SchemaProperty .Required )
832+
833+ ageCtrl := layout .Elements [1 ].(* Control )
834+ require .NotNil (t , ageCtrl .SchemaProperty )
835+ assert .Equal (t , "integer" , ageCtrl .SchemaProperty .Type )
836+ assert .InDelta (t , float64 (0 ), * ageCtrl .SchemaProperty .Minimum , 0 )
837+ assert .InDelta (t , float64 (150 ), * ageCtrl .SchemaProperty .Maximum , 0 )
838+ assert .False (t , ageCtrl .SchemaProperty .Required )
839+ }
840+
628841// countingVisitor counts all element types encountered during a walk
629842type countingVisitor struct {
630843 BaseVisitor
0 commit comments