1577 lines
72 KiB
Swift
Executable File
1577 lines
72 KiB
Swift
Executable File
import XCTest
|
||
@testable import SwiftMath
|
||
|
||
//
|
||
// MathTypesetterTests.swift
|
||
// MathTypesetterTests
|
||
//
|
||
// Created by Mike Griebling on 2023-01-02.
|
||
//
|
||
|
||
extension CGPoint {
|
||
|
||
func isEqual(to p:CGPoint, accuracy:CGFloat) -> Bool {
|
||
abs(self.x - p.x) < accuracy && abs(self.y - p.y) < accuracy
|
||
}
|
||
|
||
}
|
||
|
||
final class MTTypesetterTests: XCTestCase {
|
||
|
||
var font:MTFont!
|
||
|
||
override func setUpWithError() throws {
|
||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||
try super.setUpWithError()
|
||
self.font = MTFontManager.fontManager.defaultFont
|
||
}
|
||
|
||
override func tearDownWithError() throws {
|
||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
||
try super.tearDownWithError()
|
||
}
|
||
|
||
func testSimpleVariable() throws {
|
||
let mathList = MTMathList()
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay)
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, line.ascent);
|
||
XCTAssertEqual(display.descent, line.descent);
|
||
XCTAssertEqual(display.width, line.width);
|
||
|
||
XCTAssertEqual(display.ascent, 8.834, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 0.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 11.44, accuracy: 0.01)
|
||
}
|
||
|
||
func testMultipleVariables() throws {
|
||
let mathList = MTMathAtomFactory.mathListForCharacters("xyzw")
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 4)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 4);
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥𝑦𝑧𝑤");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 4)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, line.ascent);
|
||
XCTAssertEqual(display.descent, line.descent);
|
||
XCTAssertEqual(display.width, line.width);
|
||
|
||
XCTAssertEqual(display.ascent, 8.834, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.10, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 44.86, accuracy: 0.01)
|
||
}
|
||
|
||
func testVariablesAndNumbers() throws {
|
||
let mathList = MTMathAtomFactory.mathListForCharacters("xy2w")
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular)
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 4)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript)
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 4);
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥𝑦2𝑤");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 4)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, line.ascent);
|
||
XCTAssertEqual(display.descent, line.descent);
|
||
XCTAssertEqual(display.width, line.width);
|
||
|
||
XCTAssertEqual(display.ascent, 13.32, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.10, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 45.56, accuracy: 0.01)
|
||
}
|
||
|
||
func testEquationWithOperatorsAndRelations() throws {
|
||
let mathList = MTMathAtomFactory.mathListForCharacters("2x+3=y")
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 6)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 6);
|
||
XCTAssertEqual(line.attributedString?.string, "2𝑥+3=𝑦");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 6)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, line.ascent);
|
||
XCTAssertEqual(display.descent, line.descent);
|
||
XCTAssertEqual(display.width, line.width);
|
||
|
||
XCTAssertEqual(display.ascent, 13.32, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.10, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 92.36, accuracy: 0.01)
|
||
}
|
||
|
||
// #define XCTAssertTrue(CGPointEqualToPoint(p1, p2, accuracy, ...) \
|
||
// XCTAssertEqual(p1.x, p2.x, accuracy, __VA_ARGS__); \
|
||
// XCTAssertEqual(p1.y, p2.y, accuracy, __VA_ARGS__)
|
||
//
|
||
//
|
||
// #define XCTAssertTrue(NSEqualRanges(r1, r2, ...) \
|
||
// XCTAssertEqual(r1.location, r2.location, __VA_ARGS__); \
|
||
// XCTAssertEqual(r1.length, r2.length, __VA_ARGS__)
|
||
|
||
func testSuperscript() throws {
|
||
let mathList = MTMathList()
|
||
let x = MTMathAtomFactory.atom(forCharacter: "x")
|
||
let supersc = MTMathList()
|
||
supersc.add(MTMathAtomFactory.atom(forCharacter: "2"))
|
||
x?.superScript = supersc;
|
||
mathList.add(x)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTMathListDisplay)
|
||
let display2 = sub1 as! MTMathListDisplay
|
||
XCTAssertEqual(display2.type, .superscript)
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(11.44, 7.26)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, 0);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let sub1sub0 = display2.subDisplays[0];
|
||
XCTAssertTrue(sub1sub0 is MTCTLineDisplay);
|
||
let line2 = sub1sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "2");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 16.584, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 0.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 18.44, accuracy: 0.01)
|
||
}
|
||
|
||
func testSubscript() throws {
|
||
let mathList = MTMathList()
|
||
let x = MTMathAtomFactory.atom(forCharacter: "x")
|
||
let subsc = MTMathList()
|
||
subsc.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
x?.subScript = subsc
|
||
mathList.add(x)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTMathListDisplay);
|
||
let display2 = sub1 as! MTMathListDisplay
|
||
XCTAssertEqual(display2.type, .ssubscript);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(11.44, -4.94)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, 0);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let sub1sub0 = display2.subDisplays[0];
|
||
XCTAssertTrue(sub1sub0 is MTCTLineDisplay);
|
||
let line2 = sub1sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 8.834, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.940, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 18.44, accuracy: 0.01)
|
||
}
|
||
|
||
func testSupersubscript() throws {
|
||
let mathList = MTMathList()
|
||
let x = MTMathAtomFactory.atom(forCharacter: "x")
|
||
let supersc = MTMathList()
|
||
supersc.add(MTMathAtomFactory.atom(forCharacter: "2"))
|
||
let subsc = MTMathList()
|
||
subsc.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
x?.subScript = subsc;
|
||
x?.superScript = supersc;
|
||
mathList.add(x)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 3);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTMathListDisplay);
|
||
let display2 = sub1 as! MTMathListDisplay
|
||
XCTAssertEqual(display2.type, .superscript);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(11.44, 7.26)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, 0);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let sub1sub0 = display2.subDisplays[0];
|
||
XCTAssertTrue(sub1sub0 is MTCTLineDisplay);
|
||
let line2 = sub1sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "2");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let sub2 = display.subDisplays[2];
|
||
XCTAssertTrue(sub2 is MTMathListDisplay);
|
||
let display3 = sub2 as! MTMathListDisplay
|
||
XCTAssertEqual(display3.type, .ssubscript);
|
||
// Positioned differently when both subscript and superscript present.
|
||
XCTAssertTrue(CGPointEqualToPoint(display3.position, CGPointMake(11.44, -5.264)))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, 0);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let sub2sub0 = display3.subDisplays[0];
|
||
XCTAssertTrue(sub2sub0 is MTCTLineDisplay)
|
||
let line3 = sub2sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 16.584, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 5.264, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 18.44, accuracy: 0.01)
|
||
}
|
||
|
||
func testRadical() throws {
|
||
let mathList = MTMathList()
|
||
let rad = MTRadical()
|
||
let radicand = MTMathList()
|
||
radicand.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
rad.radicand = radicand;
|
||
mathList.add(rad)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTRadicalDisplay);
|
||
let radical = sub0 as! MTRadicalDisplay
|
||
XCTAssertTrue(NSEqualRanges(radical.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(radical.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(radical.position, CGPointZero));
|
||
XCTAssertNotNil(radical.radicand);
|
||
XCTAssertNil(radical.degree);
|
||
|
||
let display2 = radical.radicand!
|
||
XCTAssertEqual(display2.type, .regular)
|
||
XCTAssertTrue(CGPointMake(16.66, 0).isEqual(to: display2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subrad = display2.subDisplays[0];
|
||
XCTAssertTrue(subrad is MTCTLineDisplay);
|
||
let line2 = subrad as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 19.34, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 1.46, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 26.66, accuracy: 0.01)
|
||
}
|
||
|
||
func testRadicalWithDegree() throws {
|
||
let mathList = MTMathList()
|
||
let rad = MTRadical()
|
||
let radicand = MTMathList()
|
||
radicand.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
let degree = MTMathList()
|
||
degree.add(MTMathAtomFactory.atom(forCharacter: "3"))
|
||
rad.radicand = radicand;
|
||
rad.degree = degree;
|
||
mathList.add(rad)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTRadicalDisplay);
|
||
let radical = sub0 as! MTRadicalDisplay
|
||
XCTAssertTrue(NSEqualRanges(radical.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(radical.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(radical.position, CGPointZero));
|
||
XCTAssertNotNil(radical.radicand);
|
||
XCTAssertNotNil(radical.degree);
|
||
|
||
let display2 = radical.radicand!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(16.66, 0)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subrad = display2.subDisplays[0];
|
||
XCTAssertTrue(subrad is MTCTLineDisplay);
|
||
let line2 = subrad as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let display3 = radical.degree!
|
||
XCTAssertEqual(display3.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display3.position, CGPointMake(6.12, 10.728)))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, NSNotFound);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let subdeg = display3.subDisplays[0];
|
||
XCTAssertTrue(subdeg is MTCTLineDisplay);
|
||
let line3 = subdeg as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "3");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 19.34, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 1.46, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 26.66, accuracy: 0.01)
|
||
}
|
||
|
||
func testFraction() throws {
|
||
let mathList = MTMathList()
|
||
let frac = MTFraction(hasRule: true)
|
||
let num = MTMathList()
|
||
num.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
let denom = MTMathList()
|
||
denom.add(MTMathAtomFactory.atom(forCharacter: "3"))
|
||
frac.numerator = num;
|
||
frac.denominator = denom;
|
||
mathList.add(frac)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTFractionDisplay)
|
||
let fraction = sub0 as! MTFractionDisplay
|
||
XCTAssertTrue(NSEqualRanges(fraction.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(fraction.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(fraction.position, CGPointZero));
|
||
XCTAssertNotNil(fraction.numerator);
|
||
XCTAssertNotNil(fraction.denominator);
|
||
|
||
let display2 = fraction.numerator!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(0, 13.54)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subnum = display2.subDisplays[0];
|
||
XCTAssertTrue(subnum is MTCTLineDisplay)
|
||
let line2 = subnum as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let display3 = fraction.denominator!
|
||
XCTAssertEqual(display3.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display3.position, CGPointMake(0, -13.72)))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, NSNotFound);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let subdenom = display3.subDisplays[0];
|
||
XCTAssertTrue(subdenom is MTCTLineDisplay);
|
||
let line3 = subdenom as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "3");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 26.86, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 14.16, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 10, accuracy: 0.01)
|
||
}
|
||
|
||
func testAtop() throws {
|
||
let mathList = MTMathList()
|
||
let frac = MTFraction(hasRule: false)
|
||
let num = MTMathList()
|
||
num.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
let denom = MTMathList()
|
||
denom.add(MTMathAtomFactory.atom(forCharacter: "3"))
|
||
frac.numerator = num;
|
||
frac.denominator = denom;
|
||
mathList.add(frac)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTFractionDisplay)
|
||
let fraction = sub0 as! MTFractionDisplay
|
||
XCTAssertTrue(NSEqualRanges(fraction.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(fraction.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(fraction.position, CGPointZero));
|
||
XCTAssertNotNil(fraction.numerator);
|
||
XCTAssertNotNil(fraction.denominator);
|
||
|
||
let display2 = fraction.numerator!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointMake(0, 13.54)))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subnum = display2.subDisplays[0];
|
||
XCTAssertTrue(subnum is MTCTLineDisplay);
|
||
let line2 = subnum as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let display3 = fraction.denominator!
|
||
XCTAssertEqual(display3.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display3.position, CGPointMake(0, -13.72)))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, NSNotFound);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let subdenom = display3.subDisplays[0];
|
||
XCTAssertTrue(subdenom is MTCTLineDisplay);
|
||
let line3 = subdenom as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "3");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 26.86, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 14.16, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 10, accuracy: 0.01)
|
||
}
|
||
|
||
func testBinomial() throws {
|
||
let mathList = MTMathList()
|
||
let frac = MTFraction(hasRule: false)
|
||
let num = MTMathList()
|
||
num.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
let denom = MTMathList()
|
||
denom.add(MTMathAtomFactory.atom(forCharacter: "3"))
|
||
frac.numerator = num;
|
||
frac.denominator = denom;
|
||
frac.leftDelimiter = "(";
|
||
frac.rightDelimiter = ")";
|
||
mathList.add(frac)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTMathListDisplay);
|
||
let display0 = sub0 as! MTMathListDisplay
|
||
XCTAssertNotNil(display0);
|
||
XCTAssertEqual(display0.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display0.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display0.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display0.hasScript);
|
||
XCTAssertEqual(display0.index, NSNotFound);
|
||
XCTAssertEqual(display0.subDisplays.count, 3);
|
||
|
||
let subLeft = display0.subDisplays[0];
|
||
XCTAssertTrue(subLeft is MTGlyphDisplay);
|
||
let glyph = subLeft;
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(NSNotFound, 0)));
|
||
XCTAssertFalse(glyph.hasScript);
|
||
|
||
let subFrac = display0.subDisplays[1];
|
||
XCTAssertTrue(subFrac is MTFractionDisplay)
|
||
let fraction = subFrac as! MTFractionDisplay
|
||
XCTAssertTrue(NSEqualRanges(fraction.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(fraction.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(fraction.position, CGPointMake(14.72, 0)))
|
||
XCTAssertNotNil(fraction.numerator);
|
||
XCTAssertNotNil(fraction.denominator);
|
||
|
||
let display2 = fraction.numerator!
|
||
XCTAssertEqual(display2.type, .regular)
|
||
XCTAssertTrue(CGPointMake(14.72, 13.54).isEqual(to: display2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subnum = display2.subDisplays[0];
|
||
XCTAssertTrue(subnum is MTCTLineDisplay);
|
||
let line2 = subnum as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let display3 = fraction.denominator!
|
||
XCTAssertEqual(display3.type, .regular)
|
||
XCTAssertTrue(CGPointMake(14.72, -13.72).isEqual(to: display3.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, NSNotFound);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let subdenom = display3.subDisplays[0];
|
||
XCTAssertTrue(subdenom is MTCTLineDisplay);
|
||
let line3 = subdenom as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "3");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
let subRight = display0.subDisplays[2];
|
||
XCTAssertTrue(subRight is MTGlyphDisplay);
|
||
let glyph2 = subRight as! MTGlyphDisplay
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph2.position, CGPointMake(24.72, 0)))
|
||
XCTAssertTrue(NSEqualRanges(glyph2.range, NSMakeRange(NSNotFound, 0)), "Got \(glyph2.range) instead")
|
||
XCTAssertFalse(glyph2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 28.92, accuracy: 0.001);
|
||
XCTAssertEqual(display.descent, 18.92, accuracy: 0.001);
|
||
XCTAssertEqual(display.width, 39.44, accuracy: 0.001);
|
||
}
|
||
|
||
func testLargeOpNoLimitsText() throws {
|
||
let mathList = MTMathList()
|
||
mathList.add(MTMathAtomFactory.atom(forLatexSymbol: "sin"))
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 2)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
XCTAssertEqual(line.attributedString?.string, "sin");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTCTLineDisplay);
|
||
let line2 = sub1 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointMake(27.893, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(1, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
XCTAssertEqual(display.ascent, 13.14, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 0.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 39.33, accuracy: 0.01)
|
||
}
|
||
|
||
func testLargeOpNoLimitsSymbol() throws {
|
||
let mathList = MTMathList()
|
||
// Integral
|
||
mathList.add(MTMathAtomFactory.atom(forLatexSymbol:"int"))
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 2)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTGlyphDisplay);
|
||
let glyph = sub0;
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(glyph.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTCTLineDisplay);
|
||
let line2 = sub1 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointMake(23.313, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(1, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
XCTAssertEqual(display.ascent, 27.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 17.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 34.753, accuracy: 0.01)
|
||
}
|
||
|
||
func testLargeOpNoLimitsSymbolWithScripts() throws {
|
||
let mathList = MTMathList()
|
||
// Integral
|
||
let op = MTMathAtomFactory.atom(forLatexSymbol:"int")!
|
||
op.superScript = MTMathList()
|
||
op.superScript?.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
op.subScript = MTMathList()
|
||
op.subScript?.add(MTMathAtomFactory.atom(forCharacter: "0"))
|
||
mathList.add(op)
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 2)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 4);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTMathListDisplay);
|
||
let display0 = sub0 as! MTMathListDisplay
|
||
XCTAssertEqual(display0.type, .superscript);
|
||
XCTAssertTrue(CGPointEqualToPoint(display0.position, CGPointMake(19.98, 23.72)))
|
||
XCTAssertTrue(NSEqualRanges(display0.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display0.hasScript);
|
||
XCTAssertEqual(display0.index, 0);
|
||
XCTAssertEqual(display0.subDisplays.count, 1);
|
||
|
||
let sub0sub0 = display0.subDisplays[0];
|
||
XCTAssertTrue(sub0sub0 is MTCTLineDisplay);
|
||
let line1 = sub0sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line1.atoms.count, 1);
|
||
XCTAssertEqual(line1.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line1.position, CGPointZero));
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTMathListDisplay);
|
||
let display1 = sub1 as! MTMathListDisplay
|
||
XCTAssertEqual(display1.type, .ssubscript);
|
||
// Due to italic correction, positioned before subscript.
|
||
XCTAssertTrue(CGPointEqualToPoint(display1.position, CGPointMake(8.16, -20.02)))
|
||
XCTAssertTrue(NSEqualRanges(display1.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display1.hasScript);
|
||
XCTAssertEqual(display1.index, 0);
|
||
XCTAssertEqual(display1.subDisplays.count, 1);
|
||
|
||
let sub1sub0 = display1.subDisplays[0];
|
||
XCTAssertTrue(sub1sub0 is MTCTLineDisplay);
|
||
let line3 = sub1sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "0");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
let sub2 = display.subDisplays[2];
|
||
XCTAssertTrue(sub2 is MTGlyphDisplay);
|
||
let glyph = sub2;
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(0, 1)));
|
||
XCTAssertTrue(glyph.hasScript); // There are subscripts and superscripts
|
||
|
||
let sub3 = display.subDisplays[3];
|
||
XCTAssertTrue(sub3 is MTCTLineDisplay);
|
||
let line2 = sub3 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointMake(31.433, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(1, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
XCTAssertEqual(display.ascent, 33.044, accuracy: 0.001);
|
||
XCTAssertEqual(display.descent, 20.328, accuracy: 0.001);
|
||
XCTAssertEqual(display.width, 42.873, accuracy: 0.001);
|
||
}
|
||
|
||
|
||
func testLargeOpWithLimitsTextWithScripts() throws {
|
||
let mathList = MTMathList()
|
||
let op = MTMathAtomFactory.atom(forLatexSymbol:"lim")!
|
||
op.subScript = MTMathList()
|
||
op.subScript?.add(MTMathAtomFactory.atom(forLatexSymbol:"infty"))
|
||
mathList.add(op)
|
||
mathList.add(MTMathAtom(type: .variable, value:"x"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 2)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTLargeOpLimitsDisplay)
|
||
let largeOp = sub0 as! MTLargeOpLimitsDisplay
|
||
XCTAssertTrue(CGPointEqualToPoint(largeOp.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(largeOp.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(largeOp.hasScript);
|
||
XCTAssertNotNil(largeOp.lowerLimit);
|
||
XCTAssertNil(largeOp.upperLimit);
|
||
|
||
let display2 = largeOp.lowerLimit!
|
||
XCTAssertEqual(display2.type, .regular)
|
||
XCTAssertTrue(CGPointMake(6.89, -12.00).isEqual(to: display2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let sub0sub0 = display2.subDisplays[0];
|
||
XCTAssertTrue(sub0sub0 is MTCTLineDisplay);
|
||
let line1 = sub0sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line1.atoms.count, 1);
|
||
XCTAssertEqual(line1.attributedString?.string, "∞");
|
||
XCTAssertTrue(CGPointEqualToPoint(line1.position, CGPointZero));
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
let sub3 = display.subDisplays[1];
|
||
XCTAssertTrue(sub3 is MTCTLineDisplay);
|
||
let line2 = sub3 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointMake(31.1133, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(1, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
XCTAssertEqual(display.ascent, 13.88, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 12.154, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 42.553, accuracy: 0.01)
|
||
}
|
||
|
||
func testLargeOpWithLimitsSymboltWithScripts() throws {
|
||
let mathList = MTMathList()
|
||
let op = MTMathAtomFactory.atom(forLatexSymbol:"sum")!
|
||
op.superScript = MTMathList()
|
||
op.superScript?.add(MTMathAtomFactory.atom(forLatexSymbol:"infty"))
|
||
op.subScript = MTMathList()
|
||
op.subScript?.add(MTMathAtomFactory.atom(forCharacter: "0"))
|
||
mathList.add(op)
|
||
mathList.add(MTMathAtom(type: .variable, value:"x"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 2)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTLargeOpLimitsDisplay);
|
||
let largeOp = sub0 as! MTLargeOpLimitsDisplay
|
||
XCTAssertTrue(CGPointEqualToPoint(largeOp.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(largeOp.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(largeOp.hasScript);
|
||
XCTAssertNotNil(largeOp.lowerLimit);
|
||
XCTAssertNotNil(largeOp.upperLimit);
|
||
|
||
let display2 = largeOp.lowerLimit!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointMake(10.94, -21.664).isEqual(to: display2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let sub0sub0 = display2.subDisplays[0];
|
||
XCTAssertTrue(sub0sub0 is MTCTLineDisplay);
|
||
let line1 = sub0sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line1.atoms.count, 1);
|
||
XCTAssertEqual(line1.attributedString?.string, "0");
|
||
XCTAssertTrue(CGPointEqualToPoint(line1.position, CGPointZero));
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
let displayU = largeOp.upperLimit!
|
||
XCTAssertEqual(displayU.type, .regular);
|
||
XCTAssertTrue(CGPointMake(7.44, 23.154).isEqual(to: displayU.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(displayU.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(displayU.hasScript);
|
||
XCTAssertEqual(displayU.index, NSNotFound);
|
||
XCTAssertEqual(displayU.subDisplays.count, 1);
|
||
|
||
let sub0subU = displayU.subDisplays[0];
|
||
XCTAssertTrue(sub0subU is MTCTLineDisplay);
|
||
let line3 = sub0subU as! MTCTLineDisplay
|
||
XCTAssertEqual(line3.atoms.count, 1);
|
||
XCTAssertEqual(line3.attributedString?.string, "∞");
|
||
XCTAssertTrue(CGPointEqualToPoint(line3.position, CGPointZero));
|
||
XCTAssertFalse(line3.hasScript);
|
||
|
||
let sub3 = display.subDisplays[1];
|
||
XCTAssertTrue(sub3 is MTCTLineDisplay);
|
||
let line2 = sub3 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointMake(32.2133, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(1, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
XCTAssertEqual(display.ascent, 29.342, accuracy: 0.001);
|
||
XCTAssertEqual(display.descent, 21.972, accuracy: 0.001);
|
||
XCTAssertEqual(display.width, 43.653, accuracy: 0.001);
|
||
}
|
||
|
||
func testInner() throws {
|
||
let innerList = MTMathList()
|
||
innerList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
let inner = MTInner()
|
||
inner.innerList = innerList;
|
||
inner.leftBoundary = MTMathAtom(type: .boundary, value:"(")
|
||
inner.rightBoundary = MTMathAtom(type: .boundary, value:")")
|
||
|
||
let mathList = MTMathList()
|
||
mathList.add(inner)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTMathListDisplay);
|
||
let display2 = sub0 as! MTMathListDisplay
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 3);
|
||
|
||
let subLeft = display2.subDisplays[0];
|
||
XCTAssertTrue(subLeft is MTGlyphDisplay);
|
||
let glyph = subLeft;
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(NSNotFound, 0)));
|
||
XCTAssertFalse(glyph.hasScript);
|
||
|
||
let sub3 = display2.subDisplays[1];
|
||
XCTAssertTrue(sub3 is MTMathListDisplay);
|
||
let display3 = sub3 as! MTMathListDisplay
|
||
XCTAssertEqual(display3.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display3.position, CGPointMake(7.78, 0)))
|
||
XCTAssertTrue(NSEqualRanges(display3.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display3.hasScript);
|
||
XCTAssertEqual(display3.index, NSNotFound);
|
||
XCTAssertEqual(display3.subDisplays.count, 1);
|
||
|
||
let subsub3 = display3.subDisplays[0];
|
||
XCTAssertTrue(subsub3 is MTCTLineDisplay);
|
||
let line = subsub3 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
let subRight = display2.subDisplays[2];
|
||
XCTAssertTrue(subRight is MTGlyphDisplay);
|
||
let glyph2 = subRight as! MTGlyphDisplay
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph2.position, CGPointMake(19.22, 0)))
|
||
XCTAssertTrue(NSEqualRanges(glyph2.range, NSMakeRange(NSNotFound, 0)), "Got \(glyph2.range) instead");
|
||
XCTAssertFalse(glyph2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, display2.ascent);
|
||
XCTAssertEqual(display.descent, display2.descent);
|
||
XCTAssertEqual(display.width, display2.width);
|
||
|
||
XCTAssertEqual(display.ascent, 14.96, accuracy: 0.001);
|
||
XCTAssertEqual(display.descent, 4.96, accuracy: 0.001);
|
||
XCTAssertEqual(display.width, 27, accuracy: 0.01)
|
||
}
|
||
|
||
func testOverline() throws {
|
||
let mathList = MTMathList()
|
||
let over = MTOverLine()
|
||
let inner = MTMathList()
|
||
inner.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
over.innerList = inner;
|
||
mathList.add(over)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTLineDisplay);
|
||
let overline = sub0 as! MTLineDisplay
|
||
XCTAssertTrue(NSEqualRanges(overline.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(overline.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(overline.position, CGPointZero));
|
||
XCTAssertNotNil(overline.inner);
|
||
|
||
let display2 = overline.inner!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subover = display2.subDisplays[0];
|
||
XCTAssertTrue(subover is MTCTLineDisplay);
|
||
let line2 = subover as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 17.32, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 0.00, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 10, accuracy: 0.01)
|
||
}
|
||
|
||
func testUnderline() throws {
|
||
let mathList = MTMathList()
|
||
let under = MTUnderLine()
|
||
let inner = MTMathList()
|
||
inner.add(MTMathAtomFactory.atom(forCharacter: "1"))
|
||
under.innerList = inner;
|
||
mathList.add(under)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTLineDisplay)
|
||
let underline = sub0 as! MTLineDisplay
|
||
XCTAssertTrue(NSEqualRanges(underline.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(underline.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(underline.position, CGPointZero));
|
||
XCTAssertNotNil(underline.inner);
|
||
|
||
let display2 = underline.inner!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subover = display2.subDisplays[0];
|
||
XCTAssertTrue(subover is MTCTLineDisplay);
|
||
let line2 = subover as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "1");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 13.32, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.00, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 10, accuracy: 0.01)
|
||
}
|
||
|
||
func testSpacing() throws {
|
||
let mathList = MTMathList()
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
mathList.add(MTMathSpace(space: 9))
|
||
mathList.add(MTMathAtomFactory.atom(forCharacter: "y"))
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 3)), "Got \(display.range) instead")
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 2);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
// The x is italicized
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTCTLineDisplay);
|
||
let line2 = sub1 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
// The y is italicized
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑦")
|
||
XCTAssertTrue(CGPointMake(21.44, 0).isEqual(to: line2.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(2, 1)), "Got \(line2.range) instead")
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let noSpace = MTMathList()
|
||
noSpace.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
noSpace.add(MTMathAtomFactory.atom(forCharacter: "y"))
|
||
|
||
let noSpaceDisplay = MTTypesetter.createLineForMathList(noSpace, font:self.font, style:.display)!
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, noSpaceDisplay.ascent, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, noSpaceDisplay.descent, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, noSpaceDisplay.width + 10, accuracy: 0.01)
|
||
}
|
||
|
||
// For issue: https://github.com/kostub/iosMath/issues/5
|
||
func testLargeRadicalDescent() throws {
|
||
let list = MTMathListBuilder.build(fromString: "\\sqrt{\\frac{\\sqrt{\\frac{1}{2}} + 3}{\\sqrt{5}^x}}")
|
||
let display = MTTypesetter.createLineForMathList(list, font:self.font, style:.display)!
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 49.16, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 21.288, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 82.569, accuracy: 0.01)
|
||
}
|
||
|
||
func testMathTable() throws {
|
||
let c00 = MTMathAtomFactory.mathListForCharacters("1")
|
||
let c01 = MTMathAtomFactory.mathListForCharacters("y+z")
|
||
let c02 = MTMathAtomFactory.mathListForCharacters("y")
|
||
|
||
let c11 = MTMathList()
|
||
c11.add(MTMathAtomFactory.fraction(withNumeratorString: "1", denominatorString:"2x"))
|
||
let c12 = MTMathAtomFactory.mathListForCharacters("x-y")
|
||
|
||
let c20 = MTMathAtomFactory.mathListForCharacters("x+5")
|
||
let c22 = MTMathAtomFactory.mathListForCharacters("12")
|
||
|
||
let table = MTMathTable()
|
||
table.set(cell: c00!, forRow:0, column:0)
|
||
table.set(cell: c01!, forRow:0, column:1)
|
||
table.set(cell: c02!, forRow:0, column:2)
|
||
table.set(cell: c11, forRow:1, column:1)
|
||
table.set(cell: c12!, forRow:1, column:2)
|
||
table.set(cell: c20!, forRow:2, column:0)
|
||
table.set(cell: c22!, forRow:2, column:2)
|
||
|
||
// alignments
|
||
table.set(alignment: .right, forColumn:0)
|
||
table.set(alignment: .left, forColumn:2)
|
||
|
||
table.interColumnSpacing = 18; // 1 quad
|
||
|
||
let mathList = MTMathList()
|
||
mathList.add(table)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTMathListDisplay);
|
||
|
||
let display2 = sub0 as! MTMathListDisplay
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 3);
|
||
let rowPos = [ 30.28, -2.68, -31.95 ]
|
||
// alignment is right, center, left.
|
||
let cellPos = [ [ 35.89, 65.89, 129.438 ], [ 45.89, 76.94, 129.438 ], [ 0, 87.66, 129.438] ]
|
||
// check the 3 rows of the matrix
|
||
for i in 0..<3 {
|
||
let sub0i = display2.subDisplays[i];
|
||
XCTAssertTrue(sub0i is MTMathListDisplay);
|
||
|
||
let row = sub0i as! MTMathListDisplay
|
||
XCTAssertEqual(row.type, .regular)
|
||
XCTAssertTrue(CGPointMake(0, rowPos[i]).isEqual(to: row.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(row.range, NSMakeRange(0, 3)));
|
||
XCTAssertFalse(row.hasScript);
|
||
XCTAssertEqual(row.index, NSNotFound);
|
||
XCTAssertEqual(row.subDisplays.count, 3);
|
||
|
||
for j in 0..<3 {
|
||
let sub0ij = row.subDisplays[j];
|
||
XCTAssertTrue(sub0ij is MTMathListDisplay);
|
||
|
||
let col = sub0ij as! MTMathListDisplay
|
||
XCTAssertEqual(col.type, .regular);
|
||
XCTAssertTrue(CGPointMake(cellPos[i][j], 0).isEqual(to: col.position, accuracy: 0.01))
|
||
XCTAssertFalse(col.hasScript)
|
||
XCTAssertEqual(col.index, NSNotFound);
|
||
}
|
||
}
|
||
}
|
||
|
||
func testLatexSymbols() throws {
|
||
// Test all latex symbols
|
||
let allSymbols = MTMathAtomFactory.supportedLatexSymbolNames
|
||
for symName in allSymbols {
|
||
let list = MTMathList()
|
||
let atom = MTMathAtomFactory.atom(forLatexSymbol:symName)
|
||
XCTAssertNotNil(atom)
|
||
if atom!.type >= .boundary {
|
||
// Skip these types as they aren't symbols.
|
||
continue;
|
||
}
|
||
|
||
list.add(atom)
|
||
|
||
let display = MTTypesetter.createLineForMathList(list, font:self.font, style:.display)!
|
||
XCTAssertNotNil(display, "Symbol \(symName)")
|
||
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1, "Symbol \(symName)");
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
if atom!.type == .largeOperator && atom!.nucleus.count == 1 {
|
||
// These large operators are rendered differently;
|
||
XCTAssertTrue(sub0 is MTGlyphDisplay);
|
||
let glyph = sub0 as! MTGlyphDisplay
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(glyph.hasScript);
|
||
} else {
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay, "Symbol \(symName)");
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
if atom!.type != .variable {
|
||
XCTAssertEqual(line.attributedString?.string, atom!.nucleus);
|
||
}
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(line.hasScript);
|
||
}
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, sub0.ascent);
|
||
XCTAssertEqual(display.descent, sub0.descent);
|
||
XCTAssertEqual(display.width, sub0.width);
|
||
|
||
// All chars will occupy some space.
|
||
if atom!.nucleus != " " {
|
||
// all chars except space have height
|
||
XCTAssertGreaterThan(display.ascent + display.descent, 0, "Symbol \(symName)")
|
||
}
|
||
// all chars have a width.
|
||
XCTAssertGreaterThan(display.width, 0);
|
||
}
|
||
}
|
||
|
||
func testAtomWithAllFontStyles(_ atom:MTMathAtom?) throws {
|
||
guard let atom = atom else { return }
|
||
let fontStyles = [
|
||
MTFontStyle.defaultStyle,
|
||
.roman,
|
||
.bold,
|
||
.caligraphic,
|
||
.typewriter,
|
||
.italic,
|
||
.sansSerif,
|
||
.fraktur,
|
||
.blackboard,
|
||
.boldItalic,
|
||
]
|
||
for fontStyle in fontStyles {
|
||
let style = fontStyle
|
||
let copy : MTMathAtom = atom.copy()
|
||
copy.fontStyle = style
|
||
let list = MTMathList(atom: copy)
|
||
|
||
let display = MTTypesetter.createLineForMathList(list, font:self.font, style:.display)!
|
||
XCTAssertNotNil(display, "Symbol \(atom.nucleus)")
|
||
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1, "Symbol \(atom.nucleus)")
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay, "Symbol \(atom.nucleus)")
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, sub0.ascent);
|
||
XCTAssertEqual(display.descent, sub0.descent);
|
||
XCTAssertEqual(display.width, sub0.width);
|
||
|
||
// All chars will occupy some space.
|
||
XCTAssertGreaterThan(display.ascent + display.descent, 0, "Symbol \(atom.nucleus)")
|
||
// all chars have a width.
|
||
XCTAssertGreaterThan(display.width, 0);
|
||
}
|
||
}
|
||
|
||
func testVariables() throws {
|
||
// Test all variables
|
||
let allSymbols = MTMathAtomFactory.supportedLatexSymbolNames
|
||
for symName in allSymbols {
|
||
let atom = MTMathAtomFactory.atom(forLatexSymbol:symName)!
|
||
XCTAssertNotNil(atom)
|
||
if atom.type != .variable {
|
||
// Skip these types as we are only interested in variables.
|
||
continue;
|
||
}
|
||
try self.testAtomWithAllFontStyles(atom)
|
||
}
|
||
let alphaNum = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789."
|
||
let mathList = MTMathAtomFactory.mathListForCharacters(alphaNum)
|
||
for atom in mathList!.atoms {
|
||
try self.testAtomWithAllFontStyles(atom)
|
||
}
|
||
}
|
||
|
||
func testStyleChanges() throws {
|
||
let frac = MTMathAtomFactory.fraction(withNumeratorString: "1", denominatorString: "2")
|
||
let list = MTMathList(atoms: [frac])
|
||
let style = MTMathStyle(style: .text)
|
||
let textList = MTMathList(atoms: [style, frac])
|
||
|
||
// This should make the display same as text.
|
||
let display = MTTypesetter.createLineForMathList(textList, font:self.font, style:.display)!
|
||
let textDisplay = MTTypesetter.createLineForMathList(list, font:self.font, style:.text)!
|
||
let originalDisplay = MTTypesetter.createLineForMathList(list, font:self.font, style:.display)!
|
||
|
||
// Display should be the same as rendering the fraction in text style.
|
||
XCTAssertEqual(display.ascent, textDisplay.ascent);
|
||
XCTAssertEqual(display.descent, textDisplay.descent);
|
||
XCTAssertEqual(display.width, textDisplay.width);
|
||
|
||
// Original display should be larger than display since it is greater.
|
||
XCTAssertGreaterThan(originalDisplay.ascent, display.ascent);
|
||
XCTAssertGreaterThan(originalDisplay.descent, display.descent);
|
||
XCTAssertGreaterThan(originalDisplay.width, display.width);
|
||
}
|
||
|
||
func testStyleMiddle() throws {
|
||
let atom1 = MTMathAtomFactory.atom(forCharacter: "x")!
|
||
let style1 = MTMathStyle(style: .script) as MTMathAtom
|
||
let atom2 = MTMathAtomFactory.atom(forCharacter: "y")!
|
||
let style2 = MTMathStyle(style: .scriptOfScript) as MTMathAtom
|
||
let atom3 = MTMathAtomFactory.atom(forCharacter: "z")!
|
||
let list = MTMathList(atoms: [atom1, style1, atom2, style2, atom3])
|
||
|
||
let display = MTTypesetter.createLineForMathList(list, font:self.font, style:.display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 5)))
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 3);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTCTLineDisplay);
|
||
let line = sub0 as! MTCTLineDisplay
|
||
XCTAssertEqual(line.atoms.count, 1);
|
||
XCTAssertEqual(line.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(line.hasScript);
|
||
|
||
let sub1 = display.subDisplays[1];
|
||
XCTAssertTrue(sub1 is MTCTLineDisplay);
|
||
let line1 = sub1 as! MTCTLineDisplay
|
||
XCTAssertEqual(line1.atoms.count, 1);
|
||
XCTAssertEqual(line1.attributedString?.string, "𝑦");
|
||
XCTAssertTrue(NSEqualRanges(line1.range, NSMakeRange(2, 1)))
|
||
XCTAssertFalse(line1.hasScript);
|
||
|
||
let sub2 = display.subDisplays[2];
|
||
XCTAssertTrue(sub2 is MTCTLineDisplay);
|
||
let line2 = sub2 as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑧");
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(4, 1)))
|
||
XCTAssertFalse(line2.hasScript);
|
||
}
|
||
|
||
func testAccent() throws {
|
||
let mathList = MTMathList()
|
||
let accent = MTMathAtomFactory.accent(withName: "hat")
|
||
let inner = MTMathList()
|
||
inner.add(MTMathAtomFactory.atom(forCharacter: "x"))
|
||
accent?.innerList = inner;
|
||
mathList.add(accent)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTAccentDisplay)
|
||
let accentDisp = sub0 as! MTAccentDisplay
|
||
XCTAssertTrue(NSEqualRanges(accentDisp.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(accentDisp.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(accentDisp.position, CGPointZero));
|
||
XCTAssertNotNil(accentDisp.accentee);
|
||
XCTAssertNotNil(accentDisp.accent);
|
||
|
||
let display2 = accentDisp.accentee!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subaccentee = display2.subDisplays[0];
|
||
XCTAssertTrue(subaccentee is MTCTLineDisplay);
|
||
let line2 = subaccentee as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 1);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let glyph = accentDisp.accent!
|
||
XCTAssertTrue(CGPointEqualToPoint(glyph.position, CGPointMake(11.86, 0)))
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(glyph.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 14.68, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 0.22, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 11.44, accuracy: 0.01)
|
||
}
|
||
|
||
func testWideAccent() throws {
|
||
let mathList = MTMathList()
|
||
let accent = MTMathAtomFactory.accent(withName: "hat")
|
||
accent?.innerList = MTMathAtomFactory.mathListForCharacters("xyzw")
|
||
mathList.add(accent)
|
||
|
||
let display = MTTypesetter.createLineForMathList(mathList, font: self.font, style: .display)!
|
||
XCTAssertNotNil(display);
|
||
XCTAssertEqual(display.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(display.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(display.hasScript);
|
||
XCTAssertEqual(display.index, NSNotFound);
|
||
XCTAssertEqual(display.subDisplays.count, 1);
|
||
|
||
let sub0 = display.subDisplays[0];
|
||
XCTAssertTrue(sub0 is MTAccentDisplay)
|
||
let accentDisp = sub0 as! MTAccentDisplay
|
||
XCTAssertTrue(NSEqualRanges(accentDisp.range, NSMakeRange(0, 1)));
|
||
XCTAssertFalse(accentDisp.hasScript);
|
||
XCTAssertTrue(CGPointEqualToPoint(accentDisp.position, CGPointZero));
|
||
XCTAssertNotNil(accentDisp.accentee);
|
||
XCTAssertNotNil(accentDisp.accent);
|
||
|
||
let display2 = accentDisp.accentee!
|
||
XCTAssertEqual(display2.type, .regular);
|
||
XCTAssertTrue(CGPointEqualToPoint(display2.position, CGPointZero))
|
||
XCTAssertTrue(NSEqualRanges(display2.range, NSMakeRange(0, 4)));
|
||
XCTAssertFalse(display2.hasScript);
|
||
XCTAssertEqual(display2.index, NSNotFound);
|
||
XCTAssertEqual(display2.subDisplays.count, 1);
|
||
|
||
let subaccentee = display2.subDisplays[0];
|
||
XCTAssertTrue(subaccentee is MTCTLineDisplay);
|
||
let line2 = subaccentee as! MTCTLineDisplay
|
||
XCTAssertEqual(line2.atoms.count, 4);
|
||
XCTAssertEqual(line2.attributedString?.string, "𝑥𝑦𝑧𝑤");
|
||
XCTAssertTrue(CGPointEqualToPoint(line2.position, CGPointZero));
|
||
XCTAssertTrue(NSEqualRanges(line2.range, NSMakeRange(0, 4)));
|
||
XCTAssertFalse(line2.hasScript);
|
||
|
||
let glyph = accentDisp.accent!
|
||
XCTAssertTrue(CGPointMake(3.47, 0).isEqual(to: glyph.position, accuracy: 0.01))
|
||
XCTAssertTrue(NSEqualRanges(glyph.range, NSMakeRange(0, 1)))
|
||
XCTAssertFalse(glyph.hasScript);
|
||
|
||
// dimensions
|
||
XCTAssertEqual(display.ascent, 14.98, accuracy: 0.01)
|
||
XCTAssertEqual(display.descent, 4.10, accuracy: 0.01)
|
||
XCTAssertEqual(display.width, 44.86, accuracy: 0.01)
|
||
}
|
||
|
||
}
|
||
|