[UI] add line wrapping functionality
This commit is contained in:
194
Tests/SwiftMathTests/MTMathUILabelLineWrappingTests.swift
Normal file
194
Tests/SwiftMathTests/MTMathUILabelLineWrappingTests.swift
Normal file
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// MTMathUILabelLineWrappingTests.swift
|
||||
// SwiftMathTests
|
||||
//
|
||||
// Tests for line wrapping functionality in MTMathUILabel
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import SwiftMath
|
||||
|
||||
class MTMathUILabelLineWrappingTests: XCTestCase {
|
||||
|
||||
func testBasicIntrinsicContentSize() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(x + y\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
|
||||
// Debug: check if parsing worked
|
||||
XCTAssertNotNil(label.mathList, "Math list should not be nil")
|
||||
XCTAssertNil(label.error, "Should have no parsing error, got: \(String(describing: label.error))")
|
||||
XCTAssertNotNil(label.font, "Font should not be nil")
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
}
|
||||
|
||||
func testTextModeIntrinsicContentSize() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Hello World}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
}
|
||||
|
||||
func testLongTextIntrinsicContentSize() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Rappelons la conversion : 1 km équivaut à 1000 m.}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
}
|
||||
|
||||
func testSizeThatFitsWithoutConstraint() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Hello World}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
|
||||
let size = label.sizeThatFits(CGSize.zero)
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
}
|
||||
|
||||
func testSizeThatFitsWithWidthConstraint() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Rappelons la conversion : 1 km équivaut à 1000 m.}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
// Get unconstrained size first
|
||||
let unconstrainedSize = label.sizeThatFits(CGSize.zero)
|
||||
XCTAssertGreaterThan(unconstrainedSize.width, 0, "Unconstrained width should be > 0")
|
||||
|
||||
// Test with width constraint (use 300 since longest word might be ~237pt)
|
||||
let constrainedSize = label.sizeThatFits(CGSize(width: 300, height: CGFloat.greatestFiniteMagnitude))
|
||||
|
||||
XCTAssertGreaterThan(constrainedSize.width, 0, "Constrained width should be greater than 0, got \(constrainedSize.width)")
|
||||
XCTAssertLessThan(constrainedSize.width, unconstrainedSize.width, "Constrained width (\(constrainedSize.width)) should be less than unconstrained (\(unconstrainedSize.width))")
|
||||
XCTAssertGreaterThan(constrainedSize.height, 0, "Constrained height should be greater than 0, got \(constrainedSize.height)")
|
||||
|
||||
// When constrained, height should increase when text wraps
|
||||
XCTAssertGreaterThan(constrainedSize.height, unconstrainedSize.height,
|
||||
"Constrained height (\(constrainedSize.height)) should be > unconstrained (\(unconstrainedSize.height)) when text wraps")
|
||||
}
|
||||
|
||||
func testPreferredMaxLayoutWidth() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Rappelons la conversion : 1 km équivaut à 1000 m.}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
// Get unconstrained size
|
||||
let unconstrainedSize = label.intrinsicContentSize
|
||||
|
||||
// Now set preferred max width (use 300 since longest word might be ~237pt)
|
||||
label.preferredMaxLayoutWidth = 300
|
||||
let constrainedSize = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(constrainedSize.width, 0, "Width should be greater than 0, got \(constrainedSize.width)")
|
||||
XCTAssertLessThan(constrainedSize.width, unconstrainedSize.width, "Constrained width (\(constrainedSize.width)) should be < unconstrained (\(unconstrainedSize.width))")
|
||||
XCTAssertGreaterThan(constrainedSize.height, unconstrainedSize.height, "Constrained height (\(constrainedSize.height)) should be > unconstrained (\(unconstrainedSize.height)) due to wrapping")
|
||||
}
|
||||
|
||||
func testWordBoundaryBreaking() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Word1 Word2 Word3 Word4 Word5}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
label.preferredMaxLayoutWidth = 150
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
|
||||
// Verify it actually uses the layout
|
||||
label.frame = CGRect(origin: .zero, size: size)
|
||||
#if os(macOS)
|
||||
label.layout()
|
||||
#else
|
||||
label.layoutSubviews()
|
||||
#endif
|
||||
|
||||
XCTAssertNotNil(label.displayList, "Display list should be created")
|
||||
}
|
||||
|
||||
func testEmptyLatex() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = ""
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
// Empty latex should still return a valid size (might be zero or minimal)
|
||||
XCTAssertGreaterThanOrEqual(size.width, 0, "Width should be >= 0 for empty latex, got \(size.width)")
|
||||
XCTAssertGreaterThanOrEqual(size.height, 0, "Height should be >= 0 for empty latex, got \(size.height)")
|
||||
}
|
||||
|
||||
func testMathAndTextMixed() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Result: } x^2 + y^2 = z^2\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
let size = label.intrinsicContentSize
|
||||
|
||||
XCTAssertGreaterThan(size.width, 0, "Width should be greater than 0, got \(size.width)")
|
||||
XCTAssertGreaterThan(size.height, 0, "Height should be greater than 0, got \(size.height)")
|
||||
}
|
||||
|
||||
func testDebugSizeThatFitsWithConstraint() {
|
||||
let label = MTMathUILabel()
|
||||
label.latex = "\\(\\text{Word1 Word2 Word3 Word4 Word5}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
let unconstr = label.sizeThatFits(CGSize.zero)
|
||||
let constr = label.sizeThatFits(CGSize(width: 150, height: 999))
|
||||
|
||||
XCTAssertLessThan(constr.width, unconstr.width, "Constrained (\(constr.width)) should be < unconstrained (\(unconstr.width))")
|
||||
XCTAssertGreaterThan(constr.height, unconstr.height, "Constrained height (\(constr.height)) should be > unconstrained (\(unconstr.height))")
|
||||
}
|
||||
|
||||
func testAccentedCharactersWithLineWrapping() {
|
||||
let label = MTMathUILabel()
|
||||
// French text with accented characters: è, é, à
|
||||
label.latex = "\\(\\text{Rappelons la relation entre kilomètres et mètres.}\\)"
|
||||
label.font = MTFontManager.fontManager.defaultFont
|
||||
label.labelMode = .text
|
||||
|
||||
// Get unconstrained size
|
||||
let unconstrainedSize = label.intrinsicContentSize
|
||||
|
||||
// Set a width constraint that should cause wrapping
|
||||
label.preferredMaxLayoutWidth = 250
|
||||
let constrainedSize = label.intrinsicContentSize
|
||||
|
||||
// Verify wrapping occurred
|
||||
XCTAssertGreaterThan(constrainedSize.width, 0, "Width should be > 0")
|
||||
XCTAssertLessThan(constrainedSize.width, unconstrainedSize.width, "Constrained width should be < unconstrained")
|
||||
XCTAssertGreaterThan(constrainedSize.height, unconstrainedSize.height, "Height should increase when wrapped")
|
||||
|
||||
// Verify the label can render without errors
|
||||
label.frame = CGRect(origin: .zero, size: constrainedSize)
|
||||
#if os(macOS)
|
||||
label.layout()
|
||||
#else
|
||||
label.layoutSubviews()
|
||||
#endif
|
||||
|
||||
XCTAssertNotNil(label.displayList, "Display list should be created")
|
||||
XCTAssertNil(label.error, "Should have no rendering error")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user