mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 22:27:13 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
158 lines
5.6 KiB
Swift
158 lines
5.6 KiB
Swift
import XCTest
|
|
import TelegramCore
|
|
import Postbox
|
|
|
|
final class SynchronizeableChatInputStateTests: XCTestCase {
|
|
// MARK: - Faithful persistence round-trip (the real storage path)
|
|
|
|
// SynchronizeableChatInputState is persisted by encoding the enclosing
|
|
// InternalChatInterfaceState via AdaptedPostboxEncoder/Decoder. Both its
|
|
// encode(to:) and init(from:) open a keyed container, so encoding the
|
|
// struct itself directly through the same encoder/decoder is a faithful
|
|
// check of the exact bytes that hit the draft store / cloud.
|
|
|
|
func test_textEntities_roundTripsViaAdaptedPostbox() throws {
|
|
let state = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .textEntities(text: "hello", entities: [MessageTextEntity(range: 0 ..< 5, type: .Bold)]),
|
|
timestamp: 123,
|
|
textSelection: 1 ..< 3,
|
|
messageEffectId: 42,
|
|
suggestedPost: nil
|
|
)
|
|
|
|
let data = try AdaptedPostboxEncoder().encode(state)
|
|
let decoded = try AdaptedPostboxDecoder().decode(SynchronizeableChatInputState.self, from: data)
|
|
|
|
XCTAssertEqual(decoded, state)
|
|
if case let .textEntities(text, entities) = decoded.content {
|
|
XCTAssertEqual(text, "hello")
|
|
XCTAssertEqual(entities, [MessageTextEntity(range: 0 ..< 5, type: .Bold)])
|
|
} else {
|
|
XCTFail("expected .textEntities after round-trip")
|
|
}
|
|
// The legacy flat encoding is unchanged: text/entities survive byte-for-byte.
|
|
XCTAssertEqual(decoded.text, "hello")
|
|
XCTAssertEqual(decoded.entities, [MessageTextEntity(range: 0 ..< 5, type: .Bold)])
|
|
XCTAssertEqual(decoded.textSelection, 1 ..< 3)
|
|
XCTAssertEqual(decoded.messageEffectId, 42)
|
|
}
|
|
|
|
func test_instantPage_roundTripsViaAdaptedPostbox() throws {
|
|
let page = InstantPage(
|
|
blocks: [.paragraph(.plain("hello"))],
|
|
media: [:],
|
|
isComplete: true,
|
|
rtl: false,
|
|
url: "",
|
|
views: nil
|
|
)
|
|
let state = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .instantPage(page),
|
|
timestamp: 7,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
|
|
let data = try AdaptedPostboxEncoder().encode(state)
|
|
let decoded = try AdaptedPostboxDecoder().decode(SynchronizeableChatInputState.self, from: data)
|
|
|
|
XCTAssertEqual(decoded, state)
|
|
if case let .instantPage(decodedPage) = decoded.content {
|
|
XCTAssertEqual(decodedPage, page)
|
|
} else {
|
|
XCTFail("expected .instantPage after round-trip")
|
|
}
|
|
}
|
|
|
|
// MARK: - Derived accessors
|
|
|
|
func test_derivedAccessors_textEntities() {
|
|
let state = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .textEntities(text: "abc", entities: [MessageTextEntity(range: 0 ..< 3, type: .Italic)]),
|
|
timestamp: 0,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
XCTAssertEqual(state.text, "abc")
|
|
XCTAssertEqual(state.entities, [MessageTextEntity(range: 0 ..< 3, type: .Italic)])
|
|
}
|
|
|
|
func test_derivedAccessors_instantPage_fallsBackToPlainTextNoEntities() {
|
|
let page = InstantPage(
|
|
blocks: [.paragraph(.plain("line one")), .paragraph(.plain("line two"))],
|
|
media: [:],
|
|
isComplete: true,
|
|
rtl: false,
|
|
url: "",
|
|
views: nil
|
|
)
|
|
let state = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .instantPage(page),
|
|
timestamp: 0,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
// Old clients see the plainText projection and no entities.
|
|
XCTAssertEqual(state.text, page.plainText)
|
|
XCTAssertEqual(state.text, "line one\nline two")
|
|
XCTAssertTrue(state.entities.isEmpty)
|
|
}
|
|
|
|
// MARK: - Equatable distinguishes the two content kinds
|
|
|
|
func test_equatable_distinguishesContentKinds() {
|
|
let page = InstantPage(
|
|
blocks: [.paragraph(.plain("hello"))],
|
|
media: [:],
|
|
isComplete: true,
|
|
rtl: false,
|
|
url: "",
|
|
views: nil
|
|
)
|
|
let textState = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .textEntities(text: "hello", entities: []),
|
|
timestamp: 0,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
let pageState = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
content: .instantPage(page),
|
|
timestamp: 0,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
// Same derived plainText, but distinct content kinds → not equal.
|
|
XCTAssertEqual(textState.text, pageState.text)
|
|
XCTAssertNotEqual(textState, pageState)
|
|
}
|
|
|
|
// MARK: - The text:entities: forwarding init still produces .textEntities
|
|
|
|
func test_textEntitiesInit_forwardsToContent() {
|
|
let state = SynchronizeableChatInputState(
|
|
replySubject: nil,
|
|
text: "fwd",
|
|
entities: [],
|
|
timestamp: 0,
|
|
textSelection: nil,
|
|
messageEffectId: nil,
|
|
suggestedPost: nil
|
|
)
|
|
guard case .textEntities = state.content else {
|
|
return XCTFail("text:entities: init should produce .textEntities content")
|
|
}
|
|
XCTAssertEqual(state.text, "fwd")
|
|
}
|
|
}
|