Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 0 additions & 65 deletions src/entities/attdef.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,68 +161,3 @@ fn read_tv(c: &mut BitCursor<'_>, version: Version) -> Result<String> {
Ok(crate::code_page::decode_active(&bytes))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;

#[test]
fn r2007_split_stream_attdef_reads_value_tag_and_prompt() {
let mut body = BitWriter::new();
text::tests::write_r2018_preamble(&mut body);
body.write_rc(0xFF);
body.write_rd(0.0);
body.write_rd(0.0);
body.write_b(true); // extrusion default
body.write_b(true); // thickness zero
body.write_rd(2.5); // height
body.write_rc(0); // ATTRIB's R2010+ version byte
body.write_rc(1); // R2018+ attribute type = single line
body.write_bs(0); // field length
body.write_rc(0x00); // flags
body.write_b(false); // lock position
body.write_rc(0); // ATTDEF's own R2010+ version byte
let bits = crate::string_stream::tests::bits_of(&body);
let payload =
crate::string_stream::tests::build_payload(&bits, &["1", "ATTINFO", "Enter number:"]);
let a = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap();
assert_eq!(a.tag, "ATTINFO");
assert_eq!(a.prompt, "Enter number:");
assert_eq!(a.text.text, "1");
assert_eq!(a.text.height, 2.5);
assert_eq!(a.attribute_type, 1);
assert!(a.mtext.is_none());
}

#[test]
fn roundtrip_attdef_r2000() {
let mut w = BitWriter::new();
// TEXT preamble — minimal
w.write_rc(0xFF);
w.write_rd(0.0);
w.write_rd(0.0);
w.write_b(true);
w.write_b(true);
w.write_rd(2.5);
w.write_bs_u(0); // empty default text
// ATTRIB fields
w.write_bs_u(5); // tag
for b in b"PRICE" {
w.write_rc(*b);
}
w.write_bs(0); // field length
w.write_rc(0x00); // flags
// ATTDEF's own prompt, last
w.write_bs_u(14); // prompt
for b in b"Enter price: " {
w.write_rc(*b);
}
w.write_rc(0); // trailing NUL (stripped)
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let a = decode(&mut c, Version::R2000).unwrap();
assert_eq!(a.prompt, "Enter price: ");
assert_eq!(a.tag, "PRICE");
}
}
142 changes: 0 additions & 142 deletions src/entities/attrib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,145 +250,3 @@ fn read_tv(c: &mut BitCursor<'_>, version: Version) -> Result<String> {
Ok(crate::code_page::decode_active(&bytes))
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;

#[test]
fn r2007_split_stream_attrib_reads_value_and_tag() {
let mut body = BitWriter::new();
text::tests::write_r2018_preamble(&mut body);
body.write_rc(0xFF);
body.write_rd(0.0);
body.write_rd(0.0);
body.write_b(true); // extrusion default
body.write_b(true); // thickness zero
body.write_rd(2.5); // height
body.write_rc(0); // R2010+ version byte
body.write_rc(1); // R2018+ attribute type = single line
body.write_bs(0); // field length
body.write_rc(0x01); // flags — invisible
body.write_b(false); // lock position
let bits = crate::string_stream::tests::bits_of(&body);
let payload = crate::string_stream::tests::build_payload(&bits, &["17", "ATTINFO"]);
let a = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap();
assert_eq!(a.tag, "ATTINFO");
assert_eq!(a.text.text, "17");
assert_eq!(a.text.height, 2.5);
assert_eq!(a.attribute_type, 1);
assert!(a.mtext.is_none());
assert!(a.is_invisible());
assert!(!a.lock_position);
}

/// The R2018 multi-line shape measured on `sample_AC1032.dwg`
/// handle `0x79D`: attribute type `2`, then a whole MTEXT record
/// embedded from its entity-mode bits on, then the annotative-data
/// size and the attribute's own flags. Its three strings are the
/// (empty) TEXT value, the embedded MTEXT's text, and the tag.
#[test]
fn r2018_multi_line_attrib_embeds_an_mtext() {
let mut body = BitWriter::new();
text::tests::write_r2018_preamble(&mut body);
body.write_rc(0xFF); // TEXT data flags: nothing optional present
body.write_rd(977.28); // insertion x
body.write_rd(27.03); // insertion y
body.write_b(true); // extrusion default
body.write_b(true); // thickness zero
body.write_rd(1.72); // height
body.write_rc(0); // R2010+ version byte
body.write_rc(2); // R2018+ attribute type = multi-line ATTRIB
// Embedded MTEXT: the common entity preamble from entmode on.
body.write_bb(0b00); // entmode
body.write_bl(0); // num reactors
body.write_b(true); // no xdictionary
body.write_b(false); // no AcDs binary data
body.write_bs(0); // colour
body.write_bd(1.0); // linetype scale
body.write_bb(0b00);
body.write_bb(0b00);
body.write_bb(0b00);
body.write_rc(0);
body.write_b(false);
body.write_b(false);
body.write_b(false);
body.write_bs(0); // invisibility
body.write_rc(0x1D); // lineweight
// Embedded MTEXT field body.
for v in [977.28, 28.75, 0.0] {
body.write_bd(v);
}
for v in [0.0, 0.0, 1.0] {
body.write_bd(v);
}
for v in [1.0, 0.0, 0.0] {
body.write_bd(v);
}
body.write_bd(0.0); // rect width
body.write_bd(0.0); // rect height
body.write_bd(1.72); // nominal text height
body.write_bs(1); // attachment point
body.write_bs(5); // drawing direction
body.write_bd(1.84); // extents height
body.write_bd(16.37); // extents width
body.write_bs(1); // linespace style
body.write_bd(1.0); // linespace factor
body.write_b(false); // unknown bit
body.write_bl(0); // background flags
body.write_b(false); // R2018 "is NOT annotative" — clear
// Back in the ATTRIB.
body.write_bs(0); // annotative data size
body.write_bs(0); // unknown 73
body.write_rc(0x00); // flags
body.write_b(true); // lock position

let bits = crate::string_stream::tests::bits_of(&body);
let payload = crate::string_stream::tests::build_payload(
&bits,
&["", "my multi line text for the attrrib", "MULTI_LINE_ATT"],
);
let a = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap();
assert_eq!(a.attribute_type, 2);
assert_eq!(a.tag, "MULTI_LINE_ATT");
assert_eq!(a.text.text, "");
let m = a.mtext.expect("embedded MTEXT");
assert_eq!(m.text, "my multi line text for the attrrib");
assert_eq!(m.extents_width, 16.37);
assert!(a.lock_position);
}

#[test]
fn roundtrip_invisible_constant_attrib() {
let mut w = BitWriter::new();
// minimal TEXT payload
w.write_rc(0xFF);
w.write_rd(0.0);
w.write_rd(0.0);
w.write_b(true); // ext default
w.write_b(true); // thickness default
w.write_rd(2.5);
w.write_bs_u(3); // "ABC"
w.write_rc(b'A');
w.write_rc(b'B');
w.write_rc(b'C');
// attrib-specific
w.write_bs_u(5); // tag "PRICE"
w.write_rc(b'P');
w.write_rc(b'R');
w.write_rc(b'I');
w.write_rc(b'C');
w.write_rc(b'E');
w.write_bs(0); // field_length
w.write_rc(0x03); // invisible + constant
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let a = decode(&mut c, Version::R2000).unwrap();
assert_eq!(a.tag, "PRICE");
assert_eq!(a.text.text, "ABC");
assert!(a.is_invisible());
assert!(a.is_constant());
assert!(!a.is_verifiable());
}
}
20 changes: 0 additions & 20 deletions src/entities/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,3 @@ pub fn decode(c: &mut BitCursor<'_>, version: Version) -> Result<Block> {
})
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;

