Files
legado-ios/Tests/LegadoCoreTests/ReadingActivityRepositoryTests.swift
T

138 lines
6.2 KiB
Swift

import Foundation
import Testing
@testable import LegadoCore
struct ReadingActivityRepositoryTests {
@Test func decodesAndEncodesBookmarkPosition() throws {
let data = Data(#"{"time":7,"bookName":"书","bookAuthor":"作者","chapterIndex":2,"chapterPos":88,"chapterName":"第二章","bookText":"片段","content":"备注"}"#.utf8)
let bookmark = try JSONDecoder().decode(Bookmark.self, from: data)
let encoded = try JSONEncoder().encode(bookmark)
let object = try #require(JSONSerialization.jsonObject(with: encoded) as? [String: Any])
#expect(bookmark.chapterPosition == 88)
#expect(object["chapterPos"] as? Int == 88)
#expect(object["chapterPosition"] == nil)
}
@Test func accumulatesPerDeviceAndSummarizesAcrossDevices() {
let service = ReadingActivityService()
let now: Int64 = 2_000
var records = [ReadRecord(deviceId: "a", bookName: "书", readTime: 1_000, lastRead: 1_000)]
records = service.addingReadTime(500, deviceID: "a", bookName: "书", now: now, to: records)
records = service.addingReadTime(700, deviceID: "b", bookName: "书", now: now + 1, to: records)
let summary = service.summaries(records)
#expect(records.count == 2)
#expect(summary == [.init(bookName: "书", readTime: 2_200, lastRead: 2_001)])
}
@Test func decodesLegacyReadRecordWithoutDailyStatistics() throws {
let data = Data(#"{"deviceId":"ios","bookName":"旧书","readTime":120000,"lastRead":7}"#.utf8)
let record = try JSONDecoder().decode(ReadRecord.self, from: data)
#expect(record.dailyReadTimes.isEmpty)
#expect(record.readTime == 120_000)
}
@Test func calculatesTodayStreakTotalsAndUniqueBooks() throws {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = try #require(TimeZone(identifier: "Asia/Shanghai"))
let now = try #require(calendar.date(from: DateComponents(year: 2026, month: 8, day: 20, hour: 12)))
let service = ReadingActivityService()
let records = [
ReadRecord(
deviceId: "a",
bookName: "第一本",
readTime: 9_000_000,
lastRead: Int64(now.timeIntervalSince1970 * 1_000),
dailyReadTimes: ["2026-08-18": 600_000, "2026-08-19": 1_200_000, "2026-08-20": 1_800_000]
),
ReadRecord(
deviceId: "b",
bookName: "第一本",
readTime: 3_000_000,
dailyReadTimes: ["2026-08-20": 300_000]
),
ReadRecord(
deviceId: "a",
bookName: "第二本",
readTime: 4_000_000,
dailyReadTimes: ["2026-08-17": 60_000]
)
]
let statistics = service.statistics(records, now: now, calendar: calendar)
#expect(statistics.todayReadTime == 2_100_000)
#expect(statistics.currentStreak == 4)
#expect(statistics.totalReadTime == 16_000_000)
#expect(statistics.bookCount == 2)
#expect(statistics.recentDays.count == 7)
}
@Test func keepsCurrentStreakUntilTheDayAfterLastReading() throws {
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = try #require(TimeZone(identifier: "Asia/Shanghai"))
let now = try #require(calendar.date(from: DateComponents(year: 2026, month: 8, day: 20, hour: 8)))
let records = [ReadRecord(
deviceId: "a",
bookName: "书",
readTime: 120_000,
dailyReadTimes: ["2026-08-18": 60_000, "2026-08-19": 60_000]
)]
let statistics = ReadingActivityService().statistics(records, now: now, calendar: calendar)
#expect(statistics.todayReadTime == 0)
#expect(statistics.currentStreak == 2)
}
@Test func filtersAndSortsReadRecords() {
let records = [
ReadRecord(deviceId: "a", bookName: "Beta", readTime: 5_000, lastRead: 20),
ReadRecord(deviceId: "a", bookName: "Alpha", readTime: 1_000, lastRead: 30),
ReadRecord(deviceId: "b", bookName: "Beta", readTime: 2_000, lastRead: 40)
]
let service = ReadingActivityService()
#expect(service.displayedSummaries(records, searchKey: "", sortMode: 0).map(\.bookName) == ["Alpha", "Beta"])
#expect(service.displayedSummaries(records, searchKey: "", sortMode: 1).map(\.bookName) == ["Beta", "Alpha"])
#expect(service.displayedSummaries(records, searchKey: "", sortMode: 2).map(\.bookName) == ["Beta", "Alpha"])
#expect(service.displayedSummaries(records, searchKey: "alp", sortMode: 0).map(\.bookName) == ["Alpha"])
}
@Test func sortsBookmarksByBookAndPosition() {
var later = Bookmark(time: 1, bookName: "B", bookAuthor: "作者")
later.chapterIndex = 1
later.chapterPosition = 20
var earlierPosition = Bookmark(time: 2, bookName: "A", bookAuthor: "作者")
earlierPosition.chapterIndex = 2
earlierPosition.chapterPosition = 30
var first = Bookmark(time: 3, bookName: "A", bookAuthor: "作者")
first.chapterIndex = 1
first.chapterPosition = 40
let sorted = ReadingActivityService().sortedBookmarks([later, earlierPosition, first])
#expect(sorted.map(\.time) == [first.time, earlierPosition.time, later.time])
}
@Test func persistsBookmarksAndRecordsAtomically() async throws {
let directory = FileManager.default.temporaryDirectory.appending(path: UUID().uuidString, directoryHint: .isDirectory)
defer { try? FileManager.default.removeItem(at: directory) }
let repository = FileReadingActivityRepository(
bookmarksURL: directory.appending(path: "bookmarks.json"),
recordsURL: directory.appending(path: "records.json")
)
var bookmark = Bookmark(time: 4, bookName: "书")
bookmark.chapterPosition = 19
let record = ReadRecord(deviceId: "ios", bookName: "书", readTime: 3_000, lastRead: 5)
try await repository.saveBookmarks([bookmark])
try await repository.saveReadRecords([record])
#expect(try await repository.loadBookmarks() == [bookmark])
#expect(try await repository.loadReadRecords() == [record])
}
}