Skip to content

Commit f505376

Browse files
committed
Test parsing keepalive messages
1 parent b969d92 commit f505376

File tree

6 files changed

+77
-19
lines changed

6 files changed

+77
-19
lines changed

crates/core/src/bson/de.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,14 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
140140
let (_, bytes) = self.parser.read_binary()?;
141141
visitor.visit_borrowed_bytes(bytes)
142142
}
143-
ElementType::ObjectId => todo!(),
143+
ElementType::ObjectId => visitor.visit_borrowed_bytes(self.parser.read_object_id()?),
144144
ElementType::Boolean => visitor.visit_bool(self.parser.read_bool()?),
145-
ElementType::DatetimeUtc => todo!(),
145+
ElementType::DatetimeUtc | ElementType::Timestamp => {
146+
visitor.visit_u64(self.parser.read_uint64()?)
147+
}
146148
ElementType::Null | ElementType::Undefined => visitor.visit_unit(),
147149
ElementType::Int32 => visitor.visit_i32(self.parser.read_int32()?),
148150
ElementType::Int64 => visitor.visit_i64(self.parser.read_int64()?),
149-
ElementType::Timestamp => todo!(),
150151
}
151152
}
152153

@@ -196,9 +197,21 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut Deserializer<'de> {
196197
}
197198
}
198199

200+
fn deserialize_newtype_struct<V>(
201+
self,
202+
name: &'static str,
203+
visitor: V,
204+
) -> Result<V::Value, Self::Error>
205+
where
206+
V: Visitor<'de>,
207+
{
208+
self.prepare_to_read_value()?;
209+
visitor.visit_newtype_struct(self)
210+
}
211+
199212
forward_to_deserialize_any! {
200213
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
201-
bytes byte_buf unit unit_struct newtype_struct seq tuple
214+
bytes byte_buf unit unit_struct seq tuple
202215
tuple_struct map struct ignored_any identifier
203216
}
204217
}

crates/core/src/bson/mod.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ pub fn from_bytes<'de, T: Deserialize<'de>>(bytes: &'de [u8]) -> Result<T, BsonE
1515

1616
#[cfg(test)]
1717
mod test {
18-
use crate::sync::line::SyncLine;
18+
use core::assert_matches::assert_matches;
19+
20+
use crate::sync::line::{SyncLine, TokenExpiresIn};
1921

2022
use super::*;
2123

@@ -44,4 +46,12 @@ mod test {
4446

4547
assert_eq!(checkpoint.buckets.len(), 1);
4648
}
49+
50+
#[test]
51+
fn test_newtype_tuple() {
52+
let bson = b"\x1b\x00\x00\x00\x10token_expires_in\x00<\x00\x00\x00\x00";
53+
54+
let expected: SyncLine = from_bytes(bson.as_slice()).expect("should deserialize");
55+
assert_matches!(expected, SyncLine::KeepAlive(TokenExpiresIn(60)));
56+
}
4757
}

crates/core/src/bson/parser.rs

+25-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use core::ffi::CStr;
22

33
use super::{error::ErrorKind, BsonError};
4+
use num_traits::{FromBytes, Num};
45

56
pub struct Parser<'de> {
67
offset: usize,
@@ -49,6 +50,11 @@ impl<'de> Parser<'de> {
4950
Ok(value)
5051
}
5152

53+
fn advance_bytes<const N: usize>(&mut self) -> Result<&'de [u8; N], BsonError> {
54+
let bytes = self.advance_checked(N)?;
55+
Ok(bytes.try_into().expect("should have correct length"))
56+
}
57+
5258
pub fn read_cstr(&mut self) -> Result<&'de str, BsonError> {
5359
let raw = CStr::from_bytes_until_nul(self.remaining_input)
5460
.map_err(|_| self.error(ErrorKind::UnterminatedCString))?;
@@ -60,11 +66,15 @@ impl<'de> Parser<'de> {
6066
Ok(str)
6167
}
6268

