guardia-messenger/node_modules/expo-modules-core/ios/Tests/ConvertiblesSpec.swift
DESKTOP-TKLFCPRython f29f525c77 refactor: 101.79.17.164 → zioinfo.co.kr 전체 도메인 변환 + Manager UI 배포
- 37개 파일 IP → zioinfo.co.kr 치환 (소스/매뉴얼/설정/하네스)
- Manager DrConsole/NetworkConsole/CsapConsole 빌드 + /var/www/manager/ 배포
- 테스트: Manager HTTP 200, ITSM 신규 API 7개 전체 200

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-31 10:09:17 +09:00

423 lines
17 KiB
Swift

// Copyright 2018-present 650 Industries. All rights reserved.
import CoreGraphics
import ExpoModulesTestCore
@testable import ExpoModulesCore
class ConvertiblesSpec: ExpoSpec {
override class func spec() {
let appContext = AppContext.create()
describe("URL") {
it("converts from remote url") {
let remoteUrlString = "https://expo.dev"
let url = try URL.convert(from: remoteUrlString, appContext: appContext)
expect(url.path) == ""
expect(url.absoluteString) == remoteUrlString
}
it("converts from url with unencoded query") {
let query = "param=🥓"
let urlString = "https://expo.dev/?\(query)"
let url = try URL.convert(from: urlString, appContext: appContext)
if #available(iOS 16.0, *) {
expect(url.query(percentEncoded: true)) == "param=%F0%9F%A5%93"
expect(url.query(percentEncoded: false)) == query
}
expect(url.query) == "param=%F0%9F%A5%93"
expect(url.absoluteString) == "https://expo.dev/?param=%F0%9F%A5%93"
expect(url.absoluteString.removingPercentEncoding) == urlString
}
it("converts from url with encoded query") {
let query = "param=%F0%9F%A5%93"
let urlString = "https://expo.dev/?\(query)"
let url = try URL.convert(from: urlString, appContext: appContext)
if #available(iOS 16.0, *) {
expect(url.query(percentEncoded: true)) == query
expect(url.query(percentEncoded: false)) == "param=🥓"
}
expect(url.query) == query
expect(url.absoluteString) == urlString
expect(url.absoluteString.removingPercentEncoding) == "https://expo.dev/?param=🥓"
}
it("converts from url with encoded query containg the anchor") {
let query = "color=%230000ff"
let urlString = "https://expo.dev/?\(query)#anchor"
let url = try URL.convert(from: urlString, appContext: appContext)
expect(url.query) == query
expect(url.absoluteString) == urlString
expect(url.absoluteString.removingPercentEncoding) == "https://expo.dev/?color=#0000ff#anchor"
expect(url.fragment) == "anchor"
}
it("converts from url with encoded path") {
let path = "/expo/%2F%25%3F%5E%26/test" // -> /expo//%?^&/test
let urlString = "https://expo.dev\(path)"
let url = try URL.convert(from: urlString, appContext: appContext)
expect(url.absoluteString) == urlString
expect(url.path) == path.removingPercentEncoding
if #available(iOS 16.0, *) {
expect(url.path(percentEncoded: true)) == path
expect(url.path(percentEncoded: false)) == path.removingPercentEncoding
}
}
it("converts from url containing the anchor") {
// The hash is not allowed in the query (requires percent-encoding),
// but we want it to be recognized as the beginning of the fragment,
// thus it cannot be percent-encoded.
let query = "param=#expo"
let urlString = "https://expo.dev/?\(query)"
let url = try URL.convert(from: urlString, appContext: appContext)
expect(url.query) == "param="
expect(url.fragment) == "expo"
expect(url.absoluteString) == urlString
}
it("converts from file url") {
let fileUrlString = "file:///expo/tmp"
let url = try URL.convert(from: fileUrlString, appContext: appContext)
expect(url.path) == "/expo/tmp"
expect(url.absoluteString) == fileUrlString
expect(url.isFileURL) == true
}
it("converts from file path") {
let filePath = "/expo/image.png"
let url = try URL.convert(from: filePath, appContext: appContext)
expect(url.scheme) == "file"
expect(url.path) == filePath
expect(url.absoluteString) == "file://\(filePath)"
expect(url.isFileURL) == true
}
it("converts from file path with UTF8 characters") {
let filePath = "/中文ÅÄÖąÓśĆñ.gif"
let url = try URL.convert(from: filePath, appContext: appContext)
expect(url.scheme) == "file"
expect(url.path) == filePath
expect(url.isFileURL) == true
}
it("converts from file path containing percent character") {
let filePath = "/%.png"
let url = try URL.convert(from: filePath, appContext: appContext)
expect(url.scheme) == "file"
expect(url.path) == filePath
expect(url.isFileURL) == true
}
it("throws when no string") {
expect { try URL.convert(from: 29.5, appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<URL>.self)
)
}
}
describe("CGPoint") {
let x = -8.3
let y = 4.6
it("converts from array of doubles") {
let point = try CGPoint.convert(from: [x, y], appContext: appContext)
expect(point.x) == x
expect(point.y) == y
}
it("converts from dict") {
let point = try CGPoint.convert(from: ["x": x, "y": y], appContext: appContext)
expect(point.x) == x
expect(point.y) == y
}
it("throws when array size is unexpected") { // different than two
expect { try CGPoint.convert(from: [], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
)
expect { try CGPoint.convert(from: [x], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
)
expect { try CGPoint.convert(from: [x, y, x], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGPoint>.self)
)
}
it("throws when dict is missing some keys") {
expect { try CGPoint.convert(from: ["test": x], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["x", "y"]).description
})
}
it("throws when dict has uncastable keys") {
expect { try CGPoint.convert(from: ["x": x, "y": "string"], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["y"]).description
})
}
}
describe("CGSize") {
let width = 52.8
let height = 81.7
it("converts from array of doubles") {
let size = try CGSize.convert(from: [width, height], appContext: appContext)
expect(size.width) == width
expect(size.height) == height
}
it("converts from dict") {
let size = try CGSize.convert(from: ["width": width, "height": height], appContext: appContext)
expect(size.width) == width
expect(size.height) == height
}
it("throws when array size is unexpected") { // different than two
expect { try CGSize.convert(from: [], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGSize>.self)
)
expect { try CGSize.convert(from: [width], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGSize>.self)
)
expect { try CGSize.convert(from: [width, height, width], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGSize>.self)
)
}
it("throws when dict is missing some keys") {
expect { try CGSize.convert(from: ["width": width], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["height"]).description
})
}
it("throws when dict has uncastable keys") {
expect { try CGSize.convert(from: ["width": "test", "height": height], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["width"]).description
})
}
}
describe("CGVector") {
let dx = 11.6
let dy = -4.0
it("converts from array of doubles") {
let vector = try CGVector.convert(from: [dx, dy], appContext: appContext)
expect(vector.dx) == dx
expect(vector.dy) == dy
}
it("converts from dict") {
let vector = try CGVector.convert(from: ["dx": dx, "dy": dy], appContext: appContext)
expect(vector.dx) == dx
expect(vector.dy) == dy
}
it("throws when array size is unexpected") { // different than two
expect { try CGVector.convert(from: [], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGVector>.self)
)
expect { try CGVector.convert(from: [dx], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGVector>.self)
)
expect { try CGVector.convert(from: [dx, dy, dx], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGVector>.self)
)
}
it("throws when dict is missing some keys") {
expect { try CGVector.convert(from: ["dx": dx], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["dy"]).description
})
}
it("throws when dict has uncastable keys") {
expect { try CGVector.convert(from: ["dx": "dx", "dy": dy], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["dx"]).description
})
}
}
describe("CGRect") {
let x = -8.3
let y = 4.6
let width = 52.8
let height = 81.7
it("converts from array of doubles") {
let rect = try CGRect.convert(from: [x, y, width, height], appContext: appContext)
expect(rect.origin.x) == x
expect(rect.origin.y) == y
expect(rect.width) == width
expect(rect.height) == height
}
it("converts from dict") {
let rect = try CGRect.convert(from: ["x": x, "y": y, "width": width, "height": height], appContext: appContext)
expect(rect.origin.x) == x
expect(rect.origin.y) == y
expect(rect.width) == width
expect(rect.height) == height
}
it("throws when array size is unexpected") { // different than four
expect { try CGRect.convert(from: [x], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGRect>.self)
)
expect { try CGRect.convert(from: [x, y], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGRect>.self)
)
expect { try CGRect.convert(from: [x, y, width, height, y], appContext: appContext) }.to(
throwError(errorType: Conversions.ConvertingException<CGRect>.self)
)
}
it("throws when dict is missing some keys") {
expect { try CGRect.convert(from: ["x": x], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.MissingKeysException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.MissingKeysException<Double>(["y", "width", "height"]).description
})
}
it("throws when dict has uncastable keys") {
expect { try CGRect.convert(from: ["x": x, "y": nil, "width": width, "height": "\(height)"], appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.CastingValuesException<Double>.self))
expect(($0 as! CodedError).description) == Conversions.CastingValuesException<Double>(["y", "height"]).description
})
}
}
describe("UIColor/CGColor") {
func testColorComponents(_ color: CGColor, _ red: CGFloat, _ green: CGFloat, _ blue: CGFloat, _ alpha: CGFloat) {
expect(color.components?[0]) == red / 255.0
expect(color.components?[1]) == green / 255.0
expect(color.components?[2]) == blue / 255.0
expect(color.components?[3]) == alpha / 255.0
}
func testInvalidHexColor(_ hex: String) {
expect { try CGColor.convert(from: hex, appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.InvalidHexColorException.self))
expect(($0 as! CodedError).description) == Conversions.InvalidHexColorException(hex).description
})
}
it("converts from ARGB int") {
// NOTE: int representation has alpha channel at the beginning
let color = try CGColor.convert(from: 0x5147AC7F, appContext: appContext)
testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
}
it("converts from RGBA hex string") {
let color = try CGColor.convert(from: "47AC7F51", appContext: appContext)
testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
}
it("converts from #RGBA hex string") {
let color = try CGColor.convert(from: " #47AC7F51", appContext: appContext)
testColorComponents(color, 0x47, 0xAC, 0x7F, 0x51)
}
it("converts from 3-character shorthand hex string") {
let color = try CGColor.convert(from: "C2B ", appContext: appContext)
testColorComponents(color, 0xCC, 0x22, 0xBB, 0xFF)
}
it("converts from 4-character shorthand hex string") {
let color = try CGColor.convert(from: " #9EA5 ", appContext: appContext)
testColorComponents(color, 0x99, 0xEE, 0xAA, 0x55)
}
it("converts from CSS named color") {
let papayawhip = try CGColor.convert(from: "papayawhip", appContext: appContext)
testColorComponents(papayawhip, 0xFF, 0xEF, 0xD5, 0xFF)
}
it("converts from transparent") {
let transparent = try CGColor.convert(from: "transparent", appContext: appContext)
expect(transparent.alpha) == .zero
}
it("converts from PlatformColor") {
let color = try CGColor.convert(from: ["semantic": ["invalid_color", "systemRed", "systemBlue"]], appContext: appContext)
expect(color) == UIColor.systemRed.cgColor
}
it("converts from DynamicColorIOS") {
let color = try CGColor.convert(from: ["dynamic": ["light": "#000", "dark": ["semantic": "systemGray"]]], appContext: appContext)
testColorComponents(color, 0x00, 0x00, 0x00, 0xFF)
}
it("converts from DynamicColorIOS with traits") {
let color = try UIColor.convert(from: ["dynamic": ["light": "#000", "dark": ["semantic": "systemGray"]]], appContext: appContext)
let traits = UITraitCollection(userInterfaceStyle: .dark)
expect(color.resolvedColor(with: traits)) == UIColor.systemGray.resolvedColor(with: traits)
}
it("throws when string is invalid") {
testInvalidHexColor("")
testInvalidHexColor("#21")
testInvalidHexColor("ABCDEFGH")
testInvalidHexColor("1122334455")
testInvalidHexColor("XYZ")
testInvalidHexColor("!@#$%")
}
it("throws when int overflows") {
let hex = 0xBBAA88FF2
expect { try CGColor.convert(from: hex, appContext: appContext) }.to(throwError {
expect($0).to(beAKindOf(Conversions.HexColorOverflowException.self))
expect(($0 as! CodedError).description) == Conversions.HexColorOverflowException(UInt64(hex)).description
})
}
}
describe("Date") {
it("converts from `ISO 8601` String to Date") {
let date = try Date.convert(from: "2023-12-27T10:58:20.654Z", appContext: appContext)
let components = Calendar.current.dateComponents([.day, .month], from: date)
expect(components.month) == 12
expect(components.day) == 27
}
it("converts from `Date.now()` to Date") {
let date = try Date.convert(from: 1703718341639, appContext: appContext)
var components = Calendar.current.dateComponents([.day, .month], from: date)
// The current calendar uses the local timezone, so basically the `day` component
// could differ depending on the current timezone. Set it to GMT for correctness.
components.timeZone = TimeZone(abbreviation: "GMT")
expect(components.month) == 12
expect(components.day) == 27
}
}
}
}