Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 006dddc

Browse files
MaxDesiatovmattt
andauthored
Test that all.css contains a valid CSS selector (#199)
Verifies that generated `all.css` contains the `:root` string on CI. It doesn't do any actual CSS parsing to verify its full validity, only does a simple `grep` check, but I hope this will be enough to prevent issues like #198 in the future. * Test that `all.css` contains a valid CSS selector * Update `CHANGELOG.md` * Install graphviz to avoid warnings on macOS * Add EndToEndTests subclassing XCTest * Apply suggestions from code review Co-authored-by: Mattt <[email protected]> * Remove stray comment leftover from review * Set macOS 10.13 as minimum platform target * Refactor EndToEndTests Create helper methods on Process and Bundle * Test whether generated HTML output contains subdirectories * Add test for CommonMark output * Add tests for coverage subcommand * Add tests for diagram subcommand * Update Changelog entry for #199 * Work around unavailability of hasDirectoryPath * Update Changelog.md Co-authored-by: Max Desiatov <[email protected]> * Update Changelog entry for #199 Co-authored-by: Mattt <[email protected]>
2 parents 5a68c76 + 0774eae commit 006dddc

10 files changed

+233
-2
lines changed

.github/workflows/ci.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ jobs:
2525
key: ${{ runner.os }}-spm-xcode-${{ matrix.xcode }}-${{ hashFiles('**/Package.resolved') }}
2626
restore-keys: |
2727
${{ runner.os }}-spm-xcode-${{ matrix.xcode }}-
28+
- name: Install System Dependencies
29+
run: |
30+
brew install graphviz
2831
- name: Build and Test
29-
run: swift test -c release
32+
run: |
33+
swift test -c release
3034
env:
3135
DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer
3236

@@ -52,6 +56,6 @@ jobs:
5256
- name: Install System Dependencies
5357
run: |
5458
apt-get update
55-
apt-get install -y libxml2-dev
59+
apt-get install -y libxml2-dev graphviz
5660
- name: Build and Test
5761
run: swift test -c release --enable-test-discovery

Changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Added end-to-end tests for command-line interface.
13+
#199 by @MaxDesiatov and @mattt.
14+
1015
## [1.0.0-beta.5] - 2020-09-29
1116

1217
### Added

Package.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import PackageDescription
55

66
let package = Package(
77
name: "swift-doc",
8+
platforms: [
9+
.macOS(.v10_13)
10+
],
811
products: [
912
.executable(name: "swift-doc", targets: ["swift-doc"]),
1013
.library(name: "SwiftDoc", targets: ["SwiftDoc"])
@@ -63,5 +66,11 @@ let package = Package(
6366
.product(name: "SwiftMarkup", package: "SwiftMarkup")
6467
]
6568
),
69+
.testTarget(
70+
name: "EndToEndTests",
71+
dependencies: [
72+
.target(name: "swift-doc"),
73+
]
74+
),
6675
]
6776
)

