internal void EventIDSerialization( BatchID batch, DateTime timestamp, long raw, EventID id, EventID deserialized ) { GIVEN["a BatchID"] = () => batch = new BatchID(timestamp = DateTime.UtcNow); AND["its last EventID"] = () => id = EventID.GetLast(batch); WHEN["calling Serialize"] = () => raw = id.Serialize(); THEN["the last 2 bytes should contain the event sequence"] = () => (raw & 0xFFFF).Should().Be(65535); AND["the next 9 bits should contain the batch sequence"] = () => (raw >> 16 & 0x1FF).Should().Be(1); AND["the first 31 bits should contain the timestamp"] = () => new DateTime(2015, 1, 1).AddSeconds((raw >> 32 & 0x7FFFFFFF)).Should().BeCloseTo(timestamp, precision: 1000); WHEN["it is serialized and deserialized"] = () => deserialized = new EventID(id.Serialize()); THEN["its value is the same"] = () => deserialized.Should().Be(id); GIVEN["a timestamp with zero ms"] = () => timestamp = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc); AND["the subseconds serialize to 0"] = () => Subseconds(timestamp).Should().Be(0); GIVEN["a timestamp with 9 ms"] = null; AND["the subseconds serialize to 0"] = () => Subseconds(timestamp.AddMilliseconds(9)).Should().Be(0); GIVEN["a timestamp with 10 ms"] = null; AND["the subseconds serialize to 1"] = () => Subseconds(timestamp.AddMilliseconds(10)).Should().Be(1); GIVEN["a timestamp with 19 ms"] = null; AND["the subseconds serialize to 1"] = () => Subseconds(timestamp.AddMilliseconds(19)).Should().Be(1); GIVEN["a timestamp with 999 ms"] = null; AND["the subseconds serialize to 99"] = () => Subseconds(timestamp.AddMilliseconds(999)).Should().Be(99); long Subseconds(DateTime ts) { long r = EventID.GetFirst(new BatchID(ts)).Serialize(); return(r >> 25 & 0x7F); }; }