 // MARK: - Tests
 
 #if !FOUNDATION_XCTEST
+var tests = [
+    "test_Calendar_JSON" : TestCodable.test_Calendar_JSON,
+    "test_Calendar_Plist" : TestCodable.test_Calendar_Plist,
+    "test_CharacterSet_JSON" : TestCodable.test_CharacterSet_JSON,
+    "test_CharacterSet_Plist" : TestCodable.test_CharacterSet_Plist,
+    "test_CGAffineTransform_JSON" : TestCodable.test_CGAffineTransform_JSON,
+    "test_CGAffineTransform_Plist" : TestCodable.test_CGAffineTransform_Plist,
+    "test_CGPoint_JSON" : TestCodable.test_CGPoint_JSON,
+    "test_CGPoint_Plist" : TestCodable.test_CGPoint_Plist,
+    "test_CGSize_JSON" : TestCodable.test_CGSize_JSON,
+    "test_CGSize_Plist" : TestCodable.test_CGSize_Plist,
+    "test_CGRect_JSON" : TestCodable.test_CGRect_JSON,
+    "test_CGRect_Plist" : TestCodable.test_CGRect_Plist,
+    "test_CGVector_JSON" : TestCodable.test_CGVector_JSON,
+    "test_CGVector_Plist" : TestCodable.test_CGVector_Plist,
+    "test_DateComponents_JSON" : TestCodable.test_DateComponents_JSON,
+    "test_DateComponents_Plist" : TestCodable.test_DateComponents_Plist,
+    "test_Decimal_JSON" : TestCodable.test_Decimal_JSON,
+    "test_Decimal_Plist" : TestCodable.test_Decimal_Plist,
+    "test_IndexPath_JSON" : TestCodable.test_IndexPath_JSON,
+    "test_IndexPath_Plist" : TestCodable.test_IndexPath_Plist,
+    "test_IndexSet_JSON" : TestCodable.test_IndexSet_JSON,
+    "test_IndexSet_Plist" : TestCodable.test_IndexSet_Plist,
+    "test_Locale_JSON" : TestCodable.test_Locale_JSON,
+    "test_Locale_Plist" : TestCodable.test_Locale_Plist,
+    "test_NSRange_JSON" : TestCodable.test_NSRange_JSON,
+    "test_NSRange_Plist" : TestCodable.test_NSRange_Plist,
+    "test_TimeZone_JSON" : TestCodable.test_TimeZone_JSON,
+    "test_TimeZone_Plist" : TestCodable.test_TimeZone_Plist,
+    "test_URL_JSON" : TestCodable.test_URL_JSON,
+    "test_URL_Plist" : TestCodable.test_URL_Plist,
+    "test_UUID_JSON" : TestCodable.test_UUID_JSON,
+    "test_UUID_Plist" : TestCodable.test_UUID_Plist,
+]
+
+#if os(OSX)
+    tests["test_AffineTransform_JSON"] = TestCodable.test_AffineTransform_JSON
+    tests["test_AffineTransform_Plist"] = TestCodable.test_AffineTransform_Plist
+#endif
+
+if #available(OSX 10.11, iOS 9.0, *) {
+    tests["test_PersonNameComponents_JSON"] = TestCodable.test_PersonNameComponents_JSON
+    tests["test_PersonNameComponents_Plist"] = TestCodable.test_PersonNameComponents_Plist
+}
+
+if #available(OSX 10.12, iOS 10.10, watchOS 3.0, tvOS 10.0, *) {
+    // tests["test_DateInterval_JSON"] = TestCodable.test_DateInterval_JSON
+    tests["test_DateInterval_Plist"] = TestCodable.test_DateInterval_Plist
+    // tests["test_Measurement_JSON"] = TestCodable.test_Measurement_JSON
+    // tests["test_Measurement_Plist"] = TestCodable.test_Measurement_Plist
+}
+
 var CodableTests = TestSuite("TestCodable")
