Viewing is open to everyone. Downloading and starring need a GitHub sign-in. Sign in with GitHub

CKeyTests.swift

v0.1.0-build.85 Latest Commit ede38f5

Size
10 KB
Lines
233
Language
swift
SHA-256
70cbf93f455e…
View on GitHub

Sign in with GitHub to download. Each download is recorded with your GitHub username.

1import CKey
2import CoreGraphics
3import CoreVideo
4import XCTest
5
6final class CKeyRoundTripTests: XCTestCase {
7 func testEncodeRenderDecodeText() throws {
8 let symbol = try CKeySymbol.encode("Hello, CKey")
9 XCTAssertGreaterThanOrEqual(symbol.version, 1)
10 XCTAssertEqual(symbol.level, .m)
11 XCTAssertEqual(symbol.layout, .standard)
12 XCTAssertEqual(symbol.payloadLength, 11)
13
14 let image = try symbol.cgImage(size: 512)
15 XCTAssertEqual(image.width, 512)
16 XCTAssertEqual(image.height, 512)
17 let result = try XCTUnwrap(CKeyDecoder.decode(cgImage: image))
18 XCTAssertEqual(result.bytes, Data("Hello, CKey".utf8))
19 XCTAssertEqual(result.text, "Hello, CKey")
20 XCTAssertEqual(result.profile, .scalable)
21 XCTAssertEqual(result.version, symbol.version)
22 XCTAssertEqual(result.layout, .standard)
23 XCTAssertEqual(result.telemetryProfileCode, 0)
24 }
25
26 func testTransparentRenderingDecodesOverWhite() throws {
27 let symbol = try CKeySymbol.encode("https://openckey.org")
28 let image = try symbol.cgImage(size: 400, transparent: true)
29 XCTAssertEqual(image.alphaInfo, .last)
30 let result = try XCTUnwrap(CKeyDecoder.decode(cgImage: image))
31 XCTAssertEqual(result.text, "https://openckey.org")
32 }
33
34 func testEveryPolicyAndPrintLayoutRoundTrip() throws {
35 for layout in CKeyLayout.allCases {
36 for policy in CKeyRasterPolicy.allCases {
37 let symbol = try CKeySymbol.encode("CKey \(layout) \(policy)", level: .q, layout: layout)
38 let image = try symbol.cgImage(size: 600, policy: policy)
39 let result = try XCTUnwrap(CKeyDecoder.decode(cgImage: image), "\(layout) \(policy)")
40 XCTAssertEqual(result.text, "CKey \(layout) \(policy)")
41 XCTAssertEqual(result.layout, layout)
42 }
43 }
44 }
45
46 func testBinaryPayloadRoundTripThroughPixelBuffer() throws {
47 let payload = Data((0..<37).map { UInt8(($0 * 37 + 11) & 0xff) } + [0, 1, 2])
48 let symbol = try CKeySymbol.encode(payload, version: 6, level: .h)
49 XCTAssertEqual(symbol.version, 6)
50 let pixels = try symbol.pixels(size: 640)
51
52 var buffer: CVPixelBuffer?
53 XCTAssertEqual(CVPixelBufferCreate(nil, pixels.width, pixels.height, kCVPixelFormatType_32BGRA, nil, &buffer),
54 kCVReturnSuccess)
55 let pixelBuffer = try XCTUnwrap(buffer)
56 CVPixelBufferLockBaseAddress(pixelBuffer, [])
57 let base = try XCTUnwrap(CVPixelBufferGetBaseAddress(pixelBuffer)).assumingMemoryBound(to: UInt8.self)
58 let rowBytes = CVPixelBufferGetBytesPerRow(pixelBuffer)
59 pixels.rgba.withUnsafeBytes { raw in
60 let rgba = raw.bindMemory(to: UInt8.self)
61 for y in 0..<pixels.height {
62 for x in 0..<pixels.width {
63 let s = (y * pixels.width + x) * 4
64 let d = base + y * rowBytes + x * 4
65 d[0] = rgba[s + 2]; d[1] = rgba[s + 1]; d[2] = rgba[s]; d[3] = rgba[s + 3]
66 }
67 }
68 }
69 CVPixelBufferUnlockBaseAddress(pixelBuffer, [])
70
71 let result = try XCTUnwrap(CKeyDecoder.decode(pixelBuffer: pixelBuffer))
72 XCTAssertEqual(result.bytes, payload)
73 XCTAssertNil(result.text, "binary payloads have no text")
74 XCTAssertEqual(result.version, 6)
75 }
76
77 func testBlankImageDoesNotDecode() throws {
78 let symbol = try CKeySymbol.encode("x")
79 // A plain white image has no border candidates.
80 let space = CGColorSpaceCreateDeviceGray()
81 let context = try XCTUnwrap(CGContext(data: nil, width: 300, height: 300, bitsPerComponent: 8, bytesPerRow: 300,
82 space: space, bitmapInfo: CGImageAlphaInfo.none.rawValue))
83 context.setFillColor(gray: 1, alpha: 1)
84 context.fill(CGRect(x: 0, y: 0, width: 300, height: 300))
85 XCTAssertNil(CKeyDecoder.decode(cgImage: try XCTUnwrap(context.makeImage())))
86 XCTAssertNotNil(CKeyDecoder.decode(cgImage: try symbol.cgImage(size: 300)))
87 }
88}
89
90final class CKeyExportTests: XCTestCase {
91 func testPNGHeader() throws {
92 let png = try CKeySymbol.encode("PNG").pngData(size: 256, transparent: true, dpi: 300)
93 XCTAssertGreaterThan(png.count, 64)
94 XCTAssertEqual(Array(png.prefix(8)), [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
95 XCTAssertEqual(Array(png[12..<16]), Array("IHDR".utf8))
96 }
97
98 func testPDFHeaderAndTrailer() throws {
99 let pdf = try CKeySymbol.encode("PDF").pdfData(widthPoints: 144)
100 XCTAssertEqual(Array(pdf.prefix(5)), Array("%PDF-".utf8))
101 let tail = String(decoding: pdf.suffix(32), as: UTF8.self)
102 XCTAssertTrue(tail.contains("%%EOF"), tail)
103 }
104
105 func testSVG() throws {
106 let svg = try CKeySymbol.encode("SVG").svg(scale: 8, style: .concept)
107 XCTAssertTrue(svg.contains("<svg"))
108 XCTAssertTrue(svg.hasSuffix(">") || svg.hasSuffix(">\n"))
109 XCTAssertFalse(svg.contains("\u{0}"))
110 }
111
112 func testTransparentAlpha() throws {
113 let symbol = try CKeySymbol.encode("alpha")
114 let transparent = try symbol.pixels(size: 128, transparent: true)
115 XCTAssertEqual(transparent.rgba.count, 128 * 128 * 4)
116 XCTAssertTrue(transparent.hasAlpha)
117 XCTAssertEqual(transparent.rgba[3], 0, "the quiet-margin corner is unpainted")
118 XCTAssertTrue(stride(from: 3, to: transparent.rgba.count, by: 4).contains { transparent.rgba[$0] == 255 },
119 "ink is opaque")
120
121 let opaque = try symbol.pixels(size: 128, transparent: false)
122 XCTAssertFalse(opaque.hasAlpha)
123 XCTAssertTrue(stride(from: 3, to: opaque.rgba.count, by: 4).allSatisfy { opaque.rgba[$0] == 255 })
124
125 let image = try symbol.cgImage(size: 128, transparent: true)
126 let data = try XCTUnwrap(image.dataProvider?.data) as Data
127 XCTAssertEqual(data[3], 0)
128 }
129
130 func testStylesAndCapacity() throws {
131 XCTAssertEqual(CKeyStyle(), CKeyStyle.plain)
132 XCTAssertEqual(CKeyStyle.plain.ink, .black)
133 XCTAssertEqual(CKeyStyle.plain.policy, .strict)
134 XCTAssertNotEqual(CKeyStyle.concept, CKeyStyle.plain)
135
136 let symbol = try CKeySymbol.encode("style")
137 XCTAssertNoThrow(try symbol.check(style: .plain))
138 XCTAssertNoThrow(try symbol.cgImage(size: 256, style: .concept))
139
140 var unreadable = CKeyStyle.plain
141 unreadable.ink = CKeyColor(red: 250, green: 250, blue: 250)
142 unreadable.inkShade = unreadable.ink
143 XCTAssertThrowsError(try symbol.check(style: unreadable))
144 XCTAssertThrowsError(try symbol.cgImage(size: 256, style: unreadable), "strict policy refuses")
145 unreadable.policy = .override
146 XCTAssertNoThrow(try symbol.cgImage(size: 256, style: unreadable), "override draws as given")
147
148 XCTAssertGreaterThan(CKeySymbol.capacity(version: 1), 0)
149 XCTAssertEqual(CKeySymbol.capacity(version: 0), 0)
150 XCTAssertThrowsError(try CKeySymbol.encode("x", version: 32))
151 let tooLong = String(repeating: "A", count: CKeySymbol.capacity(version: 1) + 1)
152 XCTAssertThrowsError(try CKeySymbol.encode(tooLong, version: 1)) { error in
153 XCTAssertTrue(error is CKeyError)
154 }
155 }
156
157 func testCertification() throws {
158 let symbol = try CKeySymbol.encode("certify")
159 let plain = try symbol.certify()
160 XCTAssertTrue(plain.accepted, plain.message)
161 XCTAssertTrue(plain.certified, plain.message)
162
163 let unknownBackground = try symbol.certify(transparent: true)
164 XCTAssertFalse(unknownBackground.certified, "a transparent symbol over an unknown background is never certified")
165
166 let onWhite = try symbol.certify(transparent: true, backdrops: [.white])
167 XCTAssertTrue(onWhite.certified, onWhite.message)
168 }
169}
170
171final class CKeyTelemetryTests: XCTestCase {
172 override func tearDown() {
173 CKey.telemetry = .on
174 super.tearDown()
175 }
176
177 func testDefaultAndValidation() throws {
178 XCTAssertEqual(CKeyTelemetryMode.on.rawValue, 1)
179 CKey.telemetry = .local
180 for invalid in [-1, 3, 42, Int.max] {
181 XCTAssertThrowsError(try CKey.setTelemetry(rawValue: invalid)) { error in
182 XCTAssertEqual((error as? CKeyError)?.code, .invalidConfiguration)
183 }
184 XCTAssertEqual(CKey.telemetry, .local, "an invalid value leaves the mode unchanged")
185 }
186 try CKey.setTelemetry(rawValue: 0)
187 XCTAssertEqual(CKey.telemetry, .off)
188 try CKey.setTelemetry(rawValue: 1)
189 XCTAssertEqual(CKey.telemetry, .on)
190 CKey.telemetry = 2
191 XCTAssertEqual(CKey.telemetry, .local)
192 CKey.telemetry = 0
193 XCTAssertEqual(CKey.telemetry, .off)
194 XCTAssertNil(CKeyTelemetryMode(rawValue: 5))
195 }
196
197 func testLocalModeCountsSessionsAndOffPurges() throws {
198 CKey.telemetry = .off // purge
199 CKey.telemetry = .local // count from zero, never send
200 let session = CKeyTelemetrySession.shared
201 let symbol = try CKeySymbol.encode("telemetry")
202 let result = try XCTUnwrap(CKeyDecoder.decode(cgImage: try symbol.cgImage(size: 400)))
203
204 session.scanSessionDidBegin()
205 session.scanFrameProcessed(milliseconds: 12)
206 session.scanSessionDidDecode(result)
207 session.scanSessionDidEnd()
208 session.scanSessionDidBegin()
209 session.scanSessionDidEnd() // no decode: fails
210
211 let counters = CKey.telemetryCounters
212 XCTAssertEqual(counters.sessionsStarted, 2)
213 XCTAssertEqual(counters.sessionsSucceeded, 1)
214 XCTAssertEqual(counters.sessionsFailed, 1)
215 XCTAssertEqual(counters.frames, 1)
216 XCTAssertEqual(counters.decoded["p0"], 1)
217 XCTAssertEqual(counters.timeToDecodeMilliseconds.count, 1)
218 XCTAssertEqual(counters.frameMilliseconds.buckets.count, 10)
219 XCTAssertEqual(counters.frameMilliseconds.buckets.reduce(0, +), counters.frameMilliseconds.count)
220
221 CKey.telemetry = .off
222 let purged = CKey.telemetryCounters
223 XCTAssertEqual(purged.sessionsStarted, 0)
224 XCTAssertEqual(purged.frames, 0)
225 session.scanSessionDidBegin() // mode 0: a no-op
226 XCTAssertEqual(CKey.telemetryCounters.sessionsStarted, 0)
227 }
228
229 func testVersion() {
230 XCTAssertTrue(CKey.version.hasPrefix("0."), CKey.version)
231 XCTAssertEqual(CKeyCoreInfo.softwareVersion, CKey.version)
232 }
233}