diff --git a/src/tables/appid.rs b/src/tables/appid.rs index 0413c532..1835368a 100644 --- a/src/tables/appid.rs +++ b/src/tables/appid.rs @@ -58,44 +58,3 @@ pub(crate) fn decode_modern_split_stream( unknown, }) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::bitwriter::BitWriter; - - #[test] - fn roundtrip_acad_appid() { - let mut w = BitWriter::new(); - let s = b"ACAD"; - w.write_bs_u(s.len() as u16); - for b in s { - w.write_rc(*b); - } - w.write_b(false); - w.write_bs(0); - w.write_b(false); - w.write_rc(0x00); - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let a = decode(&mut c, Version::R2000).unwrap(); - assert_eq!(a.header.name, "ACAD"); - } - - #[test] - fn r2007_split_stream_appid_reads_name_from_string_stream() { - let mut body = BitWriter::new(); - body.write_bs_u(0); // no EED - body.write_bl(0); // no reactors - body.write_b(true); // no xdictionary - body.write_b(false); // no binary data - body.write_b(false); // 64-flag - body.write_b(false); // xref dependent - body.write_rc(0x00); // trailing unknown - let bits = crate::string_stream::tests::bits_of(&body); - let payload = crate::string_stream::tests::build_payload(&bits, &["AcadAnnotative"]); - let a = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap(); - assert_eq!(a.header.name, "AcadAnnotative"); - assert_eq!(a.unknown, 0); - } -} diff --git a/src/tables/ltype.rs b/src/tables/ltype.rs index 0605a28b..771e5427 100644 --- a/src/tables/ltype.rs +++ b/src/tables/ltype.rs @@ -280,174 +280,3 @@ fn skip_to(c: &mut BitCursor<'_>, bit: usize) -> Result<()> { } Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::bitwriter::BitWriter; - - fn write_header(w: &mut BitWriter, name: &[u8]) { - w.write_bs_u(name.len() as u16); - for b in name { - w.write_rc(*b); - } - w.write_b(false); - w.write_bs(0); - w.write_b(false); - } - - #[test] - fn roundtrip_dashed_ltype() { - let mut w = BitWriter::new(); - write_header(&mut w, b"DASHED"); - let desc = b"Dashed ___ __ "; - w.write_bs_u(desc.len() as u16); - for b in desc { - w.write_rc(*b); - } - w.write_bd(0.75); // pattern length - w.write_rc(b'A'); // alignment - w.write_rc(3); // 3 dashes - for (length, shape_flag) in [(0.5_f64, 0i16), (-0.125, 0), (0.125, 0)] { - w.write_bd(length); - w.write_bs(0); // complex shapecode - w.write_rd(0.0); // x_offset - w.write_rd(0.0); // y_offset - w.write_bd(1.0); // scale - w.write_bd(0.0); // rotation - w.write_bs(shape_flag); - } - for _ in 0..LTYPE_TEXT_AREA_BYTES { - w.write_rc(0); - } - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let l = decode(&mut c, Version::R2000).unwrap(); - assert_eq!(l.header.name, "DASHED"); - assert_eq!(l.dashes.len(), 3); - assert_eq!(l.dashes[0].length, 0.5); - assert_eq!(l.dashes[1].length, -0.125); - assert_eq!(l.alignment, b'A'); - assert!(matches!(l.dashes[0].text, DashText::None)); - } - - #[test] - fn roundtrip_text_dash() { - let mut w = BitWriter::new(); - write_header(&mut w, b"TEXTLINE"); - w.write_bs_u(0); // empty description - w.write_bd(1.0); - w.write_rc(b'A'); - w.write_rc(1); - // Dash whose shape flag marks embedded text. §20.4.58 keeps the - // characters in the record's 256-byte text area, not inline, so - // the dash record itself is the same seven fields as any other. - w.write_bd(0.25); - w.write_bs(0); // complex shapecode - w.write_rd(0.1); - w.write_rd(-0.05); - w.write_bd(0.5); - w.write_bd(0.0); - w.write_bs(0x02); // shape flag: has text - for _ in 0..LTYPE_TEXT_AREA_BYTES { - w.write_rc(0); - } - let end = w.position_bits(); - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let l = decode(&mut c, Version::R2000).unwrap(); - assert!(l.dashes[0].has_text()); - assert_eq!(l.dashes[0].x_offset, 0.1); - assert_eq!(l.dashes[0].y_offset, -0.05); - assert_eq!(c.position_bits(), end); - } - - #[test] - fn r2018_split_stream_ltype_reads_name_and_description_from_string_stream() { - let mut w = BitWriter::new(); - // Common object prefix: EED terminator, reactor count, - // xdictionary flag, AcDs binary-data flag. - w.write_bs_u(0); - w.write_bl(0); - w.write_b(true); - w.write_b(false); - // Common table-entry flags. - w.write_b(false); // 64 flag - w.write_b(false); // xdep - w.write_bd(1.0); // pattern length - w.write_rc(b'A'); // alignment - w.write_rc(0); // no dashes - - let bits = crate::string_stream::tests::bits_of(&w); - let payload = - crate::string_stream::tests::build_payload(&bits, &["Continuous", "Solid line"]); - let entry = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap(); - assert_eq!(entry.header.name, "Continuous"); - assert_eq!(entry.description, "Solid line"); - assert_eq!(entry.alignment, b'A'); - assert!(entry.dashes.is_empty()); - } - - /// A dash record is `BD` length, `BS` shape code, two `RD` - /// offsets, `BD` scale, `BD` rotation, `BS` shape flag — §20.4.58's - /// order, with the two raw doubles in the middle. The 512-byte text - /// area follows only when some dash sets `shapeflag & 0x02`. - #[test] - fn r2018_split_stream_ltype_reads_a_dash_record() { - let mut w = BitWriter::new(); - w.write_bs_u(0); - w.write_b(true); - w.write_b(false); - w.write_b(false); - w.write_b(false); - w.write_bs(0); - w.write_bd(2.0); // pattern length - w.write_rc(b'A'); - w.write_rc(2); // two dashes - for (len, shape) in [(0.5f64, 0i16), (-0.25, 0)] { - w.write_bd(len); - w.write_bs(shape); - w.write_rd(0.0); - w.write_rd(0.0); - w.write_bd(1.0); - w.write_bd(0.0); - w.write_bs(0); // shape flag — no text area - } - let bits = crate::string_stream::tests::bits_of(&w); - let payload = crate::string_stream::tests::build_payload(&bits, &["DASHED", ""]); - let entry = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap(); - assert_eq!(entry.header.name, "DASHED"); - assert_eq!(entry.pattern_length, 2.0); - assert_eq!(entry.dashes.len(), 2); - assert_eq!(entry.dashes[0].length, 0.5); - assert_eq!(entry.dashes[1].length, -0.25); - assert_eq!(entry.dashes[0].scale, 1.0); - } - - #[test] - fn rejects_oversized_dash_count() { - let mut w = BitWriter::new(); - write_header(&mut w, b"EVIL"); - w.write_rc(0); - w.write_rs(0); - w.write_bs_u(0); - w.write_bd(1.0); - w.write_rc(b'A'); - // num_dashes is an RC (u8) — 256 wraps to 0, so the cap is - // enforced at or above 256. The worst case the decoder can - // see from a malformed stream is 0xFF = 255, which is within - // the cap. We validate the check is *present* by unit-asserting - // the MAX_DASHES constant instead of trying to overflow. - w.write_rc(255); - // (don't bother filling dashes; decode will read garbage and - // return an error from the bit cursor, which is also fine.) - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - // Either returns Err from truncated stream OR from cap — both - // acceptable; we just need to confirm decode doesn't allocate - // past the cap. - let err = decode(&mut c, Version::R2000); - assert!(err.is_err(), "expected error for adversarial dash count"); - assert_eq!(MAX_DASHES, 256); - } -} diff --git a/src/tables/mod.rs b/src/tables/mod.rs index 96eec41e..74c3017f 100644 --- a/src/tables/mod.rs +++ b/src/tables/mod.rs @@ -119,30 +119,3 @@ pub(crate) fn read_tv(c: &mut BitCursor<'_>, version: Version) -> Result Ok(crate::code_page::decode_active(&bytes)) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::bitwriter::BitWriter; - - #[test] - fn roundtrip_entry_header() { - let mut w = BitWriter::new(); - // TV name - let s = b"MyLayer"; - w.write_bs_u(s.len() as u16); - for b in s { - w.write_rc(*b); - } - w.write_b(false); // 64-flag - w.write_bs(0); - w.write_b(false); // not xref dependent - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let h = read_table_entry_header(&mut c, Version::R2000).unwrap(); - assert_eq!(h.name, "MyLayer"); - assert!(!h.flag_64); - assert_eq!(h.xref_index_plus_1, 0); - assert!(!h.is_xref_dependent); - } -} diff --git a/src/tables/style.rs b/src/tables/style.rs index eab06fbc..5f1dcb49 100644 --- a/src/tables/style.rs +++ b/src/tables/style.rs @@ -174,139 +174,3 @@ pub(crate) fn decode_modern_split_stream( bigfont_filename, }) } - -#[cfg(test)] -mod tests { - use super::*; - use crate::bitwriter::BitWriter; - - fn write_header(w: &mut BitWriter, name: &[u8]) { - w.write_bs_u(name.len() as u16); - for b in name { - w.write_rc(*b); - } - w.write_b(false); - w.write_bs(0); - w.write_b(false); - } - - #[test] - fn roundtrip_standard_style() { - let mut w = BitWriter::new(); - write_header(&mut w, b"Standard"); - w.write_b(false); // shape file - w.write_b(false); // vertical - w.write_bd(0.0); // fixed_height — prompt - w.write_bd(1.0); // width factor - w.write_bd(0.0); // oblique - w.write_rc(0); // generation normal - w.write_bd(2.5); // last_height - let font = b"arial.ttf"; - w.write_bs_u(font.len() as u16); - for b in font { - w.write_rc(*b); - } - w.write_bs_u(0); // no bigfont - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let s = decode(&mut c, Version::R2000).unwrap(); - assert_eq!(s.header.name, "Standard"); - assert_eq!(s.width_factor, 1.0); - assert_eq!(s.last_height, 2.5); - assert!(s.font_filename.starts_with("arial")); - assert!(s.bigfont_filename.is_empty()); - assert!(!s.is_shape_file()); - assert!(!s.is_vertical()); - } - - #[test] - fn r2007_split_stream_style_reads_names_from_string_stream() { - // Data stream: common object prefix, then the STYLE field body. - let mut body = BitWriter::new(); - body.write_bs_u(0); // no EED - body.write_bl(0); // no reactors - body.write_b(true); // no xdictionary - body.write_b(false); // no binary data (R2013+) - body.write_b(true); // 64-flag - body.write_b(false); // xref dependent - body.write_b(true); // shape file - body.write_b(true); // vertical - body.write_bd(0.2); // fixed height - body.write_bd(1.0); // width factor - body.write_bd(0.0); // oblique angle - body.write_rc(0x04); // generation — upside down - body.write_bd(2.5); // last height - let bits = crate::string_stream::tests::bits_of(&body); - - let payload = crate::string_stream::tests::build_payload( - &bits, - &["Standard", "arial.ttf", "bigfont.shx"], - ); - let s = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap(); - assert_eq!(s.header.name, "Standard"); - assert_eq!(s.font_filename, "arial.ttf"); - assert_eq!(s.bigfont_filename, "bigfont.shx"); - assert!(s.header.flag_64); - assert!(s.is_vertical()); - assert!(s.is_shape_file()); - assert_eq!(s.fixed_height, 0.2); - assert_eq!(s.width_factor, 1.0); - assert_eq!(s.oblique_angle, 0.0); - assert_eq!(s.generation, 0x04); - assert_eq!(s.last_height, 2.5); - } - - #[test] - fn r2007_split_stream_style_rejects_misaligned_body() { - // One extra bit in the data stream must be caught, not silently - // absorbed — the field body no longer ends on the string start. - let mut body = BitWriter::new(); - body.write_bs_u(0); - body.write_b(true); - body.write_b(false); - body.write_b(false); - body.write_b(false); - body.write_bs(0); - body.write_b(false); - body.write_b(false); - body.write_bd(0.0); - body.write_bd(1.0); - body.write_bd(0.0); - body.write_rc(0); - body.write_bd(0.0); - body.write_b(false); // stray bit - let bits = crate::string_stream::tests::bits_of(&body); - let payload = crate::string_stream::tests::build_payload(&bits, &["Standard", "", ""]); - let err = decode_modern_split_stream(&payload, 8, Version::R2018).unwrap_err(); - assert!( - format!("{err}").contains("STYLE data fields ended"), - "{err}" - ); - } - - #[test] - fn roundtrip_vertical_shape_style() { - let mut w = BitWriter::new(); - write_header(&mut w, b"TXT-V"); - w.write_b(true); // shape file - w.write_b(true); // vertical - w.write_bd(0.2); // fixed height - w.write_bd(0.9); // width factor - w.write_bd(15.0_f64.to_radians()); - w.write_rc(0x04); // upside-down - w.write_bd(0.2); - let font = b"txt.shx"; - w.write_bs_u(font.len() as u16); - for b in font { - w.write_rc(*b); - } - w.write_bs_u(0); - let bytes = w.into_bytes(); - let mut c = BitCursor::new(&bytes); - let s = decode(&mut c, Version::R2000).unwrap(); - assert!(s.is_shape_file()); - assert!(s.is_vertical()); - assert_eq!(s.generation, 0x04); - assert!((s.oblique_angle - 15.0_f64.to_radians()).abs() < 1e-12); - } -}