69+
fn read_number<const N: usize, T: Num + FromBytes<Bytes = [u8; N]>>(
70+
&mut self,
71+
) -> Result<T, BsonError> {
72+
let bytes = self.advance_bytes::<N>()?;
73+
Ok(T::from_le_bytes(&bytes))
74+
}
75+
6376
pub fn read_int32(&mut self) -> Result<i32, BsonError> {
64-
let slice = self.advance_checked(4)?;
65-
Ok(i32::from_le_bytes(
66-
slice.try_into().expect("should have correct length"),
67-
))
77+
self.read_number()
6878
}
6979

7080
fn read_length(&mut self) -> Result<usize, BsonError> {
@@ -75,24 +85,26 @@ impl<'de> Parser<'de> {
7585
}
7686

7787
pub fn read_int64(&mut self) -> Result<i64, BsonError> {
78-
let slice = self.advance_checked(8)?;
79-
Ok(i64::from_le_bytes(
80-
slice.try_into().expect("should have correct length"),
81-
))
88+
self.read_number()
89+
}
90+
91+
pub fn read_uint64(&mut self) -> Result<u64, BsonError> {
92+
self.read_number()
8293
}
8394

8495
pub fn read_double(&mut self) -> Result<f64, BsonError> {
85-
let slice = self.advance_checked(8)?;
86-
Ok(f64::from_le_bytes(
87-
slice.try_into().expect("should have correct length"),
88-
))
96+
self.read_number()
8997
}
9098

9199
pub fn read_bool(&mut self) -> Result<bool, BsonError> {
92100
let byte = self.advance_byte()?;
93101
Ok(byte != 0)
94102
}
95103

104+
pub fn read_object_id(&mut self) -> Result<&'de [u8], BsonError> {
105+
self.advance_checked(12)
106+
}
107+
96108
/// Reads a BSON string, `string ::= int32 (byte*) unsigned_byte(0)`
97109
pub fn read_string(&mut self) -> Result<&'de str, BsonError> {
98110
let length_including_null = self.read_length()?;
@@ -170,7 +182,7 @@ impl<'de> Parser<'de> {
170182
Ok(self.subreader(parsed_size)?.remaining())
171183
}
172184

173-
/// If only a single byte is left in the current scope, assert that it is a zero byte.
185+
/// If only a single byte is left in the current scope, validate that it is a zero byte.
174186
///
175187
/// Otherwise returns false as we haven't reached the end of a document.
176188
pub fn end_document(&mut self) -> Result<bool, BsonError> {

crates/core/src/sync/line.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ mod tests {
388388

389389
#[test]
390390
fn parse_checkpoint_diff_no_write_checkpoint() {
391-
let SyncLine::CheckpointDiff(diff) = deserialize(
391+
let SyncLine::CheckpointDiff(_diff) = deserialize(
392392
r#"{"checkpoint_diff":{"last_op_id":"12","updated_buckets":[{"bucket":"a","count":12,"checksum":0,"priority":3}],"removed_buckets":[]}}"#,
393393
) else {
394394
panic!("Expected checkpoint diff")

dart/test/goldens/simple_iteration.json

+20
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@
6565
}
6666
]
6767
},
68+
{
69+
"operation": "line_text",
70+
"data": {
71+
"token_expires_in": 60
72+
},
73+
"output": []
74+
},
6875
{
6976
"operation": "line_text",
7077
"data": {
@@ -146,5 +153,18 @@
146153
}
147154
}
148155
]
156+
},
157+
{
158+
"operation": "line_text",
159+
"data": {
160+
"token_expires_in": 10
161+
},
162+
"output": [
163+
{
164+
"FetchCredentials": {
165+
"did_expire": false
166+
}
167+
}
168+
]
149169
}
150170
]

dart/test/sync_test.dart

+3
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,14 @@ void _syncTests<T>({
162162
],
163163
},
164164
});
165+
syncLine({'token_expires_in': 60});
165166
pushSyncData('a', '1', '1', 'PUT', {'col': 'hi'});
166167

167168
syncLine({
168169
'checkpoint_complete': {'last_op_id': '1'},
169170
});
171+
172+
syncLine({'token_expires_in': 10});
170173
});
171174
});
172175

0 commit comments

Comments
 (0)