From 32f5cab2dc0912f5039a07e0877c16fc9d548ece Mon Sep 17 00:00:00 2001 From: meatball <69751659+meatball133@users.noreply.github.com> Date: Fri, 18 Aug 2023 20:39:38 +0000 Subject: [PATCH] Fixes and updates --- changelog.md | 5 + src/testrunner/Package.swift | 30 +- src/testrunner/Sources/TestRunner/main.swift | 531 ++++++++++--------- 3 files changed, 303 insertions(+), 263 deletions(-) diff --git a/changelog.md b/changelog.md index 8e985f4..001816e 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +# 1.1.3 + +- Fixed an issue making so outputs on multiple lines missed the last line +- Formatted all files using the formatter + # 1.1.2 - Updated test files to follow a more modern design. diff --git a/src/testrunner/Package.swift b/src/testrunner/Package.swift index a221679..f0df711 100644 --- a/src/testrunner/Package.swift +++ b/src/testrunner/Package.swift @@ -4,18 +4,20 @@ import PackageDescription let package = Package( - name: "TestRunner", - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - .package(url: "https://github.com/apple/swift-syntax.git", exact: "508.0.1") - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages which this package depends on. - .target(name: "TestRunner", dependencies: [ - .product(name: "SwiftSyntax", package: "swift-syntax"), - .product(name: "SwiftParser", package: "swift-syntax"), - ]), - ] + name: "TestRunner", + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", exact: "508.0.1") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages which this package depends on. + .target( + name: "TestRunner", + dependencies: [ + .product(name: "SwiftSyntax", package: "swift-syntax"), + .product(name: "SwiftParser", package: "swift-syntax"), + ]) + ] ) diff --git a/src/testrunner/Sources/TestRunner/main.swift b/src/testrunner/Sources/TestRunner/main.swift index 413a3c6..4941a1a 100644 --- a/src/testrunner/Sources/TestRunner/main.swift +++ b/src/testrunner/Sources/TestRunner/main.swift @@ -1,95 +1,99 @@ -import SwiftParser import Foundation -import SwiftSyntax import FoundationXML +import SwiftParser +import SwiftSyntax -struct testFile: Codable { - var version: Int = 3 - var status: String = "pass" - var message: String? = nil - var tests: [testCases] = [] +struct testFile: Codable { + var version: Int = 3 + var status: String = "pass" + var message: String? = nil + var tests: [testCases] = [] } struct testCases: Codable { - var name: String = "" - var test_code: String = "" - var status: String? = nil - var message: String? = nil - var output: String? = nil - var task_id: Int? = nil + var name: String = "" + var test_code: String = "" + var status: String? = nil + var message: String? = nil + var output: String? = nil + var task_id: Int? = nil } +class TestRunner { + var xmlTests: [testCases] = [] -class TestRunner{ - var xmlTests: [testCases] = [] - - class getTestName: SyntaxVisitor { - var tests: [testCases] = [] - var taskId = 0 - var inClass = 0 - let charactersToRemove = CharacterSet(charactersIn: "\n ") - - override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { - let bodyCheck = node.body - if bodyCheck != nil{ - let name: String = String(describing: node.identifier) - guard name.hasPrefix("test") else { return SyntaxVisitorContinueKind.visitChildren } - var body: String = String(describing: bodyCheck!).trimmingCharacters(in: charactersToRemove) - body = String(body[body.index(after: body.startIndex).. 1 { - count = bodyList[1].prefix(while: { $0.isWhitespace }).count - } - for (rowIdx, row) in bodyList[1...].enumerated(){ - bodyList[rowIdx + 1] = String(row.dropFirst(count)) - } - body = bodyList.joined(separator: "\n") - tests.append(testCases(name: name, test_code: body, task_id: taskId == 0 ? nil : taskId)) - } - return SyntaxVisitorContinueKind.visitChildren - } + class getTestName: SyntaxVisitor { + var tests: [testCases] = [] + var taskId = 0 + var inClass = 0 + let charactersToRemove = CharacterSet(charactersIn: "\n ") - override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { - if inClass == 0 && String(describing: node.identifier).hasPrefix("Task") { - taskId += 1 - } - inClass += 1 - return SyntaxVisitorContinueKind.visitChildren + override func visit(_ node: FunctionDeclSyntax) -> SyntaxVisitorContinueKind { + let bodyCheck = node.body + if bodyCheck != nil { + let name: String = String(describing: node.identifier) + guard name.hasPrefix("test") else { return SyntaxVisitorContinueKind.visitChildren } + var body: String = String(describing: bodyCheck!).trimmingCharacters(in: charactersToRemove) + body = String(body[body.index(after: body.startIndex).. 1 { + count = bodyList[1].prefix(while: { $0.isWhitespace }).count } - - override func visitPost(_ node: ClassDeclSyntax) { - inClass -= 1 + for (rowIdx, row) in bodyList[1...].enumerated() { + bodyList[rowIdx + 1] = String(row.dropFirst(count)) } + body = bodyList.joined(separator: "\n") + tests.append(testCases(name: name, test_code: body, task_id: taskId == 0 ? nil : taskId)) + } + return SyntaxVisitorContinueKind.visitChildren } - class MyXMLParserDelegate: NSObject, XMLParserDelegate { - var counter = 0 - var tests: [testCases] // Add a property for tests + override func visit(_ node: ClassDeclSyntax) -> SyntaxVisitorContinueKind { + if inClass == 0 && String(describing: node.identifier).hasPrefix("Task") { + taskId += 1 + } + inClass += 1 + return SyntaxVisitorContinueKind.visitChildren + } - init(tests: [testCases]) { - self.tests = tests - } - // Called when the parser encounters the start of an element - func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName _: String?, attributes attributeDict: [String : String] = [:]) { - if elementName == "failure"{ - tests[counter].status = "fail" - } - else{ - counter = tests.firstIndex(where: {$0.name == attributeDict["name"]}) ?? counter - tests[counter].status = "pass" - } - } + override func visitPost(_ node: ClassDeclSyntax) { + inClass -= 1 } + } + class MyXMLParserDelegate: NSObject, XMLParserDelegate { + var counter = 0 + var tests: [testCases] // Add a property for tests + + init(tests: [testCases]) { + self.tests = tests + } + // Called when the parser encounters the start of an element + func parser( + _ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, + qualifiedName _: String?, attributes attributeDict: [String: String] = [:] + ) { + if elementName == "failure" { + tests[counter].status = "fail" + } else { + counter = tests.firstIndex(where: { $0.name == attributeDict["name"] }) ?? counter + tests[counter].status = "pass" + } + } + } - func run(filePath : String, xmlPath : String, contextPath : String, resultPath : String, slug : String){ + func run(filePath: String, xmlPath: String, contextPath: String, resultPath: String, slug: String) + { var swiftSource = "" do { - swiftSource = try NSString(contentsOfFile: filePath, - encoding: String.Encoding.ascii.rawValue) as String - }catch { - print("Error filePath: \(error)") + swiftSource = + try NSString( + contentsOfFile: filePath, + encoding: String.Encoding.ascii.rawValue) as String + } catch { + print("Error filePath: \(error)") } let rootNode: SourceFileSyntax = try! Parser.parse(source: swiftSource) var process = getTestName(viewMode: SyntaxTreeViewMode.all) @@ -97,209 +101,238 @@ class TestRunner{ let tests = process.tests var result = "" do { - result = try NSString(contentsOfFile: xmlPath, - encoding: String.Encoding.ascii.rawValue) as String - }catch { - print("Error xmlPath: \(error)") - writeJson(resultPath: resultPath, error: errorContext(context: contextPath, slug: slug)) - return + result = + try NSString( + contentsOfFile: xmlPath, + encoding: String.Encoding.ascii.rawValue) as String + } catch { + print("Error xmlPath: \(error)") + writeJson(resultPath: resultPath, error: errorContext(context: contextPath, slug: slug)) + return } let xmlData = Data(result.utf8) let xmlParser = XMLParser(data: xmlData) - let delegate = MyXMLParserDelegate(tests: tests) - xmlParser.delegate = delegate + let delegate = MyXMLParserDelegate(tests: tests) + xmlParser.delegate = delegate xmlParser.parse() xmlTests = delegate.tests var context = "" do { - context = try NSString(contentsOfFile: contextPath, - encoding: String.Encoding.ascii.rawValue) as String - }catch { - print("Error contextPath: \(error)") - } + context = + try NSString( + contentsOfFile: contextPath, + encoding: String.Encoding.ascii.rawValue) as String + } catch { + print("Error contextPath: \(error)") + } addContext(context: context, slug: slug) writeJson(resultPath: resultPath) - } + } - func addContext(context: String, slug: String) { - for (testIdx, testCase) in xmlTests.enumerated(){ - var error = false - if testCase.status == "fail"{ - let contextLines = context.components(separatedBy: "\n")[1...] - var found = false - var start = "" - var current = 0 - for (rowIdx, row) in contextLines.enumerated(){ - if found { - if let endRange = row.range(of: "Test Case "){ - let middle = contextLines[current.. 0{ - if row.contains(testCase.name) && row[startIndex] != "[" { - current = testCase.name - if let startRange = row.range(of: "started at", options: .backwards) { - if let newStartRange = row.range(of: ".", options: [], range: (startRange.upperBound.. 0{ - if start == 0 && row.contains(testCase.name + "'") && row[startIndex] != "[" && !row.contains("error"){ - if let startRange = row.range(of: "started at", options: .backwards) { - if let newStartRange = row.range(of: ".", options: [], range: (startRange.upperBound.. 0 { + if row.contains(testCase.name) && row[startIndex] != "[" { + current = testCase.name + if let startRange = row.range(of: "started at", options: .backwards) { + if let newStartRange = row.range( + of: ".", options: [], range: (startRange.upperBound.. String{ - var something = "" - do { - // Use contentsOfFile overload. - // ... Specify ASCII encoding. - // ... Ignore errors. - something = try NSString(contentsOfFile: context, - encoding: String.Encoding.ascii.rawValue) as String - - // If a value was returned, print it. - }catch { - print("Error context_path: \(error)") - } - let message = something.components(separatedBy: "\n")[1...] + } + if !error { + let contextLinesOutput = context.components(separatedBy: "\n")[1...] var start = 0 - for (rowIdx, row) in message.enumerated(){ - if row.contains("CompileError.swift:") || row.contains("\(camelCase(slug: slug))Tests.swift:") || row.contains("\(camelCase(slug: slug)).swift:") { - start = rowIdx + 1 - break + var startString = "" + for (rowIdx, row) in contextLinesOutput.enumerated() { + let startIndex = row.index(row.startIndex, offsetBy: 0) + if row.count > 0 { + if start == 0 && row.contains(testCase.name + "'") && row[startIndex] != "[" + && !row.contains("error") + { + if let startRange = row.range(of: "started at", options: .backwards) { + if let newStartRange = row.range( + of: ".", options: [], range: (startRange.upperBound.. String { + var something = "" + do { + // Use contentsOfFile overload. + // ... Specify ASCII encoding. + // ... Ignore errors. + something = + try NSString( + contentsOfFile: context, + encoding: String.Encoding.ascii.rawValue) as String + + // If a value was returned, print it. + } catch { + print("Error context_path: \(error)") + } + let message = something.components(separatedBy: "\n")[1...] + var start = 0 + for (rowIdx, row) in message.enumerated() { + if row.contains("CompileError.swift:") || row.contains("\(camelCase(slug: slug))Tests.swift:") + || row.contains("\(camelCase(slug: slug)).swift:") + { + start = rowIdx + 1 + break + } } + if start != 0 { + return message[start...].joined(separator: "\n") + } + return message.joined(separator: "\n") + } - private func camelCase(slug: String) -> String{ - let words = slug.components(separatedBy: "-") - var camelCase = "" - for word in words{ - if word != ""{ - camelCase += word.prefix(1).uppercased() + word.dropFirst() - } - } - return camelCase + func writeJson(resultPath: String, error: String = "") { + let encoder = JSONEncoder() + encoder.outputFormatting.update(with: .prettyPrinted) + encoder.outputFormatting.update(with: .sortedKeys) + var json: testFile + if xmlTests.contains { $0.status == "fail" } { + json = testFile(status: "fail", tests: xmlTests) + } else if error != "" { + json = testFile(status: "error", message: error) + } else { + json = testFile(tests: xmlTests) + } + var data: Data + do { + data = try encoder.encode(json) + } catch { + print("Error can't encode json: \(error)") + return + } + let dataJson = String(data: data, encoding: .utf8)! + do { + try dataJson.write(toFile: resultPath, atomically: true, encoding: String.Encoding.utf8) + } catch { + print("Error resultPath: \(error)") + return + } + } + + private func camelCase(slug: String) -> String { + let words = slug.components(separatedBy: "-") + var camelCase = "" + for word in words { + if word != "" { + camelCase += word.prefix(1).uppercased() + word.dropFirst() + } } + return camelCase + } } -TestRunner().run(filePath: CommandLine.arguments[1], xmlPath: CommandLine.arguments[2], contextPath: CommandLine.arguments[3], resultPath: CommandLine.arguments[4], slug : CommandLine.arguments[5]) +TestRunner().run( + filePath: CommandLine.arguments[1], xmlPath: CommandLine.arguments[2], + contextPath: CommandLine.arguments[3], resultPath: CommandLine.arguments[4], + slug: CommandLine.arguments[5])