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(None);
// SVG 应有正确的结构
assert!(svg.starts_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(None);
assert!(svg.contains("