#[test]
fn roundtrip_modelspace_block_r2000() {
let mut w = BitWriter::new();
let s = b"*Model_Space";
w.write_bs_u(s.len() as u16);
for b in s {
w.write_rc(*b);
}
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let b = decode(&mut c, Version::R2000).unwrap();
assert_eq!(b.name, "*Model_Space");
}
}
70 changes: 0 additions & 70 deletions src/entities/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,73 +63,3 @@ pub fn decode_record(c: &mut BitCursor<'_>, version: Version, in_data_store: boo
tail: Some(record.tail),
})
}

#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;

#[test]
fn roundtrip_empty_body_entity() {
let mut w = BitWriter::new();
w.write_b(true);
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let b = decode(&mut c).unwrap();
assert!(b.acis_empty);
assert_eq!(b.version, None);
assert_eq!(b.sat_blob, None);
}

#[test]
fn roundtrip_body_with_blob() {
let payload = b"BODY_SAT_PAYLOAD_BYTES";
let mut w = BitWriter::new();
w.write_b(false);
w.write_b(false); // §20.4.41 unknown bit
w.write_bs_u(1);
w.write_bl(payload.len() as i32);
for x in payload {
w.write_rc(*x);
}
w.write_bl(0);
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let b = decode(&mut c).unwrap();
assert!(!b.acis_empty);
assert_eq!(b.version, Some(1));
assert_eq!(b.sat_blob.as_deref(), Some(&payload[..]));
}

