Skip to content

Extend snapshot testing to completion scripts #698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
182 changes: 104 additions & 78 deletions Sources/ArgumentParserTestHelpers/TestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,11 +360,68 @@ extension XCTest {
return outputActual
}

public func AssertGenerateManual(
public func AssertJSONEqualFromString<T: Codable & Equatable>(actual: String, expected: String, for type: T.Type, file: StaticString = #filePath, line: UInt = #line) throws {
if #available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) {
AssertEqualStrings(
actual: actual.trimmingCharacters(in: .whitespacesAndNewlines),
expected: expected.trimmingCharacters(in: .whitespacesAndNewlines),
file: file,
line: line)
}

let actualJSONData = try XCTUnwrap(actual.data(using: .utf8), file: file, line: line)
let actualDumpJSON = try XCTUnwrap(JSONDecoder().decode(type, from: actualJSONData), file: file, line: line)

let expectedJSONData = try XCTUnwrap(expected.data(using: .utf8), file: file, line: line)
let expectedDumpJSON = try XCTUnwrap(JSONDecoder().decode(type, from: expectedJSONData), file: file, line: line)
XCTAssertEqual(actualDumpJSON, expectedDumpJSON)
}
}


// MARK: - Snapshot testing
extension XCTest {
@discardableResult
public func assertSnapshot(
actual: String,
extension: String,
record: Bool = false,
test: StaticString = #function,
file: StaticString = #filePath,
line: UInt = #line
) throws -> String {
let snapshotDirectoryURL = URL(fileURLWithPath: "\(file)")
.deletingLastPathComponent()
.appendingPathComponent("Snapshots")
let snapshotFileURL = snapshotDirectoryURL
.appendingPathComponent("\(test).\(`extension`)")

if record || !FileManager.default.fileExists(atPath: snapshotFileURL.path) {
let recordedValue = actual + "\n"
try FileManager.default.createDirectory(
at: snapshotDirectoryURL,
withIntermediateDirectories: true,
attributes: nil)
try recordedValue.write(to: snapshotFileURL, atomically: true, encoding: .utf8)
XCTFail("Recorded new baseline", file: file, line: line)
struct EarlyExit: Error {}
throw EarlyExit()
} else {
let expected = try String(contentsOf: snapshotFileURL, encoding: .utf8)
AssertEqualStrings(
actual: actual,
expected: expected.trimmingCharacters(in: .newlines),
file: file,
line: line)
return expected
}
}

public func assertGenerateManual(
multiPage: Bool,
command: String,
expected: URL,
record: Bool = false,
test: StaticString = #function,
file: StaticString = #filePath,
line: UInt = #line
) throws {
Expand All @@ -390,24 +447,19 @@ extension XCTest {
file: file,
line: line)

if record || !FileManager.default.fileExists(atPath: expected.path) {
let recordedValue = actual + "\n"
try recordedValue.write(to: expected, atomically: true, encoding: .utf8)
XCTFail("Recorded new baseline", file: file, line: line)
} else {
let expected = try String(contentsOf: expected, encoding: .utf8)
AssertEqualStrings(
actual: actual,
expected: expected.trimmingCharacters(in: .whitespacesAndNewlines),
file: file,
line: line)
}
try self.assertSnapshot(
actual: actual,
extension: "mdoc",
record: record,
test: test,
file: file,
line: line)
}

public func AssertGenerateDoccReference(
public func assertGenerateDoccReference(
command: String,
expected: URL,
record: Bool = false,
test: StaticString = #function,
file: StaticString = #filePath,
line: UInt = #line
) throws {
Expand All @@ -424,58 +476,55 @@ extension XCTest {
command: command,
file: file,
line: line)
if record || !FileManager.default.fileExists(atPath: expected.path) {
let recordedValue = actual + "\n"
try recordedValue.write(to: expected, atomically: true, encoding: .utf8)
XCTFail("Recorded new baseline", file: file, line: line)
} else {
let expected = try String(contentsOf: expected, encoding: .utf8)
AssertEqualStrings(
actual: actual,
expected: expected.trimmingCharacters(in: .whitespacesAndNewlines),
file: file,
line: line)
}

try self.assertSnapshot(
actual: actual,
extension: "md",
record: record,
test: test,
file: file,
line: line)
}

public func AssertDump<T: ParsableArguments>(
public func assertDumpHelp<T: ParsableArguments>(
type: T.Type,
expected: URL,
record: Bool = false,
test: StaticString = #function,
file: StaticString = #filePath,
line: UInt = #line
) throws {
let cliOutput: String
let actual: String
do {
_ = try T.parse(["--experimental-dump-help"])
XCTFail(file: file, line: line)
return
} catch {
cliOutput = T.fullMessage(for: error)
actual = T.fullMessage(for: error)
}

let apiOutput = T._dumpHelp()
AssertEqualStrings(actual: cliOutput, expected: apiOutput)
AssertEqualStrings(actual: actual, expected: apiOutput)

if record || !FileManager.default.fileExists(atPath: expected.path) {
let recordedValue = apiOutput + "\n"
try recordedValue.write(to: expected, atomically: true, encoding: .utf8)
XCTFail("Recorded new baseline", file: file, line: line)
} else {
let expected = try String(contentsOf: expected, encoding: .utf8)
try AssertJSONEqualFromString(
actual: apiOutput,
expected: expected,
for: ToolInfoV0.self,
file: file,
line: line)
}
let expected = try self.assertSnapshot(
actual: actual,
extension: "json",
record: record,
test: test,
file: file,
line: line)

try AssertJSONEqualFromString(
actual: actual,
expected: expected,
for: ToolInfoV0.self,
file: file,
line: line)
}

public func AssertDump(
public func assertDumpHelp(
command: String,
expected: URL,
record: Bool = false,
test: StaticString = #function,
file: StaticString = #filePath,
line: UInt = #line
) throws {
Expand All @@ -484,35 +533,12 @@ extension XCTest {
expected: nil,
file: file,
line: line)
if record || !FileManager.default.fileExists(atPath: expected.path) {
let recordedValue = actual + "\n"
try recordedValue.write(to: expected, atomically: true, encoding: .utf8)
XCTFail("Recorded new baseline", file: file, line: line)
} else {
let expected = try String(contentsOf: expected, encoding: .utf8)
try AssertJSONEqualFromString(
actual: actual,
expected: expected,
for: ToolInfoV0.self,
file: file,
line: line)
}
}

public func AssertJSONEqualFromString<T: Codable & Equatable>(actual: String, expected: String, for type: T.Type, file: StaticString = #filePath, line: UInt = #line) throws {
if #available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *) {
AssertEqualStrings(
actual: actual.trimmingCharacters(in: .whitespacesAndNewlines),
expected: expected.trimmingCharacters(in: .whitespacesAndNewlines),
file: file,
line: line)
}

let actualJSONData = try XCTUnwrap(actual.data(using: .utf8), file: file, line: line)
let actualDumpJSON = try XCTUnwrap(JSONDecoder().decode(type, from: actualJSONData), file: file, line: line)

let expectedJSONData = try XCTUnwrap(expected.data(using: .utf8), file: file, line: line)
let expectedDumpJSON = try XCTUnwrap(JSONDecoder().decode(type, from: expectedJSONData), file: file, line: line)
XCTAssertEqual(actualDumpJSON, expectedDumpJSON)
try self.assertSnapshot(
actual: actual,
extension: "json",
record: record,
test: test,
file: file,
line: line)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,26 @@ import XCTest
import ArgumentParserTestHelpers

final class GenerateDoccReferenceTests: XCTestCase {
let snapshotsDirectory = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.appendingPathComponent("Snapshots")

func url(_ test: StaticString = #function) -> URL {
return self.snapshotsDirectory.appendingPathComponent("\(test).md")
}

#if os(macOS)
func testCountLinesDoccReference() throws {
guard #available(macOS 12, *) else { return }
try AssertGenerateDoccReference(command: "count-lines", expected: self.url())
try assertGenerateDoccReference(command: "count-lines")
}
#endif

func testColorDoccReference() throws {
try AssertGenerateDoccReference(command: "color", expected: self.url())
try assertGenerateDoccReference(command: "color")
}

func testMathDoccReference() throws {
try AssertGenerateDoccReference(command: "math", expected: self.url())
try assertGenerateDoccReference(command: "math")
}

func testRepeatDoccReference() throws {
try AssertGenerateDoccReference(command: "repeat", expected: self.url())
try assertGenerateDoccReference(command: "repeat")
}

func testRollDoccReference() throws {
try AssertGenerateDoccReference(command: "roll", expected: self.url())
try assertGenerateDoccReference(command: "roll")
}
}
28 changes: 10 additions & 18 deletions Tests/ArgumentParserGenerateManualTests/GenerateManualTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,55 +14,47 @@ import XCTest
import ArgumentParserTestHelpers

final class GenerateManualTests: XCTestCase {
let snapshotsDirectory = URL(fileURLWithPath: #filePath)
.deletingLastPathComponent()
.appendingPathComponent("Snapshots")

func url(_ test: StaticString = #function) -> URL {
return self.snapshotsDirectory.appendingPathComponent("\(test).mdoc")
}

#if os(macOS)
func testCountLinesSinglePageManual() throws {
guard #available(macOS 12, *) else { return }
try AssertGenerateManual(multiPage: false, command: "count-lines", expected: self.url())
try assertGenerateManual(multiPage: false, command: "count-lines")
}

func testCountLinesMultiPageManual() throws {
guard #available(macOS 12, *) else { return }
try AssertGenerateManual(multiPage: true, command: "count-lines", expected: self.url())
try assertGenerateManual(multiPage: true, command: "count-lines")
}
#endif

func testColorSinglePageManual() throws {
try AssertGenerateManual(multiPage: false, command: "color", expected: self.url())
try assertGenerateManual(multiPage: false, command: "color")
}

func testColorMultiPageManual() throws {
try AssertGenerateManual(multiPage: true, command: "color", expected: self.url())
try assertGenerateManual(multiPage: true, command: "color")
}

func testMathSinglePageManual() throws {
try AssertGenerateManual(multiPage: false, command: "math", expected: self.url())
try assertGenerateManual(multiPage: false, command: "math")
}

func testMathMultiPageManual() throws {
try AssertGenerateManual(multiPage: true, command: "math", expected: self.url())
try assertGenerateManual(multiPage: true, command: "math")
}

func testRepeatSinglePageManual() throws {
try AssertGenerateManual(multiPage: false, command: "repeat", expected: self.url())
try assertGenerateManual(multiPage: false, command: "repeat")
}

func testRepeatMultiPageManual() throws {
try AssertGenerateManual(multiPage: true, command: "repeat", expected: self.url())
try assertGenerateManual(multiPage: true, command: "repeat")
}

func testRollSinglePageManual() throws {
try AssertGenerateManual(multiPage: false, command: "roll", expected: self.url())
try assertGenerateManual(multiPage: false, command: "roll")
}

func testRollMultiPageManual() throws {
try AssertGenerateManual(multiPage: true, command: "roll", expected: self.url())
try assertGenerateManual(multiPage: true, command: "roll")
}
}
Loading