Skip to content

Commit ec73231

Browse files
committed
Add unit tests tying all RedisDataDecoder together
1 parent 7d69d69 commit ec73231

File tree

2 files changed

+236
-0
lines changed

2 files changed

+236
-0
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import NIO
2+
@testable import NIORedis
3+
import XCTest
4+
5+
final class RedisDataDecoderTests: XCTestCase {
6+
private let decoder = RedisDataDecoder()
7+
private let allocator = ByteBufferAllocator()
8+
9+
func test_error() throws {
10+
XCTAssertNil(try runTest("-ERR"))
11+
XCTAssertNil(try runTest("-ERR\r"))
12+
XCTAssertEqual(try runTest("-ERROR\r\n")?.error?.description.contains("ERROR"), true)
13+
14+
let multiError: (RedisData?, RedisData?) = try runTest("-ERROR\r\n-OTHER ERROR\r\n")
15+
XCTAssertEqual(multiError.0?.error?.description.contains("ERROR"), true)
16+
XCTAssertEqual(multiError.1?.error?.description.contains("OTHER ERROR"), true)
17+
}
18+
19+
func test_simpleString() throws {
20+
XCTAssertNil(try runTest("+OK"))
21+
XCTAssertNil(try runTest("+OK\r"))
22+
XCTAssertEqual(try runTest("+\r\n")?.string, "")
23+
XCTAssertEqual(try runTest("+OK\r\n")?.string, "OK")
24+
25+
XCTAssertEqual(try runTest("+©ºmpl³x\r\n")?.string, "©ºmpl³x")
26+
27+
let multiSimpleString: (RedisData?, RedisData?) = try runTest("+OK\r\n+OTHER STRINGS\r\n")
28+
XCTAssertEqual(multiSimpleString.0?.string, "OK")
29+
XCTAssertEqual(multiSimpleString.1?.string, "OTHER STRINGS")
30+
}
31+
32+
func test_integer() throws {
33+
XCTAssertNil(try runTest(":100"))
34+
XCTAssertNil(try runTest(":100\r"))
35+
XCTAssertNil(try runTest(":\r"))
36+
XCTAssertEqual(try runTest(":0\r\n")?.int, 0)
37+
XCTAssertEqual(try runTest(":01\r\n")?.int, 1)
38+
XCTAssertEqual(try runTest(":1000\r\n")?.int, 1000)
39+
XCTAssertEqual(try runTest(":-9223372036854775807\r\n")?.int, -9223372036854775807)
40+
41+
let multiInteger: (RedisData?, RedisData?) = try runTest(":9223372036854775807\r\n:99\r\n")
42+
XCTAssertEqual(multiInteger.0?.int, 9223372036854775807)
43+
XCTAssertEqual(multiInteger.1?.int, 99)
44+
}
45+
46+
func test_bulkString() throws {
47+
XCTAssertNil(try runTest("$0"))
48+
XCTAssertNil(try runTest("$0\r"))
49+
XCTAssertNil(try runTest("$0\r\n\r"))
50+
XCTAssertNil(try runTest("$-1\r"))
51+
XCTAssertEqual(try runTest("$-1\r\n")?.isNull, true)
52+
XCTAssertEqual(try runTest("$0\r\n\r\n")?.string, "")
53+
XCTAssertNil(try runTest("$1\r\na\r"))
54+
XCTAssertEqual(try runTest("$1\r\na\r\n")?.string, "a")
55+
XCTAssertNil(try runTest("$3\r\nfoo\r"))
56+
XCTAssertEqual(try runTest("$3\r\nfoo\r\n")?.string, "foo")
57+
XCTAssertNil(try runTest("$3\r\n\r"))
58+
XCTAssertEqual(try runTest("$3\r\n\r\n")?.string, "")
59+
60+
let str = "κόσμε"
61+
let strBytes = str.convertedToData()
62+
let strInput = "$\(strBytes.count)\r\n\(str)\r\n"
63+
XCTAssertEqual(try runTest(strInput)?.string, str)
64+
XCTAssertEqual(try runTest(strInput)?.data, strBytes)
65+
66+
let multiBulkString: (RedisData?, RedisData?) = try runTest("$-1\r\n$3\r\n\r\n")
67+
XCTAssertEqual(multiBulkString.0?.isNull, true)
68+
XCTAssertEqual(multiBulkString.1?.string, "")
69+
70+
let rawBytes = Data(bytes: [0x00, 0x01, 0x02, 0x03, 0x0A, 0xff])
71+
let rawByteInput = "$\(rawBytes.count)\r\n".convertedToData() + rawBytes + "\r\n".convertedToData()
72+
XCTAssertEqual(try runTest(rawByteInput)?.data, rawBytes)
73+
}
74+
75+
func test_array() throws {
76+
func runArrayTest(_ input: String) throws -> [RedisData]? {
77+
return try runTest(input)?.array
78+
}
79+
80+
XCTAssertNil(try runArrayTest("*0\r"))
81+
XCTAssertNil(try runArrayTest("*1\r\n+OK\r"))
82+
XCTAssertEqual(try runArrayTest("*0\r\n")?.count, 0)
83+
XCTAssertTrue(arraysAreEqual(
84+
try runArrayTest("*1\r\n$3\r\nfoo\r\n"),
85+
expected: [.bulkString("foo".convertedToData())]
86+
))
87+
XCTAssertTrue(arraysAreEqual(
88+
try runArrayTest("*3\r\n+foo\r\n$3\r\nbar\r\n:3\r\n"),
89+
expected: [.simpleString("foo"), .bulkString("bar".convertedToData()), .integer(3)]
90+
))
91+
XCTAssertTrue(arraysAreEqual(
92+
try runArrayTest("*1\r\n*2\r\n+OK\r\n:1\r\n"),
93+
expected: [.array([ .simpleString("OK"), .integer(1) ])]
94+
))
95+
}
96+
97+
private func runTest(_ input: String) throws -> RedisData? {
98+
return try runTest(input.convertedToData())
99+
}
100+
101+
private func runTest(_ input: Data) throws -> RedisData? {
102+
return try runTest(input).0
103+
}
104+
105+
private func runTest(_ input: String) throws -> (RedisData?, RedisData?) {
106+
return try runTest(input.convertedToData())
107+
}
108+
109+
private func runTest(_ input: Data) throws -> (RedisData?, RedisData?) {
110+
let embeddedChannel = EmbeddedChannel()
111+
defer { _ = try? embeddedChannel.finish() }
112+
try embeddedChannel.pipeline.add(handler: decoder).wait()
113+
var buffer = allocator.buffer(capacity: 256)
114+
buffer.write(bytes: input)
115+
try embeddedChannel.writeInbound(buffer)
116+
return (embeddedChannel.readInbound(), embeddedChannel.readInbound())
117+
}
118+
119+
private func arraysAreEqual(_ lhs: [RedisData]?, expected right: [RedisData]) -> Bool {
120+
guard
121+
let left = lhs,
122+
left.count == right.count
123+
else { return false }
124+
125+
var arraysMatch = true
126+
127+
left.enumerated().forEach {
128+
let (offset, decodedElement) = $0
129+
130+
switch (decodedElement, right[offset]) {
131+
case (let .bulkString(decoded), let .bulkString(expected)): arraysMatch = decoded == expected
132+
case (let .simpleString(decoded), let .simpleString(expected)): arraysMatch = decoded == expected
133+
case (let .integer(decoded), let .integer(expected)): arraysMatch = decoded == expected
134+
case (let .error(decoded), let .error(expected)): arraysMatch = decoded == expected
135+
case (.null, .null): break
136+
case (let .array(decoded), let .array(expected)): arraysMatch = arraysAreEqual(decoded, expected: expected)
137+
default:
138+
XCTFail("Array mismatch!")
139+
arraysMatch = false
140+
}
141+
}
142+
143+
return arraysMatch
144+
}
145+
}
146+
147+
// MARK: All Types
148+
149+
extension RedisDataDecoderTests {
150+
private struct AllData {
151+
static let expectedString = "string"
152+
static let expectedError = "ERROR"
153+
static let expectedBulkString = "aa"
154+
static let expectedInteger = -1000
155+
156+
static var messages = [
157+
"+\(expectedString)\r\n",
158+
":\(expectedInteger)\r\n",
159+
"-\(expectedError)\r\n",
160+
"$2\r\n\(expectedBulkString)\r\n",
161+
"$-1\r\n",
162+
"$0\r\n\r\n",
163+
"*3\r\n+\(expectedString)\r\n$2\r\n\(expectedBulkString)\r\n:\(expectedInteger)\r\n",
164+
"*1\r\n*1\r\n:\(expectedInteger)\r\n",
165+
"*0\r\n",
166+
"*-1\r\n"
167+
]
168+
}
169+
170+
func test_all() throws {
171+
let embeddedChannel = EmbeddedChannel()
172+
defer { _ = try? embeddedChannel.finish() }
173+
try embeddedChannel.pipeline.add(handler: decoder).wait()
174+
175+
var buffer = allocator.buffer(capacity: 256)
176+
for message in AllData.messages {
177+
buffer.write(string: message)
178+
}
179+
180+
try embeddedChannel.writeInbound(buffer)
181+
182+
var results = [RedisData?]()
183+
for _ in 0..<AllData.messages.count {
184+
results.append(embeddedChannel.readInbound())
185+
}
186+
187+
XCTAssertEqual(results[0]?.string, AllData.expectedString)
188+
XCTAssertEqual(results[1]?.int, AllData.expectedInteger)
189+
XCTAssertEqual(results[2]?.error?.description.contains(AllData.expectedError), true)
190+
191+
XCTAssertEqual(results[3]?.string, AllData.expectedBulkString)
192+
XCTAssertEqual(results[3]?.data, AllData.expectedBulkString.convertedToData())
193+
194+
XCTAssertEqual(results[4]?.isNull, true)
195+
196+
XCTAssertEqual(results[5]?.data?.count, 0)
197+
XCTAssertEqual(results[5]?.string, "")
198+
199+
XCTAssertEqual(results[6]?.array?.count, 3)
200+
XCTAssertTrue(arraysAreEqual(
201+
results[6]?.array,
202+
expected: [
203+
.simpleString(AllData.expectedString),
204+
.bulkString(AllData.expectedBulkString.convertedToData()),
205+
.integer(AllData.expectedInteger)
206+
]
207+
))
208+
209+
XCTAssertEqual(results[7]?.array?.count, 1)
210+
XCTAssertTrue(arraysAreEqual(
211+
results[7]?.array,
212+
expected: [.array([.integer(AllData.expectedInteger)])]
213+
))
214+
215+
XCTAssertEqual(results[8]?.array?.count, 0)
216+
XCTAssertEqual(results[9]?.isNull, true)
217+
}
218+
}
219+
220+
extension RedisDataDecoderTests {
221+
static var allTests = [
222+
("test_error", test_error),
223+
("test_simpleString", test_simpleString),
224+
("test_integer", test_integer),
225+
("test_bulkString", test_bulkString),
226+
("test_array", test_array),
227+
("test_all", test_all),
228+
]
229+
}
230+
231+
extension RedisError: Equatable {
232+
public static func == (lhs: RedisError, rhs: RedisError) -> Bool {
233+
return lhs.description == rhs.description
234+
}
235+
}

Tests/NIORedisTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import XCTest
44
public func allTests() -> [XCTestCaseEntry] {
55
return [
66
testCase(NIORedisTests.allTests),
7+
testCase(RedisDataDecoderTests.allTests),
78
testCase(RedisDataDecoderParsingTests.allTests),
89
testCase(RedisDataDecoderByteToMessageDecoderTests.allTests),
910
]

0 commit comments

Comments
 (0)