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