Viewing is open to everyone. Downloading and starring need a GitHub sign-in.
Sign in with GitHub
CKeyScanKitTests.swift
v0.1.0-build.85
Latest
Commit ede38f5
Sign in with GitHub to download. Each download is recorded with your GitHub username.
| 1 | import CKeyScanKit |
| 2 | import CoreGraphics |
| 3 | import CoreVideo |
| 4 | import XCTest |
| 5 | |
| 6 | /// The scan-only product: no renderer and no telemetry are linked here. |
| 7 | final class CKeyPayloadTests: XCTestCase { |
| 8 | func testTextDetection() { |
| 9 | XCTAssertEqual(CKeyPayload.text(from: Data("hello\r\nworld\t!".utf8)), "hello\r\nworld\t!") |
| 10 | XCTAssertNil(CKeyPayload.text(from: Data([0xff, 0xfe])), "invalid UTF-8") |
| 11 | XCTAssertNil(CKeyPayload.text(from: Data([0x41, 0x00, 0x42])), "NUL is a control character") |
| 12 | XCTAssertNil(CKeyPayload.text(from: Data([0x41, 0x1b])), "ESC is a control character") |
| 13 | XCTAssertNil(CKeyPayload.text(from: Data())) |
| 14 | XCTAssertEqual(CKeyPayload.hex(Data([0x00, 0xab, 0x10])), "00ab10") |
| 15 | } |
| 16 | |
| 17 | func testAllowlistedForms() { |
| 18 | XCTAssertEqual(CKeyPayload.classify(" https://citeory.com/tour \n"), .web(URL(string: "https://citeory.com/tour")!)) |
| 19 | XCTAssertEqual(CKeyPayload.classify("HTTP://example.com"), .web(URL(string: "HTTP://example.com")!)) |
| 20 | XCTAssertEqual(CKeyPayload.classify("mailto:hello@citeory.com?subject=Hi"), |
| 21 | .email(URL(string: "mailto:hello@citeory.com?subject=Hi")!, address: "hello@citeory.com")) |
| 22 | XCTAssertEqual(CKeyPayload.classify("tel:+1 (555) 123-4567"), |
| 23 | .call(URL(string: "tel:+15551234567")!, number: "+15551234567")) |
| 24 | if case .message(_, let number)? = CKeyPayload.classify("sms:+15551234567?body=Hi") { |
| 25 | XCTAssertEqual(number, "+15551234567") |
| 26 | } else { |
| 27 | XCTFail("sms") |
| 28 | } |
| 29 | if case .geo(let lat, let lon, let label, let url)? = CKeyPayload.classify("geo:37.33490,-122.00900?q=Apple%20Park") { |
| 30 | XCTAssertEqual(lat, 37.3349, accuracy: 1e-9) |
| 31 | XCTAssertEqual(lon, -122.009, accuracy: 1e-9) |
| 32 | XCTAssertEqual(label, "Apple Park") |
| 33 | XCTAssertEqual(url.host, "maps.apple.com") |
| 34 | } else { |
| 35 | XCTFail("geo") |
| 36 | } |
| 37 | if case .address(let address, let url)? = CKeyPayload.classify("address:1 Infinite Loop\n\nCupertino, CA 95014") { |
| 38 | XCTAssertEqual(address, "1 Infinite Loop, Cupertino, CA 95014") |
| 39 | XCTAssertTrue(url.absoluteString.contains("address=")) |
| 40 | } else { |
| 41 | XCTFail("address") |
| 42 | } |
| 43 | let card = "BEGIN:VCARD\r\nVERSION:3.0\r\nFN:Ada Lovelace\r\nEND:VCARD" |
| 44 | XCTAssertEqual(CKeyPayload.classify(card), .contact(vCard: card, name: "Ada Lovelace")) |
| 45 | } |
| 46 | |
| 47 | func testRejectedForms() { |
| 48 | for text in ["javascript:alert(1)", "data:text/html,hi", "file:///etc/passwd", "intent://x", |
| 49 | "myapp://open", "mailto:nobody", "tel:12", "sms:", "geo:91,0", "geo:0,181", "geo:abc", |
| 50 | "address: \n ", "https://", "plain words", "BEGIN:VCARD\nFN:x"] { |
| 51 | XCTAssertNil(CKeyPayload.classify(text), text) |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | final class CKeyDecoderTests: XCTestCase { |
| 57 | func testBlankFramesDoNotDecode() throws { |
| 58 | let white = [UInt8](repeating: 255, count: 320 * 240) |
| 59 | white.withUnsafeBufferPointer { buffer in |
| 60 | XCTAssertNil(CKeyDecoder.decode(gray: buffer.baseAddress!, width: 320, height: 240, stride: 320)) |
| 61 | } |
| 62 | var pixelBuffer: CVPixelBuffer? |
| 63 | XCTAssertEqual(CVPixelBufferCreate(nil, 64, 64, kCVPixelFormatType_OneComponent8, nil, &pixelBuffer), |
| 64 | kCVReturnSuccess) |
| 65 | XCTAssertNil(CKeyDecoder.decode(pixelBuffer: try XCTUnwrap(pixelBuffer))) |
| 66 | } |
| 67 | |
| 68 | func testInvalidGeometryIsRejected() { |
| 69 | let gray = [UInt8](repeating: 0, count: 16) |
| 70 | gray.withUnsafeBufferPointer { buffer in |
| 71 | XCTAssertNil(CKeyDecoder.decode(gray: buffer.baseAddress!, width: 4, height: 4, stride: 2)) |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | func testResultMetadata() { |
| 76 | let result = CKeyResult(bytes: Data("hi".utf8), profile: .scalable, version: 3, layout: .print) |
| 77 | XCTAssertEqual(result.text, "hi") |
| 78 | XCTAssertEqual(result.telemetryProfileCode, 1) |
| 79 | XCTAssertEqual(result.profileDescription, "Profile 0.1 · print · v3") |
| 80 | XCTAssertEqual(CKeyResult(bytes: Data(count: 16), profile: .locator).telemetryProfileCode, 2) |
| 81 | XCTAssertFalse(CKeyCoreInfo.softwareVersion.isEmpty) |
| 82 | XCTAssertGreaterThanOrEqual(CKeyCoreInfo.abiVersion, 4) |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | final class CKeyPayloadEdgeCaseTests: XCTestCase { |
| 87 | func testPhoneParametersAreNeverDialled() { |
| 88 | guard case .call(let url, let number)? = CKeyPayload.classify("tel:+15550100;ext=7") else { return XCTFail("tel") } |
| 89 | XCTAssertEqual(number, "+15550100") |
| 90 | XCTAssertEqual(url.absoluteString, "tel:+15550100") |
| 91 | guard case .message(_, let sms)? = CKeyPayload.classify("sms:+15550100?body=Hi") else { return XCTFail("sms") } |
| 92 | XCTAssertEqual(sms, "+15550100") |
| 93 | } |
| 94 | |
| 95 | func testFormatCharactersAreText() { |
| 96 | // Family emoji (ZWJ sequence), a soft hyphen and a BOM are text, not binary. |
| 97 | let text = "👨👩👧 co\u{00AD}operate \u{FEFF}hello" |
| 98 | XCTAssertEqual(CKeyPayload.text(from: Data(text.utf8)), text) |
| 99 | XCTAssertNil(CKeyPayload.text(from: Data([0x41, 0x07, 0x42]))) // BEL is a control character |
| 100 | XCTAssertNil(CKeyPayload.text(from: Data("a\u{0085}b".utf8))) // C1 control |
| 101 | } |
| 102 | |
| 103 | func testVCardMustBeComplete() { |
| 104 | XCTAssertNotNil(CKeyPayload.classify("BEGIN:VCARD\nVERSION:4.0\nFN:Ada\nEND:VCARD")) |
| 105 | XCTAssertNil(CKeyPayload.classify("BEGIN:VCARD\nFN:Ada\nEND:VCARD trailing words")) |
| 106 | XCTAssertNil(CKeyPayload.classify("BEGIN:VCARDS and more END:VCARD")) |
| 107 | } |
| 108 | } |