-
-#if os(OSX)
-    CodableTests.test("test_AffineTransform_JSON") { TestCodable().test_AffineTransform_JSON() }
-    CodableTests.test("test_AffineTransform_Plist") { TestCodable().test_AffineTransform_Plist() }
-#endif
-
-CodableTests.test("test_Calendar_JSON") { TestCodable().test_Calendar_JSON() }
-CodableTests.test("test_Calendar_Plist") { TestCodable().test_Calendar_Plist() }
-CodableTests.test("test_CharacterSet_JSON") { TestCodable().test_CharacterSet_JSON() }
-CodableTests.test("test_CharacterSet_Plist") { TestCodable().test_CharacterSet_Plist() }
-CodableTests.test("test_CGAffineTransform_JSON") { TestCodable().test_CGAffineTransform_JSON() }
-CodableTests.test("test_CGAffineTransform_Plist") { TestCodable().test_CGAffineTransform_Plist() }
-CodableTests.test("test_CGPoint_JSON") { TestCodable().test_CGPoint_JSON() }
-CodableTests.test("test_CGPoint_Plist") { TestCodable().test_CGPoint_Plist() }
-CodableTests.test("test_CGSize_JSON") { TestCodable().test_CGSize_JSON() }
-CodableTests.test("test_CGSize_Plist") { TestCodable().test_CGSize_Plist() }
-CodableTests.test("test_CGRect_JSON") { TestCodable().test_CGRect_JSON() }
-CodableTests.test("test_CGRect_Plist") { TestCodable().test_CGRect_Plist() }
-CodableTests.test("test_CGVector_JSON") { TestCodable().test_CGVector_JSON() }
-CodableTests.test("test_CGVector_Plist") { TestCodable().test_CGVector_Plist() }
-CodableTests.test("test_DateComponents_JSON") { TestCodable().test_DateComponents_JSON() }
-CodableTests.test("test_DateComponents_Plist") { TestCodable().test_DateComponents_Plist() }
-
-if #available(OSX 10.12, iOS 10.10, watchOS 3.0, tvOS 10.0, *) {
-    // CodableTests.test("test_DateInterval_JSON") { TestCodable().test_DateInterval_JSON() }
-    CodableTests.test("test_DateInterval_Plist") { TestCodable().test_DateInterval_Plist() }
-}
-
-CodableTests.test("test_Decimal_JSON") { TestCodable().test_Decimal_JSON() }
-CodableTests.test("test_Decimal_Plist") { TestCodable().test_Decimal_Plist() }
-CodableTests.test("test_IndexPath_JSON") { TestCodable().test_IndexPath_JSON() }
-CodableTests.test("test_IndexPath_Plist") { TestCodable().test_IndexPath_Plist() }
-CodableTests.test("test_IndexSet_JSON") { TestCodable().test_IndexSet_JSON() }
-CodableTests.test("test_IndexSet_Plist") { TestCodable().test_IndexSet_Plist() }
-CodableTests.test("test_Locale_JSON") { TestCodable().test_Locale_JSON() }
-CodableTests.test("test_Locale_Plist") { TestCodable().test_Locale_Plist() }
-
-if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {
-    // CodableTests.test("test_Measurement_JSON") { TestCodable().test_Measurement_JSON() }
-    // CodableTests.test("test_Measurement_Plist") { TestCodable().test_Measurement_Plist() }
-}
-
-CodableTests.test("test_NSRange_JSON") { TestCodable().test_NSRange_JSON() }
-CodableTests.test("test_NSRange_Plist") { TestCodable().test_NSRange_Plist() }
-
-if #available(OSX 10.11, iOS 9.0, *) {
-    CodableTests.test("test_PersonNameComponents_JSON") { TestCodable().test_PersonNameComponents_JSON() }
-    CodableTests.test("test_PersonNameComponents_Plist") { TestCodable().test_PersonNameComponents_Plist() }
-}
-
-CodableTests.test("test_TimeZone_JSON") { TestCodable().test_TimeZone_JSON() }
-CodableTests.test("test_TimeZone_Plist") { TestCodable().test_TimeZone_Plist() }
-CodableTests.test("test_URL_JSON") { TestCodable().test_URL_JSON() }
-CodableTests.test("test_URL_Plist") { TestCodable().test_URL_Plist() }
-CodableTests.test("test_UUID_JSON") { TestCodable().test_UUID_JSON() }
-CodableTests.test("test_UUID_Plist") { TestCodable().test_UUID_Plist() }
+for (name, test) in tests {
+    CodableTests.test(name) { test(TestCodable())() }
+}
+
 runAllTests()
 #endif

    // MARK: - AffineTransform
