test: add ReadingPositionAdapter.fromValue unit tests (IOS-INFO-034)
- 23 tests: fromValue (12) + clamp (2) + blockId (8) - fromValue: Markdown/Text/Pdf/Image/Epub complete + defaults - fromValue: nil blockId→nil for Markdown, nil chapterId→nil for Epub - fromValue: unknown/nil type → .unknown - clamp: > 1 → 1.0, < 0 → 0.0 - blockId: all 7 DocumentBlock variants + horizontalRule Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
86054edd5f
commit
4348823ca1
202
AIStudyApp/AIStudyAppTests/ReadingPositionAdapterTests.swift
Normal file
202
AIStudyApp/AIStudyAppTests/ReadingPositionAdapterTests.swift
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
import XCTest
|
||||||
|
@testable import AIStudyApp
|
||||||
|
|
||||||
|
final class ReadingPositionAdapterTests: XCTestCase {
|
||||||
|
|
||||||
|
// MARK: - fromValue: Markdown
|
||||||
|
|
||||||
|
func test_fromValue_markdown_with_blockId() {
|
||||||
|
let v = ReadingPositionValue(type: "Markdown", blockId: "b1", lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: 0.5, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
let pos = ReadingPositionAdapter.fromValue(v)
|
||||||
|
guard case let .markdown(blockId, scrollProgress) = pos else {
|
||||||
|
return XCTFail("Expected .markdown, got \(String(describing: pos))")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(blockId, "b1")
|
||||||
|
XCTAssertEqual(scrollProgress, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_markdown_nil_blockId_returns_nil() {
|
||||||
|
let v = ReadingPositionValue(type: "Markdown", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
XCTAssertNil(ReadingPositionAdapter.fromValue(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - fromValue: Text
|
||||||
|
|
||||||
|
func test_fromValue_text_with_optional_fields() {
|
||||||
|
let v = ReadingPositionValue(type: "Text", blockId: nil, lineNumber: 42,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: 0.8, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .text(lineNumber, scrollProgress) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .text")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(lineNumber, 42)
|
||||||
|
XCTAssertEqual(scrollProgress, 0.8)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_text_defaults_lineNumber_to_1() {
|
||||||
|
let v = ReadingPositionValue(type: "Text", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .text(lineNumber, _) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .text")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(lineNumber, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - fromValue: Pdf
|
||||||
|
|
||||||
|
func test_fromValue_pdf_with_all_fields() {
|
||||||
|
let v = ReadingPositionValue(type: "Pdf", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: 5, chapterId: nil, scrollProgress: nil, pageProgress: 0.3,
|
||||||
|
overallProgress: 0.15, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .pdf(pageNumber, pageProgress, overallProgress) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .pdf")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(pageNumber, 5)
|
||||||
|
XCTAssertEqual(pageProgress, 0.3)
|
||||||
|
XCTAssertEqual(overallProgress, 0.15)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_pdf_defaults_to_page_1() {
|
||||||
|
let v = ReadingPositionValue(type: "Pdf", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .pdf(pageNumber, _, _) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .pdf")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(pageNumber, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - fromValue: Image
|
||||||
|
|
||||||
|
func test_fromValue_image_with_zoom_and_offset() {
|
||||||
|
let v = ReadingPositionValue(type: "Image", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: 2.0, offsetX: 100, offsetY: 200, chapterProgress: nil)
|
||||||
|
guard case let .image(zoomScale, offsetX, offsetY) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .image")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(zoomScale, 2.0)
|
||||||
|
XCTAssertEqual(offsetX, 100)
|
||||||
|
XCTAssertEqual(offsetY, 200)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_image_defaults_zoom_to_1() {
|
||||||
|
let v = ReadingPositionValue(type: "Image", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .image(zoomScale, _, _) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .image")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(zoomScale, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - fromValue: Epub
|
||||||
|
|
||||||
|
func test_fromValue_epub_with_chapterId() {
|
||||||
|
let v = ReadingPositionValue(type: "Epub", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: "ch3", scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: 0.6, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: 0.4)
|
||||||
|
guard case let .epub(chapterId, chapterProgress, overallProgress) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .epub")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(chapterId, "ch3")
|
||||||
|
XCTAssertEqual(chapterProgress, 0.4)
|
||||||
|
XCTAssertEqual(overallProgress, 0.6)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_epub_nil_chapterId_returns_nil() {
|
||||||
|
let v = ReadingPositionValue(type: "Epub", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
XCTAssertNil(ReadingPositionAdapter.fromValue(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - fromValue: Unknown / default
|
||||||
|
|
||||||
|
func test_fromValue_unknown_type_returns_unknown() {
|
||||||
|
let v = ReadingPositionValue(type: "UnknownType", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case .unknown = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_fromValue_nil_type_returns_unknown() {
|
||||||
|
let v = ReadingPositionValue(type: nil, blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: nil, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case .unknown = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .unknown")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Clamp behavior
|
||||||
|
|
||||||
|
func test_clamp_scrollProgress_above_1() {
|
||||||
|
let v = ReadingPositionValue(type: "Text", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: 1.5, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .text(_, scrollProgress) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .text")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(scrollProgress, 1.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_clamp_progress_negative() {
|
||||||
|
let v = ReadingPositionValue(type: "Text", blockId: nil, lineNumber: nil,
|
||||||
|
pageNumber: nil, chapterId: nil, scrollProgress: -0.5, pageProgress: nil,
|
||||||
|
overallProgress: nil, zoomScale: nil, offsetX: nil, offsetY: nil, chapterProgress: nil)
|
||||||
|
guard case let .text(_, scrollProgress) = ReadingPositionAdapter.fromValue(v) else {
|
||||||
|
return XCTFail("Expected .text")
|
||||||
|
}
|
||||||
|
XCTAssertEqual(scrollProgress, 0.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - blockId extraction
|
||||||
|
|
||||||
|
func test_blockId_from_heading() {
|
||||||
|
let block = DocumentBlock.heading(id: "h1", level: 2, text: "Title")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "h1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_paragraph() {
|
||||||
|
let block = DocumentBlock.paragraph(id: "p1", text: "Content")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "p1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_list() {
|
||||||
|
let block = DocumentBlock.list(id: "l1", items: [], ordered: true)
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "l1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_codeBlock() {
|
||||||
|
let block = DocumentBlock.codeBlock(id: "c1", language: "swift", code: "print(\"hi\")")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "c1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_quote() {
|
||||||
|
let block = DocumentBlock.quote(id: "q1", text: "quote")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "q1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_table() {
|
||||||
|
let block = DocumentBlock.table(id: "t1", headers: [], rows: [])
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "t1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_imageBlock() {
|
||||||
|
let block = DocumentBlock.imageBlock(id: "img1", alt: "img", source: "file.png")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "img1")
|
||||||
|
}
|
||||||
|
|
||||||
|
func test_blockId_from_horizontalRule() {
|
||||||
|
let block = DocumentBlock.horizontalRule(id: "hr1")
|
||||||
|
XCTAssertEqual(ReadingPositionAdapter.blockId(from: block), "hr1")
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user