Skip to content

Commit dfc55d5

Browse files
committed
[docs] Add documentation about writing tests
1 parent 3df2d00 commit dfc55d5

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed

Documentation/Development.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# Development
2+
3+
This document contains notes about development and testing of IndexStoreDB.
4+
5+
## Table of Contents
6+
7+
* [Writing Tests](#writing-tests)
8+
* [Tibs, the "Test Index Build System"](Tibs.md)
9+
10+
## Writing Tests
11+
12+
As much as is practical, all code should be covered by tests. New tests can be added under the `Tests` directory and should use `XCTest`. The rest of this section will describe the additional tools available in the `ISDBTestSupport` module to make it easier to write good and efficient tests.
13+
14+
Most indexer tests follow a pattern:
15+
16+
1. Build and index a test project
17+
2. Perform index queries
18+
3. Compare the results against known locations in the test code
19+
4. (Optional) modify the code and repeat.
20+
21+
### Test Projects (Fixtures)
22+
23+
Index test projects should be put in the `Tests/INPUTS` directory, and use the [Tibs](Tibs.md) build system to define their sources and targets. An example test project might look like:
24+
25+
```
26+
Tests/
27+
Inputs/
28+
MyTestProj/
29+
a.swift
30+
b.swift
31+
c.cpp
32+
```
33+
34+
Where `project.json` describes the project's targets, for example
35+
36+
```
37+
{ "sources": ["a.swift", "b.swift", "c.cpp"] }
38+
```
39+
40+
Tibs supports more advanced project configurations, such as multiple swift modules with dependencies, etc. For much more information about Tibs, including what features it supports and how it works, see [Tibs.md](Tibs.md).
41+
42+
### TibsTestWorkspace
43+
44+
The `TibsTestWorkspace` pulls together the various pieces needed for working with tests, including building the project, creating an IndexStoreDB instance, and keeping it up to date after modifying sources.
45+
46+
To create a `TibsTestWorkspace`, use the `staticTibsTestWorkspace` and `mutableTibsTestWorkspace` methods. Tests that do not mutate sources should use `staticTibsTestWorkspace`.
47+
48+
```swift
49+
func testFoo() {
50+
51+
// Loads an immutable workspace for the test project "MyTestProj" and resolves
52+
// all of its targets, ready to be indexed.
53+
guard let ws = try staticTibsTestWorkspace(name: "MyTestProj") else { return }
54+
55+
// Perform the build and read the produced index data.
56+
try ws.buildAndIndex()
57+
58+
// See the results
59+
ws.index.occurrences(ofUSR: "<some usr>", ...)
60+
61+
...
62+
}
63+
```
64+
65+
#### Source Locations
66+
67+
It is common to want to refer to specific locations in the source code of a test project. This is supported using inline comment syntax.
68+
69+
```swift
70+
Test.swift:
71+
func /*myFuncDef*/myFunc() {
72+
/*myFuncCall*/myFunc()
73+
}
74+
```
75+
76+
In a test, these locations can be referenced by name. The named location is immediately after the comment.
77+
78+
```swift
79+
80+
let loc = ws.testLoc("myFuncDef")
81+
// TestLocation(url: ..., line: 1, column: 19)
82+
```
83+
84+
A common use of a `TestLocation` is to form a `SymbolOccurrence` at that location.
85+
86+
```swift
87+
let occurrence = Symbol(...).at(ws.testLoc("myFuncDef"), roles: .definition)
88+
```
89+
90+
#### Comparing SymbolOccurrences
91+
92+
Rather than attempting to compare `SymbolOccurrences` for equality, prefer using the custom XCTest assertion method `checkOccurrences`. This API avoids accidentally comparing details that are undefined (e.g. the order of occurrences), or likely to change frequently (e.g. `SymbolRole`s are checked to be a superset instead of an exact match, as we often add new roles).
93+
94+
```
95+
checkOccurrences(ws.index.occurrences(ofUSR: sym.usr, roles: .all), expected: [
96+
sym.at(ws.testLoc("c"), roles: .definition),
97+
sym.at(ws.testLoc("c_call"), roles: .call),
98+
])
99+
```
100+
101+
#### Mutating Test Sources
102+
103+
In order to test changes to the index, we create a mutable test workspace. The mutable project takes care of copying the sources to a new location. Afterwards, we can mutate the sources using the `TibsTestWorkspace.edit(rebuild: Bool, block: ...)` method.
104+
105+
```
106+
func testMutating() {
107+
guard let ws = try mutableTibsTestWorkspace(name: "MyTestProj") else { return }
108+
try ws.buildAndIndex()
109+
110+
// Check initial state...
111+
112+
// Perform modifications to "url"!
113+
ws.edit(rebuild: true) { editor, files in
114+
115+
// Read the original contents and add a new line.
116+
let new = try files.get(url).appending("func /*moreCodeDef*/moreCode() {}")
117+
118+
// Provide the new contents for "url".
119+
editor.write(new, to: url)
120+
}
121+
}
122+
```
123+
124+
After we return from `edit()`, the sources are modified and any changes to stored source locations are reflected. We can now `buildAndIndex()` to update the index, or as a convenience we can pass `rebuild: true` to `edit`.

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,7 @@ The C++ code in the index requires `libdispatch`, but unlike Swift code, it cann
2222
```sh
2323
$ swift build -Xcxx -I<path_to_swift_toolchain>/usr/lib/swift -Xcxx -I<path_to_swift_toolchain>/usr/lib/swift/Block
2424
```
25+
26+
## Development
27+
28+
For more information about developing IndexStoreDB, see [Development](Documentation/Development.md).

0 commit comments

Comments
 (0)