use super::*;
use std::{
fs::{self, File},
io::{Seek, SeekFrom},
};
const REGION: &Region = unsafe { Region::from_array(include_bytes!("../test/r.0.0.mca")) };
const EXPECTED_CHUNK_LEN: usize = 10717;
const EXPECTED_DATA_VERSION: i32 = 3700;
macro_rules! assert_matches {
($a: expr, $b: pat) => {
assert!(
matches!($a, $b),
concat!("provided: {:?}, expected: ", stringify!($b)),
$a,
)
};
}
#[test]
fn test_slice() {
let vec = fs::read("./test/r.0.0.mca").unwrap();
let reg = Region::from_slice(&vec).unwrap();
assert_eq!(std::mem::size_of_val(reg), vec.len());
let chunk = reg.get_chunk(0, 0).unwrap().unwrap();
assert_eq!(chunk.compression_type, CompressionType::Zlib);
assert_eq!(chunk.len(), EXPECTED_CHUNK_LEN);
let parsed = chunk.parse().unwrap();
assert_eq!(parsed.data_version, EXPECTED_DATA_VERSION);
assert_matches!(Region::from_slice(&[0u8; 16]), Err(Error::MissingHeader));
}
#[test]
fn test_reader() {
let mut file = File::open("./test/r.0.0.mca").unwrap();
let reg = Region::from_reader(&mut file).unwrap();
assert_eq!(
std::mem::size_of_val(reg.as_ref()) as u64,
file.seek(SeekFrom::End(0)).unwrap()
);
assert_eq!(*REGION, *reg);
drop(file);
let chunk = reg.get_chunk(0, 0).unwrap().unwrap();
assert_eq!(chunk.compression_type, CompressionType::Zlib);
assert_eq!(chunk.len(), EXPECTED_CHUNK_LEN);
let parsed = chunk.parse().unwrap();
assert_eq!(parsed.data_version, EXPECTED_DATA_VERSION);
assert_matches!(
Region::from_reader(&mut &[0; 16][..]),
Err(Error::MissingHeader)
);
}
#[test]
fn test_array() {
let bytes = include_bytes!("../test/r.0.0.mca");
let reg = unsafe { Region::from_array(bytes) };
assert_eq!(std::mem::size_of_val(reg), bytes.len());
let chunk = reg.get_chunk(0, 0).unwrap().unwrap();
assert_eq!(chunk.compression_type, CompressionType::Zlib);
assert_eq!(chunk.len(), EXPECTED_CHUNK_LEN);
let parsed = chunk.parse().unwrap();
assert_eq!(parsed.data_version, EXPECTED_DATA_VERSION);
}
#[test]
fn test_boxed() {
let chunk = REGION.get_chunk(0, 0).unwrap().unwrap();
let box_chunk = chunk.boxed();
assert_eq!(*box_chunk, *chunk);
let parsed = chunk.parse().unwrap();
let box_parsed = box_chunk.parse().unwrap();
assert_eq!(parsed, box_parsed);
}
#[test]
fn test_get_timestamp() {
let points = [(0, 0), (1, 2), (2, 5), (8, 10), (25, 29), (31, 31)];
let expected = [
1709838433, 1709837896, 1709837897, 1709837898, 1697927255, 1689320056,
];
for ((x, z), expected) in points.iter().zip(expected.iter()) {
let ts = REGION.get_timestamp(*x, *z);
assert_eq!(ts, *expected, "Checking timestamp at {:?}", (x, z));
}
}
#[test]
fn test_bounds_checking() {
let points = [(0, 32), (32, 0), (32, 32)];
for (x, z) in points {
assert!(
std::panic::catch_unwind(|| REGION.get_chunk(x, z)).is_err(),
"Checking {:?} out of bounds",
(x, z)
);
}
}
#[test]
fn test_no_chunks() {
let bytes = &include_bytes!("../test/r.0.0.mca")[..8192];
let reg = Region::from_slice(bytes).unwrap();
assert_matches!(reg.get_chunk(0, 0), Err(Error::UnexpectedEof));
}
#[test]
fn test_not_enough_chunk_data() {
let bytes = &include_bytes!("../test/r.0.0.mca")[..8192];
let reg = Region::from_slice(bytes).unwrap();
assert_matches!(reg.get_chunk(0, 0), Err(Error::UnexpectedEof));
}
#[test]
fn test_missing_chunk() {
let mut bytes: Vec<u8> = Vec::new();
let chunk_data = [0, 0, 0, 0];
bytes.extend([0, 0, 2, 2]); bytes.extend([0; 1023 * 4]); bytes.extend([0; 1024 * 4]); bytes.extend(BigEndian::from(chunk_data.len() as u32 + 10 + 10).into_bytes());
bytes.push(2);
bytes.extend(chunk_data);
let reg = Region::from_slice(&bytes).unwrap();
assert_matches!(reg.get_chunk(0, 0), Err(Error::UnexpectedEof));
}
#[test]
fn test_invalid_chunks_compress() {
let mut bytes: Vec<u8> = Vec::new();
let chunk_data = [0, 0, 0, 0];
bytes.extend([0, 0, 2, 2]); bytes.extend([0; 1023 * 4]); bytes.extend([0; 1024 * 4]); bytes.extend(BigEndian::from(chunk_data.len() as u32 + 1).into_bytes());
bytes.push(2);
bytes.extend(chunk_data);
let reg = Region::from_slice(&bytes).unwrap();
let chunk = dbg!(reg.get_chunk(0, 0).unwrap().unwrap());
assert_matches!(chunk.parse().unwrap_err(), Error::DecompressError(_));
}
#[test]
fn test_invalid_chunks_invalid_nbt() {
let mut bytes: Vec<u8> = Vec::new();
let chunk_data = [120, 218, 99, 96, 96, 96, 0, 0, 0, 4, 0, 1];
bytes.extend([0, 0, 2, 2]); bytes.extend([0; 1023 * 4]); bytes.extend([0; 1024 * 4]); bytes.extend(BigEndian::from(chunk_data.len() as u32 + 1).into_bytes());
bytes.push(2);
bytes.extend(chunk_data);
let reg = Region::from_slice(&bytes).unwrap();
let chunk = dbg!(reg.get_chunk(0, 0).unwrap().unwrap());
assert_matches!(chunk.parse().unwrap_err(), Error::NbtError(_));
}
#[test]
fn test_missing_chunks() {
let mut bytes: Vec<u8> = Vec::new();
bytes.extend([0; 1024 * 4]); bytes.extend([0; 1024 * 4]);
let reg = Region::from_slice(&bytes).unwrap();
assert_matches!(reg.get_chunk(0, 0), Ok(None));
}
#[test]
fn test_region_file() {
let rf = RegionFile::new("./test/r.0.0.mca");
{
let rf = RegionFile::new("./test/r.-1.100.mca");
assert_eq!(rf.position(), Some((-1, 100)));
let rf = RegionFile::new("./test/r.10.-100.mca");
assert_eq!(rf.position(), Some((10, -100)));
let rf = RegionFile::new("./test/r.20.10.mca");
assert_eq!(rf.position(), Some((20, 10)));
}
let region = rf.parse().unwrap();
assert_eq!(*REGION, *region);
}
#[test]
fn test_parse_directory() {
let dir: Vec<_> = parse_directory("./test/regions")
.unwrap()
.filter_map(|rf| rf.position())
.collect();
dbg!(dir);
}
#[test]
fn test_validate() {
}
#[test]
fn test_has_chunk() {
assert!(REGION.has_chunk(0, 0));
}
#[test]
fn test_dim_id() {
for i in -50..50 {
let did = DimensionID::from(i);
assert_eq!(did.id(), i);
}
}
#[test]
fn test_dimension() {
let dim = Dimension::from_path("./test/regions").unwrap();
dim.regions().for_each(|r| {
dbg!(r.parse().unwrap().has_chunk(0, 0));
});
}
#[test]
fn test_heightmaps() {
let chunk = REGION.get_chunk(0, 0).unwrap().unwrap().parse().unwrap();
let mb = &chunk.height_maps.motion_blocking.as_ref().unwrap();
dbg!(mb.get_height(0, 0));
}
#[test]
fn test_block_in_chunk() {
let chunk = REGION.get_chunk(0, 0).unwrap().unwrap().parse().unwrap();
assert_eq!(
*chunk.get_block(4, 84, 10).unwrap(),
nbt::BlockState {
name: nbt::NamespacedKey::minecraft("grass_block".into()),
properties: Some(fastnbt::nbt!({
"snowy": "false",
})),
}
);
assert_eq!(chunk.get_block(13, 200, 15), None)
}