mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-11-03 14:17:19 +01:00
Ghostgram for iOS, rebuilt from scratch on Telegram iOS 13.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.9 KiB
Swift
80 lines
2.9 KiB
Swift
import Foundation
|
|
import XCTest
|
|
@testable import Postbox
|
|
|
|
private struct Chunk: Codable, Equatable {
|
|
var index: Int32
|
|
var payload: Data
|
|
}
|
|
|
|
private struct Container: Codable, Equatable {
|
|
var chunks: [Chunk]
|
|
}
|
|
|
|
/// Arrays of Codable objects travel through `PostboxDecoder.decodeObjectDataArrayRaw`.
|
|
/// Its only job is to split the array bytes into elements; it must accept any element
|
|
/// that fits inside the buffer, and reject corruption by failing the decode rather than
|
|
/// returning a partial array.
|
|
final class AdaptedPostboxDecoderArrayTests: XCTestCase {
|
|
private func encode(_ container: Container) -> Data {
|
|
let encoder = PostboxEncoder()
|
|
encoder.encode(container, forKey: "c")
|
|
return encoder.makeData()
|
|
}
|
|
|
|
private func decode(_ data: Data) -> Container? {
|
|
return PostboxDecoder(buffer: MemoryBuffer(data: data)).decode(Container.self, forKey: "c")
|
|
}
|
|
|
|
func testArrayWithAnElementLargerThanTwoMebibytesRoundTrips() {
|
|
let large = Data(repeating: 0xAB, count: 3 * 1024 * 1024)
|
|
let container = Container(chunks: [
|
|
Chunk(index: 1, payload: Data([1, 2, 3])),
|
|
Chunk(index: 2, payload: large),
|
|
Chunk(index: 3, payload: Data([4, 5])),
|
|
])
|
|
|
|
let decoded = self.decode(self.encode(container))
|
|
|
|
XCTAssertEqual(decoded?.chunks.count, 3)
|
|
XCTAssertEqual(decoded, container)
|
|
}
|
|
|
|
func testElementLengthPointingPastTheBufferFailsTheWholeDecode() {
|
|
let container = Container(chunks: [
|
|
Chunk(index: 1, payload: Data([1, 2, 3])),
|
|
Chunk(index: 2, payload: Data([4, 5, 6])),
|
|
])
|
|
var data = self.encode(container)
|
|
XCTAssertEqual(self.decode(data), container, "fixture must decode before it is corrupted")
|
|
|
|
// Layout after the "chunks" key: [type: 1][count: 4][typeHash: 4][objectLength: 4] ...
|
|
guard let keyRange = data.range(of: "chunks".data(using: .utf8)!) else {
|
|
return XCTFail("key not found in encoded data")
|
|
}
|
|
let objectLengthOffset = keyRange.upperBound + 1 + 4 + 4
|
|
var corruptLength: Int32 = 0x7FFF_0000
|
|
withUnsafeBytes(of: &corruptLength) { bytes in
|
|
data.replaceSubrange(objectLengthOffset ..< objectLengthOffset + 4, with: bytes)
|
|
}
|
|
|
|
XCTAssertNil(self.decode(data))
|
|
}
|
|
|
|
func testNegativeElementLengthFailsTheWholeDecode() {
|
|
let container = Container(chunks: [Chunk(index: 1, payload: Data([1]))])
|
|
var data = self.encode(container)
|
|
|
|
guard let keyRange = data.range(of: "chunks".data(using: .utf8)!) else {
|
|
return XCTFail("key not found in encoded data")
|
|
}
|
|
let objectLengthOffset = keyRange.upperBound + 1 + 4 + 4
|
|
var corruptLength: Int32 = -1
|
|
withUnsafeBytes(of: &corruptLength) { bytes in
|
|
data.replaceSubrange(objectLengthOffset ..< objectLengthOffset + 4, with: bytes)
|
|
}
|
|
|
|
XCTAssertNil(self.decode(data))
|
|
}
|
|
}
|