From be03720d96cb3792141b73e3ffc39350d030a374 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Fri, 20 Oct 2017 18:45:28 -0400 Subject: [PATCH] Allow custom CheckString file buffers --- Sources/FileCheck/CheckString.swift | 8 ++++- Sources/FileCheck/FileCheck.swift | 40 +++++++++++++++++++++--- Tests/FileCheckTests/FileCheckSpec.swift | 23 +++++++++++++- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Sources/FileCheck/CheckString.swift b/Sources/FileCheck/CheckString.swift index a11fa21..71a51b3 100644 --- a/Sources/FileCheck/CheckString.swift +++ b/Sources/FileCheck/CheckString.swift @@ -307,12 +307,18 @@ private func diagnoseFailedCheck( _ buffer: String ) { if let rtm = pattern.computeRegexToMatch(variableTable) { - if !pattern.fixedString.isEmpty { + if !pattern.fixedString.isEmpty && !rtm.isEmpty { diagnose(.error, at: loc, with: prefix + ": could not find '\(pattern.fixedString)' (with regex '\(rtm)') in input", options: options ) + } else if !pattern.fixedString.isEmpty { + diagnose(.error, + at: loc, + with: prefix + ": could not find '\(pattern.fixedString)' in input", + options: options + ) } else { diagnose(.error, at: loc, diff --git a/Sources/FileCheck/FileCheck.swift b/Sources/FileCheck/FileCheck.swift index 1a5bb9a..ebdc010 100644 --- a/Sources/FileCheck/FileCheck.swift +++ b/Sources/FileCheck/FileCheck.swift @@ -72,6 +72,25 @@ public enum FileCheckFD { } } +/// `FileCheckSource` enumerates possible sources of Check Strings that act as +/// the model against which output is checked. +public enum FileCheckSource { + /// A path to a file that will be opened and parsed for check strings. If the + /// file path is invalid, checking will abort. + case filePath(String) + /// A buffer of check strings. + case buffer(String) +} + +/// - Bug: (SR-3258) Expansion of magic literals like #file does not behave +/// correctly when in argument position. Making it convertible from String +/// does do the expansion for some reason. +extension FileCheckSource: ExpressibleByStringLiteral { + public init(stringLiteral value: String) { + self = .filePath(value) + } +} + /// Reads from the given output stream and runs a file verification procedure /// by comparing the output to a specified result. /// @@ -92,7 +111,7 @@ public enum FileCheckFD { /// file descriptor. /// /// - returns: Whether or not FileCheck succeeded in verifying the file. -public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes : [String] = ["CHECK"], checkNot : [String] = [], against file : String = #file, options: FileCheckOptions = [], block : () -> ()) -> Bool { +public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes : [String] = ["CHECK"], checkNot : [String] = [], against source : FileCheckSource = #file, options: FileCheckOptions = [], block : () -> ()) -> Bool { guard let validPrefixes = validateCheckPrefixes(prefixes) else { print("Supplied check-prefix is invalid! Prefixes must be unique and", "start with a letter and contain only alphanumeric characters,", @@ -109,16 +128,25 @@ public func fileCheckOutput(of FD : FileCheckFD = .stdout, withPrefixes prefixes let input = overrideFDAndCollectOutput(file: FD, of: block) if input.isEmpty { guard options.contains(.allowEmptyInput) else { - print("FileCheck error: input from file descriptor \(FD) is empty.\n") + print("FileCheck error: input from file descriptor \(FD) is empty.") return false } return true } - guard let contents = try? String(contentsOfFile: file, encoding: .utf8) else { - return false + let contents : String + switch source { + case .filePath(let file): + guard let openFile = try? String(contentsOfFile: file, encoding: .utf8) else { + print("FileCheck error: unable to open check file at path \(file).") + return false + } + contents = openFile + case .buffer(let buf): + contents = buf } + let buf = contents.cString(using: .utf8)?.withUnsafeBufferPointer { buffer in return readCheckStrings(in: buffer, withPrefixes: validPrefixes, checkNot: checkNot, options: options, prefixRE) } @@ -407,7 +435,9 @@ private func readCheckStrings(in buf : UnsafeBufferPointer, withPrefixes } // Scan ahead to the end of line. - let EOL : Int = buffer.index(of: ("\n" as Character).utf8CodePoint) ?? buffer.index(of: ("\r" as Character).utf8CodePoint)! + let EOL : Int = buffer.index(of: ("\n" as Character).utf8CodePoint) + ?? buffer.index(of: ("\r" as Character).utf8CodePoint) + ?? buffer.count - 1 // Remember the location of the start of the pattern, for diagnostics. let patternLoc = CheckLocation.inBuffer(buffer.baseAddress!, buf) diff --git a/Tests/FileCheckTests/FileCheckSpec.swift b/Tests/FileCheckTests/FileCheckSpec.swift index 03f81ec..ae6b756 100644 --- a/Tests/FileCheckTests/FileCheckSpec.swift +++ b/Tests/FileCheckTests/FileCheckSpec.swift @@ -3,6 +3,26 @@ import XCTest import Foundation class FileCheckSpec : XCTestCase { + func testCustomInputBuffer() { + XCTAssert(fileCheckOutput(of: .stdout, withPrefixes: ["CUSTOMEMPTYBUF-ERR"]) { + // CUSTOMEMPTYBUF-ERR: error: no check strings found with prefixes + // CUSTOMEMPTYBUF-ERR-NEXT: CUSTOMEMPTYBUF: + XCTAssertFalse(fileCheckOutput(of: .stdout, withPrefixes: ["CUSTOMEMPTYBUF"], against: .buffer(""), options: [.disableColors]) { + print("asdf") + }) + }) + + XCTAssert(fileCheckOutput(of: .stdout, withPrefixes: ["CUSTOMBUF"], against: .buffer(""" + // CUSTOMBUF: shi shi shi shi shi + // CUSTOMBUF-NEXT: asdf + """)) { + print(""" + shi shi shi shi shi + asdf + """) + }) + } + func testWhitespace() { // Check that CHECK-NEXT without a space after the colon works. // Check that CHECK-NOT without a space after the colon works. @@ -129,7 +149,7 @@ class FileCheckSpec : XCTestCase { func testNearestPattern() { XCTAssert(fileCheckOutput(of: .stdout, withPrefixes: ["CHECK-NEAREST-PATTERN-MSG"]) { - // CHECK-NEAREST-PATTERN-MSG: error: {{.*}}: could not find 'Once more into the beach' (with regex '') in input + // CHECK-NEAREST-PATTERN-MSG: error: {{.*}}: could not find 'Once more into the beach' in input // CHECK-NEAREST-PATTERN-MSG-NEXT: // {{.*}}: Once more into the beach // CHECK-NEAREST-PATTERN-MSG-NEXT: note: possible intended match here // CHECK-NEAREST-PATTERN-MSG-NEXT: Once more into the breach @@ -189,6 +209,7 @@ class FileCheckSpec : XCTestCase { #if !os(macOS) static var allTests = testCase([ + ("testCustomInputBuffer", testCustomInputBuffer), ("testWhitespace", testWhitespace), ("testSame", testSame), ("testCheckDAG", testCheckDAG),