test fixes
This commit is contained in:
parent
d4d899da85
commit
39f3c18eea
@ -6,208 +6,211 @@ import XCTest
|
||||
// MARK: - Action Command Tests
|
||||
|
||||
class ActionIntegrationTests: XCTestCase {
|
||||
func testPerformActionSetTextEditTextAreaValue() async throws {
|
||||
let actionCommandId = "performaction-setvalue-\(UUID().uuidString)"
|
||||
let queryCommandId = "query-verify-setvalue-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
let textToSet = "Hello from AXORC performAction test! Time: \(Date())"
|
||||
// MARK: Internal
|
||||
|
||||
// Setup
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
func testPerformActionSetTextEditTextAreaValue() async throws {
|
||||
let actionCommandId = "performaction-setvalue-\(UUID().uuidString)"
|
||||
let queryCommandId = "query-verify-setvalue-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
let textToSet = "Hello from AXORC performAction test! Time: \(Date())"
|
||||
|
||||
let textAreaLocator = Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
// Setup
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
|
||||
// Perform action
|
||||
try await performSetValueAction(
|
||||
actionCommandId: actionCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
textToSet: textToSet
|
||||
)
|
||||
let textAreaLocator = Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
|
||||
// Verify the value was set
|
||||
try await verifyTextValue(
|
||||
queryCommandId: queryCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
expectedText: textToSet
|
||||
)
|
||||
}
|
||||
// Perform action
|
||||
try await performSetValueAction(
|
||||
actionCommandId: actionCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
textToSet: textToSet
|
||||
)
|
||||
|
||||
func testExtractTextFromTextEditTextArea() async throws {
|
||||
let setValueCommandId = "setvalue-for-extract-\(UUID().uuidString)"
|
||||
let extractTextCommandId = "extracttext-textedit-textarea-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
let textToSetAndExtract = "Text to be extracted by AXORC. Unique: \(UUID().uuidString)"
|
||||
|
||||
// Setup
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
|
||||
let textAreaLocator = Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
|
||||
// Set text value
|
||||
try await performSetValueAction(
|
||||
actionCommandId: setValueCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
textToSet: textToSetAndExtract
|
||||
)
|
||||
|
||||
// Extract and verify text
|
||||
try await extractAndVerifyText(
|
||||
extractTextCommandId: extractTextCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
expectedText: textToSetAndExtract
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Helper Functions
|
||||
|
||||
private func performSetValueAction(
|
||||
actionCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
textToSet: String
|
||||
) async throws {
|
||||
let performActionEnvelope = CommandEnvelope(
|
||||
commandId: actionCommandId,
|
||||
command: .performAction,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator,
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable(textToSet)
|
||||
)
|
||||
|
||||
let response = try await executeCommand(performActionEnvelope)
|
||||
|
||||
XCTAssertEqual(response.commandId , actionCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success , true,
|
||||
"performAction command was not successful. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
}
|
||||
|
||||
private func verifyTextValue(
|
||||
queryCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
expectedText: String
|
||||
) async throws {
|
||||
let queryEnvelope = CommandEnvelope(
|
||||
commandId: queryCommandId,
|
||||
command: .query,
|
||||
application: textEditBundleId,
|
||||
attributes: ["AXValue"],
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator
|
||||
)
|
||||
|
||||
let response = try await executeCommand(queryEnvelope)
|
||||
|
||||
XCTAssertEqual(response.commandId , queryCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success , true,
|
||||
"Query (verify) command failed. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
|
||||
guard let attributes = response.data?.attributes else {
|
||||
throw TestError.generic("Attributes nil in query (verify) response.")
|
||||
// Verify the value was set
|
||||
try await verifyTextValue(
|
||||
queryCommandId: queryCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
expectedText: textToSet
|
||||
)
|
||||
}
|
||||
|
||||
let retrievedValue = attributes["AXValue"]?.value as? String
|
||||
XCTAssertEqual(
|
||||
retrievedValue , expectedText,
|
||||
"AXValue did not match. Expected: '\(expectedText)'. Got: '\(retrievedValue ?? "nil")'"
|
||||
)
|
||||
func testExtractTextFromTextEditTextArea() async throws {
|
||||
let setValueCommandId = "setvalue-for-extract-\(UUID().uuidString)"
|
||||
let extractTextCommandId = "extracttext-textedit-textarea-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
let textToSetAndExtract = "Text to be extracted by AXORC. Unique: \(UUID().uuidString)"
|
||||
|
||||
XCTAssertNotEqual(response.debugLogs , nil)
|
||||
}
|
||||
// Setup
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
|
||||
private func extractAndVerifyText(
|
||||
extractTextCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
expectedText: String
|
||||
) async throws {
|
||||
let extractTextEnvelope = CommandEnvelope(
|
||||
commandId: extractTextCommandId,
|
||||
command: .extractText,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator
|
||||
)
|
||||
let textAreaLocator = Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
|
||||
let response = try await executeCommand(extractTextEnvelope)
|
||||
// Set text value
|
||||
try await performSetValueAction(
|
||||
actionCommandId: setValueCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
textToSet: textToSetAndExtract
|
||||
)
|
||||
|
||||
XCTAssertEqual(response.commandId , extractTextCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success , true,
|
||||
"extractText command failed. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
XCTAssertEqual(response.command , CommandType.extractText.rawValue)
|
||||
|
||||
guard let attributes = response.data?.attributes else {
|
||||
throw TestError.generic("Attributes nil in extractText response.")
|
||||
// Extract and verify text
|
||||
try await extractAndVerifyText(
|
||||
extractTextCommandId: extractTextCommandId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaLocator: textAreaLocator,
|
||||
expectedText: textToSetAndExtract
|
||||
)
|
||||
}
|
||||
|
||||
let extractedValue = attributes["AXValue"]?.value as? String
|
||||
XCTAssertEqual(
|
||||
extractedValue , expectedText,
|
||||
"Extracted text did not match. Expected: '\(expectedText)'. Got: '\(extractedValue ?? "nil")'"
|
||||
)
|
||||
// MARK: Private
|
||||
|
||||
XCTAssertNotEqual(response.debugLogs , nil)
|
||||
XCTAssertTrue(
|
||||
response.debugLogs?
|
||||
.contains { log in
|
||||
log.contains("Handling extractText command") ||
|
||||
log.contains("handleExtractText completed")
|
||||
} == true,
|
||||
"Debug logs should indicate extractText execution."
|
||||
)
|
||||
}
|
||||
// MARK: - Helper Functions
|
||||
|
||||
private func executeCommand(_ command: CommandEnvelope) async throws -> QueryResponse {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .withoutEscapingSlashes
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON for command.")
|
||||
private func performSetValueAction(
|
||||
actionCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
textToSet: String
|
||||
) async throws {
|
||||
let performActionEnvelope = CommandEnvelope(
|
||||
commandId: actionCommandId,
|
||||
command: .performAction,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator,
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable(textToSet)
|
||||
)
|
||||
|
||||
let response = try await executeCommand(performActionEnvelope)
|
||||
|
||||
XCTAssertEqual(response.commandId, actionCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success, true,
|
||||
"performAction command was not successful. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
|
||||
try await Task.sleep(for: .milliseconds(100))
|
||||
}
|
||||
|
||||
print("Sending command: \(jsonString)")
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
let (output, errorOutput, exitCode) = (result.output, result.errorOutput, result.exitCode)
|
||||
private func verifyTextValue(
|
||||
queryCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
expectedText: String
|
||||
) async throws {
|
||||
let queryEnvelope = CommandEnvelope(
|
||||
commandId: queryCommandId,
|
||||
command: .query,
|
||||
application: textEditBundleId,
|
||||
attributes: ["AXValue"],
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator
|
||||
)
|
||||
|
||||
XCTAssertEqual(exitCode , 0, Comment(rawValue: "Command failed. Error: \(errorOutput ?? "N/A")"))
|
||||
XCTAssertEqual(
|
||||
errorOutput , nil || errorOutput!.isEmpty,
|
||||
Comment(rawValue: "STDERR should be empty. Got: \(errorOutput ?? "")")
|
||||
)
|
||||
let response = try await executeCommand(queryEnvelope)
|
||||
|
||||
guard let outputString = output, !outputString.isEmpty else {
|
||||
throw TestError.generic("Output was nil/empty.")
|
||||
XCTAssertEqual(response.commandId, queryCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success, true,
|
||||
"Query (verify) command failed. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
|
||||
guard let attributes = response.data?.attributes else {
|
||||
throw TestError.generic("Attributes nil in query (verify) response.")
|
||||
}
|
||||
|
||||
let retrievedValue = attributes["AXValue"]?.value as? String
|
||||
XCTAssertEqual(
|
||||
retrievedValue, expectedText,
|
||||
"AXValue did not match. Expected: '\(expectedText)'. Got: '\(retrievedValue ?? "nil")'"
|
||||
)
|
||||
|
||||
XCTAssertNotEqual(response.debugLogs, nil)
|
||||
}
|
||||
|
||||
print("Received output: \(outputString)")
|
||||
private func extractAndVerifyText(
|
||||
extractTextCommandId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaLocator: Locator,
|
||||
expectedText: String
|
||||
) async throws {
|
||||
let extractTextEnvelope = CommandEnvelope(
|
||||
commandId: extractTextCommandId,
|
||||
command: .extractText,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true,
|
||||
locator: textAreaLocator
|
||||
)
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Could not convert output to data.")
|
||||
let response = try await executeCommand(extractTextEnvelope)
|
||||
|
||||
XCTAssertEqual(response.commandId, extractTextCommandId)
|
||||
XCTAssertEqual(
|
||||
response.success, true,
|
||||
"extractText command failed. Error: \(response.error?.message ?? "N/A")"
|
||||
)
|
||||
XCTAssertEqual(response.command, CommandType.extractText.rawValue)
|
||||
|
||||
guard let attributes = response.data?.attributes else {
|
||||
throw TestError.generic("Attributes nil in extractText response.")
|
||||
}
|
||||
|
||||
let extractedValue = attributes["AXValue"]?.value as? String
|
||||
XCTAssertEqual(
|
||||
extractedValue, expectedText,
|
||||
"Extracted text did not match. Expected: '\(expectedText)'. Got: '\(extractedValue ?? "nil")'"
|
||||
)
|
||||
|
||||
XCTAssertNotEqual(response.debugLogs, nil)
|
||||
XCTAssertTrue(
|
||||
response.debugLogs?
|
||||
.contains { log in
|
||||
log.contains("Handling extractText command") ||
|
||||
log.contains("handleExtractText completed")
|
||||
} == true,
|
||||
"Debug logs should indicate extractText execution."
|
||||
)
|
||||
}
|
||||
|
||||
do {
|
||||
return try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
} catch {
|
||||
throw TestError.generic("Failed to decode response: \(error.localizedDescription). JSON: \(outputString)")
|
||||
private func executeCommand(_ command: CommandEnvelope) async throws -> QueryResponse {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .withoutEscapingSlashes
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON for command.")
|
||||
}
|
||||
|
||||
print("Sending command: \(jsonString)")
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
let (output, errorOutput, exitCode) = (result.output, result.errorOutput, result.exitCode)
|
||||
|
||||
XCTAssertEqual(exitCode, 0, Comment(rawValue: "Command failed. Error: \(errorOutput ?? "N/A")"))
|
||||
XCTAssertEqual(
|
||||
errorOutput, nil || errorOutput!.isEmpty,
|
||||
Comment(rawValue: "STDERR should be empty. Got: \(errorOutput ?? "")")
|
||||
)
|
||||
|
||||
guard let outputString = output, !outputString.isEmpty else {
|
||||
throw TestError.generic("Output was nil/empty.")
|
||||
}
|
||||
|
||||
print("Received output: \(outputString)")
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Could not convert output to data.")
|
||||
}
|
||||
|
||||
do {
|
||||
return try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
} catch {
|
||||
throw TestError.generic("Failed to decode response: \(error.localizedDescription). JSON: \(outputString)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,146 +5,147 @@ import XCTest
|
||||
// MARK: - Application Query Tests
|
||||
|
||||
class ApplicationQueryTests: XCTestCase {
|
||||
func testGetAllApplications() async throws {
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-get-all-apps",
|
||||
command: .collectAll,
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
func testGetAllApplications() async throws {
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-get-all-apps",
|
||||
command: .collectAll,
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
XCTAssertEqual(result.exitCode , 0, "Command should succeed")
|
||||
XCTAssertNotEqual(result.output , nil, "Should have output")
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
// TODO: Fix response type - SimpleSuccessResponse doesn't have data property
|
||||
// The following code expects response.data which doesn't exist
|
||||
/*
|
||||
XCTAssertNotEqual(response.data?["elements"] , nil, "Should have elements")
|
||||
|
||||
if let elements = response.data?["elements"] as? [[String: Any]] {
|
||||
XCTAssertTrue(!elements.isEmpty, "Should have at least one application")
|
||||
|
||||
// Check for Finder
|
||||
let appTitles = elements.compactMap { element -> String? in
|
||||
guard let attrs = element["attributes"] as? [String: Any] else { return nil }
|
||||
return attrs["AXTitle"] as? String
|
||||
}
|
||||
XCTAssertTrue(appTitles.contains("Finder"), "Finder should be running")
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func testGetWindowsOfApplication() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
let (pid, _) = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
XCTAssertEqual(result.exitCode, 0, "Command should succeed")
|
||||
XCTAssertNotEqual(result.output, nil, "Should have output")
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
// TODO: Fix response type - SimpleSuccessResponse doesn't have data property
|
||||
// The following code expects response.data which doesn't exist
|
||||
/*
|
||||
XCTAssertNotEqual(response.data?["elements"] , nil, "Should have elements")
|
||||
|
||||
if let elements = response.data?["elements"] as? [[String: Any]] {
|
||||
XCTAssertTrue(!elements.isEmpty, "Should have at least one application")
|
||||
|
||||
// Check for Finder
|
||||
let appTitles = elements.compactMap { element -> String? in
|
||||
guard let attrs = element["attributes"] as? [String: Any] else { return nil }
|
||||
return attrs["AXTitle"] as? String
|
||||
}
|
||||
XCTAssertTrue(appTitles.contains("Finder"), "Finder should be running")
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
func testGetWindowsOfApplication() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
// Query for windows
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-get-windows",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXWindow")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
let (pid, _) = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
// Query for windows
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-get-windows",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXWindow")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
// TODO: Fix response type - SimpleSuccessResponse doesn't have data property
|
||||
/*
|
||||
if let elements = response.data?["elements"] as? [[String: Any]] {
|
||||
XCTAssertTrue(!elements.isEmpty, "Should have at least one window")
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
for window in elements {
|
||||
if let attrs = window["attributes"] as? [String: Any] {
|
||||
XCTAssertEqual(attrs["AXRole"] as? String , "AXWindow")
|
||||
XCTAssertNotEqual(attrs["AXTitle"] , nil, "Window should have title")
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
// TODO: Fix response type - SimpleSuccessResponse doesn't have data property
|
||||
/*
|
||||
if let elements = response.data?["elements"] as? [[String: Any]] {
|
||||
XCTAssertTrue(!elements.isEmpty, "Should have at least one window")
|
||||
|
||||
for window in elements {
|
||||
if let attrs = window["attributes"] as? [String: Any] {
|
||||
XCTAssertEqual(attrs["AXRole"] as? String , "AXWindow")
|
||||
XCTAssertNotEqual(attrs["AXTitle"] , nil, "Window should have title")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func testQueryNonExistentApp() async throws {
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-nonexistent",
|
||||
command: .query,
|
||||
application: "NonExistentApp12345",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")])
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
*/
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
func testQueryNonExistentApp() async throws {
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-nonexistent",
|
||||
command: .query,
|
||||
application: "NonExistentApp12345",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")])
|
||||
)
|
||||
|
||||
// Command should succeed but return no elements
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
// Command should succeed but return no elements
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
if response.success {
|
||||
// For non-existent app, we expect success but should check message or details
|
||||
// to verify no elements were found. Since SimpleSuccessResponse doesn't
|
||||
// have element data, we verify through the success status and message.
|
||||
XCTAssertTrue(response.message.contains("No") || response.message.contains("not found") || response.message.isEmpty,
|
||||
"Message should indicate no elements found or be empty")
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
|
||||
if response.success {
|
||||
// For non-existent app, we expect success but should check message or details
|
||||
// to verify no elements were found. Since SimpleSuccessResponse doesn't
|
||||
// have element data, we verify through the success status and message.
|
||||
XCTAssertTrue(
|
||||
response.message.contains("No") || response.message.contains("not found") || response.message.isEmpty,
|
||||
"Message should indicate no elements found or be empty"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,134 +5,137 @@ import XCTest
|
||||
// MARK: - Batch Command Tests
|
||||
|
||||
class BatchIntegrationTests: XCTestCase {
|
||||
func testBatchCommandGetFocusedElementAndQuery() async throws {
|
||||
let batchCommandId = "batch-textedit-\(UUID().uuidString)"
|
||||
let focusedElementSubCmdId = "batch-sub-getfocused-\(UUID().uuidString)"
|
||||
let querySubCmdId = "batch-sub-querytextarea-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
// MARK: Internal
|
||||
|
||||
// Setup TextEdit
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
func testBatchCommandGetFocusedElementAndQuery() async throws {
|
||||
let batchCommandId = "batch-textedit-\(UUID().uuidString)"
|
||||
let focusedElementSubCmdId = "batch-sub-getfocused-\(UUID().uuidString)"
|
||||
let querySubCmdId = "batch-sub-querytextarea-\(UUID().uuidString)"
|
||||
let textEditBundleId = "com.apple.TextEdit"
|
||||
let textAreaRole = ApplicationServices.kAXTextAreaRole as String
|
||||
|
||||
// Create batch command
|
||||
let batchCommand = createBatchCommand(
|
||||
batchCommandId: batchCommandId,
|
||||
focusedElementSubCmdId: focusedElementSubCmdId,
|
||||
querySubCmdId: querySubCmdId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaRole: textAreaRole
|
||||
)
|
||||
// Setup TextEdit
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer { Task { await closeTextEdit() } }
|
||||
|
||||
// Execute batch command
|
||||
let batchResponse = try await executeBatchCommand(batchCommand)
|
||||
// Create batch command
|
||||
let batchCommand = createBatchCommand(
|
||||
batchCommandId: batchCommandId,
|
||||
focusedElementSubCmdId: focusedElementSubCmdId,
|
||||
querySubCmdId: querySubCmdId,
|
||||
textEditBundleId: textEditBundleId,
|
||||
textAreaRole: textAreaRole
|
||||
)
|
||||
|
||||
// Verify results
|
||||
verifyBatchResponse(
|
||||
batchResponse,
|
||||
batchCommandId: batchCommandId,
|
||||
focusedElementSubCmdId: focusedElementSubCmdId,
|
||||
querySubCmdId: querySubCmdId,
|
||||
textAreaRole: textAreaRole
|
||||
)
|
||||
}
|
||||
// Execute batch command
|
||||
let batchResponse = try await executeBatchCommand(batchCommand)
|
||||
|
||||
// MARK: - Helper Functions
|
||||
|
||||
private func createBatchCommand(
|
||||
batchCommandId: String,
|
||||
focusedElementSubCmdId: String,
|
||||
querySubCmdId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaRole: String
|
||||
) -> CommandEnvelope {
|
||||
let getFocusedElementSubCommand = CommandEnvelope(
|
||||
commandId: focusedElementSubCmdId,
|
||||
command: .getFocusedElement,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true
|
||||
)
|
||||
|
||||
let queryTextAreaSubCommand = CommandEnvelope(
|
||||
commandId: querySubCmdId,
|
||||
command: .query,
|
||||
application: textEditBundleId,
|
||||
attributes: ["AXRole", "AXValue"],
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
)
|
||||
|
||||
return CommandEnvelope(
|
||||
commandId: batchCommandId,
|
||||
command: .batch,
|
||||
application: nil,
|
||||
debugLogging: true,
|
||||
subCommands: [getFocusedElementSubCommand, queryTextAreaSubCommand]
|
||||
)
|
||||
}
|
||||
|
||||
private func executeBatchCommand(_ command: CommandEnvelope) async throws -> BatchOperationResponse {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON string for batch command.")
|
||||
// Verify results
|
||||
verifyBatchResponse(
|
||||
batchResponse,
|
||||
batchCommandId: batchCommandId,
|
||||
focusedElementSubCmdId: focusedElementSubCmdId,
|
||||
querySubCmdId: querySubCmdId,
|
||||
textAreaRole: textAreaRole
|
||||
)
|
||||
}
|
||||
|
||||
print("Sending batch command to axorc: \(jsonString)")
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
let (output, errorOutput, exitCode) = (result.output, result.errorOutput, result.exitCode)
|
||||
// MARK: Private
|
||||
|
||||
XCTAssertEqual(
|
||||
exitCode , 0,
|
||||
Comment(rawValue: "axorc process for batch command should exit with 0. Error: \(errorOutput ?? "N/A")")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
errorOutput , nil || errorOutput!.isEmpty,
|
||||
Comment(rawValue: "STDERR should be empty. Got: \(errorOutput ?? "")")
|
||||
)
|
||||
// MARK: - Helper Functions
|
||||
|
||||
guard let outputString = output, !outputString.isEmpty else {
|
||||
throw TestError.generic("Output string was nil or empty for batch command.")
|
||||
}
|
||||
print("Received output from axorc (batch command): \(outputString)")
|
||||
private func createBatchCommand(
|
||||
batchCommandId: String,
|
||||
focusedElementSubCmdId: String,
|
||||
querySubCmdId: String,
|
||||
textEditBundleId: String,
|
||||
textAreaRole: String
|
||||
) -> CommandEnvelope {
|
||||
let getFocusedElementSubCommand = CommandEnvelope(
|
||||
commandId: focusedElementSubCmdId,
|
||||
command: .getFocusedElement,
|
||||
application: textEditBundleId,
|
||||
debugLogging: true
|
||||
)
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Could not convert output string to data for batch command.")
|
||||
let queryTextAreaSubCommand = CommandEnvelope(
|
||||
commandId: querySubCmdId,
|
||||
command: .query,
|
||||
application: textEditBundleId,
|
||||
attributes: ["AXRole", "AXValue"],
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: textAreaRole)])
|
||||
)
|
||||
|
||||
return CommandEnvelope(
|
||||
commandId: batchCommandId,
|
||||
command: .batch,
|
||||
application: nil,
|
||||
debugLogging: true,
|
||||
subCommands: [getFocusedElementSubCommand, queryTextAreaSubCommand]
|
||||
)
|
||||
}
|
||||
|
||||
return try JSONDecoder().decode(BatchOperationResponse.self, from: responseData)
|
||||
private func executeBatchCommand(_ command: CommandEnvelope) async throws -> BatchOperationResponse {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.outputFormatting = .prettyPrinted
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON string for batch command.")
|
||||
}
|
||||
|
||||
print("Sending batch command to axorc: \(jsonString)")
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
let (output, errorOutput, exitCode) = (result.output, result.errorOutput, result.exitCode)
|
||||
|
||||
XCTAssertEqual(
|
||||
exitCode, 0,
|
||||
Comment(rawValue: "axorc process for batch command should exit with 0. Error: \(errorOutput ?? "N/A")")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
errorOutput, nil || errorOutput!.isEmpty,
|
||||
Comment(rawValue: "STDERR should be empty. Got: \(errorOutput ?? "")")
|
||||
)
|
||||
|
||||
guard let outputString = output, !outputString.isEmpty else {
|
||||
throw TestError.generic("Output string was nil or empty for batch command.")
|
||||
}
|
||||
print("Received output from axorc (batch command): \(outputString)")
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Could not convert output string to data for batch command.")
|
||||
}
|
||||
|
||||
return try JSONDecoder().decode(BatchOperationResponse.self, from: responseData)
|
||||
}
|
||||
|
||||
private func verifyBatchResponse(
|
||||
_ batchResponse: BatchOperationResponse,
|
||||
batchCommandId: String,
|
||||
focusedElementSubCmdId: String,
|
||||
querySubCmdId: String,
|
||||
textAreaRole: String
|
||||
) {
|
||||
XCTAssertEqual(batchResponse.commandId, batchCommandId)
|
||||
XCTAssertEqual(batchResponse.success, true, "Batch command should succeed")
|
||||
XCTAssertEqual(batchResponse.results.count, 2, "Expected 2 results")
|
||||
|
||||
// Verify first sub-command
|
||||
let result1 = batchResponse.results[0]
|
||||
XCTAssertEqual(result1.commandId, focusedElementSubCmdId)
|
||||
XCTAssertEqual(result1.success, true, "GetFocusedElement should succeed")
|
||||
XCTAssertEqual(result1.command, CommandType.getFocusedElement.rawValue)
|
||||
XCTAssertNotEqual(result1.data, nil)
|
||||
XCTAssertEqual(result1.data?.attributes?["AXRole"]?.value as? String, textAreaRole)
|
||||
|
||||
// Verify second sub-command
|
||||
let result2 = batchResponse.results[1]
|
||||
XCTAssertEqual(result2.commandId, querySubCmdId)
|
||||
XCTAssertEqual(result2.success, true, "Query should succeed")
|
||||
XCTAssertEqual(result2.command, CommandType.query.rawValue)
|
||||
XCTAssertNotEqual(result2.data, nil)
|
||||
XCTAssertEqual(result2.data?.attributes?["AXRole"]?.value as? String, textAreaRole)
|
||||
|
||||
XCTAssertNotEqual(batchResponse.debugLogs, nil)
|
||||
}
|
||||
}
|
||||
|
||||
private func verifyBatchResponse(
|
||||
_ batchResponse: BatchOperationResponse,
|
||||
batchCommandId: String,
|
||||
focusedElementSubCmdId: String,
|
||||
querySubCmdId: String,
|
||||
textAreaRole: String
|
||||
) {
|
||||
XCTAssertEqual(batchResponse.commandId , batchCommandId)
|
||||
XCTAssertEqual(batchResponse.success , true, "Batch command should succeed")
|
||||
XCTAssertEqual(batchResponse.results.count , 2, "Expected 2 results")
|
||||
|
||||
// Verify first sub-command
|
||||
let result1 = batchResponse.results[0]
|
||||
XCTAssertEqual(result1.commandId , focusedElementSubCmdId)
|
||||
XCTAssertEqual(result1.success , true, "GetFocusedElement should succeed")
|
||||
XCTAssertEqual(result1.command , CommandType.getFocusedElement.rawValue)
|
||||
XCTAssertNotEqual(result1.data , nil)
|
||||
XCTAssertEqual(result1.data?.attributes?["AXRole"]?.value as? String , textAreaRole)
|
||||
|
||||
// Verify second sub-command
|
||||
let result2 = batchResponse.results[1]
|
||||
XCTAssertEqual(result2.commandId , querySubCmdId)
|
||||
XCTAssertEqual(result2.success , true, "Query should succeed")
|
||||
XCTAssertEqual(result2.command , CommandType.query.rawValue)
|
||||
XCTAssertNotEqual(result2.data , nil)
|
||||
XCTAssertEqual(result2.data?.attributes?["AXRole"]?.value as? String , textAreaRole)
|
||||
|
||||
XCTAssertNotEqual(batchResponse.debugLogs , nil)
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,248 +5,247 @@ import XCTest
|
||||
// MARK: - Element Search and Navigation Tests
|
||||
|
||||
class ElementSearchTests: XCTestCase {
|
||||
func testSearchElementsByRole() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
func testSearchElementsByRole() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Search for buttons
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-search-buttons",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXButton")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
// For a query response, we should find button elements
|
||||
if let role = attributes["AXRole"]?.value as? String {
|
||||
XCTAssertEqual(role, "AXButton", "Should find button elements")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
func testDescribeElementHierarchy() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
// Search for buttons
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-search-buttons",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXButton")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Describe the application element
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-describe",
|
||||
command: .describeElement,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")]),
|
||||
maxElements: 3,
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
XCTAssertNotEqual(response.data, nil)
|
||||
|
||||
// Check hierarchy
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
if let role = attributes["AXRole"]?.value as? String {
|
||||
XCTAssertEqual(role, "AXApplication", "Should find application element")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
func testSetAndVerifyText() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Set text
|
||||
let setText = CommandEnvelope(
|
||||
commandId: "test-set-text",
|
||||
command: .performAction,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable("Hello from AXorcist tests!")
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
var jsonData = try encoder.encode(setText)
|
||||
guard let setJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
var result = try runAXORCCommand(arguments: [setJsonString])
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
// Query to verify
|
||||
let queryText = CommandEnvelope(
|
||||
commandId: "test-query-text",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
jsonData = try encoder.encode(queryText)
|
||||
guard let queryJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
result = try runAXORCCommand(arguments: [queryJsonString])
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
if let value = attributes["AXValue"]?.value as? String {
|
||||
XCTAssertTrue(value.contains("Hello from AXorcist tests!"), "Should find the text we set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
func testExtractText() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
// For a query response, we should find button elements
|
||||
if let role = attributes["AXRole"]?.value as? String {
|
||||
XCTAssertEqual(role , "AXButton", "Should find button elements")
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Set some text first
|
||||
let setText = CommandEnvelope(
|
||||
commandId: "test-set-for-extract",
|
||||
command: .performAction,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable("This is test content.\nIt has multiple lines.\nExtract this text.")
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
var jsonData = try encoder.encode(setText)
|
||||
guard let setJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
_ = try runAXORCCommand(arguments: [setJsonString])
|
||||
|
||||
// Extract text
|
||||
let extractCommand = CommandEnvelope(
|
||||
commandId: "test-extract",
|
||||
command: .extractText,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXWindow")]),
|
||||
outputFormat: .textContent
|
||||
)
|
||||
|
||||
jsonData = try encoder.encode(extractCommand)
|
||||
guard let extractJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [extractJsonString])
|
||||
XCTAssertEqual(result.exitCode, 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success, true)
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
// For extract text commands, check for extracted text in attributes
|
||||
if let extractedText = attributes["extractedText"]?.value as? String {
|
||||
XCTAssertTrue(extractedText.contains("This is test content"), "Should extract the test content")
|
||||
XCTAssertTrue(extractedText.contains("multiple lines"), "Should extract multiple lines")
|
||||
} else if let value = attributes["AXValue"]?.value as? String {
|
||||
XCTAssertTrue(value.contains("This is test content"), "Should extract the test content")
|
||||
XCTAssertTrue(value.contains("multiple lines"), "Should extract multiple lines")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testDescribeElementHierarchy() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Describe the application element
|
||||
let command = CommandEnvelope(
|
||||
commandId: "test-describe",
|
||||
command: .describeElement,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXApplication")]),
|
||||
maxElements: 3,
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
let jsonData = try encoder.encode(command)
|
||||
guard let jsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [jsonString])
|
||||
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
XCTAssertNotEqual(response.data , nil)
|
||||
|
||||
// Check hierarchy
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
if let role = attributes["AXRole"]?.value as? String {
|
||||
XCTAssertEqual(role , "AXApplication", "Should find application element")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testSetAndVerifyText() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Set text
|
||||
let setText = CommandEnvelope(
|
||||
commandId: "test-set-text",
|
||||
command: .performAction,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable("Hello from AXorcist tests!")
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
var jsonData = try encoder.encode(setText)
|
||||
guard let setJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
var result = try runAXORCCommand(arguments: [setJsonString])
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
|
||||
// Query to verify
|
||||
let queryText = CommandEnvelope(
|
||||
commandId: "test-query-text",
|
||||
command: .query,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
outputFormat: .verbose
|
||||
)
|
||||
|
||||
jsonData = try encoder.encode(queryText)
|
||||
guard let queryJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
result = try runAXORCCommand(arguments: [queryJsonString])
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
if let value = attributes["AXValue"]?.value as? String {
|
||||
XCTAssertTrue(value.contains("Hello from AXorcist tests!"), "Should find the text we set")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testExtractText() async throws {
|
||||
await closeTextEdit()
|
||||
try await Task.sleep(for: .milliseconds(500))
|
||||
|
||||
_ = try await setupTextEditAndGetInfo()
|
||||
defer {
|
||||
if let app = NSRunningApplication.runningApplications(withBundleIdentifier: "com.apple.TextEdit").first {
|
||||
app.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
try await Task.sleep(for: .seconds(1))
|
||||
|
||||
// Set some text first
|
||||
let setText = CommandEnvelope(
|
||||
commandId: "test-set-for-extract",
|
||||
command: .performAction,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXTextArea")]),
|
||||
actionName: "AXSetValue",
|
||||
actionValue: AnyCodable("This is test content.\nIt has multiple lines.\nExtract this text.")
|
||||
)
|
||||
|
||||
let encoder = JSONEncoder()
|
||||
var jsonData = try encoder.encode(setText)
|
||||
guard let setJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
_ = try runAXORCCommand(arguments: [setJsonString])
|
||||
|
||||
// Extract text
|
||||
let extractCommand = CommandEnvelope(
|
||||
commandId: "test-extract",
|
||||
command: .extractText,
|
||||
application: "TextEdit",
|
||||
debugLogging: true,
|
||||
locator: Locator(criteria: [Criterion(attribute: "AXRole", value: "AXWindow")]),
|
||||
outputFormat: .textContent
|
||||
)
|
||||
|
||||
jsonData = try encoder.encode(extractCommand)
|
||||
guard let extractJsonString = String(data: jsonData, encoding: String.Encoding.utf8) else {
|
||||
throw TestError.generic("Failed to create JSON")
|
||||
}
|
||||
|
||||
let result = try runAXORCCommand(arguments: [extractJsonString])
|
||||
XCTAssertEqual(result.exitCode , 0)
|
||||
|
||||
guard let output = result.output,
|
||||
let responseData = output.data(using: String.Encoding.utf8)
|
||||
else {
|
||||
throw TestError.generic("No output")
|
||||
}
|
||||
|
||||
let response = try JSONDecoder().decode(QueryResponse.self, from: responseData)
|
||||
|
||||
XCTAssertEqual(response.success , true)
|
||||
|
||||
if let data = response.data, let attributes = data.attributes {
|
||||
// For extract text commands, check for extracted text in attributes
|
||||
if let extractedText = attributes["extractedText"]?.value as? String {
|
||||
XCTAssertTrue(extractedText.contains("This is test content"), "Should extract the test content")
|
||||
XCTAssertTrue(extractedText.contains("multiple lines"), "Should extract multiple lines")
|
||||
} else if let value = attributes["AXValue"]?.value as? String {
|
||||
XCTAssertTrue(value.contains("This is test content"), "Should extract the test content")
|
||||
XCTAssertTrue(value.contains("multiple lines"), "Should extract multiple lines")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -5,203 +5,213 @@ import XCTest
|
||||
// MARK: - Ping Command Tests
|
||||
|
||||
class PingIntegrationTests: XCTestCase {
|
||||
func testPingViaStdin() async throws {
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_ping_stdin",
|
||||
"command": "ping",
|
||||
"payload": {
|
||||
"message": "Hello from testPingViaStdin"
|
||||
func testPingViaStdin() async throws {
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_ping_stdin",
|
||||
"command": "ping",
|
||||
"payload": {
|
||||
"message": "Hello from testPingViaStdin"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
let result = try runAXORCCommandWithStdin(
|
||||
inputJSON: inputJSON,
|
||||
arguments: ["--stdin"]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode , 0,
|
||||
Comment(rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
result.errorOutput , nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput!)")
|
||||
)
|
||||
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via STDIN"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for ping via STDIN. Output: \(outputString)")
|
||||
"""
|
||||
let result = try runAXORCCommandWithStdin(
|
||||
inputJSON: inputJSON,
|
||||
arguments: ["--stdin"]
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success , true)
|
||||
XCTAssertEqual(
|
||||
decodedResponse.message , "Ping handled by AXORCCommand. Input source: STDIN",
|
||||
Comment(rawValue: "Unexpected success message: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details , "Hello from testPingViaStdin")
|
||||
}
|
||||
|
||||
func testPingViaFile() async throws {
|
||||
let payloadMessage = "Hello from testPingViaFile"
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_ping_file",
|
||||
"command": "ping",
|
||||
"payload": { "message": "\(payloadMessage)" }
|
||||
}
|
||||
"""
|
||||
let tempFilePath = try createTempFile(content: inputJSON)
|
||||
defer { try? FileManager.default.removeItem(atPath: tempFilePath) }
|
||||
|
||||
let result = try runAXORCCommand(arguments: ["--file", tempFilePath])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode , 0,
|
||||
Comment(rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
result.errorOutput , nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via file"))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for ping via file. Output: \(outputString)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success , true)
|
||||
XCTAssertTrue(
|
||||
decodedResponse.message.lowercased().contains("file: \(tempFilePath.lowercased())"),
|
||||
Comment(rawValue: "Message should contain file path. Got: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details , payloadMessage)
|
||||
}
|
||||
|
||||
func testPingViaDirectPayload() async throws {
|
||||
let payloadMessage = "Hello from testPingViaDirectPayload"
|
||||
let inputJSON =
|
||||
"{\"command_id\":\"test_ping_direct\",\"command\":\"ping\",\"payload\":{\"message\":\"\(payloadMessage)\"}}"
|
||||
|
||||
let result = try runAXORCCommand(arguments: [inputJSON])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode , 0,
|
||||
Comment(rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
XCTAssertEqual(
|
||||
result.errorOutput , nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via direct payload"))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for ping via direct payload. Output: \(outputString)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success , true)
|
||||
XCTAssertTrue(
|
||||
decodedResponse.message.contains("Direct Argument Payload"),
|
||||
Comment(rawValue: "Unexpected success message: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details , payloadMessage)
|
||||
}
|
||||
|
||||
func testErrorMultipleInputMethods() async throws {
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_error_multiple_inputs",
|
||||
"command": "ping",
|
||||
"payload": { "message": "This should not be processed" }
|
||||
}
|
||||
"""
|
||||
let tempFilePath = try createTempFile(content: "{}")
|
||||
defer { try? FileManager.default.removeItem(atPath: tempFilePath) }
|
||||
|
||||
let result = try runAXORCCommandWithStdin(
|
||||
inputJSON: inputJSON,
|
||||
arguments: ["--file", tempFilePath]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode , 0,
|
||||
Comment(rawValue: "axorc command should return 0 with error on stdout. Status: \(result.exitCode). " +
|
||||
"Error STDOUT: \(result.output ?? "nil"). Error STDERR: \(result.errorOutput ?? "nil")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output, !outputString.isEmpty else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil or empty for multiple input methods error test"))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
XCTAssertEqual(
|
||||
result.exitCode, 0,
|
||||
Comment(
|
||||
rawValue: "Failed to convert output to Data for multiple input methods error. Output: \(outputString)"
|
||||
rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")"
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: responseData)
|
||||
XCTAssertEqual(errorResponse.success , false)
|
||||
XCTAssertTrue(
|
||||
errorResponse.error.message.contains("Multiple input flags specified"),
|
||||
Comment(rawValue: "Unexpected error message: \(errorResponse.error.message)")
|
||||
)
|
||||
}
|
||||
|
||||
func testErrorNoInputProvidedForPing() async throws {
|
||||
let result = try runAXORCCommand(arguments: [])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode , 0,
|
||||
Comment(rawValue: "axorc should return 0 with error on stdout. Status: \(result.exitCode). " +
|
||||
"Error STDOUT: \(result.output ?? "nil"). Error STDERR: \(result.errorOutput ?? "nil")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output, !outputString.isEmpty else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil or empty for no input test."))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for no input error. Output: \(outputString)")
|
||||
XCTAssertEqual(
|
||||
result.errorOutput, nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput!)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: responseData)
|
||||
XCTAssertEqual(errorResponse.success , false)
|
||||
XCTAssertEqual(
|
||||
errorResponse.commandId , "input_error",
|
||||
Comment(rawValue: "Expected commandId to be input_error, got \(errorResponse.commandId)")
|
||||
)
|
||||
XCTAssertTrue(
|
||||
errorResponse.error.message.contains("No JSON input method specified"),
|
||||
Comment(rawValue: "Unexpected error message for no input: \(errorResponse.error.message)")
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via STDIN"))
|
||||
return
|
||||
}
|
||||
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for ping via STDIN. Output: \(outputString)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success, true)
|
||||
XCTAssertEqual(
|
||||
decodedResponse.message, "Ping handled by AXORCCommand. Input source: STDIN",
|
||||
Comment(rawValue: "Unexpected success message: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details, "Hello from testPingViaStdin")
|
||||
}
|
||||
|
||||
func testPingViaFile() async throws {
|
||||
let payloadMessage = "Hello from testPingViaFile"
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_ping_file",
|
||||
"command": "ping",
|
||||
"payload": { "message": "\(payloadMessage)" }
|
||||
}
|
||||
"""
|
||||
let tempFilePath = try createTempFile(content: inputJSON)
|
||||
defer { try? FileManager.default.removeItem(atPath: tempFilePath) }
|
||||
|
||||
let result = try runAXORCCommand(arguments: ["--file", tempFilePath])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode, 0,
|
||||
Comment(
|
||||
rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")"
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
result.errorOutput, nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via file"))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for ping via file. Output: \(outputString)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success, true)
|
||||
XCTAssertTrue(
|
||||
decodedResponse.message.lowercased().contains("file: \(tempFilePath.lowercased())"),
|
||||
Comment(rawValue: "Message should contain file path. Got: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details, payloadMessage)
|
||||
}
|
||||
|
||||
func testPingViaDirectPayload() async throws {
|
||||
let payloadMessage = "Hello from testPingViaDirectPayload"
|
||||
let inputJSON =
|
||||
"{\"command_id\":\"test_ping_direct\",\"command\":\"ping\",\"payload\":{\"message\":\"\(payloadMessage)\"}}"
|
||||
|
||||
let result = try runAXORCCommand(arguments: [inputJSON])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode, 0,
|
||||
Comment(
|
||||
rawValue: "axorc command failed with status \(result.exitCode). Error: \(result.errorOutput ?? "N/A")"
|
||||
)
|
||||
)
|
||||
XCTAssertEqual(
|
||||
result.errorOutput, nil || result.errorOutput!.isEmpty,
|
||||
Comment(rawValue: "Expected no error output, but got: \(result.errorOutput ?? "N/A")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil for ping via direct payload"))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(
|
||||
rawValue: "Failed to convert output to Data for ping via direct payload. Output: \(outputString)"
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
let decodedResponse = try JSONDecoder().decode(SimpleSuccessResponse.self, from: responseData)
|
||||
XCTAssertEqual(decodedResponse.success, true)
|
||||
XCTAssertTrue(
|
||||
decodedResponse.message.contains("Direct Argument Payload"),
|
||||
Comment(rawValue: "Unexpected success message: \(decodedResponse.message)")
|
||||
)
|
||||
XCTAssertEqual(decodedResponse.details, payloadMessage)
|
||||
}
|
||||
|
||||
func testErrorMultipleInputMethods() async throws {
|
||||
let inputJSON = """
|
||||
{
|
||||
"command_id": "test_error_multiple_inputs",
|
||||
"command": "ping",
|
||||
"payload": { "message": "This should not be processed" }
|
||||
}
|
||||
"""
|
||||
let tempFilePath = try createTempFile(content: "{}")
|
||||
defer { try? FileManager.default.removeItem(atPath: tempFilePath) }
|
||||
|
||||
let result = try runAXORCCommandWithStdin(
|
||||
inputJSON: inputJSON,
|
||||
arguments: ["--file", tempFilePath]
|
||||
)
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode, 0,
|
||||
Comment(rawValue: "axorc command should return 0 with error on stdout. Status: \(result.exitCode). " +
|
||||
"Error STDOUT: \(result.output ?? "nil"). Error STDERR: \(result.errorOutput ?? "nil")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output, !outputString.isEmpty else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Output was nil or empty for multiple input methods error test")
|
||||
)
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(
|
||||
rawValue: "Failed to convert output to Data for multiple input methods error. Output: \(outputString)"
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: responseData)
|
||||
XCTAssertEqual(errorResponse.success, false)
|
||||
XCTAssertTrue(
|
||||
errorResponse.error.message.contains("Multiple input flags specified"),
|
||||
Comment(rawValue: "Unexpected error message: \(errorResponse.error.message)")
|
||||
)
|
||||
}
|
||||
|
||||
func testErrorNoInputProvidedForPing() async throws {
|
||||
let result = try runAXORCCommand(arguments: [])
|
||||
|
||||
XCTAssertEqual(
|
||||
result.exitCode, 0,
|
||||
Comment(rawValue: "axorc should return 0 with error on stdout. Status: \(result.exitCode). " +
|
||||
"Error STDOUT: \(result.output ?? "nil"). Error STDERR: \(result.errorOutput ?? "nil")")
|
||||
)
|
||||
|
||||
guard let outputString = result.output, !outputString.isEmpty else {
|
||||
XCTAssertTrue(Bool(false), Comment(rawValue: "Output was nil or empty for no input test."))
|
||||
return
|
||||
}
|
||||
guard let responseData = outputString.data(using: String.Encoding.utf8) else {
|
||||
XCTAssertTrue(
|
||||
Bool(false),
|
||||
Comment(rawValue: "Failed to convert output to Data for no input error. Output: \(outputString)")
|
||||
)
|
||||
return
|
||||
}
|
||||
let errorResponse = try JSONDecoder().decode(ErrorResponse.self, from: responseData)
|
||||
XCTAssertEqual(errorResponse.success, false)
|
||||
XCTAssertEqual(
|
||||
errorResponse.commandId, "input_error",
|
||||
Comment(rawValue: "Expected commandId to be input_error, got \(errorResponse.commandId)")
|
||||
)
|
||||
XCTAssertTrue(
|
||||
errorResponse.error.message.contains("No JSON input method specified"),
|
||||
Comment(rawValue: "Unexpected error message for no input: \(errorResponse.error.message)")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user