Initial commit: MangaReader iOS App
✨ Features: - App iOS completa para leer manga sin publicidad - Scraper con WKWebView para manhwaweb.com - Sistema de descargas offline - Lector con zoom y navegación - Favoritos y progreso de lectura - Compatible con iOS 15+ y Sideloadly/3uTools 📦 Contenido: - Backend Node.js con Puppeteer (opcional) - App iOS con SwiftUI - Scraper de capítulos e imágenes - Sistema de almacenamiento local - Testing completo - Documentación exhaustiva 🧪 Prueba: Capítulo 789 de One Piece descargado exitosamente - 21 páginas descargadas - 4.68 MB total - URLs verificadas y funcionales 🎉 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
609
ios-app/Tests/IntegrationTests.swift
Normal file
609
ios-app/Tests/IntegrationTests.swift
Normal file
@@ -0,0 +1,609 @@
|
||||
import XCTest
|
||||
import UIKit
|
||||
@testable import MangaReader
|
||||
|
||||
/// Tests de integración para el flujo completo: scraper -> storage -> view
|
||||
/// Pruebas de descarga de capítulos y navegación entre vistas
|
||||
@MainActor
|
||||
final class IntegrationTests: XCTestCase {
|
||||
|
||||
var scraper: ManhwaWebScraper!
|
||||
var storageService: StorageService!
|
||||
|
||||
// MARK: - Setup & Teardown
|
||||
|
||||
override func setUp() async throws {
|
||||
try await super.setUp()
|
||||
|
||||
// Limpiar estado antes de cada test
|
||||
UserDefaults.standard.removeObject(forKey: "favoriteMangas")
|
||||
UserDefaults.standard.removeObject(forKey: "readingProgress")
|
||||
|
||||
scraper = ManhwaWebScraper.shared
|
||||
storageService = StorageService.shared
|
||||
storageService.clearAllDownloads()
|
||||
|
||||
// Esperar un momento para asegurar limpieza completa
|
||||
try await Task.sleep(nanoseconds: 100_000_000) // 0.1 segundos
|
||||
}
|
||||
|
||||
override func tearDown() async throws {
|
||||
// Limpiar después de los tests
|
||||
storageService.clearAllDownloads()
|
||||
UserDefaults.standard.removeObject(forKey: "favoriteMangas")
|
||||
UserDefaults.standard.removeObject(forKey: "readingProgress")
|
||||
|
||||
scraper = nil
|
||||
storageService = nil
|
||||
|
||||
try await super.tearDown()
|
||||
}
|
||||
|
||||
// MARK: - Complete Flow Tests: Scraper -> Storage
|
||||
|
||||
func testCompleteScrapingAndStorageFlow() async throws {
|
||||
// Este test simula el flujo completo: scraper -> storage
|
||||
|
||||
// 1. Simular datos del scraper (capítulos)
|
||||
let mockChapters = [
|
||||
Chapter(number: 10, title: "Chapter 10", url: "url10", slug: "slug10"),
|
||||
Chapter(number: 9, title: "Chapter 9", url: "url9", slug: "slug9"),
|
||||
Chapter(number: 8, title: "Chapter 8", url: "url8", slug: "slug8")
|
||||
]
|
||||
|
||||
// 2. Guardar progreso de lectura simulado
|
||||
let progress = ReadingProgress(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 9,
|
||||
pageNumber: 5,
|
||||
timestamp: Date()
|
||||
)
|
||||
storageService.saveReadingProgress(progress)
|
||||
|
||||
// 3. Verificar que el progreso se guardó
|
||||
let retrievedProgress = storageService.getReadingProgress(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 9
|
||||
)
|
||||
|
||||
XCTAssertNotNil(retrievedProgress)
|
||||
XCTAssertEqual(retrievedProgress?.pageNumber, 5)
|
||||
|
||||
// 4. Marcar manga como favorito
|
||||
storageService.saveFavorite(mangaSlug: "test-manga")
|
||||
|
||||
// 5. Verificar favoritos
|
||||
let favorites = storageService.getFavorites()
|
||||
XCTAssertTrue(favorites.contains("test-manga"))
|
||||
|
||||
// 6. Simular guardado de capítulo descargado
|
||||
let pages = mockChapters[0].number == 10 ? [
|
||||
MangaPage(url: "page1.jpg", index: 0),
|
||||
MangaPage(url: "page2.jpg", index: 1)
|
||||
] : []
|
||||
|
||||
let downloadedChapter = DownloadedChapter(
|
||||
mangaSlug: "test-manga",
|
||||
mangaTitle: "Test Manga",
|
||||
chapterNumber: 10,
|
||||
pages: pages,
|
||||
downloadedAt: Date()
|
||||
)
|
||||
|
||||
storageService.saveDownloadedChapter(downloadedChapter)
|
||||
|
||||
// 7. Verificar capítulo descargado
|
||||
XCTAssertTrue(storageService.isChapterDownloaded(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 10
|
||||
))
|
||||
|
||||
// 8. Obtener todos los datos relacionados
|
||||
let allProgress = storageService.getAllReadingProgress()
|
||||
let lastRead = storageService.getLastReadChapter(mangaSlug: "test-manga")
|
||||
let downloadedChapters = storageService.getDownloadedChapters()
|
||||
|
||||
XCTAssertEqual(allProgress.count, 1)
|
||||
XCTAssertNotNil(lastRead)
|
||||
XCTAssertEqual(downloadedChapters.count, 1)
|
||||
}
|
||||
|
||||
func testChapterDownloadFlow() async throws {
|
||||
// Simular el flujo completo de descarga de un capítulo
|
||||
|
||||
// 1. Crear imágenes de prueba
|
||||
let image1 = createTestImage(color: .red, size: CGSize(width: 800, height: 1200))
|
||||
let image2 = createTestImage(color: .blue, size: CGSize(width: 800, height: 1200))
|
||||
let image3 = createTestImage(color: .green, size: CGSize(width: 800, height: 1200))
|
||||
|
||||
// 2. Guardar imágenes
|
||||
let url1 = try await storageService.saveImage(
|
||||
image1,
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 0
|
||||
)
|
||||
|
||||
let url2 = try await storageService.saveImage(
|
||||
image2,
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 1
|
||||
)
|
||||
|
||||
let url3 = try await storageService.saveImage(
|
||||
image3,
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 2
|
||||
)
|
||||
|
||||
// 3. Verificar que las imágenes se guardaron
|
||||
XCTAssertTrue(FileManager.default.fileExists(atPath: url1.path))
|
||||
XCTAssertTrue(FileManager.default.fileExists(atPath: url2.path))
|
||||
XCTAssertTrue(FileManager.default.fileExists(atPath: url3.path))
|
||||
|
||||
// 4. Crear objeto de capítulo descargado
|
||||
let pages = [
|
||||
MangaPage(url: url1.absoluteString, index: 0, isCached: true),
|
||||
MangaPage(url: url2.absoluteString, index: 1, isCached: true),
|
||||
MangaPage(url: url3.absoluteString, index: 2, isCached: true)
|
||||
]
|
||||
|
||||
let downloadedChapter = DownloadedChapter(
|
||||
mangaSlug: "test-manga",
|
||||
mangaTitle: "Test Manga",
|
||||
chapterNumber: 1,
|
||||
pages: pages,
|
||||
downloadedAt: Date()
|
||||
)
|
||||
|
||||
// 5. Guardar metadatos del capítulo
|
||||
storageService.saveDownloadedChapter(downloadedChapter)
|
||||
|
||||
// 6. Verificar que el capítulo está marcado como descargado
|
||||
XCTAssertTrue(storageService.isChapterDownloaded(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1
|
||||
))
|
||||
|
||||
// 7. Recuperar el capítulo descargado
|
||||
let retrieved = storageService.getDownloadedChapter(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1
|
||||
)
|
||||
|
||||
XCTAssertNotNil(retrieved)
|
||||
XCTAssertEqual(retrieved?.pages.count, 3)
|
||||
|
||||
// 8. Cargar imágenes desde disco
|
||||
let loadedImage1 = storageService.loadImage(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 0
|
||||
)
|
||||
|
||||
let loadedImage2 = storageService.loadImage(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 1
|
||||
)
|
||||
|
||||
let loadedImage3 = storageService.loadImage(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 2
|
||||
)
|
||||
|
||||
XCTAssertNotNil(loadedImage1)
|
||||
XCTAssertNotNil(loadedImage2)
|
||||
XCTAssertNotNil(loadedImage3)
|
||||
}
|
||||
|
||||
func testReadingProgressTrackingFlow() async throws {
|
||||
// Simular el flujo de seguimiento de progreso de lectura
|
||||
|
||||
let mangaSlug = "tower-of-god"
|
||||
|
||||
// 1. Usuario comienza a leer capítulo 1
|
||||
let progress1 = ReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 1,
|
||||
pageNumber: 0,
|
||||
timestamp: Date()
|
||||
)
|
||||
storageService.saveReadingProgress(progress1)
|
||||
|
||||
// 2. Usuario avanza a página 5
|
||||
let progress2 = ReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 1,
|
||||
pageNumber: 5,
|
||||
timestamp: Date().addingTimeInterval(60) // 1 minuto después
|
||||
)
|
||||
storageService.saveReadingProgress(progress2)
|
||||
|
||||
// 3. Usuario cambia al capítulo 2
|
||||
let progress3 = ReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 2,
|
||||
pageNumber: 0,
|
||||
timestamp: Date().addingTimeInterval(120) // 2 minutos después
|
||||
)
|
||||
storageService.saveReadingProgress(progress3)
|
||||
|
||||
// 4. Usuario lee capítulo 2 hasta página 10
|
||||
let progress4 = ReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 2,
|
||||
pageNumber: 10,
|
||||
timestamp: Date().addingTimeInterval(300) // 5 minutos después
|
||||
)
|
||||
storageService.saveReadingProgress(progress4)
|
||||
|
||||
// 5. Verificar progreso del capítulo 1
|
||||
let ch1Progress = storageService.getReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 1
|
||||
)
|
||||
XCTAssertEqual(ch1Progress?.pageNumber, 5)
|
||||
|
||||
// 6. Verificar progreso del capítulo 2
|
||||
let ch2Progress = storageService.getReadingProgress(
|
||||
mangaSlug: mangaSlug,
|
||||
chapterNumber: 2
|
||||
)
|
||||
XCTAssertEqual(ch2Progress?.pageNumber, 10)
|
||||
|
||||
// 7. Verificar último capítulo leído
|
||||
let lastRead = storageService.getLastReadChapter(mangaSlug: mangaSlug)
|
||||
XCTAssertEqual(lastRead?.chapterNumber, 2)
|
||||
|
||||
// 8. Verificar que el capítulo se marca como completado
|
||||
XCTAssertTrue(ch2Progress?.isCompleted ?? false)
|
||||
}
|
||||
|
||||
func testFavoriteManagementFlow() {
|
||||
// Simular el flujo de gestión de favoritos
|
||||
|
||||
let mangaSlugs = [
|
||||
"solo-leveling",
|
||||
"tower-of-god",
|
||||
"the-beginning-after-the-end",
|
||||
"omniscient-reader"
|
||||
]
|
||||
|
||||
// 1. Agregar varios favoritos
|
||||
mangaSlugs.forEach { slug in
|
||||
storageService.saveFavorite(mangaSlug: slug)
|
||||
}
|
||||
|
||||
// 2. Verificar que todos están en favoritos
|
||||
let favorites = storageService.getFavorites()
|
||||
XCTAssertEqual(favorites.count, 4)
|
||||
|
||||
mangaSlugs.forEach { slug in
|
||||
XCTAssertTrue(storageService.isFavorite(mangaSlug: slug))
|
||||
}
|
||||
|
||||
// 3. Remover uno
|
||||
storageService.removeFavorite(mangaSlug: "tower-of-god")
|
||||
|
||||
// 4. Verificar que se eliminó
|
||||
XCTAssertFalse(storageService.isFavorite(mangaSlug: "tower-of-god"))
|
||||
XCTAssertEqual(storageService.getFavorites().count, 3)
|
||||
|
||||
// 5. Intentar agregar duplicado
|
||||
storageService.saveFavorite(mangaSlug: "solo-leveling")
|
||||
|
||||
// 6. Verificar que no se duplicó
|
||||
let updatedFavorites = storageService.getFavorites()
|
||||
XCTAssertEqual(updatedFavorites.count, 3)
|
||||
|
||||
// 7. Contar ocurrencias
|
||||
let soloLevelingCount = updatedFavorites.filter { $0 == "solo-leveling" }.count
|
||||
XCTAssertEqual(soloLevelingCount, 1, "Should only appear once")
|
||||
}
|
||||
|
||||
// MARK: - Multi-Manga Scenarios
|
||||
|
||||
func testMultipleMangasProgressTracking() async throws {
|
||||
// Simular seguimiento de progreso para múltiples mangas
|
||||
|
||||
let mangas = [
|
||||
"solo-leveling",
|
||||
"tower-of-god",
|
||||
"the-beginning-after-the-end"
|
||||
]
|
||||
|
||||
// Agregar progreso para cada manga
|
||||
for (index, manga) in mangas.enumerated() {
|
||||
let progress = ReadingProgress(
|
||||
mangaSlug: manga,
|
||||
chapterNumber: index + 1,
|
||||
pageNumber: (index + 1) * 10,
|
||||
timestamp: Date().addingTimeInterval(Double(index * 100))
|
||||
)
|
||||
storageService.saveReadingProgress(progress)
|
||||
}
|
||||
|
||||
// Verificar progreso individual
|
||||
for (index, manga) in mangas.enumerated() {
|
||||
let progress = storageService.getLastReadChapter(mangaSlug: manga)
|
||||
XCTAssertNotNil(progress)
|
||||
XCTAssertEqual(progress?.chapterNumber, index + 1)
|
||||
}
|
||||
|
||||
// Verificar todo el progreso
|
||||
let allProgress = storageService.getAllReadingProgress()
|
||||
XCTAssertEqual(allProgress.count, 3)
|
||||
}
|
||||
|
||||
func testMultipleChapterDownloads() async throws {
|
||||
// Simular descarga de múltiples capítulos de diferentes mangas
|
||||
|
||||
let downloads = [
|
||||
("manga1", 1),
|
||||
("manga1", 2),
|
||||
("manga2", 1),
|
||||
("manga2", 3),
|
||||
("manga3", 5)
|
||||
]
|
||||
|
||||
// Crear y guardar capítulos descargados
|
||||
for (manga, chapter) in downloads {
|
||||
let chapter = DownloadedChapter(
|
||||
mangaSlug: manga,
|
||||
mangaTitle: "Manga \(manga)",
|
||||
chapterNumber: chapter,
|
||||
pages: [],
|
||||
downloadedAt: Date()
|
||||
)
|
||||
storageService.saveDownloadedChapter(chapter)
|
||||
}
|
||||
|
||||
// Verificar todos los capítulos descargados
|
||||
let allDownloaded = storageService.getDownloadedChapters()
|
||||
XCTAssertEqual(allDownloaded.count, 5)
|
||||
|
||||
// Verificar capítulos por manga
|
||||
let manga1Chapters = allDownloaded.filter { $0.mangaSlug == "manga1" }
|
||||
XCTAssertEqual(manga1Chapters.count, 2)
|
||||
|
||||
let manga2Chapters = allDownloaded.filter { $0.mangaSlug == "manga2" }
|
||||
XCTAssertEqual(manga2Chapters.count, 2)
|
||||
|
||||
let manga3Chapters = allDownloaded.filter { $0.mangaSlug == "manga3" }
|
||||
XCTAssertEqual(manga3Chapters.count, 1)
|
||||
}
|
||||
|
||||
// MARK: - Error Handling Scenarios
|
||||
|
||||
func testDownloadFlowWithMissingImages() async throws {
|
||||
// Simular descarga con imágenes faltantes
|
||||
|
||||
// Guardar solo algunas imágenes
|
||||
let image1 = createTestImage(color: .red, size: CGSize(width: 800, height: 1200))
|
||||
_ = try await storageService.saveImage(
|
||||
image1,
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 0
|
||||
)
|
||||
|
||||
// Intentar cargar imagen que no existe
|
||||
let missingImage = storageService.loadImage(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 1
|
||||
)
|
||||
|
||||
XCTAssertNil(missingImage, "Missing image should return nil")
|
||||
|
||||
// Verificar que la imagen existente sí se carga
|
||||
let existingImage = storageService.loadImage(
|
||||
mangaSlug: "test-manga",
|
||||
chapterNumber: 1,
|
||||
pageIndex: 0
|
||||
)
|
||||
|
||||
XCTAssertNotNil(existingImage, "Existing image should load successfully")
|
||||
}
|
||||
|
||||
func testStorageCleanupFlow() async throws {
|
||||
// Simular flujo de limpieza de almacenamiento
|
||||
|
||||
// 1. Llenar almacenamiento con datos
|
||||
for i in 0..<5 {
|
||||
let image = createTestImage(color: .blue, size: CGSize(width: 800, height: 1200))
|
||||
_ = try await storageService.saveImage(
|
||||
image,
|
||||
mangaSlug: "test",
|
||||
chapterNumber: i,
|
||||
pageIndex: 0
|
||||
)
|
||||
|
||||
let chapter = DownloadedChapter(
|
||||
mangaSlug: "test",
|
||||
mangaTitle: "Test",
|
||||
chapterNumber: i,
|
||||
pages: [],
|
||||
downloadedAt: Date()
|
||||
)
|
||||
storageService.saveDownloadedChapter(chapter)
|
||||
}
|
||||
|
||||
// Verificar que hay datos
|
||||
XCTAssertGreaterThan(storageService.getStorageSize(), 0)
|
||||
XCTAssertEqual(storageService.getDownloadedChapters().count, 5)
|
||||
|
||||
// 2. Limpiar todo
|
||||
storageService.clearAllDownloads()
|
||||
|
||||
// 3. Verificar que todo se eliminó
|
||||
XCTAssertEqual(storageService.getStorageSize(), 0)
|
||||
XCTAssertEqual(storageService.getDownloadedChapters().count, 0)
|
||||
}
|
||||
|
||||
// MARK: - Data Persistence Tests
|
||||
|
||||
func testDataPersistenceAcrossOperations() async throws {
|
||||
// Verificar que los datos persisten a través de múltiples operaciones
|
||||
|
||||
// 1. Guardar datos iniciales
|
||||
storageService.saveFavorite(mangaSlug: "persistent-manga")
|
||||
|
||||
let progress1 = ReadingProgress(
|
||||
mangaSlug: "persistent-manga",
|
||||
chapterNumber: 1,
|
||||
pageNumber: 5,
|
||||
timestamp: Date()
|
||||
)
|
||||
storageService.saveReadingProgress(progress1)
|
||||
|
||||
// 2. Verificar que existen
|
||||
XCTAssertTrue(storageService.isFavorite(mangaSlug: "persistent-manga"))
|
||||
XCTAssertNotNil(storageService.getReadingProgress(
|
||||
mangaSlug: "persistent-manga",
|
||||
chapterNumber: 1
|
||||
))
|
||||
|
||||
// 3. Realizar operaciones intermedias
|
||||
storageService.saveFavorite(mangaSlug: "temp-manga")
|
||||
storageService.removeFavorite(mangaSlug: "temp-manga")
|
||||
|
||||
// 4. Verificar que los datos originales persistieron
|
||||
XCTAssertTrue(storageService.isFavorite(mangaSlug: "persistent-manga"))
|
||||
let originalProgress = storageService.getReadingProgress(
|
||||
mangaSlug: "persistent-manga",
|
||||
chapterNumber: 1
|
||||
)
|
||||
XCTAssertEqual(originalProgress?.pageNumber, 5)
|
||||
}
|
||||
|
||||
// MARK: - Concurrent Operations Tests
|
||||
|
||||
func testConcurrentFavoriteOperations() {
|
||||
// Probar operaciones concurrentes en favoritos
|
||||
let expectations = (0..<10).map { _ in
|
||||
XCTestExpectation(description: "Favorite operation")
|
||||
}
|
||||
|
||||
let queue = DispatchQueue.global(qos: .userInitiated)
|
||||
|
||||
for i in 0..<10 {
|
||||
queue.async {
|
||||
self.storageService.saveFavorite(mangaSlug: "manga-\(i)")
|
||||
expectations[i].fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: expectations, timeout: 5.0)
|
||||
|
||||
let favorites = storageService.getFavorites()
|
||||
XCTAssertEqual(favorites.count, 10)
|
||||
}
|
||||
|
||||
func testConcurrentProgressOperations() {
|
||||
// Probar operaciones concurrentes de progreso
|
||||
let expectations = (0..<10).map { _ in
|
||||
XCTestExpectation(description: "Progress operation")
|
||||
}
|
||||
|
||||
let queue = DispatchQueue.global(qos: .userInitiated)
|
||||
|
||||
for i in 0..<10 {
|
||||
queue.async {
|
||||
let progress = ReadingProgress(
|
||||
mangaSlug: "manga-\(i % 3)",
|
||||
chapterNumber: i,
|
||||
pageNumber: i * 2,
|
||||
timestamp: Date()
|
||||
)
|
||||
self.storageService.saveReadingProgress(progress)
|
||||
expectations[i].fulfill()
|
||||
}
|
||||
}
|
||||
|
||||
wait(for: expectations, timeout: 5.0)
|
||||
|
||||
let allProgress = storageService.getAllReadingProgress()
|
||||
XCTAssertEqual(allProgress.count, 10)
|
||||
}
|
||||
|
||||
func testConcurrentImageOperations() async throws {
|
||||
// Probar guardado concurrente de imágenes
|
||||
await withTaskGroup(of: URL.self) { group in
|
||||
for i in 0..<20 {
|
||||
group.addTask {
|
||||
let image = self.createTestImage(
|
||||
color: .red,
|
||||
size: CGSize(width: 800, height: 1200)
|
||||
)
|
||||
return try! await self.storageService.saveImage(
|
||||
image,
|
||||
mangaSlug: "concurrent-test",
|
||||
chapterNumber: 1,
|
||||
pageIndex: i
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verificar que todas las imágenes se guardaron
|
||||
for i in 0..<20 {
|
||||
let image = storageService.loadImage(
|
||||
mangaSlug: "concurrent-test",
|
||||
chapterNumber: 1,
|
||||
pageIndex: i
|
||||
)
|
||||
XCTAssertNotNil(image, "Image at index \(i) should exist")
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Large Scale Tests
|
||||
|
||||
func testLargeScaleFavoriteOperations() {
|
||||
// Probar con muchos favoritos
|
||||
let count = 1000
|
||||
|
||||
measure {
|
||||
for i in 0..<count {
|
||||
storageService.saveFavorite(mangaSlug: "manga-\(i)")
|
||||
}
|
||||
}
|
||||
|
||||
let favorites = storageService.getFavorites()
|
||||
XCTAssertEqual(favorites.count, count)
|
||||
}
|
||||
|
||||
func testLargeScaleProgressOperations() {
|
||||
// Probar con mucho progreso de lectura
|
||||
let count = 500
|
||||
|
||||
measure {
|
||||
for i in 0..<count {
|
||||
let progress = ReadingProgress(
|
||||
mangaSlug: "manga-\(i % 50)",
|
||||
chapterNumber: i,
|
||||
pageNumber: i,
|
||||
timestamp: Date()
|
||||
)
|
||||
storageService.saveReadingProgress(progress)
|
||||
}
|
||||
}
|
||||
|
||||
let allProgress = storageService.getAllReadingProgress()
|
||||
XCTAssertEqual(allProgress.count, count)
|
||||
}
|
||||
|
||||
// MARK: - Helper Methods
|
||||
|
||||
private func createTestImage(color: UIColor, size: CGSize) -> UIImage {
|
||||
let renderer = UIGraphicsImageRenderer(size: size)
|
||||
return renderer.image { context in
|
||||
color.setFill()
|
||||
context.fill(CGRect(origin: .zero, size: size))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user