A device runs no tool-hosted test bundle, so the package's tests run on one hosted in TestHost/: a minimal application (an empty window) and an Xcode project whose unit-test target compiles the same test files against this package by its path, with the corpus in its resources and local networking allowed for the loopback origin and relay. The package itself is unchanged for consumers. The tests import WaiSink plainly (they use only its public interface) and read the corpus from Bundle.module in the package, from their own bundle in the host. Co-Authored-By: Claude Opus 5.5 <[email protected]>
79 lines
4.3 KiB
Swift
79 lines
4.3 KiB
Swift
// The Swift wrapper gives every call of the native sink corpus the answer the corpus states
|
|
// (native-sink §10), through the same C interface every native integration links.
|
|
import XCTest
|
|
import WaiSink
|
|
|
|
final class CorpusTests: XCTestCase {
|
|
func testEveryCaseGetsItsAnswers() throws {
|
|
let doc = try corpus()
|
|
let objects = doc["objects"] as! [String: String]
|
|
func body(_ v: Any?) -> Data? { (v as? String).map { hexData(objects[$0]!) } }
|
|
let cases = doc["cases"] as! [[String: Any]]
|
|
XCTAssertGreaterThan(cases.count, 10)
|
|
var calls = 0
|
|
for c in cases {
|
|
let name = c["name"] as! String
|
|
let sink = try WaiSink(configJSON: c["config"] as! [String: Any], seed: hexData(c["seed"] as! String), startUs: (c["start_us"] as! NSNumber).uint64Value)
|
|
for (i, call) in (c["calls"] as! [[String: Any]]).enumerated() {
|
|
let d = call["do"] as! [String: Any]
|
|
let want = call["answer"]!
|
|
let got: Any
|
|
do {
|
|
switch d["call"] as! String {
|
|
case "playlist":
|
|
got = try sink.playlist(url: d["url"] as! String, bytes: body(d["body"])!, receipt: body(d["receipt"]))
|
|
case "parent":
|
|
try sink.playlistParent(url: d["url"] as! String, name: d["name"] as! String, bytes: body(d["body"]))
|
|
got = ["ok": true]
|
|
case "object":
|
|
got = try sink.object(meta: d["meta"] as! [String: Any], bytes: body(d["body"])!)
|
|
case "event":
|
|
try sink.event(d["name"] as! String, atUs: (d["t_us"] as! NSNumber).uint64Value)
|
|
got = ["ok": true]
|
|
case "observe":
|
|
let e = try sink.observe(d["obs"] as! [String: Any])
|
|
got = ["end": e?.rawValue ?? NSNull()] as [String: Any]
|
|
case "energy":
|
|
try sink.energy(d["entry"] as! [String: Any])
|
|
got = ["ok": true]
|
|
case "attach":
|
|
try sink.attach(name: d["name"] as! String, bytes: body(d["body"])!)
|
|
got = ["ok": true]
|
|
case "cmcd":
|
|
got = ["cmcd": try sink.takeCMCD()]
|
|
case "end":
|
|
let b = try sink.end(WaiSink.Ended(rawValue: d["ended"] as! String)!, atUs: (d["t_us"] as! NSNumber).uint64Value)
|
|
got = ["bundle": String(decoding: b, as: UTF8.self)]
|
|
default:
|
|
XCTFail("\(name): an unknown call"); continue
|
|
}
|
|
} catch let e as WaiSinkError {
|
|
got = ["error": e.reason]
|
|
}
|
|
XCTAssertEqual(canonical(got), canonical(want), "\(name): call \(i)")
|
|
calls += 1
|
|
}
|
|
}
|
|
print("WAI-SINK corpus: \(cases.count) cases, \(calls) calls through the C interface, ABI \(WaiSink.abiVersion)")
|
|
}
|
|
|
|
func testABundleVerifiesAsTheCollectorVerifiesIt() throws {
|
|
let doc = try corpus()
|
|
let c = (doc["cases"] as! [[String: Any]]).first { $0["name"] as? String == "signed-vod" }!
|
|
let end = (c["calls"] as! [[String: Any]]).compactMap { ($0["answer"] as? [String: Any])?["bundle"] as? String }.first!
|
|
let out = try WaiSink.verifyBundle(Data(end.utf8), owner: hexData(doc["owner"] as! String), channels: doc["channels"] as! [String])
|
|
XCTAssertEqual(canonical(out), canonical(c["outcome"]!))
|
|
let other = try WaiSink.verifyBundle(Data(end.utf8), owner: Data(repeating: 7, count: 32), channels: doc["channels"] as! [String])
|
|
XCTAssertEqual(other["reason"] as? String, "audit_wrong_owner")
|
|
}
|
|
|
|
func testAFreshKeyPerSession() throws {
|
|
let cfg = WaiSink.Config(channel: "film-library", owner: String(repeating: "0", count: 64))
|
|
let a = try WaiSink(config: cfg).info()["player"] as! String
|
|
let b = try WaiSink(config: cfg).info()["player"] as! String
|
|
XCTAssertNotEqual(a, b)
|
|
XCTAssertThrowsError(try WaiSink(configJSON: ["channel": "film library", "owner": String(repeating: "0", count: 64)])) { e in
|
|
XCTAssertEqual((e as? WaiSinkError)?.reason, "native_config_invalid")
|
|
}
|
|
}
|
|
}
|