@@ -504,8 +504,8 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
504504 identifier: " test-button-id " ,
505505 hint: " Double tap to activate " ,
506506 userInputLabels: [ " tap button " , " press button " ] ,
507- shape: . frame( CGRect ( x: 10 , y: 20 , width: 100 , height: 44 ) ) ,
508- activationPoint: CGPoint ( x: 60 , y: 42 ) ,
507+ shape: . frame( AccessibilityRect ( x: 10 , y: 20 , width: 100 , height: 44 ) ) ,
508+ activationPoint: AccessibilityPoint ( x: 60 , y: 42 ) ,
509509 usesDefaultActivationPoint: true ,
510510 customActions: [ " Delete " ] ,
511511 customContent: [ ] ,
@@ -538,7 +538,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
538538 func testAccessibilityContainerCodable( ) throws {
539539 let container = AccessibilityContainer (
540540 type: . list,
541- frame: CGRect ( x: 0 , y: 0 , width: 320 , height: 200 )
541+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 320 , height: 200 )
542542 )
543543
544544 let encoder = JSONEncoder ( )
@@ -560,8 +560,8 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
560560 identifier: nil ,
561561 hint: nil ,
562562 userInputLabels: nil ,
563- shape: . frame( CGRect ( x: 0 , y: 0 , width: 100 , height: 44 ) ) ,
564- activationPoint: CGPoint ( x: 50 , y: 22 ) ,
563+ shape: . frame( AccessibilityRect ( x: 0 , y: 0 , width: 100 , height: 44 ) ) ,
564+ activationPoint: AccessibilityPoint ( x: 50 , y: 22 ) ,
565565 usesDefaultActivationPoint: true ,
566566 customActions: [ ] ,
567567 customContent: [ ] ,
@@ -578,8 +578,8 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
578578 identifier: nil ,
579579 hint: nil ,
580580 userInputLabels: nil ,
581- shape: . frame( CGRect ( x: 0 , y: 50 , width: 100 , height: 44 ) ) ,
582- activationPoint: CGPoint ( x: 50 , y: 72 ) ,
581+ shape: . frame( AccessibilityRect ( x: 0 , y: 50 , width: 100 , height: 44 ) ) ,
582+ activationPoint: AccessibilityPoint ( x: 50 , y: 72 ) ,
583583 usesDefaultActivationPoint: true ,
584584 customActions: [ ] ,
585585 customContent: [ ] ,
@@ -590,7 +590,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
590590
591591 let container = AccessibilityContainer (
592592 type: . list,
593- frame: CGRect ( x: 0 , y: 0 , width: 100 , height: 100 )
593+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 100 , height: 100 )
594594 )
595595
596596 let hierarchy : [ AccessibilityHierarchy ] = [
@@ -632,21 +632,66 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
632632
633633 func testShapeCodableWithPath( ) throws {
634634 let path = UIBezierPath ( roundedRect: CGRect ( x: 10 , y: 20 , width: 100 , height: 50 ) , cornerRadius: 8 )
635- let shape = AccessibilityElement . Shape. path ( path)
635+ let elements = AccessibilityPathElement . elements ( from: path. cgPath)
636+ let shape = AccessibilityShape . path ( elements)
636637
637638 let encoder = JSONEncoder ( )
638639 let data = try encoder. encode ( shape)
639640
640641 let decoder = JSONDecoder ( )
641- let decoded = try decoder. decode ( AccessibilityElement . Shape . self, from: data)
642+ let decoded = try decoder. decode ( AccessibilityShape . self, from: data)
642643
643644 if case let . path( decodedPath) = decoded {
644- XCTAssertEqual ( decodedPath. bounds , path . bounds )
645+ XCTAssertEqual ( decodedPath, elements )
645646 } else {
646647 XCTFail ( " Expected path shape " )
647648 }
648649 }
649650
651+ // MARK: - Wire-Format Compatibility
652+
653+ // The portable model types replaced CoreGraphics geometry but must keep the exact
654+ // JSON wire format that the previous `CGPoint`/`CGRect`/`AccessibilityElement.Shape`
655+ // Codable conformances produced, so persisted payloads keep decoding.
656+
657+ func testGeometryEncodesAsLegacyCGGeometryArrays( ) throws {
658+ let encoder = JSONEncoder ( )
659+
660+ let point = try encoder. encode ( AccessibilityPoint ( x: 1 , y: 2 ) )
661+ XCTAssertEqual ( String ( data: point, encoding: . utf8) , " [1,2] " )
662+
663+ let size = try encoder. encode ( AccessibilitySize ( width: 100 , height: 44 ) )
664+ XCTAssertEqual ( String ( data: size, encoding: . utf8) , " [100,44] " )
665+
666+ let rect = try encoder. encode ( AccessibilityRect ( x: 10 , y: 20 , width: 100 , height: 44 ) )
667+ XCTAssertEqual ( String ( data: rect, encoding: . utf8) , " [[10,20],[100,44]] " )
668+ }
669+
670+ func testShapeDecodesLegacyFrameWireFormat( ) throws {
671+ let legacyJSON = Data ( #"{"type":"frame","frame":[[10,20],[100,44]]}"# . utf8)
672+ let decoded = try JSONDecoder ( ) . decode ( AccessibilityShape . self, from: legacyJSON)
673+ XCTAssertEqual ( decoded, . frame( AccessibilityRect ( x: 10 , y: 20 , width: 100 , height: 44 ) ) )
674+ }
675+
676+ func testShapeDecodesLegacyPathWireFormat( ) throws {
677+ let legacyJSON = Data ( #"""
678+ {"type":"path","pathElements":[{"move":{"to":[0,0]}},{"line":{"to":[100,0]}},{"closeSubpath":{}}]}
679+ """# . utf8)
680+ let decoded = try JSONDecoder ( ) . decode ( AccessibilityShape . self, from: legacyJSON)
681+ XCTAssertEqual ( decoded, . path( [
682+ . move( to: AccessibilityPoint ( x: 0 , y: 0 ) ) ,
683+ . line( to: AccessibilityPoint ( x: 100 , y: 0 ) ) ,
684+ . closeSubpath,
685+ ] ) )
686+ }
687+
688+ func testShapeFrameEncodesWithTypeDiscriminator( ) throws {
689+ let data = try JSONEncoder ( ) . encode ( AccessibilityShape . frame ( AccessibilityRect ( x: 10 , y: 20 , width: 100 , height: 44 ) ) )
690+ let object = try JSONSerialization . jsonObject ( with: data) as! [ String : Any ]
691+ XCTAssertEqual ( object [ " type " ] as? String , " frame " )
692+ XCTAssertEqual ( object [ " frame " ] as? [ [ Double ] ] , [ [ 10 , 20 ] , [ 100 , 44 ] ] )
693+ }
694+
650695 func testContainerTypeCodable( ) throws {
651696 let types : [ AccessibilityContainer . ContainerType ] = [
652697 . list,
@@ -708,17 +753,18 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
708753 path. addLine ( to: CGPoint ( x: 100 , y: 50 ) )
709754 path. close ( )
710755
711- let shape = AccessibilityElement . Shape. path ( path)
756+ let elements = AccessibilityPathElement . elements ( from: path. cgPath)
757+ let shape = AccessibilityShape . path ( elements)
712758
713759 let encoder = JSONEncoder ( )
714760 let data = try encoder. encode ( shape)
715761
716762 // Verify round-trip works
717763 let decoder = JSONDecoder ( )
718- let decoded = try decoder. decode ( AccessibilityElement . Shape . self, from: data)
764+ let decoded = try decoder. decode ( AccessibilityShape . self, from: data)
719765
720766 if case let . path( decodedPath) = decoded {
721- XCTAssertEqual ( decodedPath. bounds , path . bounds )
767+ XCTAssertEqual ( decodedPath, elements )
722768 } else {
723769 XCTFail ( " Expected path shape " )
724770 }
@@ -786,7 +832,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
786832 func testDataTableContainerCodable( ) throws {
787833 let container = AccessibilityContainer (
788834 type: . dataTable( rowCount: 5 , columnCount: 4 ) ,
789- frame: CGRect ( x: 0 , y: 0 , width: 320 , height: 200 )
835+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 320 , height: 200 )
790836 )
791837
792838 let encoder = JSONEncoder ( )
@@ -806,7 +852,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
806852 func testSemanticGroupContainerCodable( ) throws {
807853 let container = AccessibilityContainer (
808854 type: . semanticGroup( label: " Group Label " , value: " Group Value " , identifier: " group-id " ) ,
809- frame: CGRect ( x: 0 , y: 0 , width: 200 , height: 100 )
855+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 200 , height: 100 )
810856 )
811857
812858 let encoder = JSONEncoder ( )
@@ -827,7 +873,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
827873 func testTabBarContainerCodable( ) throws {
828874 let container = AccessibilityContainer (
829875 type: . tabBar,
830- frame: CGRect ( x: 0 , y: 0 , width: 320 , height: 49 )
876+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 320 , height: 49 )
831877 )
832878
833879 let encoder = JSONEncoder ( )
@@ -842,7 +888,7 @@ final class AccessibilityHierarchyParserTests: XCTestCase {
842888 func testLandmarkContainerCodable( ) throws {
843889 let container = AccessibilityContainer (
844890 type: . landmark,
845- frame: CGRect ( x: 0 , y: 0 , width: 320 , height: 200 )
891+ frame: AccessibilityRect ( x: 0 , y: 0 , width: 320 , height: 200 )
846892 )
847893
848894 let encoder = JSONEncoder ( )
0 commit comments