Files
guara/crates/guara-core/tests/formats.rs
T
Lucas RayanandClaude Sonnet 5 6328220c60
CI / Format and clippy (push) Successful in 1m57s
CI / Dependency audit (push) Successful in 13s
CI / Check desktop app (Linux) (push) Successful in 3m54s
CI / Tests (Linux) (push) Failing after 7m25s
Release / Create release (push) Successful in 6s
Release / CLI (linux-aarch64) (push) Successful in 1m48s
Release / CLI (linux-x86_64) (push) Successful in 2m39s
Release / Desktop app (linux-aarch64) (push) Successful in 10m9s
Release / Desktop app (linux-x86_64) (push) Successful in 12m20s
Release / Desktop app (windows) (push) Successful in 7m32s
Release / Build latest.json (push) Successful in 5s
chore(i18n): finish translating code comments and scripts to English
Completes the English-only standardization for code, comments, scripts
and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en,
untouched). Covers the remaining crates/, apps/gui/ui/ and
apps/gui/src-tauri/ comments, .gitea/ workflow and template comments,
.githooks/ hooks, and the scripts/ source comments for the files
already renamed in a prior commit (check.sh, generate-logo.py,
install-hooks.sh).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
2026-10-30 20:43:02 -03:00

168 lines
5.1 KiB
Rust

//! Structural format detectors: real files with trailing garbage appended (carved size must be exact).
use guara_core::signatures::detect;
use guara_core::source::MemSource;
use guara_core::Confidence;
use std::path::Path;
fn check(path: &str, ext: &str, min_conf: Confidence) -> bool {
let p = Path::new(path);
if !p.exists() {
eprintln!("SKIP {path}");
return false;
}
let mut data = std::fs::read(p).unwrap();
let real = data.len();
// append trailing bytes to simulate subsequent disk blocks after EOF
data.extend((0..5000u32).map(|i| (i.wrapping_mul(2654435761) >> 7) as u8 | 0x81));
let src = MemSource(data.clone());
let h =
detect(&src, 0, &data[..128], 1 << 30).unwrap_or_else(|| panic!("{path}: não reconhecido"));
assert_eq!(h.len as usize, real, "{path}: tamanho");
assert_eq!(h.ext, ext, "{path}: extensão");
assert!(
h.confidence >= min_conf,
"{path}: confiança {:?}",
h.confidence
);
true
}
fn first(dir: &str, ext: &str) -> Option<String> {
let out = std::process::Command::new("find")
.args([
dir,
"-iname",
&format!("*.{ext}"),
"-type",
"f",
"-size",
"+2k",
"-size",
"-20M",
])
.output()
.ok()?;
String::from_utf8_lossy(&out.stdout)
.lines()
.next()
.map(String::from)
}
#[test]
fn real_files_have_exact_lengths() {
let mut n = 0;
let cases: Vec<(Option<String>, &str, Confidence)> = vec![
(
first("/usr/share/cinnamon/sounds", "ogg"),
"ogg",
Confidence::High,
),
(first("/usr/share", "gz"), "gz", Confidence::High),
(first("/usr/share/doc", "bz2"), "bz2", Confidence::High),
(first("/usr/lib/firmware", "zst"), "zst", Confidence::Medium),
(
first(
"/usr/share/texlive/texmf-dist/tex/latex/media9/players",
"swf",
),
"swf",
Confidence::Medium,
),
(
first("/usr/share/code/resources/app", "rtf"),
"rtf",
Confidence::High,
),
(
first("/usr/share/app-install/icons", "tiff"),
"tif",
Confidence::Medium,
),
(Some("/usr/bin/ls".to_string()), "elf", Confidence::High),
(
first(
"/home/lucas/Documents/Desenvolvimento/pop-hub/public",
"ico",
),
"ico",
Confidence::High,
),
];
for (path, ext, conf) in cases {
if let Some(p) = path {
if check(&p, ext, conf) {
n += 1;
}
}
}
eprintln!("{n} arquivos reais verificados");
}
#[test]
fn webm_rar_deb_with_unknown_locations() {
for (dir, ext, out, conf) in [
(
"/media/lucas/d9d2ba04-f925-4b9a-97d7-92c2e3bfdb78/Nextcloud/apps/firstrunwizard/img",
"webm",
"webm",
Confidence::High,
),
(
"/home/lucas/Documents/Pessoal/dev/power_vision/.trabalho/libbsd",
"deb",
"deb",
Confidence::Medium,
),
(
"/media/lucas/d9d2ba04-f925-4b9a-97d7-92c2e3bfdb78/war_cloud/lucasrguerra/Backups",
"rar",
"rar",
Confidence::High,
),
] {
if let Some(p) = first(dir, ext) {
check(&p, out, conf);
}
}
}
#[test]
fn synthetic_structures() {
// Synthetic CAB, MIDI, PCAP, and AIFF containers with trailing garbage.
let mut cab = b"MSCF\0\0\0\0".to_vec();
cab.extend_from_slice(&200u32.to_le_bytes());
cab.resize(200, 0);
let mut d = cab.clone();
d.extend_from_slice(&[0x99; 3000]);
let h = detect(&MemSource(d.clone()), 0, &d[..64], 1 << 30).unwrap();
assert_eq!((h.len, h.ext), (200, "cab"));
let mut mid = b"MThd\0\0\0\x06\0\x01\0\x02\x01\xE0".to_vec();
for n in [10u32, 7] {
mid.extend_from_slice(b"MTrk");
mid.extend_from_slice(&n.to_be_bytes());
mid.extend(std::iter::repeat(0x41).take(n as usize));
}
let real = mid.len();
let mut d = mid.clone();
d.extend_from_slice(&[0x77; 500]);
let h = detect(&MemSource(d.clone()), 0, &d[..64], 1 << 30).unwrap();
assert_eq!((h.len as usize, h.ext), (real, "mid"));
let mut pcap = vec![0xD4, 0xC3, 0xB2, 0xA1, 2, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0];
pcap.extend_from_slice(&65535u32.to_le_bytes());
pcap.extend_from_slice(&1u32.to_le_bytes());
for len in [60u32, 100, 1514] {
pcap.extend_from_slice(&[0; 8]);
pcap.extend_from_slice(&len.to_le_bytes());
pcap.extend_from_slice(&len.to_le_bytes());
pcap.extend(std::iter::repeat(0x33).take(len as usize));
}
let real = pcap.len();
let mut d = pcap.clone();
d.extend_from_slice(&[0xFF; 400]);
let h = detect(&MemSource(d.clone()), 0, &d[..64], 1 << 30).unwrap();
assert_eq!((h.len as usize, h.ext), (real, "pcap"));
}