Files
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

68 lines
3.1 KiB
Swift

#if canImport(UIKit)
import XCTest
import UIKit
import QuartzCore
@testable import RichTextEditorUIKit
final class SpoilerDustViewTests: XCTestCase {
func test_init_doesNotCrash_andIsNonInteractive() {
let v = SpoilerDustView()
XCTAssertFalse(v.isUserInteractionEnabled)
XCTAssertFalse(v.isRevealed)
}
func test_realSpeckleAsset_isBundled() {
// Telegram's actual 4x4 particle texture must ship in the UIKit resource bundle — it's what makes the
// dust read as fine shimmer instead of coarse blobs. A missing resource silently falls back to a dot.
XCTAssertNotNil(SpoilerDustView.bundledSpeckleForTesting,
"textSpeckle_Normal.png must be bundled via Package.swift resources")
}
func test_emitterBehaviorPrivateAPI_isAvailable() {
// Canary: if a future OS removes the private CAEmitterBehavior, fail here (not silently in the UI).
let behavior = CAEmitterCell.createEmitterBehavior(type: "simpleAttractor")
XCTAssertNotNil(behavior)
}
func test_update_setsEmitterGeometryAndBirthRate() {
let v = SpoilerDustView()
v.update(size: CGSize(width: 100, height: 20), color: .label,
lineRects: [CGRect(x: 0, y: 0, width: 100, height: 20)],
wordRects: [CGRect(x: 0, y: 0, width: 40, height: 20), CGRect(x: 50, y: 0, width: 40, height: 20)])
XCTAssertEqual(v.emitterLayerForTesting.frame.size, CGSize(width: 100, height: 20))
XCTAssertGreaterThan(v.emitterLayerForTesting.birthRateForCellForTesting, 0)
}
func test_dissolve_marksRevealed_andRemovesOnCompletion() {
let host = UIView()
let v = SpoilerDustView()
v.update(size: CGSize(width: 100, height: 20), color: .label,
lineRects: [CGRect(x: 0, y: 0, width: 100, height: 20)], wordRects: [CGRect(x: 0, y: 0, width: 100, height: 20)])
host.addSubview(v)
let done = expectation(description: "removed")
v.dissolve(explodingAt: CGPoint(x: 10, y: 10)) { done.fulfill() }
XCTAssertTrue(v.isRevealed)
wait(for: [done], timeout: 2.0)
XCTAssertNil(v.superview)
}
func test_pointInside_onlyHitsLineRects_whenHidden() {
let v = SpoilerDustView()
v.update(size: CGSize(width: 100, height: 20), color: .label,
lineRects: [CGRect(x: 0, y: 0, width: 40, height: 20)], wordRects: [CGRect(x: 0, y: 0, width: 40, height: 20)])
XCTAssertTrue(v.point(inside: CGPoint(x: 10, y: 10), with: nil))
XCTAssertFalse(v.point(inside: CGPoint(x: 80, y: 10), with: nil))
}
func test_dissolve_isIdempotent_secondCallCompletesSynchronously() {
let v = SpoilerDustView()
v.update(size: CGSize(width: 50, height: 20), color: .label,
lineRects: [CGRect(x: 0, y: 0, width: 50, height: 20)], wordRects: [CGRect(x: 0, y: 0, width: 50, height: 20)])
v.dissolve(explodingAt: nil) {}
var secondFired = false
v.dissolve(explodingAt: nil) { secondFired = true } // already revealed → completion fires synchronously
XCTAssertTrue(secondFired)
}
}
#endif