Files
swiftui-math/Tests/SwiftMathTests/MTTypesetterTests.swift
2024-12-15 12:21:08 -05:00

1577 lines
72 KiB
Swift
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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