✨ 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>
687 lines
20 KiB
Swift
687 lines
20 KiB
Swift
import XCTest
|
|
import UIKit
|
|
@testable import MangaReader
|
|
|
|
/// Tests para el StorageService
|
|
/// Tests para guardar/cargar favoritos, progreso de lectura y capítulos descargados
|
|
final class StorageServiceTests: XCTestCase {
|
|
|
|
var storageService: StorageService!
|
|
var mockUserDefaults: UserDefaults!
|
|
|
|
// MARK: - Setup & Teardown
|
|
|
|
override func setUp() async throws {
|
|
try await super.setUp()
|
|
|
|
// Crear un UserDefaults aislado para los tests
|
|
mockUserDefaults = UserDefaults(suiteName: "test_manga_reader_\(UUID().uuidString)")!
|
|
|
|
// Inyectar el mock UserDefaults si fuera posible (requiere modificación del StorageService)
|
|
// Por ahora, limpiaremos UserDefaults después de cada test
|
|
|
|
// Limpiar UserDefaults antes de cada test
|
|
UserDefaults.standard.removeObject(forKey: "favoriteMangas")
|
|
UserDefaults.standard.removeObject(forKey: "readingProgress")
|
|
UserDefaults.standard.removeObject(forKey: "downloadedChaptersMetadata")
|
|
|
|
storageService = StorageService.shared
|
|
}
|
|
|
|
override func tearDown() async throws {
|
|
// Limpiar después de los tests
|
|
UserDefaults.standard.removeObject(forKey: "favoriteMangas")
|
|
UserDefaults.standard.removeObject(forKey: "readingProgress")
|
|
|
|
// Limpiar archivos de test
|
|
storageService.clearAllDownloads()
|
|
|
|
try await super.tearDown()
|
|
}
|
|
|
|
// MARK: - Favorites Tests
|
|
|
|
func testSaveFavorite() {
|
|
// Given
|
|
let mangaSlug = "solo-leveling"
|
|
|
|
// When
|
|
storageService.saveFavorite(mangaSlug: mangaSlug)
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertTrue(favorites.contains(mangaSlug))
|
|
XCTAssertEqual(favorites.count, 1)
|
|
}
|
|
|
|
func testSaveMultipleFavorites() {
|
|
// Given
|
|
let slugs = ["solo-leveling", "tower-of-god", "the-beginning-after-the-end"]
|
|
|
|
// When
|
|
slugs.forEach { storageService.saveFavorite(mangaSlug: $0) }
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertEqual(favorites.count, 3)
|
|
XCTAssertTrue(favorites.contains("solo-leveling"))
|
|
XCTAssertTrue(favorites.contains("tower-of-god"))
|
|
XCTAssertTrue(favorites.contains("the-beginning-after-the-end"))
|
|
}
|
|
|
|
func testSaveDuplicateFavorite() {
|
|
// Given
|
|
let mangaSlug = "solo-leveling"
|
|
|
|
// When
|
|
storageService.saveFavorite(mangaSlug: mangaSlug)
|
|
storageService.saveFavorite(mangaSlug: mangaSlug) // Intentar guardar duplicado
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertEqual(favorites.count, 1, "Duplicate favorites should not be added")
|
|
XCTAssertEqual(favorites.first, mangaSlug)
|
|
}
|
|
|
|
func testRemoveFavorite() {
|
|
// Given
|
|
let mangaSlug = "solo-leveling"
|
|
storageService.saveFavorite(mangaSlug: mangaSlug)
|
|
|
|
// When
|
|
storageService.removeFavorite(mangaSlug: mangaSlug)
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertFalse(favorites.contains(mangaSlug))
|
|
XCTAssertEqual(favorites.count, 0)
|
|
}
|
|
|
|
func testRemoveNonExistentFavorite() {
|
|
// Given
|
|
storageService.saveFavorite(mangaSlug: "manga1")
|
|
storageService.saveFavorite(mangaSlug: "manga2")
|
|
|
|
// When
|
|
storageService.removeFavorite(mangaSlug: "non-existent")
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertEqual(favorites.count, 2, "Removing non-existent favorite should not affect others")
|
|
}
|
|
|
|
func testIsFavorite() {
|
|
// Given
|
|
let favoriteSlug = "solo-leveling"
|
|
let nonFavoriteSlug = "tower-of-god"
|
|
storageService.saveFavorite(mangaSlug: favoriteSlug)
|
|
|
|
// When & Then
|
|
XCTAssertTrue(storageService.isFavorite(mangaSlug: favoriteSlug))
|
|
XCTAssertFalse(storageService.isFavorite(mangaSlug: nonFavoriteSlug))
|
|
}
|
|
|
|
func testGetFavoritesWhenEmpty() {
|
|
// When
|
|
let favorites = storageService.getFavorites()
|
|
|
|
// Then
|
|
XCTAssertTrue(favorites.isEmpty)
|
|
XCTAssertEqual(favorites.count, 0)
|
|
}
|
|
|
|
// MARK: - Reading Progress Tests
|
|
|
|
func testSaveReadingProgress() {
|
|
// Given
|
|
let progress = ReadingProgress(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50,
|
|
pageNumber: 10,
|
|
timestamp: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveReadingProgress(progress)
|
|
|
|
// Then
|
|
let retrievedProgress = storageService.getReadingProgress(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50
|
|
)
|
|
|
|
XCTAssertNotNil(retrievedProgress)
|
|
XCTAssertEqual(retrievedProgress?.mangaSlug, "solo-leveling")
|
|
XCTAssertEqual(retrievedProgress?.chapterNumber, 50)
|
|
XCTAssertEqual(retrievedProgress?.pageNumber, 10)
|
|
}
|
|
|
|
func testSaveMultipleReadingProgress() {
|
|
// Given
|
|
let progress1 = ReadingProgress(
|
|
mangaSlug: "manga1",
|
|
chapterNumber: 1,
|
|
pageNumber: 5,
|
|
timestamp: Date()
|
|
)
|
|
|
|
let progress2 = ReadingProgress(
|
|
mangaSlug: "manga1",
|
|
chapterNumber: 2,
|
|
pageNumber: 15,
|
|
timestamp: Date()
|
|
)
|
|
|
|
let progress3 = ReadingProgress(
|
|
mangaSlug: "manga2",
|
|
chapterNumber: 1,
|
|
pageNumber: 20,
|
|
timestamp: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveReadingProgress(progress1)
|
|
storageService.saveReadingProgress(progress2)
|
|
storageService.saveReadingProgress(progress3)
|
|
|
|
// Then
|
|
let allProgress = storageService.getAllReadingProgress()
|
|
XCTAssertEqual(allProgress.count, 3)
|
|
}
|
|
|
|
func testUpdateExistingReadingProgress() {
|
|
// Given
|
|
let initialProgress = ReadingProgress(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50,
|
|
pageNumber: 10,
|
|
timestamp: Date(timeIntervalSince1970: 1609459200)
|
|
)
|
|
|
|
let updatedProgress = ReadingProgress(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50,
|
|
pageNumber: 25,
|
|
timestamp: Date(timeIntervalSince1970: 1609459300)
|
|
)
|
|
|
|
// When
|
|
storageService.saveReadingProgress(initialProgress)
|
|
storageService.saveReadingProgress(updatedProgress)
|
|
|
|
// Then
|
|
let retrieved = storageService.getReadingProgress(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50
|
|
)
|
|
|
|
XCTAssertEqual(retrieved?.pageNumber, 25, "Progress should be updated")
|
|
XCTAssertEqual(retrieved?.timestamp.timeIntervalSince1970, 1609459300, accuracy: 0.001)
|
|
}
|
|
|
|
func testGetReadingProgressWhenNotExists() {
|
|
// When
|
|
let progress = storageService.getReadingProgress(
|
|
mangaSlug: "non-existent",
|
|
chapterNumber: 999
|
|
)
|
|
|
|
// Then
|
|
XCTAssertNil(progress)
|
|
}
|
|
|
|
func testGetLastReadChapter() {
|
|
// Given
|
|
let oldDate = Date(timeIntervalSince1970: 1609459200)
|
|
let newDate = Date(timeIntervalSince1970: 1609459300)
|
|
|
|
let progress1 = ReadingProgress(
|
|
mangaSlug: "manga1",
|
|
chapterNumber: 1,
|
|
pageNumber: 10,
|
|
timestamp: oldDate
|
|
)
|
|
|
|
let progress2 = ReadingProgress(
|
|
mangaSlug: "manga1",
|
|
chapterNumber: 2,
|
|
pageNumber: 5,
|
|
timestamp: newDate
|
|
)
|
|
|
|
// When
|
|
storageService.saveReadingProgress(progress1)
|
|
storageService.saveReadingProgress(progress2)
|
|
|
|
let lastRead = storageService.getLastReadChapter(mangaSlug: "manga1")
|
|
|
|
// Then
|
|
XCTAssertNotNil(lastRead)
|
|
XCTAssertEqual(lastRead?.chapterNumber, 2, "Should return the most recent chapter")
|
|
XCTAssertEqual(lastRead?.timestamp.timeIntervalSince1970, 1609459300, accuracy: 0.001)
|
|
}
|
|
|
|
func testGetLastReadChapterWhenNoProgress() {
|
|
// When
|
|
let lastRead = storageService.getLastReadChapter(mangaSlug: "non-existent")
|
|
|
|
// Then
|
|
XCTAssertNil(lastRead)
|
|
}
|
|
|
|
func testGetAllReadingProgressWhenEmpty() {
|
|
// When
|
|
let allProgress = storageService.getAllReadingProgress()
|
|
|
|
// Then
|
|
XCTAssertTrue(allProgress.isEmpty)
|
|
}
|
|
|
|
// MARK: - Downloaded Chapters Tests
|
|
|
|
func testSaveDownloadedChapter() {
|
|
// Given
|
|
let pages = [
|
|
MangaPage(url: "page1.jpg", index: 0),
|
|
MangaPage(url: "page2.jpg", index: 1)
|
|
]
|
|
|
|
let downloadedChapter = DownloadedChapter(
|
|
mangaSlug: "solo-leveling",
|
|
mangaTitle: "Solo Leveling",
|
|
chapterNumber: 50,
|
|
pages: pages,
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveDownloadedChapter(downloadedChapter)
|
|
|
|
// Then
|
|
let retrieved = storageService.getDownloadedChapter(
|
|
mangaSlug: "solo-leveling",
|
|
chapterNumber: 50
|
|
)
|
|
|
|
XCTAssertNotNil(retrieved)
|
|
XCTAssertEqual(retrieved?.mangaSlug, "solo-leveling")
|
|
XCTAssertEqual(retrieved?.chapterNumber, 50)
|
|
XCTAssertEqual(retrieved?.pages.count, 2)
|
|
}
|
|
|
|
func testIsChapterDownloaded() {
|
|
// Given
|
|
let chapter = DownloadedChapter(
|
|
mangaSlug: "test-manga",
|
|
mangaTitle: "Test",
|
|
chapterNumber: 10,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveDownloadedChapter(chapter)
|
|
|
|
// Then
|
|
XCTAssertTrue(storageService.isChapterDownloaded(
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 10
|
|
))
|
|
|
|
XCTAssertFalse(storageService.isChapterDownloaded(
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 11
|
|
))
|
|
}
|
|
|
|
func testGetDownloadedChapters() {
|
|
// Given
|
|
let chapter1 = DownloadedChapter(
|
|
mangaSlug: "manga1",
|
|
mangaTitle: "Manga 1",
|
|
chapterNumber: 1,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
let chapter2 = DownloadedChapter(
|
|
mangaSlug: "manga2",
|
|
mangaTitle: "Manga 2",
|
|
chapterNumber: 5,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveDownloadedChapter(chapter1)
|
|
storageService.saveDownloadedChapter(chapter2)
|
|
|
|
// Then
|
|
let downloaded = storageService.getDownloadedChapters()
|
|
XCTAssertEqual(downloaded.count, 2)
|
|
}
|
|
|
|
func testDeleteDownloadedChapter() {
|
|
// Given
|
|
let chapter = DownloadedChapter(
|
|
mangaSlug: "test-manga",
|
|
mangaTitle: "Test",
|
|
chapterNumber: 10,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
storageService.saveDownloadedChapter(chapter)
|
|
XCTAssertTrue(storageService.isChapterDownloaded(mangaSlug: "test-manga", chapterNumber: 10))
|
|
|
|
// When
|
|
storageService.deleteDownloadedChapter(mangaSlug: "test-manga", chapterNumber: 10)
|
|
|
|
// Then
|
|
XCTAssertFalse(storageService.isChapterDownloaded(mangaSlug: "test-manga", chapterNumber: 10))
|
|
}
|
|
|
|
func testDeleteNonExistentDownloadedChapter() {
|
|
// When - No debería lanzar error
|
|
storageService.deleteDownloadedChapter(mangaSlug: "non-existent", chapterNumber: 999)
|
|
|
|
// Then - Simplemente no hace nada
|
|
let downloaded = storageService.getDownloadedChapters()
|
|
XCTAssertTrue(downloaded.isEmpty)
|
|
}
|
|
|
|
// MARK: - Image Caching Tests
|
|
|
|
func testSaveAndLoadImage() async throws {
|
|
// Given
|
|
let testImage = createTestImage(size: CGSize(width: 800, height: 1200))
|
|
|
|
// When
|
|
let savedURL = try await storageService.saveImage(
|
|
testImage,
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
// Then
|
|
XCTAssertTrue(FileManager.default.fileExists(atPath: savedURL.path))
|
|
XCTAssertEqual(savedURL.lastPathComponent, "page_0.jpg")
|
|
|
|
let loadedImage = storageService.loadImage(
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
XCTAssertNotNil(loadedImage)
|
|
}
|
|
|
|
func testLoadNonExistentImage() {
|
|
// When
|
|
let image = storageService.loadImage(
|
|
mangaSlug: "non-existent",
|
|
chapterNumber: 999,
|
|
pageIndex: 999
|
|
)
|
|
|
|
// Then
|
|
XCTAssertNil(image)
|
|
}
|
|
|
|
func testGetImageURL() async throws {
|
|
// Given
|
|
let testImage = createTestImage(size: CGSize(width: 800, height: 1200))
|
|
|
|
// When
|
|
let savedURL = try await storageService.saveImage(
|
|
testImage,
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
let retrievedURL = storageService.getImageURL(
|
|
mangaSlug: "test-manga",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
// Then
|
|
XCTAssertNotNil(retrievedURL)
|
|
XCTAssertEqual(retrievedURL, savedURL)
|
|
}
|
|
|
|
func testGetImageURLForNonExistentImage() {
|
|
// When
|
|
let url = storageService.getImageURL(
|
|
mangaSlug: "test",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
// Then
|
|
XCTAssertNil(url)
|
|
}
|
|
|
|
// MARK: - Storage Management Tests
|
|
|
|
func testGetStorageSize() async throws {
|
|
// Given
|
|
let image1 = createTestImage(size: CGSize(width: 800, height: 1200))
|
|
let image2 = createTestImage(size: CGSize(width: 800, height: 1200))
|
|
|
|
// When
|
|
_ = try await storageService.saveImage(image1, mangaSlug: "test", chapterNumber: 1, pageIndex: 0)
|
|
_ = try await storageService.saveImage(image2, mangaSlug: "test", chapterNumber: 1, pageIndex: 1)
|
|
|
|
let size = storageService.getStorageSize()
|
|
|
|
// Then
|
|
XCTAssertGreaterThan(size, 0, "Storage size should be greater than 0")
|
|
}
|
|
|
|
func testClearAllDownloads() async throws {
|
|
// Given
|
|
let image = createTestImage(size: CGSize(width: 800, height: 1200))
|
|
_ = try await storageService.saveImage(image, mangaSlug: "test", chapterNumber: 1, pageIndex: 0)
|
|
|
|
let chapter = DownloadedChapter(
|
|
mangaSlug: "test",
|
|
mangaTitle: "Test",
|
|
chapterNumber: 1,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
storageService.saveDownloadedChapter(chapter)
|
|
|
|
// When
|
|
storageService.clearAllDownloads()
|
|
|
|
// Then
|
|
let downloaded = storageService.getDownloadedChapters()
|
|
XCTAssertTrue(downloaded.isEmpty)
|
|
|
|
let size = storageService.getStorageSize()
|
|
XCTAssertEqual(size, 0, "Storage size should be 0 after clearing")
|
|
}
|
|
|
|
func testFormatFileSize() {
|
|
// Given
|
|
let bytes: Int64 = 1536000 // ~1.5 MB
|
|
|
|
// When
|
|
let formatted = storageService.formatFileSize(bytes)
|
|
|
|
// Then
|
|
XCTAssertTrue(formatted.contains("MB") || formatted.contains("KB"))
|
|
}
|
|
|
|
func testFormatFileSizeWithVariousSizes() {
|
|
let tests: [(Int64, String)] = [
|
|
(500, "B"), // Bytes
|
|
(1024, "KB"), // 1 KB
|
|
(1048576, "MB"), // 1 MB
|
|
(1073741824, "GB") // 1 GB
|
|
]
|
|
|
|
for (size, expectedUnit) in {
|
|
let formatted = storageService.formatFileSize(size)
|
|
XCTAssertTrue(
|
|
formatted.contains(expectedUnit),
|
|
"Expected \(expectedUnit) in formatted string: \(formatted)"
|
|
)
|
|
}
|
|
}
|
|
|
|
// MARK: - Directory Management Tests
|
|
|
|
func testGetChapterDirectory() {
|
|
// When
|
|
let directory = storageService.getChapterDirectory(mangaSlug: "test-manga", chapterNumber: 10)
|
|
|
|
// Then
|
|
XCTAssertTrue(directory.path.contains("test-manga"))
|
|
XCTAssertTrue(directory.path.contains("Chapter10"))
|
|
}
|
|
|
|
func testChapterDirectoryCreation() async throws {
|
|
// Given
|
|
let image = createTestImage(size: CGSize(width: 100, height: 100))
|
|
|
|
// When
|
|
let savedURL = try await storageService.saveImage(
|
|
image,
|
|
mangaSlug: "new-manga",
|
|
chapterNumber: 1,
|
|
pageIndex: 0
|
|
)
|
|
|
|
// Then
|
|
let directory = savedURL.deletingLastPathComponent()
|
|
XCTAssertTrue(FileManager.default.fileExists(atPath: directory.path))
|
|
}
|
|
|
|
// MARK: - Edge Cases Tests
|
|
|
|
func testSaveFavoriteWithEmptySlug() {
|
|
// When
|
|
storageService.saveFavorite(mangaSlug: "")
|
|
|
|
// Then
|
|
let favorites = storageService.getFavorites()
|
|
XCTAssertTrue(favorites.contains(""), "Empty slug should be saved")
|
|
}
|
|
|
|
func testSaveFavoriteWithSpecialCharacters() {
|
|
// Given
|
|
let specialSlug = "manga-with-special-chars-áéíóú-ñ-@#$"
|
|
|
|
// When
|
|
storageService.saveFavorite(mangaSlug: specialSlug)
|
|
|
|
// Then
|
|
XCTAssertTrue(storageService.isFavorite(mangaSlug: specialSlug))
|
|
}
|
|
|
|
func testReadingProgressWithZeroPage() {
|
|
// Given
|
|
let progress = ReadingProgress(
|
|
mangaSlug: "test",
|
|
chapterNumber: 1,
|
|
pageNumber: 0,
|
|
timestamp: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveReadingProgress(progress)
|
|
|
|
// Then
|
|
let retrieved = storageService.getReadingProgress(mangaSlug: "test", chapterNumber: 1)
|
|
XCTAssertEqual(retrieved?.pageNumber, 0)
|
|
}
|
|
|
|
func testDownloadedChapterWithZeroChapterNumber() {
|
|
// Given
|
|
let chapter = DownloadedChapter(
|
|
mangaSlug: "test",
|
|
mangaTitle: "Test",
|
|
chapterNumber: 0,
|
|
pages: [],
|
|
downloadedAt: Date()
|
|
)
|
|
|
|
// When
|
|
storageService.saveDownloadedChapter(chapter)
|
|
|
|
// Then
|
|
XCTAssertTrue(storageService.isChapterDownloaded(mangaSlug: "test", chapterNumber: 0))
|
|
}
|
|
|
|
func testConcurrentImageSave() async throws {
|
|
// Given
|
|
let images = (0..<10).map { _ in createTestImage(size: CGSize(width: 800, height: 1200)) }
|
|
|
|
// When - Guardar imágenes concurrentemente
|
|
await withTaskGroup(of: URL.self) { group in
|
|
for (index, image) in images.enumerated() {
|
|
group.addTask {
|
|
try! await self.storageService.saveImage(
|
|
image,
|
|
mangaSlug: "concurrent-test",
|
|
chapterNumber: 1,
|
|
pageIndex: index
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Then - Verificar que todas se guardaron
|
|
for index in 0..<10 {
|
|
let image = storageService.loadImage(
|
|
mangaSlug: "concurrent-test",
|
|
chapterNumber: 1,
|
|
pageIndex: index
|
|
)
|
|
XCTAssertNotNil(image, "Image at index \(index) should exist")
|
|
}
|
|
}
|
|
|
|
// MARK: - Helper Methods
|
|
|
|
private func createTestImage(size: CGSize) -> UIImage {
|
|
let renderer = UIGraphicsImageRenderer(size: size)
|
|
return renderer.image { context in
|
|
UIColor.blue.setFill()
|
|
context.fill(CGRect(origin: .zero, size: size))
|
|
}
|
|
}
|
|
|
|
// MARK: - Performance Tests
|
|
|
|
func testSaveManyFavoritesPerformance() {
|
|
measure {
|
|
for i in 0..<1000 {
|
|
storageService.saveFavorite(mangaSlug: "manga-\(i)")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testSaveManyReadingProgressPerformance() {
|
|
let progresses = (0..<100).map { i in
|
|
ReadingProgress(
|
|
mangaSlug: "manga-\(i % 10)",
|
|
chapterNumber: i,
|
|
pageNumber: i * 2,
|
|
timestamp: Date()
|
|
)
|
|
}
|
|
|
|
measure {
|
|
for progress in progresses {
|
|
storageService.saveReadingProgress(progress)
|
|
}
|
|
}
|
|
}
|
|
}
|