use qr_core::qr::{QrCode, QrConfig, VersionMode}; use qr_core::version::EcLevel; /// 诊断: 验证格式信息编码 + 解码是否正确 #[test] fn test_format_info_roundtrip() { use qr_core::matrix::patterns::{encode_format_info, encode_version_info}; // M 级 (00) + mask 0 (000): data = 00000 = 0 let fmt0 = encode_format_info(0b00, 0); // L 级 (01) + mask 3 (011): data = 01011 = 11 let fmt1 = encode_format_info(0b01, 3); // H 级 (10) + mask 7 (111): data = 10111 = 23 let fmt2 = encode_format_info(0b10, 7); // 不同输入应产生不同输出 assert_ne!(fmt0, fmt1); assert_ne!(fmt1, fmt2); assert_ne!(fmt0, fmt2); // 应该在 15-bit 范围内 assert!(fmt0 < 0x8000); assert!(fmt1 < 0x8000); println!("格式信息 M+mask0: 0x{:04X}", fmt0); println!("格式信息 L+mask3: 0x{:04X}", fmt1); println!("格式信息 H+mask7: 0x{:04X}", fmt2); // 版本信息编码 let v7 = encode_version_info(7); println!("版本信息 v7: 0x{:06X}", v7); // 前 6 bit 是版本号 assert_eq!((v7 >> 12) & 0x3F, 7); } /// 诊断: 打印 QR 码的格式信息比特 #[test] fn test_dump_format_info() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let m = qr.modules(); println!("\n=== 格式信息 15 bit (bit14 到 bit0) ==="); println!("EC 级别: {:?}, 掩码: {}", qr.level, qr.mask); // 格式信息位置 (按标准顺序 bit14→bit0) let coords = [ (0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (7, 8), (8, 8), (8, 7), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0), ]; let mut fmt_bits = 0u16; for (i, &(x, y)) in coords.iter().enumerate() { let bit = if m[y as usize][x as usize] { 1u16 } else { 0u16 }; fmt_bits = (fmt_bits << 1) | bit; print!( "{} ", if m[y as usize][x as usize] { '█' } else { '_' } ); } println!(); println!( "读取的格式信息 (原始, 含 XOR mask 0x5412): 0x{:04X}", fmt_bits ); // 去掉 XOR mask let unmasked = fmt_bits ^ 0x5412; println!("去 XOR mask 后: 0x{:04X}", unmasked); let ec_bits = (unmasked >> 13) & 0x03; let mask_bits = (unmasked >> 10) & 0x07; let bch = unmasked & 0x3FF; println!( "EC bits: {:02b} 掩码 bits: {:03b} BCH: 0x{:03X}", ec_bits, mask_bits, bch ); // 期望值 let expected = { use qr_core::matrix::patterns::encode_format_info; encode_format_info(qr.level.indicator_bits(), qr.mask) }; println!("期望的格式信息: 0x{:04X}", expected); println!( "匹配: {}", if fmt_bits == expected { "✅" } else { "❌ 不匹配!" } ); assert_eq!(fmt_bits, expected, "格式信息不匹配!"); } #[test] fn test_finder_patterns_present() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let size = qr.size() as usize; let m = qr.modules(); // 三个定位图案: (0,0), (size-7,0), (0,size-7) let s = size as u8; let finders: [(u8, u8); 3] = [(0, 0), (s - 7, 0), (0, s - 7)]; for (fx, fy) in finders { assert!( m[fy as usize][fx as usize], "定位({},{}): 左上角应为暗", fx, fy ); assert!( m[fy as usize][(fx + 6) as usize], "定位({},{}): 右上角应为暗", fx, fy ); assert!( m[(fy + 6) as usize][fx as usize], "定位({},{}): 左下角应为暗", fx, fy ); // 内部 3×3 是暗色 assert!( m[(fy + 2) as usize][(fx + 2) as usize], "定位({},{}): 中心3×3应为暗", fx, fy ); } } #[test] fn test_timing_pattern_alternates() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let m = qr.modules(); let s = qr.size() as usize; // 行6: 从列8到列s-8-1 应交替 for x in (8..s - 8).step_by(2) { assert!(m[6][x], "时序 y=6 x={}: 偶数应为暗", x); if x + 1 < s - 8 { assert!(!m[6][x + 1], "时序 y=6 x={}: 奇数应为亮", x + 1); } } // 列6: 从行8到行s-8-1 应交替 for y in (8..s - 8).step_by(2) { assert!(m[y][6], "时序 x=6 y={}: 偶数应为暗", y); if y + 1 < s - 8 { assert!(!m[y + 1][6], "时序 x=6 y={}: 奇数应为亮", y + 1); } } } #[test] fn test_dark_module_present() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let m = qr.modules(); let s = qr.size() as usize; // 暗模块总是位于 (8, size-8) assert!(m[s - 8][8], "暗模块 (8,{}) 缺失!", s - 8); } #[test] fn test_format_info_written() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let m = qr.modules(); // 格式信息在定位图案旁,检查几个位置不是全亮 assert!( m[8][0] || m[8][1] || m[8][2] || !m[8][0], "格式信息应已写入" ); } #[test] fn test_svg_valid_structure() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let svg = qr.to_svg(); // SVG 应有正确的结构 assert!(svg.starts_with("\n") || svg.ends_with(""), "SVG 应以 结尾" ); } #[test] fn test_quiet_zone_is_white() { let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let m = qr.modules(); let s = qr.size() as usize; // 左上角分隔符区域 (7,0..7) 和 (0..7,7) 应为白色 for i in 0..8usize { assert!(!m[7][i], "定位分隔符 (7,{}) 应为白色", i); assert!(!m[i][7], "定位分隔符 ({},7) 应为白色", i); } } #[test] fn test_qr_structure_dump() { // 打印矩阵到 stdout(用于调试) let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap(); let size = qr.size() as usize; let m = qr.modules(); println!( "\n=== QR Matrix {}x{} v{} mask{} ===", size, size, qr.version.0, qr.mask ); for y in 0..size { for x in 0..size { print!("{}", if m[y][x] { "##" } else { " " }); } println!(); } // 统计 let dark: usize = m.iter().flatten().filter(|&&x| x).count(); let total = size * size; println!( "\n暗/总: {}/{} = {:.1}%", dark, total, dark as f64 / total as f64 * 100.0 ); println!("尺寸: {}×{}", size, size); println!( "版本: {} 掩码: {} 纠错: {:?}", qr.version.0, qr.mask, qr.level ); } #[test] fn test_encode_simple_text() { let config = QrConfig::default(); let qr = QrCode::encode("HELLO WORLD", config).unwrap(); assert_eq!(qr.version.0, 1); assert_eq!(qr.size(), 21); } #[test] fn test_all_levels() { for level in [EcLevel::L, EcLevel::M, EcLevel::Q, EcLevel::H] { let config = QrConfig { level, ..Default::default() }; let qr = QrCode::encode("TEST", config).unwrap(); assert!(qr.size() >= 21); assert!(qr.size() <= 177); } } #[test] fn test_chinese_text() { let config = QrConfig::default(); let qr = QrCode::encode("你好世界", config).unwrap(); assert!(qr.size() >= 21); } #[test] fn test_url_encoding() { let config = QrConfig::default(); let qr = QrCode::encode("https://example.com/path?q=1", config).unwrap(); assert!(qr.size() >= 21); } #[test] fn test_numeric_only_small_version() { let mut config = QrConfig::default(); config.version = VersionMode::Fixed(1); let qr = QrCode::encode("12345678901234567890", config).unwrap(); assert_eq!(qr.version.0, 1); } #[test] fn test_fixed_version() { let config = QrConfig { version: VersionMode::Fixed(5), ..Default::default() }; let qr = QrCode::encode("FIXED VERSION TEST", config).unwrap(); assert_eq!(qr.version.0, 5); } #[test] fn test_empty_input_fails() { let config = QrConfig::default(); let result = QrCode::encode("", config); assert!(result.is_err()); } #[test] fn test_svg_output() { let qr = QrCode::encode("TEST", QrConfig::default()).unwrap(); let svg = qr.to_svg(); assert!(svg.contains("")); assert!(svg.contains("fill=\"black\"")); } #[test] fn test_ascii_output() { let qr = QrCode::encode("TEST", QrConfig::default()).unwrap(); let ascii = qr.to_ascii(false); assert!(!ascii.is_empty()); assert!(ascii.contains('\n')); // 应该有暗模块 assert!(ascii.contains("██")); } #[test] fn test_png_output() { let qr = QrCode::encode("TEST", QrConfig::default()).unwrap(); let png = qr.to_png_bytes(4).unwrap(); assert!(!png.is_empty()); // PNG 文件应以 8 字节魔术签名开头 assert_eq!(&png[..8], &[137, 80, 78, 71, 13, 10, 26, 10]); } #[test] fn test_modules_matrix() { let qr = QrCode::encode("QR", QrConfig::default()).unwrap(); let modules = qr.modules(); assert_eq!(modules.len(), qr.size() as usize); assert_eq!(modules[0].len(), qr.size() as usize); // 至少有一些暗模块 let has_dark = modules.iter().any(|row| row.iter().any(|&m| m)); assert!(has_dark, "QR 码应该包含暗模块"); } #[test] fn test_margin_is_included_in_dimensions() { let mut config = QrConfig::default(); config.margin = 2; let qr = QrCode::encode("MARGIN TEST", config).unwrap(); // SVG 的总宽度应该包含 margin let svg = qr.to_svg(); let matrix_size = qr.size() as u32; let expected_total = matrix_size + 2 * 2u32; assert!(svg.contains(&format!("width=\"{}\"", expected_total))); // ASCII 输出行应该包含 margin 列 let ascii = qr.to_ascii(false); let first_line = ascii.lines().next().unwrap(); let chars_per_module = 2; // ██ 是两个字符 assert_eq!( first_line.chars().count(), expected_total as usize * chars_per_module ); } #[test] fn test_long_text_auto_version() { // 长文本应该自动选择更高的版本 let long_text = "A".repeat(200); let qr = QrCode::encode(&long_text, QrConfig::default()).unwrap(); // 至少要 Version 2 以上 assert!(qr.version.0 >= 2); } #[test] fn test_special_chars() { let config = QrConfig::default(); let qr = QrCode::encode("$%*+-./: SPACE", config).unwrap(); assert!(qr.size() >= 21); } #[test] fn test_numeric_mode_efficiency() { // 纯数字在 Version 1 L 级最多 41 位(约 7089 位数字) let digits = "1".repeat(20); let mut config = QrConfig::default(); config.version = VersionMode::Fixed(1); config.level = EcLevel::L; let qr = QrCode::encode(&digits, config).unwrap(); assert_eq!(qr.version.0, 1); }