Skip to content

Commit

Permalink
Fully test & fix implementation of custom scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
Jeehut committed Sep 7, 2021
1 parent 8b4416d commit 791b963
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 25 deletions.
50 changes: 35 additions & 15 deletions Sources/Checkers/Lint.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,26 +131,46 @@ public enum Lint {

/// Run custom scripts as checks.
///
/// - Returns: If the command produces an output in the ``LintResults`` JSON format, will forward them. If the output iis an array of ``Violation`` instances, they will be wrapped in a ``LintResults`` object. Else, it will report exactly one violation if the command has a non-zero exit code with the last line(s) of output.
/// - Returns: If the command produces an output in the ``LintResults`` JSON format, will forward them.
/// If the output iis an array of ``Violation`` instances, they will be wrapped in a ``LintResults`` object.
/// Else, it will report exactly one violation if the command has a non-zero exit code with the last line(s) of output.
public static func runCustomScript(check: Check, command: String) throws -> LintResults {
let tempScriptFileUrl = URL(fileURLWithPath: "_\(check.id).tempscript")
try command.write(to: tempScriptFileUrl, atomically: true, encoding: .utf8)

let output = try shellOut(to: "/bin/bash", arguments: [tempScriptFileUrl.path])
if let jsonString = output.lintResultsJsonString,
let jsonData = jsonString.data(using: .utf8),
let lintResults: LintResults = try? JSONDecoder.iso.decode(LintResults.self, from: jsonData)
{
return lintResults
}
else if let jsonString = output.violationsArrayJsonString,
let jsonData = jsonString.data(using: .utf8),
let violations: [Violation] = try? JSONDecoder.iso.decode([Violation].self, from: jsonData)
{
return [check.severity: [check: violations]]
do {
let output = try shellOut(to: "/bin/bash", arguments: [tempScriptFileUrl.path])
try FileManager.default.removeItem(at: tempScriptFileUrl)

if let jsonString = output.lintResultsJsonString,
let jsonData = jsonString.data(using: .utf8),
let lintResults: LintResults = try? JSONDecoder.iso.decode(LintResults.self, from: jsonData)
{
return lintResults
}
else if let jsonString = output.violationsArrayJsonString,
let jsonData = jsonString.data(using: .utf8),
let violations: [Violation] = try? JSONDecoder.iso.decode([Violation].self, from: jsonData)
{
return [check.severity: [check: violations]]
}
else {
// if the command fails, a ShellOutError will be thrown – here, none is thrown, so no violations
return [check.severity: [check: []]]
}
}
else {
return [check.severity: [check: [Violation()]]]
catch {
if let shellOutError = error as? ShellOutError, shellOutError.terminationStatus != 0 {
return [
check.severity: [
check: [
Violation(message: shellOutError.output.components(separatedBy: .newlines).last)
]
]
]
}

throw error
}
}

Expand Down
7 changes: 6 additions & 1 deletion Sources/Core/Violation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,22 @@ public struct Violation: Codable, Equatable {
/// The autocorrection applied to fix this violation.
public let appliedAutoCorrection: AutoCorrection?

/// A custom violation message.
public let message: String?

/// Initializes a violation object.
public init(
discoverDate: Date = Date(),
matchedString: String? = nil,
location: Location? = nil,
appliedAutoCorrection: AutoCorrection? = nil
appliedAutoCorrection: AutoCorrection? = nil,
message: String? = nil
) {
self.discoverDate = discoverDate
self.matchedString = matchedString
self.location = location
self.appliedAutoCorrection = appliedAutoCorrection
self.message = message
}
}

Expand Down
78 changes: 69 additions & 9 deletions Tests/CheckersTests/LintTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,17 +122,18 @@ final class LintTests: XCTestCase {
func testRunCustomScript() throws {
var lintResults: LintResults = try Lint.runCustomScript(
check: .init(id: "1", hint: "hint #1"),
command: """
command: #"""
if which echo > /dev/null; then
echo 'Executed custom checks with following result:
{
"warning": {
"A@warning: hint for A": [
{},
{ "matchedString": "A" },
{ "discoverDate": "2001-01-01T00:00:00Z" },
{ "discoverDate" : "2001-01-01T01:00:00Z", "matchedString": "A" },
{
"discoverDate" : "2001-01-01T02:00:00Z",
"matchedString": "AAA",
"location": { "filePath": "/some/path", "row": 5 },
"location": { "filePath": "\/some\/path", "row": 5 },
"appliedAutoCorrection": { "before": "AAA", "after": "A" }
}
]
Expand All @@ -145,17 +146,76 @@ final class LintTests: XCTestCase {
Total: 0 errors, 3 warnings, 0 info.'
fi
"""
"""#
)

XCTAssertNoDifference(lintResults.allExecutedChecks.map(\.id), ["A", "B"])
XCTAssertEqual(lintResults.allFoundViolations.count, 3)
XCTAssertNoDifference(lintResults.allFoundViolations.map(\.matchedString), ["A", "AAA"])
XCTAssertEqual(lintResults.allFoundViolations.dropFirst().first?.location?.filePath, "/some/path")
XCTAssertEqual(lintResults.allFoundViolations.dropFirst().first?.location?.row, 5)
XCTAssertEqual(lintResults.allFoundViolations.dropFirst().first?.appliedAutoCorrection?.after, "A")
XCTAssertNoDifference(lintResults.allFoundViolations.map(\.matchedString), [nil, "A", "AAA"])
XCTAssertEqual(lintResults.allFoundViolations[2].location?.filePath, "/some/path")
XCTAssertEqual(lintResults.allFoundViolations[2].location?.row, 5)
XCTAssertEqual(lintResults.allFoundViolations[2].appliedAutoCorrection?.after, "A")
XCTAssertNil(lintResults.checkViolationsBySeverity[.error]?.keys.first)
XCTAssertEqual(lintResults.checkViolationsBySeverity[.info]?.keys.first?.id, "B")

lintResults = try Lint.runCustomScript(
check: .init(id: "1", hint: "hint #1", severity: .info),
command: #"""
if which echo > /dev/null; then
echo 'Executed custom check with following violations:
[
{ "discoverDate": "2001-01-01T00:00:00Z" },
{ "discoverDate" : "2001-01-01T01:00:00Z", "matchedString": "A" },
{
"discoverDate" : "2001-01-01T02:00:00Z",
"matchedString": "AAA",
"location": { "filePath": "\/some\/path", "row": 5 },
"appliedAutoCorrection": { "before": "AAA", "after": "A" }
}
]
Total: 0 errors, 3 warnings, 0 info.'
fi
"""#
)

XCTAssertNoDifference(lintResults.allExecutedChecks.map(\.id), ["1"])
XCTAssertEqual(lintResults.allFoundViolations.count, 3)
XCTAssertNoDifference(lintResults.allFoundViolations.map(\.matchedString), [nil, "A", "AAA"])
XCTAssertEqual(lintResults.allFoundViolations[2].location?.filePath, "/some/path")
XCTAssertEqual(lintResults.allFoundViolations[2].location?.row, 5)
XCTAssertEqual(lintResults.allFoundViolations[2].appliedAutoCorrection?.after, "A")
XCTAssertNil(lintResults.checkViolationsBySeverity[.error]?.keys.first)
XCTAssertEqual(lintResults.checkViolationsBySeverity[.info]?.keys.first?.id, "1")

lintResults = try Lint.runCustomScript(
check: .init(id: "1", hint: "hint #1", severity: .info),
command:
"echo 'Executed custom check with 100 files.\nCustom check failed, please check file at path /some/path.' && exit 1"
)

XCTAssertNoDifference(lintResults.allExecutedChecks.map(\.id), ["1"])
XCTAssertEqual(lintResults.allFoundViolations.count, 1)
XCTAssertNoDifference(
lintResults.allFoundViolations.map(\.message),
["Custom check failed, please check file at path /some/path."]
)
XCTAssertNil(lintResults.checkViolationsBySeverity[.error]?.keys.first)
XCTAssertEqual(lintResults.checkViolationsBySeverity[.info]?.keys.first?.id, "1")

lintResults = try Lint.runCustomScript(
check: .init(id: "1", hint: "hint #1", severity: .info),
command: #"""
echo 'Executed custom check with 100 files.\nNo issues found.' && exit 0
"""#
)

XCTAssertNoDifference(lintResults.allExecutedChecks.map(\.id), ["1"])
XCTAssertEqual(lintResults.allFoundViolations.count, 0)
XCTAssertNoDifference(lintResults.allFoundViolations.map(\.matchedString), [])
XCTAssertNil(lintResults.checkViolationsBySeverity[.error]?.keys.first)
XCTAssertEqual(lintResults.checkViolationsBySeverity[.info]?.keys.first?.id, "1")
}

func testValidateParameterCombinations() {
Expand Down

0 comments on commit 791b963

Please sign in to comment.