import XCTest @testable import SaplingEditor #if os(macOS) import AppKit final class MarkdownTextStylerRenderingTests: XCTestCase { func testRenderedHeadingHidesMarkerWhileActiveHeadingKeepsSourceVisible() { let source = "Intro\n# Heading" let renderedStorage = styledStorage(source: source, activeLineIndex: 0) let activeStorage = styledStorage(source: source, activeLineIndex: 1) let headingMarker = (source as NSString).range(of: "#") let headingText = (source as NSString).range(of: "Heading") XCTAssertTrue(isHidden(renderedStorage, at: headingMarker.location)) XCTAssertGreaterThan(font(in: renderedStorage, at: headingText.location).pointSize, 20) XCTAssertFalse(isHidden(activeStorage, at: headingMarker.location)) } func testRenderedInlineMarkdownHidesDelimitersOnly() { let source = "Intro\nThis has **bold**, *italic*, and `code`." let storage = styledStorage(source: source, activeLineIndex: 0) let nsSource = source as NSString XCTAssertTrue(isHidden(storage, at: nsSource.range(of: "**").location)) XCTAssertFalse(isHidden(storage, at: nsSource.range(of: "bold").location)) XCTAssertTrue(isHidden(storage, at: nsSource.range(of: "*italic*").location)) XCTAssertFalse(isHidden(storage, at: nsSource.range(of: "italic").location)) XCTAssertTrue(isHidden(storage, at: nsSource.range(of: "`").location)) XCTAssertNotNil(storage.attribute(.backgroundColor, at: nsSource.range(of: "code").location, effectiveRange: nil)) } func testRenderedTaskListHidesListMarkerAndShowsTaskState() { let source = "Intro\n* [x] Done\n* [ ] Todo" let storage = styledStorage(source: source, activeLineIndex: 0) let nsSource = source as NSString let checkedMarker = nsSource.range(of: "* [x]") let uncheckedMarker = nsSource.range(of: "* [ ]") let doneRange = nsSource.range(of: "Done") XCTAssertTrue(isHidden(storage, at: checkedMarker.location)) XCTAssertFalse(isHidden(storage, at: checkedMarker.location + 2)) XCTAssertNotNil(storage.attribute(.backgroundColor, at: checkedMarker.location + 2, effectiveRange: nil)) XCTAssertTrue(isHidden(storage, at: uncheckedMarker.location)) XCTAssertFalse(isHidden(storage, at: uncheckedMarker.location + 2)) XCTAssertNotNil(storage.attribute(.strikethroughStyle, at: doneRange.location, effectiveRange: nil)) } func testRenderedCodeBlockHidesFencesAndStylesCodeContent() { let source = "Intro\n```swift\nstruct Example {\n let value = 42\n}\n```" let storage = styledStorage(source: source, activeLineIndex: 0) let nsSource = source as NSString let openingFence = nsSource.range(of: "```swift") let language = nsSource.range(of: "swift") let code = nsSource.range(of: "let value = 42") let keyword = nsSource.range(of: "struct") let closingFence = nsSource.range(of: "```", options: .backwards) XCTAssertTrue(isHidden(storage, at: openingFence.location)) XCTAssertTrue(isHidden(storage, at: language.location)) XCTAssertNil(storage.attribute(.backgroundColor, at: code.location, effectiveRange: nil)) XCTAssertEqual(font(in: storage, at: code.location).fontDescriptor.symbolicTraits.contains(.monoSpace), true) XCTAssertGreaterThan(paragraphStyle(in: storage, at: code.location).headIndent, 0) XCTAssertEqual(font(in: storage, at: keyword.location).fontDescriptor.symbolicTraits.contains(.bold), true) XCTAssertTrue(isHidden(storage, at: closingFence.location)) } func testDirtyCodeBlockRenderingResolvesBlockContext() { let source = "Intro\n```swift\nlet value = 42\n```" let storage = NSTextStorage(string: source) let lineIndex = DocumentLineIndex(source: source) let codeLine = 2 MarkdownTextStyler.apply( to: storage, lineIndex: lineIndex, invalidationPlan: EditorDirtyLineInvalidationPlan( reason: .activeLineChange, isFullRender: false, dirtyLineIndexes: [codeLine] ), activeLineIndex: 0, backgroundColor: .textBackgroundColor, activeLineBackgroundColor: .controlAccentColor.withAlphaComponent(0.10), textColor: .labelColor, secondaryTextColor: .secondaryLabelColor, accentColor: .controlAccentColor ) let code = (source as NSString).range(of: "let value = 42") XCTAssertNil(storage.attribute(.backgroundColor, at: code.location, effectiveRange: nil)) XCTAssertEqual(font(in: storage, at: code.location).fontDescriptor.symbolicTraits.contains(.monoSpace), true) } func testRenderedJsonYamlAndMarkdownCodeHighlighting() { let json = styledStorage(source: "```json\n{\"name\": \"Sapling\", \"enabled\": true}\n```", activeLineIndex: -1) let yaml = styledStorage(source: "```yaml\nname: Sapling\nactive: true\n```", activeLineIndex: -1) let markdown = styledStorage(source: "```markdown\n# Heading\nSee **bold** text\n```", activeLineIndex: -1) XCTAssertEqual(font(in: json, at: ("```json\n{" as NSString).length).fontDescriptor.symbolicTraits.contains(.bold), true) XCTAssertEqual(font(in: yaml, at: ("```yaml\n" as NSString).length).fontDescriptor.symbolicTraits.contains(.bold), true) XCTAssertEqual(font(in: markdown, at: ("```markdown\n" as NSString).length).fontDescriptor.symbolicTraits.contains(.bold), true) } private func styledStorage(source: String, activeLineIndex: Int) -> NSTextStorage { let storage = NSTextStorage(string: source) let lineIndex = DocumentLineIndex(source: source) MarkdownTextStyler.apply( to: storage, lineIndex: lineIndex, invalidationPlan: EditorDirtyLineInvalidator.plan( previousText: nil, currentLineIndex: lineIndex, edit: nil, previousActiveLineIndex: nil, currentActiveLineIndex: activeLineIndex ), activeLineIndex: activeLineIndex, backgroundColor: .textBackgroundColor, activeLineBackgroundColor: .controlAccentColor.withAlphaComponent(0.10), textColor: .labelColor, secondaryTextColor: .secondaryLabelColor, accentColor: .controlAccentColor ) return storage } private func isHidden(_ storage: NSTextStorage, at location: Int) -> Bool { let color = storage.attribute(.foregroundColor, at: location, effectiveRange: nil) as? NSColor return color?.alphaComponent == 0 && font(in: storage, at: location).pointSize < 1 } private func font(in storage: NSTextStorage, at location: Int) -> NSFont { guard let font = storage.attribute(.font, at: location, effectiveRange: nil) as? NSFont else { return NSFont.systemFont(ofSize: 0) } return font } private func paragraphStyle(in storage: NSTextStorage, at location: Int) -> NSParagraphStyle { storage.attribute(.paragraphStyle, at: location, effectiveRange: nil) as? NSParagraphStyle ?? NSParagraphStyle() } } #endif