Passing about half of the MathListTest tests. Need to work on copy-related tests.

Currently the copy() is not working.
This commit is contained in:
Michael Griebling
2023-01-09 10:59:07 -05:00
parent aef877099e
commit 04de18e5c9
5 changed files with 679 additions and 64 deletions

View File

@@ -120,7 +120,7 @@ public class MTMathAtomFactory {
return _accentValueToName! return _accentValueToName!
} }
public static var supportedLatexSymbols: [String: MTMathAtom] = [ static var supportedLatexSymbols: [String: MTMathAtom] = [
"square" : MTMathAtomFactory.placeholder(), "square" : MTMathAtomFactory.placeholder(),
// Greek characters // Greek characters
@@ -448,35 +448,16 @@ public class MTMathAtomFactory {
public static func fontNameForStyle(_ fontStyle:MTFontStyle) -> String { public static func fontNameForStyle(_ fontStyle:MTFontStyle) -> String {
switch fontStyle { switch fontStyle {
case .defaultStyle: case .defaultStyle: return "mathnormal"
return "mathnormal"; case .roman: return "mathrm"
case .bold: return "mathbf"
case .roman: case .fraktur: return "mathfrak"
return "mathrm"; case .caligraphic: return "mathcal"
case .italic: return "mathit"
case .bold: case .sansSerif: return "mathsf"
return "mathbf"; case .blackboard: return "mathbb"
case .typewriter: return "mathtt"
case .fraktur: case .boldItalic: return "bm"
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] { 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 == "int" { return MTMathAtomFactory.operatorWithName( "\u{222B}", limits: false) }
if name == "sum" { return MTMathAtomFactory.operatorWithName( "\u{2211}", limits: true) } if name == "sum" { return MTMathAtomFactory.operatorWithName( "\u{2211}", limits: true) }
return atom return atom
@@ -707,6 +689,15 @@ public class MTMathAtomFactory {
@note The reason this function returns a `MTMathAtom` and not a `MTMathTable` is because some @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. 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? { public static func table(withEnvironment env: String?, rows: [[MTMathList]], error:inout NSError?) -> MTMathAtom? {
let table = MTMathTable(environment: env) 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 { if env == nil {
table.interColumnSpacing = 0 table.interColumnSpacing = 0
table.interRowAdditionalSpacing = 1 table.interRowAdditionalSpacing = 1

View File

@@ -341,7 +341,6 @@ public class MTLargeOperator: MTMathAtom {
init(value: String, limits: Bool) { init(value: String, limits: Bool) {
super.init(type: .largeOperator, value: value) super.init(type: .largeOperator, value: value)
self.limits = limits self.limits = limits
//print("Operator \(value) limits:\(limits)")
} }
public override func copy(with zone: NSZone? = nil) -> Any { public override func copy(with zone: NSZone? = nil) -> Any {
@@ -740,7 +739,7 @@ public class MTMathList: NSObject, NSCopying {
if prevNode != nil && prevNode!.type == .binaryOperator { if prevNode != nil && prevNode!.type == .binaryOperator {
prevNode!.type = .unaryOperator prevNode!.type = .unaryOperator
finalizedList.removeLastAtom() finalizedList.removeLastAtom()
finalizedList.add(prevNode!) finalizedList.add(prevNode)
} }
return finalizedList return finalizedList
@@ -758,7 +757,19 @@ public class MTMathList: NSObject, NSCopying {
self.atoms = [] 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) { if self.isAtomAllowed(atom) {
self.atoms.append(atom) self.atoms.append(atom)
} else { } 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) { if self.isAtomAllowed(atom) {
// NSIndexException(self.atoms, index: index)
self.atoms.insert(atom, at: index) self.atoms.insert(atom, at: index)
} else { } else {
NSException(name: NSExceptionName(rawValue: "Error"), reason: "Cannot add atom of type \(atom.type.rawValue) into mathlist").raise() 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 self.atoms += list.atoms
} }
@@ -785,14 +802,17 @@ public class MTMathList: NSObject, NSCopying {
} }
func removeAtom(at index: Int) { func removeAtom(at index: Int) {
NSIndexException(self.atoms, index:index)
self.atoms.remove(at: index) self.atoms.remove(at: index)
} }
func removeAtoms(in range: ClosedRange<Int>) { func removeAtoms(in range: ClosedRange<Int>) {
NSIndexException(self.atoms, index: range.lowerBound)
NSIndexException(self.atoms, index: range.upperBound)
self.atoms.removeSubrange(range) self.atoms.removeSubrange(range)
} }
func isAtomAllowed(_ atom: MTMathAtom) -> Bool { func isAtomAllowed(_ atom: MTMathAtom?) -> Bool {
return atom.type != .boundary return atom?.type != .boundary
} }
} }

View File

@@ -10,7 +10,7 @@ import Foundation
/** `MTMathListBuilder` is a class for parsing LaTeX into an `MTMathList` that /** `MTMathListBuilder` is a class for parsing LaTeX into an `MTMathList` that
can be rendered and processed mathematically. can be rendered and processed mathematically.
*/ */
class MTEnvProperties { struct MTEnvProperties {
var envName: String? var envName: String?
var ended: Bool var ended: Bool
var numRows: Int 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 // this puts us in a recursive routine, and sets oneCharOnly to false and no stop character
let subList = self.buildInternal(false, stopChar: "}") let subList = self.buildInternal(false, stopChar: "}")
prevAtom = subList!.atoms.last prevAtom = subList!.atoms.last
list.append(subList!) list.append(subList)
if oneCharOnly { if oneCharOnly {
return list 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 // (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. // in the odd case that an _error is not set.
self.setError(.internalError, message:"Internal error") self.setError(.internalError, message:"Internal error")
return nil; return nil
} }
} else if char == "&" { } else if char == "&" {
assert(!oneCharOnly, "This should have been handled before") assert(!oneCharOnly, "This should have been handled before")
@@ -446,7 +446,7 @@ public class MTMathListBuilder {
assert(atom != nil, "Atom shouldn't be nil") assert(atom != nil, "Atom shouldn't be nil")
atom?.fontStyle = currentFontStyle atom?.fontStyle = currentFontStyle
list.add(atom!) list.add(atom)
prevAtom = atom prevAtom = atom
if oneCharOnly { if oneCharOnly {

View File

@@ -8,7 +8,7 @@ import XCTest
// Created by Mike Griebling on 2023-01-02. // Created by Mike Griebling on 2023-01-02.
// //
final class SwiftMathRenderTests: XCTestCase { final class MTMathListBuilderTests: XCTestCase {
func checkAtomTypes(_ list:MTMathList?, types:[MTMathAtomType], desc:String) { func checkAtomTypes(_ list:MTMathList?, types:[MTMathAtomType], desc:String) {
if let list = list { if let list = list {
@@ -23,13 +23,13 @@ final class SwiftMathRenderTests: XCTestCase {
} }
} }
override func setUpWithError() throws { // override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class. // // Put setup code here. This method is called before the invocation of each test method in the class.
} // }
//
override func tearDownWithError() throws { // override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class. // // Put teardown code here. This method is called after the invocation of each test method in the class.
} // }
struct TestRecord { struct TestRecord {
let build : String let build : String
@@ -1150,15 +1150,11 @@ final class SwiftMathRenderTests: XCTestCase {
for testCase in data { for testCase in data {
let str = testCase.0 let str = testCase.0
var error : NSError? = nil var error : NSError? = nil
if str == "\\begin{displaylines} x & y \\end{displaylines}" {
let x = 0
}
let list = MTMathListBuilder.build(fromString: str, error:&error) let list = MTMathListBuilder.build(fromString: str, error:&error)
let desc = "Error for string:\(str)" let desc = "Error for string:\(str)"
XCTAssertNil(list, desc) XCTAssertNil(list, desc)
XCTAssertNotNil(error, desc) XCTAssertNotNil(error, desc)
XCTAssertEqual(error!.domain, MTParseError, desc) XCTAssertEqual(error!.domain, MTParseError, desc)
let code = error!.code
let num = testCase.1 let num = testCase.1
XCTAssertEqual(error!.code, num.rawValue, desc) XCTAssertEqual(error!.code, num.rawValue, desc)
} }
@@ -1170,13 +1166,13 @@ final class SwiftMathRenderTests: XCTestCase {
var list = MTMathListBuilder.build(fromString: str, error:&error) var list = MTMathListBuilder.build(fromString: str, error:&error)
XCTAssertNil(list) XCTAssertNil(list)
XCTAssertNotNil(error) XCTAssertNotNil(error)
MTMathAtomFactory.add(latexSymbol: "lcm", value: MTMathAtomFactory.operatorWithName("lcm", limits:false)) MTMathAtomFactory.add(latexSymbol: "lcm", value: MTMathAtomFactory.operatorWithName("lcm", limits:false))
error = nil error = nil
list = MTMathListBuilder.build(fromString: str, error:&error) list = MTMathListBuilder.build(fromString: str, error:&error)
let atomTypes = [MTMathAtomType.largeOperator, .open, .variable, .punctuation, .variable, .close] let atomTypes = [MTMathAtomType.largeOperator, .open, .variable, .punctuation, .variable, .close]
self.checkAtomTypes(list, types:atomTypes, desc:"Error for lcm") self.checkAtomTypes(list, types:atomTypes, desc:"Error for lcm")
// convert it back to latex // convert it back to latex
let latex = MTMathListBuilder.mathListToString(list) let latex = MTMathListBuilder.mathListToString(list)
XCTAssertEqual(latex, "\\lcm (a,b)"); XCTAssertEqual(latex, "\\lcm (a,b)");

View File

@@ -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)
// }
//
}