#if os(OSX)
    // FIXME: Comment the tests back in once rdar://problem/33363218 is in the SDK.
    lazy var affineTransformValues: [AffineTransform] = [
        AffineTransform.identity,
        AffineTransform(),
        AffineTransform(translationByX: 2.0, byY: 2.0),
        AffineTransform(scale: 2.0),
        AffineTransform(rotationByDegrees: .pi / 2),

        AffineTransform(m11: 1.0, m12: 2.5, m21: 66.2, m22: 40.2, tX: -5.5, tY: 3.7),
        // AffineTransform(m11: -55.66, m12: 22.7, m21: 1.5, m22: 0.0, tX: -22, tY: -33),
        AffineTransform(m11: 4.5, m12: 1.1, m21: 0.025, m22: 0.077, tX: -0.55, tY: 33.2),
        // AffineTransform(m11: 7.0, m12: -2.3, m21: 6.7, m22: 0.25, tX: 0.556, tY: 0.99),
        // AffineTransform(m11: 0.498, m12: -0.284, m21: -0.742, m22: 0.3248, tX: 12, tY: 44)
    ]

    func test_AffineTransform_JSON() {
        for transform in affineTransformValues {
            expectRoundTripEqualityThroughJSON(for: transform)
        }
    }

    func test_AffineTransform_Plist() {
        for transform in affineTransformValues {
            expectRoundTripEqualityThroughPlist(for: transform)
        }
    }