/// The R2013+ data-store shape: no inline envelope, a wireframe
/// point, `num isolines = 4` and the 16-byte revision GUID.
#[test]
fn roundtrip_body_data_store_record() {
let guid = [0xCDu8; 16];
let mut w = BitWriter::new();
w.write_b(true); // wireframe data present
w.write_b(false); // point present
w.write_bl(4); // num isolines
w.write_b(false); // isolines present
w.write_b(true); // ACIS empty (2)
w.write_bl(0); // R2007+ unknown
w.write_b(true);
w.write_bb(0);
w.write_bb(0);
w.write_bb(0b10);
for b in guid {
w.write_rc(b);
}
w.write_bl(0);
let end = w.position_bits();
let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let b = decode_record(&mut c, Version::R2018, true).unwrap();
assert!(b.in_data_store);
let fields = b.tail.unwrap();
assert_eq!(fields.num_isolines, 4);
assert!(!fields.isolines_present);
assert_eq!(fields.revision_guid, Some(guid));
assert_eq!(c.position_bits(), end);
}
}
61 changes: 0 additions & 61 deletions src/entities/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,64 +65,3 @@ pub fn decode(c: &mut BitCursor<'_>, version: Version) -> Result<Camera> {
view_handle,
})
}

#[cfg(test)]
mod tests {
use super::*;
use crate::bitwriter::BitWriter;

#[test]
fn roundtrip_camera_default_focal() {
let mut w = BitWriter::new();
// origin (1.0, 2.0, 3.0)
w.write_bd(1.0);
w.write_bd(2.0);
w.write_bd(3.0);
// direction (0.0, 0.0, -1.0)
w.write_bd(0.0);
w.write_bd(0.0);
w.write_bd(-1.0);
// focal length — BD 1.0 short-form represents 1.0, so use an
// explicit double for 50.0mm.
w.write_bd(50.0);
// FoV ≈ 0.6 rad (about 34° full-angle, normal lens)
w.write_bd(0.6);
// view handle 5.1.0x42
w.write_handle(5, 0x42);

let bytes = w.into_bytes();
let mut c = BitCursor::new(&bytes);
let cam = decode(&mut c, Version::R2010).unwrap();
assert_eq!(
cam.origin,
Point3D {
x: 1.0,
y: 2.0,
z: 3.0
}
);
assert_eq!(
cam.direction,
Vec3D {
x: 0.0,
y: 0.0,
z: -1.0
}
);
assert_eq!(cam.focal_length, 50.0);
assert!((cam.field_of_view - 0.6).abs() < 1e-12);
assert_eq!(cam.view_handle.code, 5);
assert_eq!(cam.view_handle.value, 0x42);
}

#[test]
fn rejects_pre_r2007() {
let bytes = [0u8; 4];
let mut c = BitCursor::new(&bytes);
let err = decode(&mut c, Version::R2004).unwrap_err();
assert!(
matches!(&err, Error::Unsupported { feature } if feature.contains("CAMERA")),
"err={err:?}"
);
}
}
Loading
Loading