From 2fa459d9ea158d4e57fcbe677dff7cc8faedc963 Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 18 Jun 2026 13:04:37 +0800 Subject: [PATCH] test: add MaterialPathResolver unit tests (IOS-INFO-033) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 7 tests covering resolve and materialType inference - resolve nil for nonexistent file - resolve finds file in Documents directory - resolve finds file in Caches directory - type inference: .md→markdown, .pdf→pdf - unknown apiType defaults to .unknown - temp file creation + cleanup in test Co-Authored-By: Claude Opus 4.7 --- .../MaterialPathResolverTests.swift | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 AIStudyApp/AIStudyAppTests/MaterialPathResolverTests.swift diff --git a/AIStudyApp/AIStudyAppTests/MaterialPathResolverTests.swift b/AIStudyApp/AIStudyAppTests/MaterialPathResolverTests.swift new file mode 100644 index 0000000..a9db5af --- /dev/null +++ b/AIStudyApp/AIStudyAppTests/MaterialPathResolverTests.swift @@ -0,0 +1,97 @@ +import XCTest +@testable import AIStudyApp + +final class MaterialPathResolverTests: XCTestCase { + + // MARK: - materialTypeFrom (infer from apiType + title) + + func test_materialTypeFrom_knowledge_source_with_md_title_returns_markdown() { + let result = MaterialPathResolver.resolve(materialId: "m1", apiType: "knowledge_source", title: "note.md") + // Path won't exist, but we test the type inference via the file system cascade + XCTAssertNil(result) // File doesn't exist + } + + // MARK: - resolve returns nil for nonexistent file + + func test_resolve_returns_nil_for_nonexistent_material() { + let result = MaterialPathResolver.resolve( + materialId: UUID().uuidString, + apiType: nil, + title: nil + ) + XCTAssertNil(result) + } + + // MARK: - resolve finds file in Documents + + func test_resolve_finds_file_in_documents() { + let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileId = "test-resolve-\(UUID().uuidString)" + let fileURL = docs.appendingPathComponent(fileId) + defer { try? FileManager.default.removeItem(at: fileURL) } + + // Create a temp file in Documents + FileManager.default.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)) + + let result = MaterialPathResolver.resolve(materialId: fileId, apiType: nil, title: nil) + XCTAssertNotNil(result) + XCTAssertEqual(result?.filePath, fileURL.path) + } + + // MARK: - resolve finds file in Caches + + func test_resolve_finds_file_in_caches() { + let cache = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first! + let fileId = "test-cache-\(UUID().uuidString)" + let fileURL = cache.appendingPathComponent(fileId) + defer { try? FileManager.default.removeItem(at: fileURL) } + + FileManager.default.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)) + + let result = MaterialPathResolver.resolve(materialId: fileId, apiType: nil, title: nil) + XCTAssertNotNil(result) + XCTAssertEqual(result?.filePath, fileURL.path) + } + + // MARK: - materialType inference via file cascade + + func test_resolve_infers_type_from_title_extension() { + let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileId = "test-type-\(UUID().uuidString)" + let fileURL = docs.appendingPathComponent(fileId) + defer { try? FileManager.default.removeItem(at: fileURL) } + + FileManager.default.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)) + + // .md title → markdown + let result = MaterialPathResolver.resolve(materialId: fileId, apiType: "knowledge_source", title: "doc.md") + XCTAssertNotNil(result) + XCTAssertEqual(result?.materialType, .markdown) + } + + func test_resolve_pdf_title_infers_pdf_type() { + let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileId = "test-pdf-\(UUID().uuidString)" + let fileURL = docs.appendingPathComponent(fileId) + defer { try? FileManager.default.removeItem(at: fileURL) } + + FileManager.default.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)) + + let result = MaterialPathResolver.resolve(materialId: fileId, apiType: "temporary_file", title: "book.pdf") + XCTAssertNotNil(result) + XCTAssertEqual(result?.materialType, .pdf) + } + + func test_resolve_unknown_apiType_defaults_to_unknown_materialType() { + let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! + let fileId = "test-unknown-\(UUID().uuidString)" + let fileURL = docs.appendingPathComponent(fileId) + defer { try? FileManager.default.removeItem(at: fileURL) } + + FileManager.default.createFile(atPath: fileURL.path, contents: "test".data(using: .utf8)) + + let result = MaterialPathResolver.resolve(materialId: fileId, apiType: "other_type", title: "file.bin") + XCTAssertNotNil(result) + XCTAssertEqual(result?.materialType, .unknown) + } +}