import XCTest @testable import LChatCore // The format-as-you-type brain (ComposerRules.swift) — semantics pinned here, // and the regex literals drift-gated against web/static/composer-pm.js (the // ComposerTypeaheadTests pattern): a web-side rule change fails this suite // until the native mirror follows. final class ComposerRulesTests: XCTestCase { private var repoRoot: URL { URL(fileURLWithPath: #filePath) .deletingLastPathComponent() // Tests/LChatCoreTests .deletingLastPathComponent() // Tests .deletingLastPathComponent() // LChatCore .deletingLastPathComponent() // ios .deletingLastPathComponent() // repo } // MARK: inline completions func testMarkCompletions() { XCTAssertEqual(inlineCompletion(lineUpToCaret: "**bold**"), InlineCompletion(replaceRange: 0..<8, content: "bold", mark: .bold)) XCTAssertEqual(inlineCompletion(lineUpToCaret: "say *it*"), InlineCompletion(replaceRange: 4..<8, content: "it", mark: .italic)) XCTAssertEqual(inlineCompletion(lineUpToCaret: "`code`"), InlineCompletion(replaceRange: 0..<6, content: "code", mark: .code)) XCTAssertEqual(inlineCompletion(lineUpToCaret: "~gone~"), InlineCompletion(replaceRange: 0..<6, content: "gone", mark: .strike)) XCTAssertEqual(inlineCompletion(lineUpToCaret: "say _it_"), InlineCompletion(replaceRange: 4..<8, content: "it", mark: .italic)) } func testUnderscoreNeverFiresIntraword() { XCTAssertNil(inlineCompletion(lineUpToCaret: "snake_case_")) XCTAssertNil(inlineCompletion(lineUpToCaret: "a_b_")) } func testStrongWinsBeforeEm() { // "**bold**" must fire strong, and the half-typed "**bold*" must not // half-fire the em rule (its lookbehind rejects the second star). XCTAssertEqual(inlineCompletion(lineUpToCaret: "**bold**")?.mark, .bold) XCTAssertNil(inlineCompletion(lineUpToCaret: "**bold*")) } func testTildeLookbehind() { XCTAssertNil(inlineCompletion(lineUpToCaret: "~~s~"), "double-tilde opener never pairs with a single closer") } func testNoFireOnWhitespaceEdges() { XCTAssertNil(inlineCompletion(lineUpToCaret: "** x**")) XCTAssertNil(inlineCompletion(lineUpToCaret: "*x *")) } func testUnicodeContentAndOffsets() { // replaceRange is UTF-16: ✨ is BMP (1 unit), 😀 is a surrogate pair (2). XCTAssertEqual(inlineCompletion(lineUpToCaret: "✨ **bí**"), InlineCompletion(replaceRange: 2..<8, content: "bí", mark: .bold)) XCTAssertEqual(inlineCompletion(lineUpToCaret: "😀 **x**"), InlineCompletion(replaceRange: 3..<8, content: "x", mark: .bold)) } // MARK: drift gate against the web rules func testRegexLiteralsMatchComposerPmJs() throws { let js = try String(contentsOf: repoRoot.appendingPathComponent("web/static/composer-pm.js"), encoding: .utf8) // The exact JS regex literals the Swift patterns transliterate. If a // rule changes on the web, its literal disappears and this fails. let literals = [ #"/\*\*([^*\s](?:[^*]*[^*\s])?)\*\*$/"#, #"/(?