#endif

    // MARK: - Calendar
    lazy var calendarValues: [Calendar] = [
        Calendar(identifier: .gregorian),
        Calendar(identifier: .buddhist),
        Calendar(identifier: .chinese),
        Calendar(identifier: .coptic),
        Calendar(identifier: .ethiopicAmeteMihret),
        Calendar(identifier: .ethiopicAmeteAlem),
        Calendar(identifier: .hebrew),
        Calendar(identifier: .iso8601),
        Calendar(identifier: .indian),
        Calendar(identifier: .islamic),
        Calendar(identifier: .islamicCivil),
        Calendar(identifier: .japanese),
        Calendar(identifier: .persian),
        Calendar(identifier: .republicOfChina),
    ]

    func test_Calendar_JSON() {
        for calendar in calendarValues {
            expectRoundTripEqualityThroughJSON(for: calendar)
        }
    }

    func test_Calendar_Plist() {
        for calendar in calendarValues {
            expectRoundTripEqualityThroughPlist(for: calendar)
        }
    }

    // MARK: - CharacterSet
    lazy var characterSetValues: [CharacterSet] = [
        CharacterSet.controlCharacters,
        CharacterSet.whitespaces,
        CharacterSet.whitespacesAndNewlines,
        CharacterSet.decimalDigits,
        CharacterSet.letters,
        CharacterSet.lowercaseLetters,
        CharacterSet.uppercaseLetters,
        CharacterSet.nonBaseCharacters,
        CharacterSet.alphanumerics,
        CharacterSet.decomposables,
        CharacterSet.illegalCharacters,
        CharacterSet.punctuationCharacters,
        CharacterSet.capitalizedLetters,
        CharacterSet.symbols,
        CharacterSet.newlines
    ]

    func test_CharacterSet_JSON() {
        for characterSet in characterSetValues {
            expectRoundTripEqualityThroughJSON(for: characterSet)
        }
    }

    func test_CharacterSet_Plist() {
        for characterSet in characterSetValues {
            expectRoundTripEqualityThroughPlist(for: characterSet)
        }
    }

    // MARK: - CGAffineTransform
    lazy var cg_affineTransformValues: [CGAffineTransform] = {
        // FIXME: Comment the tests back in once rdar://problem/33363218 is in the SDK.
        var values = [
            CGAffineTransform.identity,
            CGAffineTransform(),
            CGAffineTransform(translationX: 2.0, y: 2.0),
            CGAffineTransform(scaleX: 2.0, y: 2.0),
            CGAffineTransform(a: 1.0, b: 2.5, c: 66.2, d: 40.2, tx: -5.5, ty: 3.7),
            // CGAffineTransform(a: -55.66, b: 22.7, c: 1.5, d: 0.0, tx: -22, ty: -33),
            CGAffineTransform(a: 4.5, b: 1.1, c: 0.025, d: 0.077, tx: -0.55, ty: 33.2),
            // CGAffineTransform(a: 7.0, b: -2.3, c: 6.7, d: 0.25, tx: 0.556, ty: 0.99),
            // CGAffineTransform(a: 0.498, b: -0.284, c: -0.742, d: 0.3248, tx: 12, ty: 44)
        ]

        if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
            values.append(CGAffineTransform(rotationAngle: .pi / 2))
        }

        return values
    }()

    func test_CGAffineTransform_JSON() {
        for transform in cg_affineTransformValues {
            expectRoundTripEqualityThroughJSON(for: transform)
        }
    }

    func test_CGAffineTransform_Plist() {
        for transform in cg_affineTransformValues {
            expectRoundTripEqualityThroughPlist(for: transform)
        }
    }

    // MARK: - CGPoint
    lazy var cg_pointValues: [CGPoint] = {
        var values = [
            CGPoint.zero,
            CGPoint(x: 10, y: 20)
        ]

        if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
            // Limit on magnitude in JSON. See rdar://problem/12717407
            values.append(CGPoint(x: CGFloat.greatestFiniteMagnitude,
                                  y: CGFloat.greatestFiniteMagnitude))
        }

        return values
    }()

    func test_CGPoint_JSON() {
        for point in cg_pointValues {
            expectRoundTripEqualityThroughJSON(for: point)
        }
    }

    func test_CGPoint_Plist() {
        for point in cg_pointValues {
            expectRoundTripEqualityThroughPlist(for: point)
        }
    }

    // MARK: - CGSize
    lazy var cg_sizeValues: [CGSize] = {
        var values = [
            CGSize.zero,
            CGSize(width: 30, height: 40)
        ]

        if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
            // Limit on magnitude in JSON. See rdar://problem/12717407
            values.append(CGSize(width: CGFloat.greatestFiniteMagnitude,
                                 height: CGFloat.greatestFiniteMagnitude))
        }

        return values
    }()

    func test_CGSize_JSON() {
        for size in cg_sizeValues {
            expectRoundTripEqualityThroughJSON(for: size)
        }
    }

    func test_CGSize_Plist() {
        for size in cg_sizeValues {
            expectRoundTripEqualityThroughPlist(for: size)
        }
    }

    // MARK: - CGRect
    lazy var cg_rectValues: [CGRect] = {
        // FIXME: Comment the tests back in once rdar://problem/33363218 is in the SDK.
        var values = [
            CGRect.zero,
            // CGRect.null,
            CGRect(x: 10, y: 20, width: 30, height: 40)
        ]

        if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
            // Limit on magnitude in JSON. See rdar://problem/12717407
            // values.append(CGRect.infinite)
        }

        return values
    }()

    func test_CGRect_JSON() {
        for rect in cg_rectValues {
            expectRoundTripEqualityThroughJSON(for: rect)
        }
    }

    func test_CGRect_Plist() {
        for rect in cg_rectValues {
            expectRoundTripEqualityThroughPlist(for: rect)
        }
    }

    // MARK: - CGVector
    lazy var cg_vectorValues: [CGVector] = {
        // FIXME: Comment the tests back in once rdar://problem/33363218 is in the SDK.
        var values = [
            CGVector.zero,
            // CGVector(dx: 0.0, dy: -9.81)
        ]

        if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {
            // Limit on magnitude in JSON. See rdar://problem/12717407
            values.append(CGVector(dx: CGFloat.greatestFiniteMagnitude,
                                   dy: CGFloat.greatestFiniteMagnitude))
        }

        return values
    }()

    func test_CGVector_JSON() {
        for vector in cg_vectorValues {
            expectRoundTripEqualityThroughJSON(for: vector)
        }
    }

    func test_CGVector_Plist() {
        for vector in cg_vectorValues {
            expectRoundTripEqualityThroughPlist(for: vector)
        }
    }


        return try decoder.decode(T.self, from: data)
    }

    expectRoundTripEquality(of: value, encode: encode, decode: decode, lineNumber: lineNumber)
}

func expectRoundTripEqualityThroughPlist<T : Codable>(for value: T, lineNumber: Int) where T : Equatable {
    let encode = { (_ value: T) throws -> Data in
        return try PropertyListEncoder().encode(value)
    }
