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!
}
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

View File

@@ -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<Int>) {
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
}
}

View File

@@ -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 {

View File

@@ -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)");

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