[email protected]

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,11 @@ let package = Package(
4141
name: "SwiftDocTests",
4242
dependencies: ["SwiftDoc", "SwiftSyntax", "SwiftSemantics", "SwiftMarkup"]
4343
),
44+
.testTarget(
45+
name: "EndToEndTests",
46+
dependencies: [
47+
.target(name: "swift-doc"),
48+
]
49+
),
4450
]
4551
)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import XCTest
2+
3+
final class CoverageSubcommandTests: XCTestCase {
4+
func testStandardOutput() throws {
5+
let command = Bundle.productsDirectory.appendingPathComponent("swift-doc")
6+
7+
let outputDirectory = try temporaryDirectory()
8+
defer { try? FileManager.default.removeItem(at: outputDirectory) }
9+
10+
try Process.run(command: command,
11+
arguments: [
12+
"coverage",
13+
"Sources"
14+
]
15+
) { result in
16+
XCTAssertEqual(result.terminationStatus, EXIT_SUCCESS)
17+
XCTAssertEqual(result.output?.starts(with: "Total"), true)
18+
XCTAssertEqual(result.error, "")
19+
}
20+
}
21+
22+
func testFileOutput() throws {
23+
let command = Bundle.productsDirectory.appendingPathComponent("swift-doc")
24+
25+
let outputDirectory = try temporaryDirectory()
26+
let outputFile = outputDirectory.appendingPathComponent("report.json")
27+
defer { try? FileManager.default.removeItem(at: outputDirectory) }
28+
29+
try Process.run(command: command,
30+
arguments: [
31+
"coverage",
32+
"--output", outputFile.path,
33+
"Sources"
34+
]
35+
) { result in
36+
XCTAssertEqual(result.terminationStatus, EXIT_SUCCESS)
37+
XCTAssertEqual(result.output, "")
38+
XCTAssertEqual(result.error, "")
39+
40+
do {
41+
let data = try Data(contentsOf: outputFile)
42+
let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
43+
XCTAssertEqual(json?["type"] as? String, "org.dcov.report.json.export")
44+
}
45+
}
46+
}
47+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import XCTest
2+
3+
final class DiagramSubcommandTests: XCTestCase {
4+
func testStandardOutput() throws {
5+
let command = Bundle.productsDirectory.appendingPathComponent("swift-doc")
6+
7+
let outputDirectory = try temporaryDirectory()
8+
defer { try? FileManager.default.removeItem(at: outputDirectory) }
9+
10+
try Process.run(command: command,
11+
arguments: [
12+
"diagram",
13+
"Sources"
14+
]
15+
) { result in
16+
XCTAssertEqual(result.terminationStatus, EXIT_SUCCESS)
17+
XCTAssertEqual(result.output?.starts(with: "digraph {"), true)
18+
XCTAssertEqual(result.error, "")
19+
}
20+
}
21+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import XCTest
2+
3+
final class GenerateSubcommandTests: XCTestCase {
4+
func testCommonMark() throws {
5+
let command = Bundle.productsDirectory.appendingPathComponent("swift-doc")
6+
7+
let outputDirectory = try temporaryDirectory()
8+
defer { try? FileManager.default.removeItem(at: outputDirectory) }
9+
10+
try Process.run(command: command,
11+
arguments: [
12+
"generate",
13+
"--module-name", "SwiftDoc",
14+
"--format", "commonmark",
15+
"--output", outputDirectory.path,
16+
"Sources"
17+
]
18+
) { result in
19+
XCTAssertEqual(result.terminationStatus, EXIT_SUCCESS)
20+
XCTAssertEqual(result.output, "")
21+
XCTAssertEqual(result.error, "")
22+
23+
do {
24+
let commonmark = try String(contentsOf: outputDirectory.appendingPathComponent("Home.md"))
25+
XCTAssertTrue(commonmark.contains("# Types"))
26+
}
27+
28+
do {
29+
let commonmark = try String(contentsOf: outputDirectory.appendingPathComponent("_Sidebar.md"))
30+
XCTAssertTrue(commonmark.contains("<summary>Types</summary>"))
31+
}
32+
33+
do {
34+
let commonmark = try String(contentsOf: outputDirectory.appendingPathComponent("_Footer.md"))
35+
XCTAssertTrue(commonmark.contains("[swift-doc](https://github.com/SwiftDocOrg/swift-doc)"))
36+
}
37+
38+
do {
39+
let contents = try FileManager.default.contentsOfDirectory(at: outputDirectory, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])
40+
let subdirectories = try contents.filter { try $0.resourceValues(forKeys: [.isDirectoryKey]).isDirectory == true }
41+
XCTAssertEqual(subdirectories.count, 0, "output should not contain any subdirectories")
42+
}
43+
}
44+
}
45+
46+
func testHTML() throws {
47+
let command = Bundle.productsDirectory.appendingPathComponent("swift-doc")
48+
let outputDirectory = try temporaryDirectory()
49+
50+
defer { try? FileManager.default.removeItem(at: outputDirectory) }
51+
try Process.run(command: command,
52+
arguments: [
53+
"generate",
54+
"--module-name", "SwiftDoc",
55+
"--format", "html",
56+
"--output", outputDirectory.path,
57+
"Sources"
58+
]
59+
) { result in
60+
XCTAssertEqual(result.terminationStatus, EXIT_SUCCESS)
61+
XCTAssertEqual(result.output, "")
62+
XCTAssertEqual(result.error, "")
63+
64+
do {
65+
let html = try String(contentsOf: outputDirectory.appendingPathComponent("index.html"))
66+
XCTAssertTrue(html.contains("<!DOCTYPE html>"))
67+
}
68+
69+
do {
70+
let css = try String(contentsOf: outputDirectory.appendingPathComponent("all.css"))
71+
XCTAssertTrue(css.contains(":root"))
72+
}
73+
74+
do {
75+
let contents = try FileManager.default.contentsOfDirectory(at: outputDirectory, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles])
76+
let subdirectories = try contents.filter { try $0.resourceValues(forKeys: [.isDirectoryKey]).isDirectory == true }
77+
.filter { FileManager.default.fileExists(atPath: $0.appendingPathComponent("index.html").path) }
78+
XCTAssertGreaterThanOrEqual(subdirectories.count, 1, "output should contain one or more subdirectories containing index.html")
79+
}
80+
}
81+
}
82+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import Foundation
2+
3+
extension Bundle {
4+
static var productsDirectory: URL = {
5+
#if os(macOS)
6+
for bundle in Bundle.allBundles where bundle.bundlePath.hasSuffix(".xctest") {
7+
return bundle.bundleURL.deletingLastPathComponent()
8+
}
9+
fatalError("couldn't find the products directory")
10+
#else
11+
return Bundle.main.bundleURL
12+
#endif
13+
}()
14+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import Foundation
2+
3+
extension Process {
4+
typealias Result = (terminationStatus: Int32, output: String?, error: String?)
5+
6+
static func run(command executableURL: URL, arguments: [String] = [], completion: (Result) throws -> Void) throws {
7+
let process = Process()
8+
if #available(OSX 10.13, *) {
9+
process.executableURL = executableURL
10+
} else {
11+
process.launchPath = executableURL.path
12+
}
13+
process.arguments = arguments
14+
15+
let standardOutput = Pipe()
16+
process.standardOutput = standardOutput
17+
18+
let standardError = Pipe()
19+
process.standardError = standardError
20+
21+
if #available(OSX 10.13, *) {
22+
try process.run()
23+
} else {
24+
process.launch()
25+
}
26+
process.waitUntilExit()
27+
28+
let output = String(data: standardOutput.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
29+
let error = String(data: standardError.fileHandleForReading.readDataToEndOfFile(), encoding: .utf8)
30+
31+
try completion((numericCast(process.terminationStatus), output, error))
32+
}
33+
34+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Foundation
2+
3+
func temporaryDirectory() throws -> URL {
4+
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString)
5+
try FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true)
6+
7+
return temporaryDirectoryURL
8+
}
9+

0 commit comments

Comments
 (0)