oficina / docs Public

Clone
git clone https://amadan.net/oficina/docs

Plain git — no account needed to clone.

Download

Download this file

1import Foundation
2import RastrilloApple
3import XCTest
4@testable import DocsKit
5
6final class DocumentToolbarSelectionTests: XCTestCase {
7 @MainActor func testTypingKeepsPresentationAvailableWhileCommandsWaitForProjection() async throws {
8 let model = DocsModel(client: NativeHTTP(origin: URL(string: "https://example.invalid")!))
9 model.detail = DocumentDetail(sqid: "fixture", title: "Fixture", guid: "fixture", can_write: true, can_share: false)
10 model.projection = CRDTProjection(children: [], canUndo: true, canRedo: false)
11 let content = NSMutableAttributedString(string: "bold\n")
12 content.addAttribute(.docsMarks, value: try JSONEncoder().encode(["strong": JSONValue.object([:])]), range: NSRange(location: 0, length: 4))
13 model.selection = NSRange(location: 4, length: 0)
14 let commands = DocumentCommands(model: model, content: content)
15 let settled = try XCTUnwrap(DocumentToolbarSelection(commands: commands))
16 XCTAssertEqual(settled.marks, ["strong"])
17 XCTAssertTrue(settled.canUndo)
18
19 // Native input advances the caret before the replica publishes its text.
20 XCTAssertTrue(model.enqueue(["op": .string("display_edit"), "at": .number(4), "length": .number(0), "text": .string("!!")]))
21 model.selection = NSRange(location: 6, length: 0)
22 XCTAssertTrue(model.hasPendingInput)
23 XCTAssertTrue(commands.isAvailable, "Transient input must not dim the whole toolbar")
24 XCTAssertFalse(commands.isEnabled)
25 XCTAssertNil(DocumentToolbarSelection(commands: commands), "Do not replace the bold highlight using stale text")
26 XCTAssertFalse(commands.format("em"), "Formatting must still reject an unacknowledged selection")
27 XCTAssertNil(model.typingMarks)
28 await model.discardAll()
29
30 // A new projection still needs the native view's acknowledgement.
31 model.detail = DocumentDetail(sqid: "fixture", title: "Fixture", guid: "fixture", can_write: true, can_share: false)
32 model.projection = CRDTProjection(children: [], canUndo: true, canRedo: false)
33 model.projectionGeneration = 2
34 model.selection = NSRange(location: 4, length: 0)
35 XCTAssertTrue(commands.isAvailable)
36 XCTAssertNil(DocumentToolbarSelection(commands: commands))
37 model.didRender(2)
38 XCTAssertEqual(DocumentToolbarSelection(commands: commands), settled)
39 model.selection = NSRange(location: 0, length: 2)
40 XCTAssertTrue(try XCTUnwrap(DocumentToolbarSelection(commands: commands)).hasSelection)
41 }
42
43 @MainActor func testToolbarLabelsFollowHeadingFontSizeAndAlignment() throws {
44 let model = DocsModel(client: NativeHTTP(origin: URL(string: "https://example.invalid")!))
45 model.detail = DocumentDetail(sqid: "fixture", title: "Fixture", guid: "fixture", can_write: true, can_share: false)
46 model.projection = CRDTProjection(children: [CRDTNode(id: "heading", type: "heading", attrs: ["level": "2", "align": "center"], children: [CRDTNode(id: "text", type: "text", runs: [CRDTRun(insert: "Title", marks: ["font_serif": .object([:]), "size_24": .object([:])])])])], canUndo: false, canRedo: false)
47 model.selection = NSRange(location: 1, length: 0)
48 let state = try XCTUnwrap(DocumentToolbarSelection(commands: DocumentCommands(model: model, content: NativeTextProjection.render(model.projection!))))
49 XCTAssertEqual(state.style, "heading2")
50 XCTAssertEqual(state.font, "serif")
51 XCTAssertEqual(state.size, 24)
52 XCTAssertEqual(state.alignment, "center")
53 for level in 4...6 {
54 model.projection?.children[0].attrs?["level"] = String(level)
55 let imported = try XCTUnwrap(DocumentToolbarSelection(commands: DocumentCommands(model: model, content: NativeTextProjection.render(model.projection!))))
56 XCTAssertEqual(imported.styleLabel, String(format: docsMacString("Heading %d"), level))
57 }
58 for (mark, expected) in [("size_sm", 10), ("size_lg", 14), ("size_xl", 18)] {
59 model.typingMarks = [mark: .object([:])]
60 let legacy = try XCTUnwrap(DocumentToolbarSelection(commands: DocumentCommands(model: model, content: NativeTextProjection.render(model.projection!))))
61 XCTAssertEqual(legacy.size, expected)
62 }
63 }
64
65 @MainActor func testReadOnlyAndPausedInputRemainDisabled() {
66 let model = DocsModel(client: NativeHTTP(origin: URL(string: "https://example.invalid")!))
67 let commands = DocumentCommands(model: model, content: NSAttributedString(string: ""))
68 model.detail = DocumentDetail(sqid: "fixture", title: "Fixture", guid: "fixture", can_write: false, can_share: false)
69 XCTAssertFalse(commands.isAvailable)
70 XCTAssertFalse(commands.format("strong"))
71 model.detail = DocumentDetail(sqid: "fixture", title: "Fixture", guid: "fixture", can_write: true, can_share: false)
72 model.inputPaused = true
73 XCTAssertFalse(commands.isAvailable)
74 XCTAssertFalse(commands.format("strong"))
75 model.inputPaused = false
76 model.composing = true
77 XCTAssertTrue(commands.isAvailable)
78 XCTAssertFalse(commands.isEnabled)
79 XCTAssertNil(DocumentToolbarSelection(commands: commands))
80 XCTAssertFalse(commands.format("strong"))
81 }
82}
83