Skip to content

Commit 957b859

Browse files
committed
Add VisibleRangeProviderTests
1 parent f01eeb0 commit 957b859

File tree

9 files changed

+191
-21
lines changed

9 files changed

+191
-21
lines changed

Package.resolved

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Sources/CodeEditSourceEditor/Highlighting/StyledRangeContainer/StyledRangeStore/StyledRangeStore+StyledRun.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@ extension StyledRangeStore {
1212
let capture: CaptureName?
1313
let modifiers: CaptureModifierSet
1414

15-
init(length: Int, capture: CaptureName?, modifiers: CaptureModifierSet) {
16-
self.length = length
17-
self.capture = capture
18-
self.modifiers = modifiers
19-
}
20-
2115
static func empty(length: Int) -> Self {
2216
StyledRun(length: length, capture: nil, modifiers: [])
2317
}
@@ -65,10 +59,6 @@ extension StyledRangeStore.StyledRun: RopeElement {
6559
extension StyledRangeStore.StyledRun {
6660
struct Summary {
6761
var length: Int
68-
69-
init(length: Int) {
70-
self.length = length
71-
}
7262
}
7363
}
7464

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import XCTest
2+
import CodeEditTextView
3+
import CodeEditLanguages
4+
@testable import CodeEditSourceEditor
5+
6+
/// Because the provider state is mostly just passing messages between providers and the highlight state, what we need
7+
/// to test is that invalidated ranges are sent to the delegate
8+
9+
class MockVisibleRangeProvider: VisibleRangeProvider {
10+
func setVisibleSet(_ newSet: IndexSet) {
11+
visibleSet = newSet
12+
delegate?.visibleSetDidUpdate(visibleSet)
13+
}
14+
}
15+
16+
class EmptyHighlightProviderStateDelegate: HighlightProviderStateDelegate {
17+
func applyHighlightResult(
18+
provider: ProviderID,
19+
highlights: [HighlightRange],
20+
rangeToHighlight: NSRange
21+
) { }
22+
}
23+
24+
@MainActor
25+
final class HighlightProviderStateTest: XCTestCase {
26+
func test_setup() {
27+
let textView = Mock.textView()
28+
let rangeProvider = MockVisibleRangeProvider(textView: textView)
29+
let delegate = EmptyHighlightProviderStateDelegate()
30+
31+
let setUpExpectation = XCTestExpectation(description: "Set up called.")
32+
33+
let mockProvider = Mock.highlightProvider(
34+
onSetUp: { _ in
35+
setUpExpectation.fulfill()
36+
},
37+
onApplyEdit: { _, _, _ in .success(IndexSet()) },
38+
onQueryHighlightsFor: { _, _ in .success([]) }
39+
)
40+
41+
_ = HighlightProviderState(
42+
id: 0,
43+
delegate: delegate,
44+
highlightProvider: mockProvider,
45+
textView: textView,
46+
visibleRangeProvider: rangeProvider,
47+
language: .swift
48+
)
49+
50+
wait(for: [setUpExpectation], timeout: 1.0)
51+
}
52+
53+
func test_setLanguage() {
54+
let textView = Mock.textView()
55+
let rangeProvider = MockVisibleRangeProvider(textView: textView)
56+
let delegate = EmptyHighlightProviderStateDelegate()
57+
58+
let firstSetUpExpectation = XCTestExpectation(description: "Set up called.")
59+
let secondSetUpExpectation = XCTestExpectation(description: "Set up called.")
60+
61+
let mockProvider = Mock.highlightProvider(
62+
onSetUp: { language in
63+
switch language {
64+
case .c:
65+
firstSetUpExpectation.fulfill()
66+
case .swift:
67+
secondSetUpExpectation.fulfill()
68+
default:
69+
XCTFail("Unexpected language: \(language)")
70+
}
71+
},
72+
onApplyEdit: { _, _, _ in .success(IndexSet()) },
73+
onQueryHighlightsFor: { _, _ in .success([]) }
74+
)
75+
76+
let state = HighlightProviderState(
77+
id: 0,
78+
delegate: delegate,
79+
highlightProvider: mockProvider,
80+
textView: textView,
81+
visibleRangeProvider: rangeProvider,
82+
language: .c
83+
)
84+
85+
wait(for: [firstSetUpExpectation], timeout: 1.0)
86+
87+
state.setLanguage(language: .swift)
88+
89+
wait(for: [secondSetUpExpectation], timeout: 1.0)
90+
}
91+
92+
func test_storageUpdatedRangesPassedOn() {
93+
let textView = Mock.textView()
94+
let rangeProvider = MockVisibleRangeProvider(textView: textView)
95+
let delegate = EmptyHighlightProviderStateDelegate()
96+
97+
var updatedRanges: [(NSRange, Int)] = []
98+
99+
let mockProvider = Mock.highlightProvider(
100+
onSetUp: { _ in },
101+
onApplyEdit: { _, range, delta in
102+
updatedRanges.append((range, delta))
103+
return .success(IndexSet())
104+
},
105+
onQueryHighlightsFor: { _, _ in .success([]) }
106+
)
107+
108+
let state = HighlightProviderState(
109+
id: 0,
110+
delegate: delegate,
111+
highlightProvider: mockProvider,
112+
textView: textView,
113+
visibleRangeProvider: rangeProvider,
114+
language: .swift
115+
)
116+
117+
let mockEdits: [(NSRange, Int)] = [
118+
(NSRange(location: 0, length: 10), 10), // Inserted 10
119+
(NSRange(location: 5, length: 0), -2), // Deleted 2 at 5
120+
(NSRange(location: 0, length: 2), 3), // Replaced 0-2 with 3
121+
(NSRange(location: 9, length: 1), 1),
122+
(NSRange(location: 0, length: 0), -10)
123+
]
124+
125+
for edit in mockEdits {
126+
state.storageDidUpdate(range: edit.0, delta: edit.1)
127+
}
128+
129+
for (range, expected) in zip(updatedRanges, mockEdits) {
130+
XCTAssertEqual(range.0, expected.0)
131+
XCTAssertEqual(range.1, expected.1)
132+
}
133+
}
134+
}

Tests/CodeEditSourceEditorTests/Highlighting/StyledRangeContainerTests.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import XCTest
22
@testable import CodeEditSourceEditor
33

4+
@MainActor
45
final class StyledRangeContainerTests: XCTestCase {
56
typealias Run = HighlightedRun
67

@@ -114,7 +115,5 @@ final class StyledRangeContainerTests: XCTestCase {
114115
XCTAssertEqual(runs[8], Run(length: 5, capture: .string, modifiers: [.static, .modification]))
115116
XCTAssertEqual(runs[9], Run(length: 5, capture: .string, modifiers: [.modification]))
116117
XCTAssertEqual(runs[10], Run(length: 90, capture: nil, modifiers: []))
117-
118118
}
119-
120119
}

Tests/CodeEditSourceEditorTests/Highlighting/StyledRangeStoreTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extension StyledRangeStore {
66
var count: Int { _guts.count }
77
}
88

9+
@MainActor
910
final class StyledRangeStoreTests: XCTestCase {
1011
override var continueAfterFailure: Bool {
1112
get { false }

Tests/CodeEditSourceEditorTests/Highlighting/VisibleRangeProviderTests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import XCTest
22
@testable import CodeEditSourceEditor
33

4+
@MainActor
45
final class VisibleRangeProviderTests: XCTestCase {
56
func test_updateOnScroll() {
67
let (scrollView, textView) = Mock.scrollingTextView()

Tests/CodeEditSourceEditorTests/Mock.swift

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,43 @@ import CodeEditTextView
44
import CodeEditLanguages
55
@testable import CodeEditSourceEditor
66

7+
class MockHighlightProvider: HighlightProviding {
8+
var onSetUp: (CodeLanguage) -> Void
9+
var onApplyEdit: (_ textView: TextView, _ range: NSRange, _ delta: Int) -> Result<IndexSet, any Error>
10+
var onQueryHighlightsFor: (_ textView: TextView, _ range: NSRange) -> Result<[HighlightRange], any Error>
11+
12+
init(
13+
onSetUp: @escaping (CodeLanguage) -> Void,
14+
onApplyEdit: @escaping (_: TextView, _: NSRange, _: Int) -> Result<IndexSet, any Error>,
15+
onQueryHighlightsFor: @escaping (_: TextView, _: NSRange) -> Result<[HighlightRange], any Error>
16+
) {
17+
self.onSetUp = onSetUp
18+
self.onApplyEdit = onApplyEdit
19+
self.onQueryHighlightsFor = onQueryHighlightsFor
20+
}
21+
22+
func setUp(textView: TextView, codeLanguage: CodeLanguage) {
23+
self.onSetUp(codeLanguage)
24+
}
25+
26+
func applyEdit(
27+
textView: TextView,
28+
range: NSRange,
29+
delta: Int,
30+
completion: @escaping @MainActor (Result<IndexSet, any Error>) -> Void
31+
) {
32+
completion(self.onApplyEdit(textView, range, delta))
33+
}
34+
35+
func queryHighlightsFor(
36+
textView: TextView,
37+
range: NSRange,
38+
completion: @escaping @MainActor (Result<[HighlightRange], any Error>) -> Void
39+
) {
40+
completion(self.onQueryHighlightsFor(textView, range))
41+
}
42+
}
43+
744
enum Mock {
845
class Delegate: TextViewDelegate { }
946

@@ -20,7 +57,7 @@ enum Mock {
2057
cursorPositions: [],
2158
editorOverscroll: 0.5,
2259
useThemeBackground: true,
23-
highlightProvider: nil,
60+
highlightProviders: [TreeSitterClient()],
2461
contentInsets: NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0),
2562
isEditable: true,
2663
isSelectable: true,
@@ -96,4 +133,12 @@ enum Mock {
96133
language: language
97134
)
98135
}
136+
137+
static func highlightProvider(
138+
onSetUp: @escaping (CodeLanguage) -> Void,
139+
onApplyEdit: @escaping (TextView, NSRange, Int) -> Result<IndexSet, any Error>,
140+
onQueryHighlightsFor: @escaping (TextView, NSRange) -> Result<[HighlightRange], any Error>
141+
) -> MockHighlightProvider {
142+
MockHighlightProvider(onSetUp: onSetUp, onApplyEdit: onApplyEdit, onQueryHighlightsFor: onQueryHighlightsFor)
143+
}
99144
}

Tests/CodeEditSourceEditorTests/TagEditingTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ final class TagEditingTests: XCTestCase {
1616
controller = Mock.textViewController(theme: theme)
1717
let tsClient = Mock.treeSitterClient(forceSync: true)
1818
controller.treeSitterClient = tsClient
19-
controller.highlightProvider = tsClient
19+
controller.highlightProviders = [tsClient]
2020
window = NSWindow()
2121
window.contentViewController = controller
2222
controller.loadView()

Tests/CodeEditSourceEditorTests/TextViewControllerTests.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ final class TextViewControllerTests: XCTestCase {
4242
cursorPositions: [],
4343
editorOverscroll: 0.5,
4444
useThemeBackground: true,
45-
highlightProvider: nil,
45+
highlightProviders: [],
4646
contentInsets: NSEdgeInsets(top: 0, left: 0, bottom: 0, right: 0),
4747
isEditable: true,
4848
isSelectable: true,
@@ -59,24 +59,24 @@ final class TextViewControllerTests: XCTestCase {
5959
func test_captureNames() throws {
6060
// test for "keyword"
6161
let captureName1 = "keyword"
62-
let color1 = controller.attributesFor(CaptureName(rawValue: captureName1))[.foregroundColor] as? NSColor
62+
let color1 = controller.attributesFor(CaptureName.fromString(captureName1))[.foregroundColor] as? NSColor
6363
XCTAssertEqual(color1, NSColor.systemPink)
6464

6565
// test for "comment"
6666
let captureName2 = "comment"
67-
let color2 = controller.attributesFor(CaptureName(rawValue: captureName2))[.foregroundColor] as? NSColor
67+
let color2 = controller.attributesFor(CaptureName.fromString(captureName2))[.foregroundColor] as? NSColor
6868
XCTAssertEqual(color2, NSColor.systemGreen)
6969

7070
/* ... additional tests here ... */
7171

7272
// test for empty case
7373
let captureName3 = ""
74-
let color3 = controller.attributesFor(CaptureName(rawValue: captureName3))[.foregroundColor] as? NSColor
74+
let color3 = controller.attributesFor(CaptureName.fromString(captureName3))[.foregroundColor] as? NSColor
7575
XCTAssertEqual(color3, NSColor.textColor)
7676

7777
// test for random case
7878
let captureName4 = "abc123"
79-
let color4 = controller.attributesFor(CaptureName(rawValue: captureName4))[.foregroundColor] as? NSColor
79+
let color4 = controller.attributesFor(CaptureName.fromString(captureName4))[.foregroundColor] as? NSColor
8080
XCTAssertEqual(color4, NSColor.textColor)
8181
}
8282

0 commit comments

Comments
 (0)