import Testing import Foundation @testable import CalcPad @Suite("RustCalculationEngine Tests") struct RustEngineTests { let engine = RustCalculationEngine() // MARK: - AC: evaluateLine returns LineResult (not raw pointer) @Test("evaluateLine 2+2 returns LineResult with result 4") func evalLineBasicArithmetic() { let result = engine.evaluateLine("2 + 2") #expect(result.result == "4") #expect(result.isError == false) #expect(result.lineNumber == 1) } @Test("evaluateLine multiplication") func evalLineMultiplication() { let result = engine.evaluateLine("6 * 7") #expect(result.result == "42") #expect(result.isError == false) } @Test("evaluateLine subtraction") func evalLineSubtraction() { let result = engine.evaluateLine("10 - 4") #expect(result.result == "6") #expect(result.isError == false) } @Test("evaluateLine division") func evalLineDivision() { let result = engine.evaluateLine("15 / 3") #expect(result.result == "5") #expect(result.isError == false) } @Test("evaluateLine decimal result") func evalLineDecimal() { let result = engine.evaluateLine("7 / 2") #expect(result.result == "3.5") #expect(result.isError == false) } // MARK: - AC: evaluateSheet returns array of LineResult, one per line @Test("evaluateSheet returns one result per line") func evalSheetMultiLine() { let text = "2 + 2\n\n10 * 3" let results = engine.evaluateSheet(text) #expect(results.count == 3) #expect(results[0].lineNumber == 1) #expect(results[0].result == "4") #expect(results[1].lineNumber == 2) #expect(results[1].result == nil) // blank line #expect(results[2].lineNumber == 3) #expect(results[2].result == "30") } @Test("evaluateSheet with comments and blanks") func evalSheetMixed() { let text = "// Title\n5 + 5\n\n// Section\n3 * 3" let results = engine.evaluateSheet(text) #expect(results.count == 5) #expect(results[0].result == nil) // comment #expect(results[0].isError == false) #expect(results[1].result == "10") #expect(results[2].result == nil) // blank #expect(results[3].result == nil) // comment #expect(results[4].result == "9") } // MARK: - AC: Error handling — errors become LineResult, no crash @Test("Malformed expression returns error LineResult, not crash") func evalLineError() { let result = engine.evaluateLine("2 + + 3") #expect(result.isError == true) #expect(result.result != nil) // has error message #expect(result.result?.starts(with: "Error") == true) } @Test("Completely invalid input returns error, not crash") func evalLineInvalidInput() { let result = engine.evaluateLine("@#$%^&") // Should not crash — either error or some result #expect(result.id == 1) } // MARK: - AC: Blank and comment lines @Test("Blank line returns nil result") func blankLine() { let result = engine.evaluateLine("") #expect(result.result == nil) #expect(result.isError == false) } @Test("Comment with // returns nil result") func commentLine() { let result = engine.evaluateLine("// this is a comment") #expect(result.result == nil) #expect(result.isError == false) } @Test("# is not a comment in Rust engine — treated as identifier lookup") func hashNotComment() { let result = engine.evaluateLine("# header") // The Rust engine does not treat # as a comment. The # is skipped and // "header" is parsed as an identifier, resulting in an undefined variable error. #expect(result.isError == true) } // MARK: - AC: Memory safety — no leaks with repeated calls @Test("Repeated evaluateLine calls don't leak (1000 iterations)") func memoryStressLine() { for i in 0..<1000 { let result = engine.evaluateLine("\(i) + 1") #expect(result.isError == false) } } @Test("Repeated evaluateSheet calls don't leak (100 iterations)") func memoryStressSheet() { let text = (1...10).map { "\($0) * 2" }.joined(separator: "\n") for _ in 0..<100 { let results = engine.evaluateSheet(text) #expect(results.count == 10) } } // MARK: - AC: Thread safety — concurrent calls @Test("Concurrent evaluateLine calls from multiple threads") func threadSafety() async { await withTaskGroup(of: LineResult.self) { group in for i in 0..<50 { group.addTask { engine.evaluateLine("\(i) + 1") } } var count = 0 for await result in group { #expect(result.isError == false) count += 1 } #expect(count == 50) } } // MARK: - AC: Variables shared across sheet lines @Test("evaluateSheet shares variables across lines") func evalSheetVariables() { let text = "x = 10\nx * 2" let results = engine.evaluateSheet(text) #expect(results.count == 2) #expect(results[0].result == "10") #expect(results[1].result == "20") } }