Files
craft-libs/crates/vectorcraft-format/tests/envelope.rs
T

489 lines
23 KiB
Rust

use std::io::Write;
use craft_vectorcraft_format::{
BLOB_MAGIC, Contents, EXTENSION, Entries, Error, File, Head, INLINE_MAX, Image, LEGACY_EXTENSION, MAX_ENTRY, ReadError, Tail, VERSION, base64,
check, entry, is_compressed, json_part, marker_at, sniff, split_tail,
};
use serde::de::IgnoredAny;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Layer {
name: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Doc {
layers: Vec<Layer>,
}
const PNG: &[u8] = &[0x89, b'P', b'N', b'G', b'\r', b'\n', 0x1a, b'\n'];
fn doc() -> Doc {
Doc { layers: vec![Layer { name: "Layer 1".into() }] }
}
fn pdf() -> Vec<u8> {
let mut pdf = b"%PDF-1.7\n".to_vec();
pdf.resize(INLINE_MAX, b' ');
pdf
}
/// A PNG entry at `[offset, length]` in the data after the JSON.
fn blob(at: [u64; 2]) -> Image {
let mut image = Image::default();
image.mime = "image/png".into();
image.blob = Some(at);
image
}
fn gzip(bytes: &[u8]) -> Vec<u8> {
let mut gz = flate2::write::GzEncoder::new(Vec::new(), flate2::Compression::default());
gz.write_all(bytes).unwrap();
gz.finish().unwrap()
}
fn written(file: &File<Doc>, tail: &Tail<'_>, pretty: bool) -> Vec<u8> {
let mut out = if pretty { serde_json::to_vec_pretty(file) } else { serde_json::to_vec(file) }.unwrap();
tail.write_to(&mut out).unwrap();
out
}
fn full_file(pdf: &[u8]) -> (File<Doc>, Tail<'_>) {
let mut tail = Tail::new(VERSION);
let mut file = File::new(doc());
file.generator = Some("VectorCraft 0.17.0".into());
file.preview = Some(Image::inline("image/png", PNG));
file.pdf = Some(tail.image("application/pdf", pdf, false));
file.images.insert("k".into(), tail.image("image/png", &[1, 2, 3, 250], false));
(file, tail)
}
#[test]
fn a_version_4_file_with_members_after_the_json_is_written_as_the_app_writes_it() {
let pdf = pdf();
let (file, tail) = full_file(&pdf);
let mut expected = br#"{"format":"vectorcraft","version":4,"generator":"VectorCraft 0.17.0","preview":{"mime":"image/png","data":"iVBORw0KGgo="},"pdf":{"mime":"application/pdf","blob":[0,8192]},"document":{"layers":[{"name":"Layer 1"}]},"images":{"k":{"mime":"image/png","data":"AQID+g=="}}}"#.to_vec();
expected.extend(b"\n\0VCBLOBS\0");
expected.extend(&pdf);
assert_eq!(written(&file, &tail, false), expected);
assert_eq!(tail.len(), INLINE_MAX as u64);
assert_eq!(tail.parts().len(), 1);
}
#[test]
fn a_pretty_file_without_optional_members_is_written_as_the_app_writes_it() {
let mut file = File::new(doc());
file.generator = Some("VectorCraft 0.17.0".into());
let expected = r#"{
"format": "vectorcraft",
"version": 4,
"generator": "VectorCraft 0.17.0",
"document": {
"layers": [
{
"name": "Layer 1"
}
]
},
"images": {}
}"#;
assert_eq!(String::from_utf8(written(&file, &Tail::new(VERSION), true)).unwrap(), expected);
}
#[test]
fn a_version_2_file_keeps_large_entries_inline_under_the_former_name() {
let pdf = pdf();
let mut tail = Tail::new(2);
let mut file = File::new(doc());
file.format = LEGACY_EXTENSION.into();
file.version = 2;
file.profiles.insert("Gray".into(), tail.image(craft_vectorcraft_format::ICC_MIME, &pdf, false));
let bytes = written(&file, &tail, false);
assert!(tail.is_empty());
assert!(!bytes.contains(&0));
let text = String::from_utf8(bytes).unwrap();
assert!(text.starts_with(r#"{"format":"drawcraft","version":2,"profiles":{"Gray":{"mime":"application/vnd.iccprofile","data":"JVBERi0xLjcK"#));
let back = File::<Doc>::read(text.as_bytes()).unwrap();
assert!(back.is_legacy());
assert_eq!(back.profiles["Gray"].bytes(&[]).unwrap(), pdf);
}
#[test]
fn a_written_file_reads_back_with_its_entries() {
let pdf = pdf();
let (file, tail) = full_file(&pdf);
for bytes in [written(&file, &tail, false), written(&file, &tail, true)] {
let (json, after) = split_tail(&bytes);
assert_eq!(json_part(&bytes), json);
assert_eq!(after, pdf.as_slice());
let back = File::<Doc>::read(json).unwrap();
assert_eq!(back, file);
back.check().unwrap();
assert!(!back.is_legacy());
assert_eq!(back.pdf.as_ref().unwrap().bytes(after).unwrap(), pdf);
assert_eq!(back.pdf.as_ref().unwrap().len(), pdf.len() as u64);
assert_eq!(back.preview.as_ref().unwrap().bytes(after).unwrap(), PNG);
assert_eq!(back.images["k"].bytes(after).unwrap(), [1, 2, 3, 250]);
assert_eq!(back.images["k"].len(), 4);
let head: Head = serde_json::from_slice(json).unwrap();
assert_eq!(head.preview, file.preview);
assert_eq!(head.pdf, file.pdf);
let skipped = File::<IgnoredAny>::read(json).unwrap();
assert_eq!(skipped.generator.as_deref(), Some("VectorCraft 0.17.0"));
}
}
#[test]
fn a_linked_image_preview_is_marked_proxy() {
let mut tail = Tail::new(VERSION);
let image = tail.image("image/png", PNG, true);
assert_eq!(serde_json::to_string(&image).unwrap(), r#"{"mime":"image/png","data":"iVBORw0KGgo=","proxy":true}"#);
let back: Image = serde_json::from_str(r#"{"mime":"image/png","data":"iVBORw0KGgo=","proxy":true}"#).unwrap();
assert_eq!(back, image);
}
#[test]
fn entries_outside_the_data_or_with_bad_base64_give_none() {
let tail = b"abcd";
assert_eq!(entry(tail, [1, 3]), Some(&b"bcd"[..]));
assert_eq!(entry(tail, [1, 4]), None);
assert_eq!(entry(tail, [u64::MAX, 1]), None);
assert_eq!(entry(tail, [1, u64::MAX]), None);
assert_eq!(blob([2, 8]).bytes(tail), None);
let mut bad = Image::default();
bad.data = "QU*D".into();
assert_eq!(bad.bytes(tail), None);
assert!(Image::default().is_empty());
}
#[test]
fn image_bytes_refuses_an_entry_past_the_limit_before_copying_it() {
assert_eq!(MAX_ENTRY, 1 << 30);
let tail = b"abcd";
let inline = Image::inline("image/png", tail);
for image in [blob([0, 4]), inline.clone()] {
assert_eq!(image.bytes_at_most(tail, 4).as_deref(), Some(&tail[..]));
assert_eq!(image.bytes_at_most(tail, 3), None);
assert_eq!(image.bytes(tail).as_deref(), Some(&tail[..]));
}
// The stated length is checked, so a range past the limit is refused even where the data
// holds it.
assert_eq!(blob([0, MAX_ENTRY + 1]).bytes_at_most(&[0; 64], MAX_ENTRY), None);
assert_eq!(blob([0, 2]).bytes_at_most(tail, 2).as_deref(), Some(&b"ab"[..]));
}
#[test]
fn entries_copy_at_most_the_data_after_the_json_in_all() {
let tail = vec![7u8; 1 << 20];
let len = tail.len() as u64;
let whole = blob([0, len]);
// Many entries naming the same range share one copy, which counts once.
let mut entries = Entries::new(&tail);
let first = entries.bytes(&whole).ok().flatten();
assert_eq!(first.as_deref().map(Vec::as_slice), Some(&tail[..]));
assert!(entries.blob([0, len]).ok().flatten().zip(first.as_ref()).is_some_and(|(a, b)| std::sync::Arc::ptr_eq(&a, b)));
for _ in 0..3 {
let again = entries.bytes(&whole).ok().flatten();
assert!(again.as_ref().zip(first.as_ref()).is_some_and(|(a, b)| std::sync::Arc::ptr_eq(a, b)));
}
assert_eq!(entries.copied(), len);
// Overlapping ranges that differ copy the shared bytes once each, and pass the data's size.
let from = |at: u64| blob([at, len - at]);
assert!(matches!(entries.bytes(&from(1)), Err(Error::TooBig)));
// A refused entry is not counted, so the entries after it still read.
assert_eq!(entries.copied(), len);
let mut entries = Entries::new(&tail);
let part = |at: u64, n: u64| blob([at, n]);
assert!(entries.bytes(&part(0, len / 2)).is_ok_and(|b| b.is_some()));
assert!(matches!(entries.bytes(&part(1, len - 1)), Err(Error::TooBig)));
assert_eq!(entries.copied(), len / 2);
assert!(entries.bytes(&part(len / 2, len / 2)).is_ok_and(|b| b.is_some()));
assert_eq!(entries.copied(), len);
// Entries that name each byte once read whole, with inline and missing entries beside them.
let mut entries = Entries::new(&tail);
let half = |at: u64| blob([at, len / 2]);
assert_eq!(entries.bytes(&half(0)).unwrap().map(|b| b.len()), Some(tail.len() / 2));
assert_eq!(entries.bytes(&Image::inline("image/png", PNG)).unwrap().as_deref().map(Vec::as_slice), Some(PNG));
assert_eq!(entries.bytes(&half(len)), Ok(None));
assert_eq!(entries.bytes(&half(len / 2)).unwrap().map(|b| b.len()), Some(tail.len() / 2));
assert_eq!(entries.copied(), len);
assert_eq!(Entries::new(&[]).bytes(&whole), Ok(None));
}
#[test]
fn optional_members_of_the_wrong_shape_read_as_none() {
let json = br#"{"format":"vectorcraft","version":4,"generator":7,"preview":"x","pdf":{"blob":"y"},"document":{"layers":[]}}"#;
let file = File::<Doc>::read(json).unwrap();
assert_eq!((file.generator, file.preview, file.pdf), (None, None, None));
let skipped = File::<IgnoredAny>::read(json).unwrap();
assert!(skipped.preview.is_none());
let head: Head = serde_json::from_slice(json).unwrap();
assert_eq!(head, Head::default());
let good = br#"{"preview":{"mime":"image/png","data":"iVBORw0KGgo="},"pdf":null}"#;
let head: Head = serde_json::from_slice(good).unwrap();
assert_eq!(head.preview, Some(Image::inline("image/png", PNG)));
assert!(head.pdf.is_none());
}
#[test]
fn contents_read_the_document_images_and_profiles_without_the_preview_and_pdf() {
let big = vec![b'%'; 64 << 10];
let mut file = File::new(doc());
file.version = 2;
file.generator = Some("VectorCraft 0.17.0".into());
file.preview = Some(Image::inline("image/png", &big));
file.pdf = Some(Image::inline("application/pdf", &big));
file.profiles.insert("Gray".into(), Image::inline(craft_vectorcraft_format::ICC_MIME, &[4, 5]));
file.images.insert("k".into(), Image::inline("image/png", PNG));
for json in [serde_json::to_vec(&file).unwrap(), serde_json::to_vec_pretty(&file).unwrap()] {
let contents = Contents::<Doc>::read(&json).unwrap();
let Contents { format, version, profiles, document, images, .. } = contents.clone();
assert_eq!((format, version, profiles, document, images), (file.format.clone(), 2, file.profiles.clone(), doc(), file.images.clone()));
assert!(contents.is_legacy() == file.is_legacy());
}
// Members of the wrong shape are skipped as `File` reads them as `None`; a missing document
// is refused as in `File`.
let odd = br#"{"format":"vectorcraft","version":4,"generator":7,"preview":"x","pdf":{"blob":"y"},"document":{"layers":[]},"z":[1]}"#;
let contents = Contents::<Doc>::read(odd).unwrap();
assert!(contents.document.layers.is_empty() && contents.images.is_empty());
let no_document = br#"{"format":"vectorcraft","version":4}"#;
assert!(File::<Doc>::read(no_document).is_err());
assert!(Contents::<Doc>::read(no_document).is_err());
}
#[test]
fn contents_read_pdf_preference_while_skipping_the_payload() {
for (members, expected) in [
("", false),
(r#", "pdf":null"#, false),
(r#", "pdf":{"data":"not base64"}"#, true),
(r#", "pdf":[1,2,3]"#, true),
(r#", "pdfCompatible":true"#, true),
(r#", "pdf":{}, "pdfCompatible":false"#, false),
(r#", "pdfCompatible":false, "pdf":{}"#, false),
(r#", "pdfCompatible":true, "pdfCompatible":null, "pdf":{}"#, true),
(r#", "pdf":{}, "pdf":null"#, false),
(r#", "pdfCompatible":false, "pdfCompatible":true"#, true),
(r#", "unknown":{"pdf":{}}"#, false),
] {
let json = format!(r#"{{"format":"vectorcraft","version":4,"document":{{"layers":[]}}{members}}}"#);
let (contents, compatible) = Contents::<Doc>::read_with_pdf_preference(json.as_bytes()).unwrap();
assert_eq!(compatible, expected, "{members}");
assert_eq!(contents, Contents::<Doc>::read(json.as_bytes()).unwrap());
}
let array = br#"["drawcraft",1,{"layers":[]}]"#;
assert!(!Contents::<Doc>::read_with_pdf_preference(array).unwrap().1);
let mut file = File::new(doc());
file.pdf = Some(Image::inline("application/pdf", &vec![7; 128 << 10]));
assert!(Contents::<Doc>::read_with_pdf_preference(&serde_json::to_vec(&file).unwrap()).unwrap().1);
}
#[test]
fn pdf_preference_read_is_opt_in_and_preserves_envelope_validation() {
let invalid = br#"{"format":"vectorcraft","version":4,"document":{"layers":[]},"pdfCompatible":"invalid"}"#;
assert!(Contents::<Doc>::read(invalid).is_ok());
assert!(File::<Doc>::read(invalid).is_ok());
assert!(Contents::<Doc>::read_with_pdf_preference(invalid).is_err());
for json in [
br#"{"format":"other","version":4,"document":{"layers":[]}}"#.as_slice(),
br#"{"format":"vectorcraft","version":999,"document":{"layers":[]}}"#.as_slice(),
br#"{"format":"vectorcraft","version":4}"#.as_slice(),
br#"{"format":"vectorcraft","version":4,"version":4,"document":{"layers":[]}}"#.as_slice(),
] {
assert_eq!(Contents::<Doc>::read(json).unwrap_err().to_string(), Contents::<Doc>::read_with_pdf_preference(json).unwrap_err().to_string());
}
}
#[test]
fn reading_refuses_another_format_and_a_newer_version() {
let newer = br#"{"format":"vectorcraft","version":5,"document":0}"#;
let other = br#"{"format":"other","version":1,"document":0}"#;
for (json, error) in [(&newer[..], Error::TooNew(5)), (other, Error::Format("other".into()))] {
let file = File::<IgnoredAny>::read(json);
assert!(matches!(&file, Err(ReadError::Envelope(e)) if *e == error), "{file:?}");
let contents = Contents::<IgnoredAny>::read(json);
assert!(matches!(&contents, Err(ReadError::Envelope(e)) if *e == error), "{contents:?}");
assert_eq!(contents.err().map(|e| e.to_string()), Some(error.to_string()));
}
for version in [0, 1, VERSION] {
let json = format!(r#"{{"format":"drawcraft","version":{version},"document":0}}"#);
assert!(File::<IgnoredAny>::read(json.as_bytes()).is_ok() && Contents::<IgnoredAny>::read(json.as_bytes()).is_ok());
}
// A document that does not read is a JSON error, as before the version is looked at.
let bad = br#"{"format":"vectorcraft","version":5,"document":7}"#;
assert!(matches!(Contents::<Doc>::read(bad), Err(ReadError::Json(_))));
assert!(Contents::<Doc>::read(b"\"x\"").is_err_and(|e| e.to_string().contains("expected struct File")));
}
#[test]
fn file_and_contents_read_a_repeated_generator_preview_or_pdf_and_refuse_other_repeated_members() {
// VectorCraft opens a file whose generator, preview or PDF is repeated, and refuses one whose
// format, version, document, images or profiles are. `File` keeps the last value, as
// serde_json reads a repeated key into a `Value`.
let png = r#"{"mime":"image/png","data":"iVBORw0KGgo="}"#;
let pdf = r#"{"mime":"application/pdf","data":"JQ=="}"#;
let file = |extra: &str| format!(r#"{{"format":"vectorcraft","version":4,{extra}"document":{{"layers":[]}},"images":{{}}}}"#);
let value = |json: &str, key: &str| serde_json::from_str::<serde_json::Value>(json).unwrap()[key].clone();
for extra in [
r#""generator":"a","generator":"b","#.to_string(),
format!(r#""preview":{png},"preview":{png},"#),
format!(r#""pdf":null,"pdf":{pdf},"#),
format!(r#""pdf":{pdf},"pdf":"x","#),
format!(r#""generator":"a","preview":{png},"generator":7,"preview":"x","pdf":1,"pdf":{pdf},"#),
r#""generator":7,"preview":"x","pdf":1,"generator":7,"preview":"x","pdf":1,"#.to_string(),
] {
let json = file(&extra);
let contents = Contents::<Doc>::read(json.as_bytes()).unwrap_or_else(|e| panic!("{extra}: {e}"));
assert!(contents.document.layers.is_empty(), "{extra}");
let read = File::<Doc>::read(json.as_bytes()).unwrap_or_else(|e| panic!("{extra}: {e}"));
let last = |key: &str| value(&json, key);
assert_eq!(read.generator, last("generator").as_str().map(String::from), "{extra}");
assert_eq!(read.preview, serde_json::from_value(last("preview")).ok(), "{extra}");
assert_eq!(read.pdf, serde_json::from_value(last("pdf")).ok(), "{extra}");
}
let read = File::<Doc>::read(file(r#""generator":"a","generator":"b","#).as_bytes()).unwrap();
assert_eq!(read.generator.as_deref(), Some("b"));
for extra in
[r#""format":"vectorcraft","#, r#""version":4,"#, r#""document":{"layers":[]},"#, r#""images":{},"#, r#""profiles":{},"profiles":{},"#]
{
let json = file(extra);
assert!(File::<Doc>::read(json.as_bytes()).is_err_and(|e| e.to_string().starts_with("duplicate field")), "{extra}");
assert!(Contents::<Doc>::read(json.as_bytes()).is_err_and(|e| e.to_string().starts_with("duplicate field")), "{extra}");
}
}
#[test]
fn an_array_holds_format_version_document_images_and_profiles_in_that_order() {
// VectorCraft reads a top-level array by position, in this order.
let png = r#"{"mime":"image/png","data":"iVBORw0KGgo="}"#;
let images = format!(r#"{{"k":{png}}}"#);
let profiles = format!(r#"{{"Gray":{png}}}"#);
let full = format!(r#"["vectorcraft",3,{{"layers":[]}},{images},{profiles}]"#);
for json in [full.clone(), format!(r#"["vectorcraft",3,{{"layers":[]}},{images}]"#), r#"["vectorcraft",3,{"layers":[]}]"#.into()] {
let contents = Contents::<Doc>::read(json.as_bytes()).unwrap_or_else(|e| panic!("{json}: {e}"));
let file = File::<Doc>::read(json.as_bytes()).unwrap_or_else(|e| panic!("{json}: {e}"));
assert_eq!(
(&file.format, file.version, &file.document, &file.images, &file.profiles),
(&contents.format, 3, &contents.document, &contents.images, &contents.profiles)
);
assert!(file.generator.is_none() && file.preview.is_none() && file.pdf.is_none());
}
let contents = Contents::<Doc>::read(full.as_bytes()).unwrap();
assert_eq!((contents.images.len(), contents.profiles.len()), (1, 1));
assert!(contents.images.contains_key("k") && contents.profiles.contains_key("Gray"));
for json in [r#"["vectorcraft",3,{},{"layers":[]},{}]"#, r#"["vectorcraft",3]"#, r#"["vectorcraft",5,{"layers":[]}]"#] {
assert!(Contents::<Doc>::read(json.as_bytes()).is_err(), "{json}");
assert!(File::<Doc>::read(json.as_bytes()).is_err(), "{json}");
}
}
#[test]
fn a_files_tail_follows_its_version() {
let mut file = File::new(doc());
let pdf = pdf();
assert_eq!(file.tail().image("application/pdf", &pdf, false).blob, Some([0, pdf.len() as u64]));
file.version = 2;
assert!(file.tail().image("application/pdf", &pdf, false).blob.is_none());
}
#[test]
fn the_json_is_split_only_at_a_marker_right_after_it() {
let with = |json: &[u8], rest: &[u8]| {
let mut f = json.to_vec();
f.extend(BLOB_MAGIC);
f.extend(rest);
f
};
for json in [&b"{}"[..], b"[1]", b"\"s\"", b"1", b"{\"a\": [true, null]}"] {
let f = with(json, b"xyz");
assert_eq!(split_tail(&f), (json, &b"xyz"[..]), "{json:?}");
}
let empty: &[u8] = &[];
let far = with(b"{} x", b"xyz");
assert_eq!(split_tail(&far), (far.as_slice(), empty));
let no_marker = b"{}\0rest".to_vec();
assert_eq!(split_tail(&no_marker), (no_marker.as_slice(), empty));
assert_eq!(split_tail(b"{}"), (&b"{}"[..], empty));
let bad = with(b"{", b"x");
assert_eq!(split_tail(&bad), (bad.as_slice(), empty));
}
#[test]
fn the_marker_is_found_where_the_writer_puts_it_in_the_first_bytes() {
let mut file = br#"{"a":[1]}"#.to_vec();
file.extend(BLOB_MAGIC);
file.extend(b"\0rest");
// The first bytes up to the end of the marker are enough.
assert_eq!(marker_at(&file), Some(9));
assert_eq!(marker_at(&file[..9 + BLOB_MAGIC.len()]), Some(9));
assert_eq!(marker_at(&file[..9 + BLOB_MAGIC.len() - 1]), None);
assert_eq!(split_tail(&file), (&file[..9], &b"\0rest"[..]));
for json in [&b"\"s\""[..], b"[]"] {
let mut f = json.to_vec();
f.extend(BLOB_MAGIC);
assert_eq!(marker_at(&f), Some(json.len()), "{json:?}");
}
// After a number, after a space, without its newline or with a NUL before it, the marker is
// not where the writer puts it.
for f in [&b"1\n\0VCBLOBS\0"[..], b"{} \n\0VCBLOBS\0", b"{}\0VCBLOBS\0", b"{}\0\n\0VCBLOBS\0", b"\n\0VCBLOBS\0", b"{}"] {
assert_eq!(marker_at(f), None, "{:?}", String::from_utf8_lossy(f));
}
}
#[test]
fn check_refuses_other_formats_and_newer_versions() {
assert_eq!(check(EXTENSION, VERSION), Ok(()));
assert_eq!(check(LEGACY_EXTENSION, 1), Ok(()));
assert_eq!(check("other", 1), Err(Error::Format("other".into())));
assert_eq!(check(EXTENSION, VERSION + 1), Err(Error::TooNew(VERSION + 1)));
assert!(File::<Doc>::read(br#"{"format":"vectorcraft","version":4}"#).is_err());
let minimal = File::<Doc>::read(br#"{"format":"vectorcraft","version":4,"document":{"layers":[]}}"#).unwrap();
assert!(minimal.images.is_empty() && minimal.generator.is_none());
}
#[test]
fn sniff_needs_a_vectorcraft_format_member() {
let pdf = pdf();
let (file, tail) = full_file(&pdf);
let plain = written(&file, &tail, false);
let pretty = written(&file, &tail, true);
assert!(sniff(&plain) && sniff(&pretty));
assert!(sniff(b" \n{\"format\" : \"drawcraft\"}"));
// Keys and values are compared as JSON reads them, escapes decoded.
let esc = |s: &str| s.replace('|', "\\");
let escaped = esc(r#"{"|u0066ormat":"vector|u0063raft","version":4,"document":{"layers":[]}}"#);
assert!(sniff(escaped.as_bytes()));
assert_eq!(File::<Doc>::read(escaped.as_bytes()).unwrap().format, EXTENSION);
assert!(sniff(esc(r#"{"format":"draw|u0063raft"}"#).as_bytes()));
for no in [r#"{"form|u0061t":"other","format":"vectorcraft"}"#, r#"{"format":"vectorcraft|u0021"}"#, r#"{"format":"vectorcraft|"}"#] {
assert!(!sniff(esc(no).as_bytes()), "{no}");
}
assert!(sniff(br#"{"generator":"format","x":{"format":"other","a":[1,"]"]},"n":-1.5e3,"t":true,"s":"\"format\":","format":"vectorcraft"}"#));
assert!(is_compressed(&gzip(&plain)) && !is_compressed(&plain));
assert!(sniff(&gzip(&plain)));
let gz = gzip(&plain);
assert!(sniff(&gz[..gz.len() / 2]));
for no in [
&br#"{"name":"vectorcraft"}"#[..],
br#"{"format":"other","vectorcraft":1}"#,
br#"["format","vectorcraft"]"#,
br#"{"metadata":{"format":"vectorcraft"},"format":"other"}"#,
br#"{"name":"\"format\":\"vectorcraft\""}"#,
br#"{"format":["vectorcraft"]}"#,
br#"{"format":"vectorcraft"#,
b"%PDF-1.7",
b"",
b"\x1f\x8b",
PNG,
] {
assert!(!sniff(no), "{:?}", String::from_utf8_lossy(no));
}
}
#[test]
fn base64_is_the_encoding_of_data_members() {
assert_eq!(base64::encode(PNG), "iVBORw0KGgo=");
assert_eq!(base64::decode("AQID+g==").unwrap(), [1, 2, 3, 250]);
}