diff --git a/Tests/FloKitTests/CodeBlockPolishTests.swift b/Tests/FloKitTests/CodeBlockPolishTests.swift index 555a6ef..b92738d 100644 --- a/Tests/FloKitTests/CodeBlockPolishTests.swift +++ b/Tests/FloKitTests/CodeBlockPolishTests.swift @@ -185,7 +185,7 @@ extension CodeBlockRenderTests { } /// With the user's substitutions turned on (Edit > Substitutions), prose gets them and code does not. - func testCodeGetsNoSubstitutions() { + func testCodeGetsNoSubstitutions() throws { for (name, doc, isCode) in [("prose", "text", false), ("fenced", "```\ncode", true), ("fenced-closed", "```\ncode\n```", true)] { let r = KeyReplayer(width: 1000, height: 600) let end = name == "fenced-closed" ? 8 : (doc as NSString).length @@ -201,7 +201,9 @@ extension CodeBlockRenderTests { if isCode { XCTAssertTrue(r.doc.contains(typed), "\(name): typed as is: \(r.doc.debugDescription)") } else { - XCTAssertFalse(r.doc.contains(typed), "\(name): prose still gets substitutions: \(r.doc.debugDescription)") + // Prose is the control. A host with no text checking service (a CI runner) substitutes nothing, + // so "code gets none" would pass for no reason. Skip there instead of passing or failing. + try XCTSkipIf(r.doc.contains(typed), "this host does not substitute text in prose: \(r.doc.debugDescription)") } XCTAssertEqual(r.viewText, r.doc, "\(name): view and state agree") } diff --git a/Tests/FloKitTests/CodeBlockRenderTests.swift b/Tests/FloKitTests/CodeBlockRenderTests.swift index 3e7d32b..ada4ea7 100644 --- a/Tests/FloKitTests/CodeBlockRenderTests.swift +++ b/Tests/FloKitTests/CodeBlockRenderTests.swift @@ -67,7 +67,12 @@ final class CodeBlockRenderTests: XCTestCase { let tlm = tv.textLayoutManager! tlm.ensureLayout(for: tlm.documentRange) let rect = tv.visibleRect - let rep = tv.bitmapImageRepForCachingDisplay(in: rect)! + // Always 2x: the ink and gap thresholds were tuned on a Retina display, and a 1x host (a CI runner) + // would draw a quarter of the pixels with bitmapImageRepForCachingDisplay. + let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(rect.width * 2), pixelsHigh: Int(rect.height * 2), + bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, + colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0)! + rep.size = rect.size tv.cacheDisplay(in: rect, to: rep) if let dir = ProcessInfo.processInfo.environment["CODEBLOCK_PNG_DIR"] { let file = "\(dir)/\(name)-\(reading ? "reading" : "writing")-\(dark ? "dark" : "light").png" diff --git a/Tests/FloStateNativeTests/PointerCursorTests.swift b/Tests/FloStateNativeTests/PointerCursorTests.swift index b600cd6..5b3caa7 100644 --- a/Tests/FloStateNativeTests/PointerCursorTests.swift +++ b/Tests/FloStateNativeTests/PointerCursorTests.swift @@ -89,6 +89,7 @@ final class PointerCursorTests: XCTestCase { func testViewsInAWindowInvalidateTheirRectsWhenTheyMoveOrHide() { // not hover: only that the hooks run without a window and with one let w = NSWindow(contentRect: NSRect(x: -10000, y: -10000, width: 200, height: 100), styleMask: [.titled], backing: .buffered, defer: true) + w.isReleasedWhenClosed = false // close() would release a window ARC also owns: a double release let host = NSView(frame: NSRect(x: 0, y: 0, width: 200, height: 100)) w.contentView = host let b = OverflowToggleButton() diff --git a/Tests/FloStateNativeTests/ShellViewTests.swift b/Tests/FloStateNativeTests/ShellViewTests.swift index ceca1c0..4b22d5f 100644 --- a/Tests/FloStateNativeTests/ShellViewTests.swift +++ b/Tests/FloStateNativeTests/ShellViewTests.swift @@ -54,8 +54,13 @@ final class ShellViewTests: XCTestCase { var box = CGRect(x: 0, y: 0, width: 300, height: 400) let ctx = CGContext(URL(fileURLWithPath: pdf) as CFURL, mediaBox: &box, nil)! ctx.beginPDFPage(nil); ctx.setFillColor(NSColor.systemBlue.cgColor); ctx.fill(CGRect(x: 40, y: 40, width: 220, height: 320)); ctx.endPDFPage(); ctx.beginPDFPage(nil); ctx.endPDFPage(); ctx.closePDF() - let img = NSImage(size: NSSize(width: 64, height: 32)); img.lockFocus(); NSColor.red.setFill(); NSRect(x: 0, y: 0, width: 64, height: 32).fill(); img.unlockFocus() - try NSBitmapImageRep(data: img.tiffRepresentation!)!.representation(using: .png, properties: [:])!.write(to: URL(fileURLWithPath: png)) + let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: 128, pixelsHigh: 64, bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, + isPlanar: false, colorSpaceName: .deviceRGB, bytesPerRow: 0, bitsPerPixel: 0)! + NSGraphicsContext.saveGraphicsState() + NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep) + NSColor.red.setFill(); NSRect(x: 0, y: 0, width: 128, height: 64).fill() + NSGraphicsContext.restoreGraphicsState() + try rep.representation(using: .png, properties: [:])!.write(to: URL(fileURLWithPath: png)) let before = try Data(contentsOf: URL(fileURLWithPath: png)) for (path, kind) in [(pdf, WorkspaceFS.ViewerKind.pdf), (png, .image)] { try await f.model.editor.openFileInTabOrFocus(path)