diff --git a/Sources/SwiftMathRender/MathRender/MTMathAtomFactory.swift b/Sources/SwiftMathRender/MathRender/MTMathAtomFactory.swift index 0bb7fcd..6caabb9 100644 --- a/Sources/SwiftMathRender/MathRender/MTMathAtomFactory.swift +++ b/Sources/SwiftMathRender/MathRender/MTMathAtomFactory.swift @@ -120,7 +120,7 @@ public class MTMathAtomFactory { return _accentValueToName! } - public static var supportedLatexSymbols: [String: MTMathAtom] = [ + static var supportedLatexSymbols: [String: MTMathAtom] = [ "square" : MTMathAtomFactory.placeholder(), // Greek characters @@ -448,35 +448,16 @@ public class MTMathAtomFactory { public static func fontNameForStyle(_ fontStyle:MTFontStyle) -> String { switch fontStyle { - case .defaultStyle: - return "mathnormal"; - - case .roman: - return "mathrm"; - - case .bold: - return "mathbf"; - - case .fraktur: - return "mathfrak"; - - case .caligraphic: - return "mathcal"; - - case .italic: - return "mathit"; - - case .sansSerif: - return "mathsf"; - - case .blackboard: - return "mathbb"; - - case .typewriter: - return "mathtt"; - - case .boldItalic: - return "bm"; + case .defaultStyle: return "mathnormal" + case .roman: return "mathrm" + case .bold: return "mathbf" + case .fraktur: return "mathfrak" + case .caligraphic: return "mathcal" + case .italic: return "mathit" + case .sansSerif: return "mathsf" + case .blackboard: return "mathbb" + case .typewriter: return "mathtt" + case .boldItalic: return "bm" } } @@ -599,6 +580,7 @@ public class MTMathAtomFactory { } if let atom = supportedLatexSymbols[name] { + // FIXME: A kludge - objects should be copied here if name == "int" { return MTMathAtomFactory.operatorWithName( "\u{222B}", limits: false) } if name == "sum" { return MTMathAtomFactory.operatorWithName( "\u{2211}", limits: true) } return atom @@ -707,6 +689,15 @@ public class MTMathAtomFactory { @note The reason this function returns a `MTMathAtom` and not a `MTMathTable` is because some matrix environments are have builtin delimiters added to the table and hence are returned as inner atoms. */ + static let matrixEnvs = [ + "matrix": [], + "pmatrix": ["(", ")"], + "bmatrix": ["[", "]"], + "Bmatrix": ["{", "}"], + "vmatrix": ["vert", "vert"], + "Vmatrix": ["Vert", "Vert"] + ] + public static func table(withEnvironment env: String?, rows: [[MTMathList]], error:inout NSError?) -> MTMathAtom? { let table = MTMathTable(environment: env) @@ -717,15 +708,6 @@ public class MTMathAtomFactory { } } - let matrixEnvs = [ - "matrix": [], - "pmatrix": ["(", ")"], - "bmatrix": ["[", "]"], - "Bmatrix": ["{", "}"], - "vmatrix": ["vert", "vert"], - "Vmatrix": ["Vert", "Vert"] - ] - if env == nil { table.interColumnSpacing = 0 table.interRowAdditionalSpacing = 1 diff --git a/Sources/SwiftMathRender/MathRender/MTMathList.swift b/Sources/SwiftMathRender/MathRender/MTMathList.swift index c63da54..72a3e10 100644 --- a/Sources/SwiftMathRender/MathRender/MTMathList.swift +++ b/Sources/SwiftMathRender/MathRender/MTMathList.swift @@ -341,7 +341,6 @@ public class MTLargeOperator: MTMathAtom { init(value: String, limits: Bool) { super.init(type: .largeOperator, value: value) self.limits = limits - //print("Operator \(value) limits:\(limits)") } public override func copy(with zone: NSZone? = nil) -> Any { @@ -740,7 +739,7 @@ public class MTMathList: NSObject, NSCopying { if prevNode != nil && prevNode!.type == .binaryOperator { prevNode!.type = .unaryOperator finalizedList.removeLastAtom() - finalizedList.add(prevNode!) + finalizedList.add(prevNode) } return finalizedList @@ -758,7 +757,19 @@ public class MTMathList: NSObject, NSCopying { self.atoms = [] } - func add(_ atom: MTMathAtom) { + func NSParamException(_ param:Any?) { + if param == nil { + NSException(name: NSExceptionName(rawValue: "Error"), reason: "Parameter cannot be nil").raise() + } + } + + func NSIndexException(_ array:[Any], index: Int) { + guard !array.indices.contains(index) else { return } + NSException(name: NSExceptionName(rawValue: "Error"), reason: "Index \(index) out of bounds").raise() + } + + func add(_ atom: MTMathAtom?) { + guard let atom = atom else { return } if self.isAtomAllowed(atom) { self.atoms.append(atom) } else { @@ -766,15 +777,21 @@ public class MTMathList: NSObject, NSCopying { } } - func insert(_ atom: MTMathAtom, at index: Int) { + func insert(_ atom: MTMathAtom?, at index: Int) { + // NSParamException(atom) + guard let atom = atom else { return } + guard self.atoms.indices.contains(index) || index == self.atoms.endIndex else { return } + // guard self.atoms.endIndex >= index else { NSIndexException(); return } if self.isAtomAllowed(atom) { + // NSIndexException(self.atoms, index: index) self.atoms.insert(atom, at: index) } else { NSException(name: NSExceptionName(rawValue: "Error"), reason: "Cannot add atom of type \(atom.type.rawValue) into mathlist").raise() } } - func append(_ list: MTMathList) { + func append(_ list: MTMathList?) { + guard let list = list else { return } self.atoms += list.atoms } @@ -785,14 +802,17 @@ public class MTMathList: NSObject, NSCopying { } func removeAtom(at index: Int) { + NSIndexException(self.atoms, index:index) self.atoms.remove(at: index) } func removeAtoms(in range: ClosedRange) { + NSIndexException(self.atoms, index: range.lowerBound) + NSIndexException(self.atoms, index: range.upperBound) self.atoms.removeSubrange(range) } - func isAtomAllowed(_ atom: MTMathAtom) -> Bool { - return atom.type != .boundary + func isAtomAllowed(_ atom: MTMathAtom?) -> Bool { + return atom?.type != .boundary } } diff --git a/Sources/SwiftMathRender/MathRender/MTMathListBuilder.swift b/Sources/SwiftMathRender/MathRender/MTMathListBuilder.swift index b1dcdef..adf76ec 100644 --- a/Sources/SwiftMathRender/MathRender/MTMathListBuilder.swift +++ b/Sources/SwiftMathRender/MathRender/MTMathListBuilder.swift @@ -10,7 +10,7 @@ import Foundation /** `MTMathListBuilder` is a class for parsing LaTeX into an `MTMathList` that can be rendered and processed mathematically. */ -class MTEnvProperties { +struct MTEnvProperties { var envName: String? var ended: Bool var numRows: Int @@ -376,7 +376,7 @@ public class MTMathListBuilder { // this puts us in a recursive routine, and sets oneCharOnly to false and no stop character let subList = self.buildInternal(false, stopChar: "}") prevAtom = subList!.atoms.last - list.append(subList!) + list.append(subList) if oneCharOnly { return list } @@ -425,7 +425,7 @@ public class MTMathListBuilder { // (note setError will not set the error if there is already one, so we flag internal error // in the odd case that an _error is not set. self.setError(.internalError, message:"Internal error") - return nil; + return nil } } else if char == "&" { assert(!oneCharOnly, "This should have been handled before") @@ -446,7 +446,7 @@ public class MTMathListBuilder { assert(atom != nil, "Atom shouldn't be nil") atom?.fontStyle = currentFontStyle - list.add(atom!) + list.add(atom) prevAtom = atom if oneCharOnly { diff --git a/Tests/SwiftMathRenderTests/SwiftMathRenderTests.swift b/Tests/SwiftMathRenderTests/MTMathListBuilderTests.swift similarity index 99% rename from Tests/SwiftMathRenderTests/SwiftMathRenderTests.swift rename to Tests/SwiftMathRenderTests/MTMathListBuilderTests.swift index 9a621c7..72a4162 100644 --- a/Tests/SwiftMathRenderTests/SwiftMathRenderTests.swift +++ b/Tests/SwiftMathRenderTests/MTMathListBuilderTests.swift @@ -8,7 +8,7 @@ import XCTest // Created by Mike Griebling on 2023-01-02. // -final class SwiftMathRenderTests: XCTestCase { +final class MTMathListBuilderTests: XCTestCase { func checkAtomTypes(_ list:MTMathList?, types:[MTMathAtomType], desc:String) { if let list = list { @@ -23,13 +23,13 @@ final class SwiftMathRenderTests: XCTestCase { } } - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } +// override func setUpWithError() throws { +// // Put setup code here. This method is called before the invocation of each test method in the class. +// } +// +// override func tearDownWithError() throws { +// // Put teardown code here. This method is called after the invocation of each test method in the class. +// } struct TestRecord { let build : String @@ -1150,15 +1150,11 @@ final class SwiftMathRenderTests: XCTestCase { for testCase in data { let str = testCase.0 var error : NSError? = nil - if str == "\\begin{displaylines} x & y \\end{displaylines}" { - let x = 0 - } let list = MTMathListBuilder.build(fromString: str, error:&error) let desc = "Error for string:\(str)" XCTAssertNil(list, desc) XCTAssertNotNil(error, desc) XCTAssertEqual(error!.domain, MTParseError, desc) - let code = error!.code let num = testCase.1 XCTAssertEqual(error!.code, num.rawValue, desc) } @@ -1170,13 +1166,13 @@ final class SwiftMathRenderTests: XCTestCase { var list = MTMathListBuilder.build(fromString: str, error:&error) XCTAssertNil(list) XCTAssertNotNil(error) - + MTMathAtomFactory.add(latexSymbol: "lcm", value: MTMathAtomFactory.operatorWithName("lcm", limits:false)) error = nil list = MTMathListBuilder.build(fromString: str, error:&error) let atomTypes = [MTMathAtomType.largeOperator, .open, .variable, .punctuation, .variable, .close] self.checkAtomTypes(list, types:atomTypes, desc:"Error for lcm") - + // convert it back to latex let latex = MTMathListBuilder.mathListToString(list) XCTAssertEqual(latex, "\\lcm (a,b)"); diff --git a/Tests/SwiftMathRenderTests/MTMathListTests.swift b/Tests/SwiftMathRenderTests/MTMathListTests.swift new file mode 100644 index 0000000..7940058 --- /dev/null +++ b/Tests/SwiftMathRenderTests/MTMathListTests.swift @@ -0,0 +1,617 @@ +import XCTest +@testable import SwiftMathRender + +// +// MathRenderSwiftTests.swift +// MathRenderSwiftTests +// +// Created by Mike Griebling on 2023-01-02. +// + +final class MTMathListTests: XCTestCase { + + func testSubScript() throws { + let str = "-52x^{13+y}_{15-} + (-12.3 *)\\frac{-12}{15.2}" + let list = MTMathListBuilder.build(fromString: str)! + let finalized = list.finalized + try self.checkListContents(finalized) + // refinalizing a finalized list should not cause any more changes + try self.checkListContents(finalized.finalized) + } + + func checkListContents(_ finalized:MTMathList) throws { + // check + XCTAssertEqual((finalized.atoms.count), 10, "Num atoms"); + var atom = finalized.atoms[0]; + XCTAssertEqual(atom.type, .unaryOperator, "Atom 0"); + XCTAssertEqual(atom.nucleus, "−", "Atom 0 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(0, 1)), "Range"); + atom = finalized.atoms[1]; + XCTAssertEqual(atom.type, .number, "Atom 1"); + XCTAssertEqual(atom.nucleus, "52", "Atom 1 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(1, 2)), "Range"); + atom = finalized.atoms[2]; + XCTAssertEqual(atom.type, .variable, "Atom 2"); + XCTAssertEqual(atom.nucleus, "x", "Atom 2 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(3, 1)), "Range"); + + let superScr = atom.superScript! + XCTAssertEqual((superScr.atoms.count), 3, "Super script"); + atom = superScr.atoms[0]; + XCTAssertEqual(atom.type, .number, "Super Atom 0"); + XCTAssertEqual(atom.nucleus, "13", "Super Atom 0 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(0, 2)), "Range"); + atom = superScr.atoms[1]; + XCTAssertEqual(atom.type, .binaryOperator, "Super Atom 1"); + XCTAssertEqual(atom.nucleus, "+", "Super Atom 1 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(2, 1)), "Range"); + atom = superScr.atoms[2]; + XCTAssertEqual(atom.type, .variable, "Super Atom 2"); + XCTAssertEqual(atom.nucleus, "y", "Super Atom 2 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(3, 1)), "Range"); + + atom = finalized.atoms[2]; + let subScr = atom.subScript! + XCTAssertEqual((subScr.atoms.count), 2, "Sub script"); + atom = subScr.atoms[0]; + XCTAssertEqual(atom.type, .number, "Sub Atom 0"); + XCTAssertEqual(atom.nucleus, "15", "Sub Atom 0 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(0, 2)), "Range"); + atom = subScr.atoms[1]; + XCTAssertEqual(atom.type, .unaryOperator, "Sub Atom 1"); + XCTAssertEqual(atom.nucleus, "−", "Sub Atom 1 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(2, 1)), "Range"); + + atom = finalized.atoms[3]; + XCTAssertEqual(atom.type, .binaryOperator, "Atom 3"); + XCTAssertEqual(atom.nucleus, "+", "Atom 3 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(4, 1)), "Range"); + atom = finalized.atoms[4]; + XCTAssertEqual(atom.type, .open, "Atom 4"); + XCTAssertEqual(atom.nucleus, "(", "Atom 4 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(5, 1)), "Range"); + atom = finalized.atoms[5]; + XCTAssertEqual(atom.type, .unaryOperator, "Atom 5"); + XCTAssertEqual(atom.nucleus, "−", "Atom 5 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(6, 1)), "Range"); + atom = finalized.atoms[6]; + XCTAssertEqual(atom.type, .number, "Atom 6"); + XCTAssertEqual(atom.nucleus, "12.3", "Atom 6 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(7, 4)), "Range"); + atom = finalized.atoms[7]; + XCTAssertEqual(atom.type, .unaryOperator, "Atom 7"); + XCTAssertEqual(atom.nucleus, "*", "Atom 7 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(11, 1)), "Range"); + atom = finalized.atoms[8]; + XCTAssertEqual(atom.type, .close, "Atom 8"); + XCTAssertEqual(atom.nucleus, ")", "Atom 8 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(12, 1)), "Range"); + + let frac = finalized.atoms[9] as! MTFraction + XCTAssertEqual(frac.type, .fraction, "Atom 9"); + XCTAssertEqual(frac.nucleus, "", "Atom 9 value"); + XCTAssertTrue(NSEqualRanges(frac.indexRange, NSMakeRange(13, 1)), "Range"); + + let numer = frac.numerator! + XCTAssertNotNil(numer, "Numerator"); + XCTAssertEqual((numer.atoms.count), 2, "Numer script"); + atom = numer.atoms[0]; + XCTAssertEqual(atom.type, .unaryOperator, "Numer Atom 0"); + XCTAssertEqual(atom.nucleus, "−", "Numer Atom 0 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(0, 1)), "Range"); + atom = numer.atoms[1]; + XCTAssertEqual(atom.type, .number, "Numer Atom 1"); + XCTAssertEqual(atom.nucleus, "12", "Numer Atom 1 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(1, 2)), "Range"); + + + let denom = frac.denominator! + XCTAssertNotNil(denom, "Denominator"); + XCTAssertEqual((denom.atoms.count), 1, "Denom script"); + atom = denom.atoms[0]; + XCTAssertEqual(atom.type, .number, "Denom Atom 0"); + XCTAssertEqual(atom.nucleus, "15.2", "Denom Atom 0 value"); + XCTAssertTrue(NSEqualRanges(atom.indexRange, NSMakeRange(0, 4)), "Range"); + + } + + func testAdd() throws { + let list = MTMathList() + XCTAssertEqual(list.atoms.count, 0); + let atom = MTMathAtomFactory.placeholder() + list.add(atom) + XCTAssertEqual(list.atoms.count, 1); + XCTAssertEqual(list.atoms[0], atom); + let atom2 = MTMathAtomFactory.placeholder() + list.add(atom2); + XCTAssertEqual(list.atoms.count, 2); + XCTAssertEqual(list.atoms[0], atom); + XCTAssertEqual(list.atoms[1], atom2); + } + + private var options : XCTExpectedFailure.Options { + let op = XCTExpectedFailure.Options() + op.isStrict = true + return op + } + + func testAddErrors() throws { + let list = MTMathList() + var atom : MTMathAtom? = nil + list.add(atom) + atom = MTMathAtom.atom(withType: .boundary, value: "") + XCTExpectFailure("Test adding an illegal atom", options:options) { + XCTAssertThrowsError(list.add(atom)) + } + } + + func testInsert() throws { + let list = MTMathList() + XCTAssertEqual(list.atoms.count, 0); + let atom = MTMathAtomFactory.placeholder() + list.insert(atom, at: 0) + XCTAssertEqual(list.atoms.count, 1); + XCTAssertEqual(list.atoms[0], atom); + let atom2 = MTMathAtomFactory.placeholder() + list.insert(atom2, at: 0) + XCTAssertEqual(list.atoms.count, 2); + XCTAssertEqual(list.atoms[0], atom2); + XCTAssertEqual(list.atoms[1], atom); + let atom3 = MTMathAtomFactory.placeholder() + list.insert(atom3, at: 2) + XCTAssertEqual(list.atoms.count, 3); + XCTAssertEqual(list.atoms[0], atom2); + XCTAssertEqual(list.atoms[1], atom); + XCTAssertEqual(list.atoms[2], atom3); + } + + func testInsertErrors() throws { + let list = MTMathList() + var atom : MTMathAtom? = nil + list.insert(atom, at: 0) + atom = MTMathAtom.atom(withType: .boundary, value:"") + XCTExpectFailure("Test adding an illegal atom", options:options) { + XCTAssertThrowsError(list.insert(atom, at:0)) + } + atom = MTMathAtomFactory.placeholder() + list.insert(atom, at:1) + } + + func testAppend() throws { + let list1 = MTMathList() + let atom = MTMathAtomFactory.placeholder() + let atom2 = MTMathAtomFactory.placeholder() + let atom3 = MTMathAtomFactory.placeholder() + list1.add(atom) + list1.add(atom2) + list1.add(atom3) + + let list2 = MTMathList() + let atom5 = MTMathAtomFactory.times() + let atom6 = MTMathAtomFactory.divide() + list2.add(atom5) + list2.add(atom6) + + XCTAssertEqual(list1.atoms.count, 3); + XCTAssertEqual(list2.atoms.count, 2); + + list1.append(list2) + XCTAssertEqual(list1.atoms.count, 5); + XCTAssertEqual(list1.atoms[3], atom5); + XCTAssertEqual(list1.atoms[4], atom6); + } + + func testRemoveLast() throws { + let list = MTMathList() + let atom = MTMathAtomFactory.placeholder() + list.add(atom) + XCTAssertEqual(list.atoms.count, 1); + list.removeLastAtom() + XCTAssertEqual(list.atoms.count, 0); + // Removing from empty list. + list.removeLastAtom() + XCTAssertEqual(list.atoms.count, 0); + let atom2 = MTMathAtomFactory.placeholder() + list.add(atom) + list.add(atom2); + XCTAssertEqual(list.atoms.count, 2); + list.removeLastAtom() + XCTAssertEqual(list.atoms.count, 1); + XCTAssertEqual(list.atoms[0], atom); + } + + func testRemoveAtomAtIndex() throws { + let list = MTMathList() + let atom = MTMathAtomFactory.placeholder() + let atom2 = MTMathAtomFactory.placeholder() + list.add(atom) + list.add(atom2); + XCTAssertEqual(list.atoms.count, 2); + list.removeAtom(at:0) + XCTAssertEqual(list.atoms.count, 1); + XCTAssertEqual(list.atoms[0], atom2); + + // Index out of range + XCTExpectFailure("Test removing an out-of-index cell", options: options) { + XCTAssertThrowsError(list.removeAtom(at:2)) + } + } + + func testRemoveAtomsInRange() throws { + let list = MTMathList() + let atom = MTMathAtomFactory.placeholder() + let atom2 = MTMathAtomFactory.placeholder() + let atom3 = MTMathAtomFactory.placeholder() + list.add(atom) + list.add(atom2); + list.add(atom3) + XCTAssertEqual(list.atoms.count, 3) + list.removeAtoms(in: 1...2) + XCTAssertEqual(list.atoms.count, 1); + XCTAssertEqual(list.atoms[0], atom); + + // Index out of range + XCTExpectFailure("Test removing an out-of-bounds range", options: options) { + XCTAssertThrowsError(list.removeAtoms(in: 1...3)) + } + } + +// func MTAssertEqual(test, expression1, expression2, ...) \ +// _XCTPrimitiveAssertEqual(test, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) +// +// func MTAssertNotEqual(test, expression1, expression2, ...) \ +// _XCTPrimitiveAssertNotEqual(test, expression1, @#expression1, expression2, @#expression2, __VA_ARGS__) + +// func checkAtomCopy(_ copy:MTMathAtom, original:MTMathAtom, forTest test:XCTestCase?) throws { +// MTAssertEqual(test, copy.type, original.type); +// MTAssertEqual(test, copy.nucleus, original.nucleus); +// // Deep copy +// MTAssertNotEqual(test, copy, original); +// } +// +// func checkListCopy(_ copy:MTMathList, original:MTMathList, forTest test:XCTestCase?) throws { +// MTAssertEqual(test, copy.atoms.count, original.atoms.count) +// for (i, copyAtom) in copy.atoms.enumerated() { +// let origAtom = original.atoms[i]; +// try self.checkAtomCopy(copyAtom, original:origAtom, forTest:test) +// } +// } +// +// func testCopy() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = list.copy() +// checkListCopy(list2, original:list, forTest:self) +// } +// +// func testAtomInit() throws { +// var atom = MTMathAtom.atom(withType: .open, value:"(") +// XCTAssertEqual(atom.nucleus, "("); +// XCTAssertEqual(atom.type, .open); +// +// atom = MTMathAtom.atom(withType: .radical, value:"(") +// XCTAssertEqual(atom.nucleus, ""); +// XCTAssertEqual(atom.type, .radical); +// } +// +// func testAtomScripts() throws { +// var atom = MTMathAtom.atom(withType: .open, value:"(") +// XCTAssertTrue(atom.isScriptAllowed()) +// atom.subScript = MTMathList() +// XCTAssertNotNil(atom.subScript); +// atom.superScript = MTMathList() +// XCTAssertNotNil(atom.superScript); +// +// atom = MTMathAtom.atom(withType: .boundary, value:"(") +// XCTAssertFalse(atom.isScriptAllowed()); +// // Can set to nil +// atom.subScript = nil; +// XCTAssertNil(atom.subScript); +// atom.superScript = nil; +// XCTAssertNil(atom.superScript); +// // Can't set to value +// let list = MTMathList() +// XCTAssertThrowsError(atom.subScript = list); +// XCTAssertThrowsError(atom.superScript = list); +// } +// +// func testAtomCopy() throws { +// let list = MTMathList() +// let atom1 = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom1) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = MTMathList() +// list2.add(atom3) +// list2.add(atom2) +// +// let atom = MTMathAtom.atom(withType: .open, value:"(") +// atom.subScript = list; +// atom.superScript = list2; +// let copy = atom.copy() +// +// checkAtomCopy(copy, original:atom, forTest:self) +// checkListCopy(copy.superScript, original:atom.superScript, forTest:self) +// checkListCopy(copy.subScript, original:atom.subScript, forTest:self) +// } +// +// func testCopyFraction() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = MTMathList() +// list2.add(atom3) +// list2.add(atom2) +// +// let frac = MTFraction(hasRule: false) +// XCTAssertEqual(frac.type, .fraction); +// frac.numerator = list; +// frac.denominator = list2; +// frac.leftDelimiter = "a"; +// frac.rightDelimiter = "b"; +// +// let copy = frac.copy() as! MTFraction +// try checkAtomCopy(copy, original:frac, forTest:self) +// checkListCopy(copy.numerator, original:frac.numerator, forTest:self) +// checkListCopy(copy.denominator, original:frac.denominator, forTest:self) +// XCTAssertFalse(copy.hasRule) +// XCTAssertEqual(copy.leftDelimiter, "a"); +// XCTAssertEqual(copy.rightDelimiter, "b"); +// } +// +// func testCopyRadical() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = MTMathList() +// list2.add(atom3) +// list2.add(atom2) +// +// let rad = [[MTRadical alloc] init) +// XCTAssertEqual(rad.type, kMTMathAtomRadical); +// rad.radicand = list; +// rad.degree = list2; +// +// let copy = [rad copy) +// checkAtomCopy(copy original:rad forTest:self) +// checkListCopy(copy.radicand original:rad.radicand forTest:self) +// checkListCopy(copy.degree original:rad.degree forTest:self) +// } +// +// func testCopyLargeOperator() throws { +// let lg = [[MTLargeOperator alloc] initWithValue:"lim" limits:true) +// XCTAssertEqual(lg.type, kMTMathAtomLargeOperator); +// XCTAssertTrue(lg.limits); +// +// let copy = [lg copy) +// checkAtomCopy(copy original:lg forTest:self) +// XCTAssertEqual(copy.limits, lg.limits); +// } +// func testCopyInner() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let inner = MTInner() +// inner.innerList = list; +// inner.leftBoundary = MTMathAtom.atom(withType: .boundary, value: "(") +// inner.rightBoundary = MTMathAtom.atom(withType: .boundary, value:")") +// XCTAssertEqual(inner.type, .inner); +// +// let copy = [inner copy) +// checkAtomCopy(copy original:inner forTest:self) +// checkListCopy(copy.innerList original:inner.innerList forTest:self) +// checkAtomCopy(copy.leftBoundary original:inner.leftBoundary forTest:self) +// checkAtomCopy(copy.rightBoundary original:inner.rightBoundary forTest:self) +// } +// +// func testSetInnerBoundary() throws { +// let inner = MTInner() +// +// // Can set non-nil +// inner.leftBoundary = MTMathAtom.atom(withType: .boundary, value:"(") +// inner.rightBoundary = MTMathAtom.atom(withType: .boundary, value:")") +// XCTAssertNotNil(inner.leftBoundary); +// XCTAssertNotNil(inner.rightBoundary); +// // Can set nil +// inner.leftBoundary = nil; +// inner.rightBoundary = nil; +// XCTAssertNil(inner.leftBoundary); +// XCTAssertNil(inner.rightBoundary); +// // Can't set non boundary +// let atom = MTMathAtomFactory.placeholder() +// XCTAssertThrowsError(inner.leftBoundary = atom); +// XCTAssertThrowsError(inner.rightBoundary = atom); +// } +// +// func testCopyOverline() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let over = MTOverLine() +// XCTAssertEqual(over.type, .overline); +// over.innerList = list; +// +// let copy = [over copy) +// checkAtomCopy(copy original:over forTest:self) +// checkListCopy(copy.innerList original:over.innerList forTest:self) +// } +// +// func testCopyUnderline() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let under = MTUnderLine() +// XCTAssertEqual(under.type, .underline); +// under.innerList = list; +// +// let copy = [under copy) +// checkAtomCopy(copy, original:under, forTest:self) +// checkListCopy(copy.innerList original:under.innerList forTest:self) +// } +// +// func testCopyAcccent() throws { +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let accent = [[MTAccent alloc] initWithValue:"^") +// XCTAssertEqual(accent.type, kMTMathAtomAccent); +// accent.innerList = list; +// +// let copy = [accent copy) +// checkAtomCopy(copy original:accent forTest:self) +// checkListCopy(copy.innerList original:accent.innerList forTest:self) +// } +// +// func testCopySpace() throws { +// let space = MTMathSpace(space: 3) +// XCTAssertEqual(space.type, .space); +// +// let copy = [space copy) +// checkAtomCopy(copy, original:space, forTest:self) +// XCTAssertEqual(space.space, copy.space); +// } +// +// func testCopyStyle() throws { +// let style = MTMathStyle(style: .script) +// XCTAssertEqual(style.type, .style); +// +// let copy = style.copy() as! MTMathStyle +// checkAtomCopy(copy, original:style, forTest:self) +// XCTAssertEqual(style.style, copy.style); +// } +// +// func testCreateMathTable() throws { +// let table = MTMathTable() +// XCTAssertEqual(table.type, .table); +// +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = MTMathList() +// list2.add(atom3) +// list2.add(atom2) +// +// table.set(cell: list, forRow:3, column:2) +// table.set(cell: list2, forRow:1, column:0) +// +// table.set(alignment: .left, forColumn: 2) +// table.set(alignment: .right, forColumn:1) +// +// // Verify that everything is created correctly +// XCTAssertEqual(table.cells.count, 4); // 4 rows +// XCTAssertNotNil(table.cells[0]); +// XCTAssertEqual(table.cells[0].count, 0); // 0 elements in row 0 +// XCTAssertEqual(table.cells[1].count, 1); // 1 element in row 1 +// XCTAssertNotNil(table.cells[2]); +// XCTAssertEqual(table.cells[2].count, 0); +// XCTAssertEqual(table.cells[3].count, 3); +// +// // Verify the elements in the rows +// XCTAssertEqual(table.cells[1][0].atoms.count, 2); +// XCTAssertEqual(table.cells[1][0], list2); +// XCTAssertNotNil(table.cells[3][0]); +// XCTAssertEqual(table.cells[3][0].atoms.count, 0); +// +// XCTAssertNotNil(table.cells[3][0]); +// XCTAssertEqual(table.cells[3][0].atoms.count, 0); +// +// XCTAssertNotNil(table.cells[3][1]); +// XCTAssertEqual(table.cells[3][1].atoms.count, 0); +// +// XCTAssertEqual(table.cells[3][2], list); +// +// XCTAssertEqual(table.numRows, 4); +// XCTAssertEqual(table.numColumns, 3); +// +// // Verify the alignments +// XCTAssertEqual(table.alignments.count, 3); +// XCTAssertEqual(table.alignments[0], .center); +// XCTAssertEqual(table.alignments[1], .right); +// XCTAssertEqual(table.alignments[2], .left); +// } +// +// func testCopyMathTable() throws { +// let table = MTMathTable() +// XCTAssertEqual(table.type, .table); +// +// let list = MTMathList() +// let atom = MTMathAtomFactory.placeholder() +// let atom2 = MTMathAtomFactory.times() +// let atom3 = MTMathAtomFactory.divide() +// list.add(atom) +// list.add(atom2); +// list.add(atom3) +// +// let list2 = MTMathList() +// list2.add(atom3) +// list2.add(atom2) +// +// table.set(cell:list, forRow:0, column:1) +// table.set(cell:list2, forRow:0, column:2) +// +// table.set(alignment: .left, forColumn:2) +// table.set(alignment: .right, forColumn:1) +// table.interRowAdditionalSpacing = 3; +// table.interColumnSpacing = 10; +// +// let copy = table.copy() as! MTMathTable +// try checkAtomCopy(copy, original:table, forTest:self) +// XCTAssertEqual(copy.interColumnSpacing, table.interColumnSpacing); +// XCTAssertEqual(copy.interRowAdditionalSpacing, table.interRowAdditionalSpacing); +// XCTAssertEqual(copy.alignments, table.alignments); +// XCTAssertNotEqual(copy.alignments, table.alignments); +// +// XCTAssertNotEqual(copy.cells, table.cells); +// XCTAssertNotEqual(copy.cells[0], table.cells[0]); +// XCTAssertEqual(copy.cells[0].count, table.cells[0].count); +// XCTAssertEqual(copy.cells[0][0].atoms.count, 0); +// XCTAssertNotEqual(copy.cells[0][0], table.cells[0][0]); +// try checkListCopy(copy.cells[0][1], original:list, forTest:self) +// try checkListCopy(copy.cells[0][2], original:list2, forTest:self) +// } +// +}