aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Sacchini <joey@sacchini.net>2020-09-29 17:05:58 -0400
committerJoey Sacchini <joey@sacchini.net>2020-09-29 17:05:58 -0400
commit56181da142f5e95a067feea5c4558fef2a2d49a7 (patch)
tree08d5bbcaaa13cf915248cf9dba2a0955d4b573cf
parent2e6119a65f260f460dd67860dd5f5af7286bcb42 (diff)
downloadmcproto-rs-56181da142f5e95a067feea5c4558fef2a2d49a7.tar.gz
mcproto-rs-56181da142f5e95a067feea5c4558fef2a2d49a7.tar.bz2
mcproto-rs-56181da142f5e95a067feea5c4558fef2a2d49a7.zip
implement automated testing of all data-types
-rw-r--r--src/lib.rs7
-rw-r--r--src/nbt.rs63
-rw-r--r--src/protocol.rs121
-rw-r--r--src/status.rs21
-rw-r--r--src/test_macros.rs80
-rw-r--r--src/types.rs196
-rw-r--r--src/v1_15_2.rs668
7 files changed, 1096 insertions, 60 deletions
diff --git a/src/lib.rs b/src/lib.rs
index b04090f..1d99ee6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -8,6 +8,7 @@ extern crate test;
mod serialize;
mod deserialize;
pub mod utils;
+#[macro_export]
pub mod protocol;
pub mod uuid;
pub mod nbt;
@@ -16,4 +17,8 @@ pub mod v1_15_2;
pub mod status;
pub use serialize::*;
-pub use deserialize::*; \ No newline at end of file
+pub use deserialize::*;
+
+#[cfg(test)]
+#[macro_export]
+mod test_macros; \ No newline at end of file
diff --git a/src/nbt.rs b/src/nbt.rs
index ac2d39c..f784454 100644
--- a/src/nbt.rs
+++ b/src/nbt.rs
@@ -1,6 +1,7 @@
use std::fmt;
use crate::{DeserializeResult, DeserializeErr, Deserialized};
use crate::utils::{read_short, take, read_int, read_long, read_one_byte, write_long, write_int, write_short};
+use crate::protocol::TestRandom;
#[derive(Clone, Debug, PartialEq)]
pub struct NamedTag {
@@ -21,6 +22,16 @@ impl NamedTag {
}
}
+#[cfg(test)]
+impl TestRandom for NamedTag {
+ fn test_gen_random() -> Self {
+ Self {
+ name: String::test_gen_random(),
+ payload: Tag::test_gen_random(),
+ }
+ }
+}
+
impl fmt::Display for NamedTag {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("TAG_{}('{}'): ", self.payload.tag_type_name(), self.name))?;
@@ -104,6 +115,50 @@ impl Tag {
}
}
+#[cfg(test)]
+impl TestRandom for Tag {
+ fn test_gen_random() -> Self {
+ let random_idx = rand::random::<usize>() % 8;
+ match random_idx {
+ 0 => Tag::Byte(i8::test_gen_random()),
+ 1 => Tag::Short(i16::test_gen_random()),
+ 2 => Tag::Int(i32::test_gen_random()),
+ 3 => Tag::Long(i64::test_gen_random()),
+ 4 => Tag::Float(f32::test_gen_random()),
+ 5 => Tag::Double(f64::test_gen_random()),
+ 6 => Tag::String(String::test_gen_random()),
+ 7 => Tag::List({
+ let count = rand::random::<usize>() % 256;
+ let mut out = Vec::with_capacity(count);
+ let random_idx = rand::random::<usize>() % 6;
+ for _ in 0..count {
+ out.push(match random_idx {
+ 0 => Tag::Byte(i8::test_gen_random()),
+ 1 => Tag::Short(i16::test_gen_random()),
+ 2 => Tag::Int(i32::test_gen_random()),
+ 3 => Tag::Long(i64::test_gen_random()),
+ 4 => Tag::Float(f32::test_gen_random()),
+ 5 => Tag::Double(f64::test_gen_random()),
+ 6 => Tag::String(String::test_gen_random()),
+ other => panic!("impossible {}", other)
+ });
+ }
+
+ out
+ }),
+ 8 => Tag::Compound({
+ let count = rand::random::<usize>() % 256;
+ let mut out = Vec::with_capacity(count);
+ for _ in 0..count {
+ out.push(NamedTag::test_gen_random());
+ }
+ out
+ }),
+ other => panic!("impossible {}", other),
+ }
+ }
+}
+
#[inline]
fn write_contents<F>(contents: &Vec<F>) -> String where F: fmt::Display {
format!("{} entries\n{{\n{}\n}}", contents.len(), contents.iter()
@@ -466,7 +521,7 @@ mod tests {
let (unzipped, result) = read_bigtest_with_bytes();
let serialized = result.bytes();
assert_eq!(unzipped, serialized);
- let Deserialized{value: unserialized, data: _} = NamedTag::root_compound_tag_from_bytes(serialized.as_slice()).expect("deserialize serialized nbt");
+ let Deserialized { value: unserialized, data: _ } = NamedTag::root_compound_tag_from_bytes(serialized.as_slice()).expect("deserialize serialized nbt");
assert_eq!(unserialized, result);
}
@@ -477,7 +532,7 @@ mod tests {
)).with_name("test");
let bytes = original.bytes();
- let Deserialized{value: unserialized, data: _} = NamedTag::root_compound_tag_from_bytes(bytes.as_slice()).expect("deserialize int array");
+ let Deserialized { value: unserialized, data: _ } = NamedTag::root_compound_tag_from_bytes(bytes.as_slice()).expect("deserialize int array");
assert_eq!(original, unserialized);
}
@@ -488,7 +543,7 @@ mod tests {
)).with_name("test");
let bytes = original.bytes();
- let Deserialized{value: unserialized, data: _} = NamedTag::root_compound_tag_from_bytes(bytes.as_slice()).expect("deserialize int array");
+ let Deserialized { value: unserialized, data: _ } = NamedTag::root_compound_tag_from_bytes(bytes.as_slice()).expect("deserialize int array");
assert_eq!(original, unserialized);
}
@@ -504,7 +559,7 @@ mod tests {
fn read_bigtest_with_bytes() -> (Vec<u8>, NamedTag) {
let unzipped = read_compressed_file("src/testdata/bigtest.nbt").expect("read nbt data");
- let Deserialized{value: result, data: rest} = NamedTag::root_compound_tag_from_bytes(unzipped.as_slice()).expect("deserialize nbt");
+ let Deserialized { value: result, data: rest } = NamedTag::root_compound_tag_from_bytes(unzipped.as_slice()).expect("deserialize nbt");
assert_eq!(rest.len(), 0);
(unzipped, result)
diff --git a/src/protocol.rs b/src/protocol.rs
index 01265df..e768fdb 100644
--- a/src/protocol.rs
+++ b/src/protocol.rs
@@ -13,6 +13,7 @@ pub struct ProtocolPacketSpec {
pub direction: String,
pub id: i32,
pub name: String,
+ pub body_struct: String,
pub fields: Vec<ProtocolPacketField>,
}
@@ -35,7 +36,7 @@ pub trait Packet<I: PacketIdentifier>: Serialize {
#[derive(Debug)]
pub enum PacketErr {
UnknownId(i32),
- DeserializeFailed(DeserializeErr)
+ DeserializeFailed(DeserializeErr),
}
#[derive(Debug, Clone, PartialEq)]
@@ -48,6 +49,11 @@ pub trait ProtocolType: Serialize + Deserialize {}
impl<T: Serialize + Deserialize> ProtocolType for T {}
+#[cfg(test)]
+pub trait TestRandom {
+ fn test_gen_random() -> Self;
+}
+
#[macro_export]
macro_rules! as_item {
($i:item) => { $i };
@@ -82,6 +88,13 @@ macro_rules! __protocol_body_def_helper {
Deserialized::ok(Self::default(), data)
}
}
+
+ #[cfg(test)]
+ impl TestRandom for $bodyt {
+ fn test_gen_random() -> Self {
+ Self::default()
+ }
+ }
};
($bodyt: ident { $($fname: ident: $ftyp: ty ),+ }) => {
$crate::as_item! {
@@ -107,6 +120,13 @@ macro_rules! __protocol_body_def_helper {
Deserialized::ok(Self{ $($fname),+ }, _rest)
}
}
+
+ #[cfg(test)]
+ impl TestRandom for $bodyt {
+ fn test_gen_random() -> Self {
+ Self{ $($fname: <$ftyp>::test_gen_random()),+ }
+ }
+ }
}
}
@@ -189,6 +209,7 @@ macro_rules! define_protocol {
direction: stringify!($direction).to_owned(),
id: $id,
name: stringify!($nam).to_owned(),
+ body_struct: stringify!($body).to_owned(),
fields: vec!(
$(crate::protocol::ProtocolPacketField{
name: stringify!($fnam).to_owned(),
@@ -206,6 +227,13 @@ macro_rules! define_protocol {
}
#[macro_export]
+macro_rules! count_num {
+ () => { 0 };
+ ($item: tt) => { 1 };
+ ($item: tt, $($rest: tt),+) => { 1 + count_num!($($rest),+) }
+}
+
+#[macro_export]
macro_rules! proto_enum_with_type {
($typ: ty, $from_nam: ident, $as_nam: ident, $fmt: literal, $typname: ident, $(($bval: literal, $nam: ident)),*) => {
$crate::as_item! {
@@ -274,6 +302,20 @@ macro_rules! proto_enum_with_type {
(*self).into()
}
}
+
+ #[cfg(test)]
+ impl TestRandom for $typname {
+ fn test_gen_random() -> Self {
+ let mut idx: usize = (rand::random::<usize>() % (count_num!($($bval),+))) + 1;
+ $(
+ idx -= 1;
+ if idx == 0 {
+ return $typname::$nam;
+ }
+ )+
+ panic!("cannot generate random {}", stringify!($typname));
+ }
+ }
}
}
@@ -345,5 +387,80 @@ macro_rules! proto_byte_flag {
Ok(u8::mc_deserialize(data)?.map(move |b| $typname(b)))
}
}
+
+ #[cfg(test)]
+ impl TestRandom for $typname {
+ fn test_gen_random() -> Self {
+ let mut out = <$typname>::default();
+ $(paste::paste! {
+ out.[<set_ $nam>](rand::random::<bool>());
+ })+
+ out
+ }
+ }
}
-} \ No newline at end of file
+}
+
+#[macro_export]
+macro_rules! counted_array_type {
+ ($name: ident, $countert: ty, $tousize_fn: ident, $fromusize_fn: ident) => {
+ #[derive(Debug, Clone, PartialEq)]
+ pub struct $name<T> where T: Debug + Clone + PartialEq {
+ pub data: Vec<T>
+ }
+
+ impl<T> Serialize for $name<T> where T: Serialize + Debug + Clone + PartialEq {
+ fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
+ let count: $countert = $fromusize_fn(self.data.len());
+ to.serialize_other(&count)?;
+
+ for entry in &self.data {
+ to.serialize_other(entry)?;
+ }
+
+ Ok(())
+ }
+ }
+
+ impl<T> Deserialize for $name<T> where T: Deserialize + Debug + Clone + PartialEq {
+ fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
+ let Deserialized{value: raw_count, mut data} = <$countert>::mc_deserialize(data)?;
+ let count: usize = $tousize_fn(raw_count);
+
+ let mut out = Vec::with_capacity(count);
+ for _ in 0..count {
+ let Deserialized{value: next, data: rest} = T::mc_deserialize(data)?;
+ data = rest;
+ out.push(next);
+ }
+
+ Deserialized::ok(Self { data: out }, data)
+ }
+ }
+
+ impl<T> Into<Vec<T>> for $name<T> where T: Debug + Clone + PartialEq {
+ fn into(self) -> Vec<T> {
+ self.data
+ }
+ }
+
+ impl<T> From<Vec<T>> for $name<T> where T: Debug + Clone + PartialEq {
+ fn from(data: Vec<T>) -> Self {
+ Self { data }
+ }
+ }
+
+ #[cfg(test)]
+ impl<T> TestRandom for $name<T> where T: TestRandom + Debug + Clone + PartialEq {
+ fn test_gen_random() -> Self {
+ let elem_count: usize = rand::random::<usize>() % 32;
+ let mut out = Vec::with_capacity(elem_count);
+ for _ in 0..elem_count {
+ out.push(T::test_gen_random());
+ }
+
+ Self { data: out }
+ }
+ }
+ }
+}
diff --git a/src/status.rs b/src/status.rs
index b8f9029..7d254aa 100644
--- a/src/status.rs
+++ b/src/status.rs
@@ -3,6 +3,7 @@ use crate::{SerializeResult, SerializeErr, Serialize as McSerialize, Deserialize
use crate::uuid::UUID4;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use std::fmt;
+use crate::protocol::TestRandom;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct StatusSpec {
@@ -31,6 +32,26 @@ impl McDeserialize for StatusSpec {
}
}
+
+#[cfg(test)]
+impl TestRandom for StatusSpec {
+ fn test_gen_random() -> Self {
+ Self {
+ version: StatusVersionSpec{
+ protocol: rand::random(),
+ name: String::test_gen_random(),
+ },
+ players: StatusPlayersSpec{
+ sample: Vec::default(),
+ max: rand::random(),
+ online: rand::random(),
+ },
+ favicon: None,
+ description: Chat::test_gen_random(),
+ }
+ }
+}
+
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub struct StatusVersionSpec {
pub name: String,
diff --git a/src/test_macros.rs b/src/test_macros.rs
new file mode 100644
index 0000000..cc573a7
--- /dev/null
+++ b/src/test_macros.rs
@@ -0,0 +1,80 @@
+use crate::{Serializer, SerializeResult};
+#[cfg(test)]
+#[macro_export]
+macro_rules! packet_test_cases {
+ ($pnam: ident, $varnam: ident, $bodnam: ident, $testnam: ident, $benchnams: ident, $benchnamd: ident) => {
+ #[test]
+ fn $testnam() {
+ for _ in 0..10 {
+ let packet = $pnam::$varnam($bodnam::test_gen_random());
+ let mut out = BytesSerializer::default();
+ packet.mc_serialize(&mut out).expect("serialize succeeds");
+ let bytes = out.into_bytes();
+
+ let raw_packet = RawPacket{
+ id: packet.id(),
+ data: bytes,
+ };
+
+ let deserialized = <$pnam>::mc_deserialize(raw_packet).expect("deserialize succeeds");
+ assert_eq!(packet, deserialized);
+ }
+ }
+
+ #[bench]
+ fn $benchnams(b: &mut Bencher) {
+ let packet = $pnam::$varnam($bodnam::test_gen_random());
+ let mut serializer = BenchSerializer::default();
+ packet.mc_serialize(&mut serializer).expect("serialize succeeds");
+ b.bytes = serializer.len() as u64;
+ serializer.reset();
+
+ b.iter(|| {
+ packet.mc_serialize(&mut serializer).expect("serialize succeeds");
+ serializer.reset();
+ })
+ }
+
+ #[bench]
+ fn $benchnamd(b: &mut Bencher) {
+ let packet = $pnam::$varnam($bodnam::test_gen_random());
+ let mut serializer = BytesSerializer::default();
+ packet.mc_serialize(&mut serializer).expect("serialize succeeds");
+
+ let bytes = serializer.into_bytes();
+ b.bytes = bytes.len() as u64;
+ let raw_packet = RawPacket{
+ id: packet.id(),
+ data: bytes,
+ };
+ b.iter(|| {
+ $pnam::mc_deserialize(raw_packet.clone()).expect("deserialize succeeds");
+ })
+ }
+ }
+}
+
+#[cfg(test)]
+#[derive(Clone, Debug, Default, PartialEq)]
+pub struct BenchSerializer {
+ data: Vec<u8>
+}
+
+#[cfg(test)]
+impl Serializer for BenchSerializer {
+ fn serialize_bytes(&mut self, data: &[u8]) -> SerializeResult {
+ self.data.extend_from_slice(data);
+ Ok(())
+ }
+}
+
+#[cfg(test)]
+impl BenchSerializer {
+ pub fn reset(&mut self) {
+ self.data.clear();
+ }
+
+ pub fn len(&self) -> usize {
+ self.data.len()
+ }
+} \ No newline at end of file
diff --git a/src/types.rs b/src/types.rs
index f62ede9..9d8f595 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -4,6 +4,9 @@ use crate::*;
use crate::utils::*;
use crate::uuid::UUID4;
+#[cfg(test)]
+use crate::protocol::TestRandom;
+
// bool
impl Serialize for bool {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -23,6 +26,13 @@ impl Deserialize for bool {
}
}
+#[cfg(test)]
+impl TestRandom for bool {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// u8
impl Serialize for u8 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -36,6 +46,13 @@ impl Deserialize for u8 {
}
}
+#[cfg(test)]
+impl TestRandom for u8 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// i8
impl Serialize for i8 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -49,6 +66,13 @@ impl Deserialize for i8 {
}
}
+#[cfg(test)]
+impl TestRandom for i8 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// u16
impl Serialize for u16 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -63,6 +87,13 @@ impl Deserialize for u16 {
}
}
+#[cfg(test)]
+impl TestRandom for u16 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// i16
impl Serialize for i16 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -76,6 +107,13 @@ impl Deserialize for i16 {
}
}
+#[cfg(test)]
+impl TestRandom for i16 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// int
impl Serialize for i32 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -90,6 +128,13 @@ impl Deserialize for i32 {
}
}
+#[cfg(test)]
+impl TestRandom for i32 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// long
impl Serialize for i64 {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
@@ -104,6 +149,13 @@ impl Deserialize for i64 {
}
}
+#[cfg(test)]
+impl TestRandom for i64 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// float
impl Serialize for f32 {
@@ -120,6 +172,13 @@ impl Deserialize for f32 {
}
}
+#[cfg(test)]
+impl TestRandom for f32 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// double
impl Serialize for f64 {
//noinspection ALL
@@ -135,6 +194,13 @@ impl Deserialize for f64 {
}
}
+#[cfg(test)]
+impl TestRandom for f64 {
+ fn test_gen_random() -> Self {
+ rand::random()
+ }
+}
+
// VAR INT AND VAR LONG
const VAR_INT_BYTES: usize = 5;
const VAR_LONG_BYTES: usize = 10;
@@ -188,6 +254,14 @@ impl std::fmt::Display for VarInt {
}
}
+#[cfg(test)]
+impl TestRandom for VarInt {
+ fn test_gen_random() -> Self {
+ let out: i32 = rand::random();
+ Self(out)
+ }
+}
+
#[derive(Copy, Clone, PartialOrd, PartialEq, Debug, Default, Hash, Ord, Eq)]
pub struct VarLong(pub i64);
@@ -204,6 +278,14 @@ impl Deserialize for VarLong {
}
}
+#[cfg(test)]
+impl TestRandom for VarLong {
+ fn test_gen_random() -> Self {
+ let out: i64 = rand::random();
+ Self(out)
+ }
+}
+
fn serialize_var_num(data: u64, out: &mut [u8]) -> &[u8] {
let mut v: u64 = data;
let mut byte_idx = 0;
@@ -274,6 +356,28 @@ impl Deserialize for String {
}
}
+#[cfg(test)]
+impl TestRandom for String {
+ fn test_gen_random() -> Self {
+ let raw_len: u8 = rand::random();
+ let len = raw_len as usize;
+ let mut out = String::with_capacity(len);
+ for _ in 0..len {
+ let c_idx: u8 = rand::random::<u8>() % 36;
+
+ let c = if c_idx <= 10 {
+ (48 + c_idx) as char
+ } else {
+ ((c_idx - 10) + 65) as char
+ };
+
+ out.push(c)
+ }
+
+ out
+ }
+}
+
// position
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
pub struct IntPosition {
@@ -335,6 +439,20 @@ impl Deserialize for IntPosition {
}
}
+#[cfg(test)]
+impl TestRandom for IntPosition {
+ fn test_gen_random() -> Self {
+ let x: i32 = ((rand::random::<u32>() % (1 << 26)) as i32) - (1 << 25);
+ let z: i32 = ((rand::random::<u32>() % (1 << 26)) as i32) - (1 << 25);
+ let y: i16 = ((rand::random::<u16>() % (1 << 12)) as i16) - (1 << 11);
+ Self{
+ x,
+ y,
+ z
+ }
+ }
+}
+
// angle
#[derive(Copy, Clone, PartialEq, Hash, Debug)]
pub struct Angle {
@@ -355,6 +473,15 @@ impl Deserialize for Angle {
}
}
+#[cfg(test)]
+impl TestRandom for Angle {
+ fn test_gen_random() -> Self {
+ Self{
+ value: rand::random()
+ }
+ }
+}
+
// UUID
impl Serialize for UUID4 {
@@ -388,6 +515,13 @@ impl Deserialize for UUID4 {
}
}
+#[cfg(test)]
+impl TestRandom for UUID4 {
+ fn test_gen_random() -> Self {
+ UUID4::random()
+ }
+}
+
// NBT
#[derive(Clone, PartialEq, Debug)]
@@ -420,6 +554,13 @@ impl Into<nbt::NamedTag> for NamedNbtTag {
}
}
+#[cfg(test)]
+impl TestRandom for NamedNbtTag {
+ fn test_gen_random() -> Self {
+ Self { root: nbt::NamedTag::test_gen_random() }
+ }
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct FixedInt {
raw: i32
@@ -449,6 +590,13 @@ impl FixedInt {
}
}
+#[cfg(test)]
+impl TestRandom for FixedInt {
+ fn test_gen_random() -> Self {
+ FixedInt::new(f64::test_gen_random(), 16)
+ }
+}
+
// chat
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq, Clone)]
pub struct Chat {
@@ -704,6 +852,19 @@ impl Chat {
to.push(formatter)
}
}
+
+ pub fn from_text(text: &str) -> Chat {
+ Chat{
+ text: text.to_owned(),
+ bold: None,
+ italic: None,
+ underlined: None,
+ strikethrough: None,
+ obfuscated: None,
+ color: None,
+ extra: None,
+ }
+ }
}
impl Serialize for Chat {
@@ -724,6 +885,14 @@ impl Deserialize for Chat {
}
}
+#[cfg(test)]
+impl TestRandom for Chat {
+ fn test_gen_random() -> Self {
+ let str = String::test_gen_random();
+ Chat::from_text(str.as_str())
+ }
+}
+
#[derive(Default)]
pub struct BytesSerializer {
data: Vec<u8>
@@ -774,6 +943,18 @@ impl<T> Deserialize for Option<T> where T: Deserialize {
}
}
+#[cfg(test)]
+impl<T> TestRandom for Option<T> where T: TestRandom {
+ fn test_gen_random() -> Self {
+ let is_present: bool = rand::random();
+ if is_present {
+ Some(T::test_gen_random())
+ } else {
+ None
+ }
+ }
+}
+
// SLOT
#[derive(Debug, PartialEq, Clone)]
pub struct Slot {
@@ -813,6 +994,21 @@ impl Deserialize for Slot {
}
#[cfg(test)]
+impl TestRandom for Slot {
+ fn test_gen_random() -> Self {
+ let item_id = VarInt::test_gen_random();
+ let item_count = i8::test_gen_random() % 65;
+ let nbt = <Option<nbt::NamedTag>>::test_gen_random();
+
+ Self{
+ item_id,
+ item_count,
+ nbt
+ }
+ }
+}
+
+#[cfg(test)]
mod tests {
use super::*;
use std::fmt::Debug;
diff --git a/src/v1_15_2.rs b/src/v1_15_2.rs
index d2ee960..1569d80 100644
--- a/src/v1_15_2.rs
+++ b/src/v1_15_2.rs
@@ -1,6 +1,9 @@
use crate::{*, uuid::*, types::*};
use std::fmt::Debug;
+#[cfg(test)]
+use crate::protocol::TestRandom;
+
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PacketDirection {
ClientBound,
@@ -804,56 +807,6 @@ proto_byte_enum!(HandshakeNextState,
0x02 :: Login
);
-macro_rules! counted_array_type {
- ($name: ident, $countert: ty, $tousize_fn: ident, $fromusize_fn: ident) => {
- #[derive(Debug, Clone, PartialEq)]
- pub struct $name<T> where T: Debug + Clone + PartialEq {
- pub data: Vec<T>
- }
-
- impl<T> Serialize for $name<T> where T: Serialize + Debug + Clone + PartialEq {
- fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
- let count: $countert = $fromusize_fn(self.data.len());
- to.serialize_other(&count)?;
-
- for entry in &self.data {
- to.serialize_other(entry)?;
- }
-
- Ok(())
- }
- }
-
- impl<T> Deserialize for $name<T> where T: Deserialize + Debug + Clone + PartialEq {
- fn mc_deserialize(data: &[u8]) -> DeserializeResult<'_, Self> {
- let Deserialized{value: raw_count, mut data} = <$countert>::mc_deserialize(data)?;
- let count: usize = $tousize_fn(raw_count);
-
- let mut out = Vec::with_capacity(count);
- for _ in 0..count {
- let Deserialized{value: next, data: rest} = T::mc_deserialize(data)?;
- data = rest;
- out.push(next);
- }
-
- Deserialized::ok(Self { data: out }, data)
- }
- }
-
- impl<T> Into<Vec<T>> for $name<T> where T: Debug + Clone + PartialEq {
- fn into(self) -> Vec<T> {
- self.data
- }
- }
-
- impl<T> From<Vec<T>> for $name<T> where T: Debug + Clone + PartialEq {
- fn from(data: Vec<T>) -> Self {
- Self { data }
- }
- }
- }
-}
-
#[inline]
fn varint_to_usize(v: VarInt) -> usize {
v.into()
@@ -927,6 +880,19 @@ impl From<Vec<u8>> for RemainingBytes {
}
}
+#[cfg(test)]
+impl TestRandom for RemainingBytes {
+ fn test_gen_random() -> Self {
+ let mut size: usize = rand::random::<usize>() % 256;
+ let mut out = Vec::with_capacity(size);
+ for _ in 0..size {
+ out.push(rand::random());
+ }
+
+ Self{ data: out }
+ }
+}
+
proto_byte_enum!(CardinalDirection,
0x00 :: South,
0x01 :: West,
@@ -1052,12 +1018,12 @@ proto_byte_enum!(ChatPosition,
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct BlockChangeHorizontalPosition {
pub rel_x: u8,
- pub rel_y: u8,
+ pub rel_z: u8,
}
impl Serialize for BlockChangeHorizontalPosition {
fn mc_serialize<S: Serializer>(&self, to: &mut S) -> SerializeResult {
- to.serialize_byte((self.rel_x & 0xF) << 4 | (self.rel_y & 0xF))
+ to.serialize_byte((self.rel_x & 0xF) << 4 | (self.rel_z & 0xF))
}
}
@@ -1066,12 +1032,22 @@ impl Deserialize for BlockChangeHorizontalPosition {
Ok(u8::mc_deserialize(data)?.map(move |b| {
BlockChangeHorizontalPosition {
rel_x: (b >> 4) & 0xF,
- rel_y: b & 0xF,
+ rel_z: b & 0xF,
}
}))
}
}
+#[cfg(test)]
+impl TestRandom for BlockChangeHorizontalPosition {
+ fn test_gen_random() -> Self {
+ BlockChangeHorizontalPosition{
+ rel_x: rand::random(),
+ rel_z: rand::random(),
+ }
+ }
+}
+
__protocol_body_def_helper!(MultiBlockChangeRecord {
horizontal_position: BlockChangeHorizontalPosition,
y_coordinate: u8,
@@ -1126,6 +1102,14 @@ impl Deserialize for BossBarAction {
}
}
+#[cfg(test)]
+impl TestRandom for BossBarAction {
+ fn test_gen_random() -> Self {
+ // todo
+ BossBarAction::Remove
+ }
+}
+
proto_varint_enum!(BossBarColor,
0x00 :: Pink,
0x01 :: Blue,
@@ -1322,6 +1306,14 @@ impl Deserialize for GameChangeReason {
}
}
+#[cfg(test)]
+impl TestRandom for GameChangeReason {
+ fn test_gen_random() -> Self {
+ // todo
+ GameChangeReason::PufferfishSting
+ }
+}
+
proto_varint_enum!(MapIconType,
0x00 :: WhiteArrow,
0x01 :: GreenArrow,
@@ -1414,6 +1406,13 @@ impl From<Option<MapColumnsSpec>> for MapColumns {
}
}
+#[cfg(test)]
+impl TestRandom for MapColumns {
+ fn test_gen_random() -> Self {
+ <Option<MapColumnsSpec>>::test_gen_random().into()
+ }
+}
+
__protocol_body_def_helper!(TradeSpec {
input_item_1: Option<Slot>,
output_item: Option<Slot>,
@@ -1516,6 +1515,13 @@ impl Deserialize for CombatEvent {
}
}
+#[cfg(test)]
+impl TestRandom for CombatEvent {
+ fn test_gen_random() -> Self {
+ CombatEvent::Enter // todo
+ }
+}
+
#[derive(Clone, PartialEq, Debug)]
pub struct PlayerInfoAction<A: Clone + PartialEq + Debug> {
pub uuid: UUID4,
@@ -1637,6 +1643,15 @@ impl Deserialize for PlayerInfoActionList {
}
}
+#[cfg(test)]
+impl TestRandom for PlayerInfoActionList {
+ fn test_gen_random() -> Self {
+ PlayerInfoActionList::Remove({
+ vec!(UUID4::random())
+ })
+ }
+}
+
fn serialize_vec_directly<I: Serialize, S: Serializer>(items: &Vec<I>, to: &mut S) -> SerializeResult {
for item in items {
to.serialize_other(item)?;
@@ -1801,6 +1816,15 @@ impl Deserialize for WorldBorderAction {
}
}
+#[cfg(test)]
+impl TestRandom for WorldBorderAction {
+ fn test_gen_random() -> Self {
+ WorldBorderAction::SetSize(WorldBorderSetSizeSpec{
+ diameter: f64::test_gen_random()
+ })
+ }
+}
+
#[derive(Clone, Copy, PartialEq, Debug, Eq)]
pub enum ScoreboardPosition {
List,
@@ -1847,6 +1871,13 @@ impl Deserialize for ScoreboardPosition {
}
}
+#[cfg(test)]
+impl TestRandom for ScoreboardPosition {
+ fn test_gen_random() -> Self {
+ ScoreboardPosition::Sidebar
+ }
+}
+
proto_varint_enum!(EquipmentSlot,
0x00 :: MainHand,
0x01 :: OffHand,
@@ -1911,6 +1942,13 @@ impl Deserialize for ScoreboardObjectiveAction {
}
}
+#[cfg(test)]
+impl TestRandom for ScoreboardObjectiveAction {
+ fn test_gen_random() -> Self {
+ ScoreboardObjectiveAction::Remove
+ }
+}
+
__protocol_body_def_helper!(EntityPropertySpec {
key: String,
value: f64,
@@ -2028,6 +2066,13 @@ impl Deserialize for InteractKind {
}
}
+#[cfg(test)]
+impl TestRandom for InteractKind {
+ fn test_gen_random() -> Self {
+ InteractKind::Attack
+ }
+}
+
proto_byte_flag!(ClientPlayerAbilities,
0x01 :: creative,
0x02 :: flying,
@@ -2241,6 +2286,16 @@ impl Deserialize for RecipeSpec {
}
}
+#[cfg(test)]
+impl TestRandom for RecipeSpec {
+ fn test_gen_random() -> Self {
+ RecipeSpec {
+ recipe: Recipe::CraftingRepairItem,
+ id: String::test_gen_random(),
+ }
+ }
+}
+
__protocol_body_def_helper!(RecipeIngredient {
items: VarIntCountedArray<Option<Slot>>
});
@@ -2292,6 +2347,19 @@ impl Deserialize for RecipeCraftingShapedSpec {
}
}
+#[cfg(test)]
+impl TestRandom for RecipeCraftingShapedSpec {
+ fn test_gen_random() -> Self {
+ RecipeCraftingShapedSpec {
+ width: VarInt::test_gen_random(),
+ height: VarInt::test_gen_random(),
+ group: String::test_gen_random(),
+ ingredients: vec!(RecipeIngredient::test_gen_random()),
+ result: <Option<Slot>>::test_gen_random(),
+ }
+ }
+}
+
__protocol_body_def_helper!(RecipeSmeltingSpec {
group: String,
ingredient: RecipeIngredient,
@@ -2388,4 +2456,498 @@ impl Deserialize for ChunkData {