Files
ghostgram/submodules/TextFormat/Tests/SynchronizeableChatInputStateTests.swift
ichmagmaus111andClaude Opus 5.5 0622057a4f Ghostgram: open-source release
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 17:57:09 +01:00

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