|
| 1 | +use bytes::Bytes; |
| 2 | +use moon_blob::Blob; |
| 3 | +use moon_hash::ContentHash; |
| 4 | +use serde::Serialize; |
| 5 | +use starbase_sandbox::create_empty_sandbox; |
| 6 | +use starbase_utils::json::serde_json; |
| 7 | + |
| 8 | +// Sanity-pin: SHA-256 of "abc" — used to assert that the digest path matches |
| 9 | +// the known-good algorithm rather than just "some" hash. |
| 10 | +const ABC_SHA256: &str = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"; |
| 11 | + |
| 12 | +#[derive(Serialize)] |
| 13 | +struct Sample { |
| 14 | + name: &'static str, |
| 15 | + count: u32, |
| 16 | +} |
| 17 | + |
| 18 | +mod blob { |
| 19 | + use super::*; |
| 20 | + |
| 21 | + #[test] |
| 22 | + fn from_bytes_retains_bytes_and_digest() { |
| 23 | + let blob = Blob::from_bytes(b"abc".to_vec()).unwrap(); |
| 24 | + |
| 25 | + assert_eq!(blob.bytes, Bytes::from("abc")); |
| 26 | + assert_eq!(blob.digest.hash.as_hex(), ABC_SHA256); |
| 27 | + assert_eq!(blob.digest.size, 3); |
| 28 | + } |
| 29 | + |
| 30 | + #[test] |
| 31 | + fn from_data_round_trips_through_json() { |
| 32 | + let sample = Sample { |
| 33 | + name: "y", |
| 34 | + count: 7, |
| 35 | + }; |
| 36 | + let blob = Blob::from_data(&sample).unwrap(); |
| 37 | + |
| 38 | + // The blob's bytes should be the canonical serde_json output. We then |
| 39 | + // confirm that re-hashing those bytes reproduces the blob's digest. |
| 40 | + let canonical = serde_json::to_vec(&sample).unwrap(); |
| 41 | + assert_eq!(blob.bytes, canonical); |
| 42 | + assert_eq!( |
| 43 | + blob.digest.hash, |
| 44 | + ContentHash::hash_bytes(&canonical).unwrap() |
| 45 | + ); |
| 46 | + } |
| 47 | + |
| 48 | + #[test] |
| 49 | + fn from_file_round_trips() { |
| 50 | + let sandbox = create_empty_sandbox(); |
| 51 | + sandbox.create_file("payload.bin", "hello bytes"); |
| 52 | + |
| 53 | + let blob = Blob::from_file(sandbox.path().join("payload.bin")).unwrap(); |
| 54 | + |
| 55 | + assert_eq!(blob.bytes, Bytes::from("hello bytes")); |
| 56 | + assert_eq!(blob.digest.size, "hello bytes".len() as i64); |
| 57 | + assert_eq!( |
| 58 | + blob.digest.hash, |
| 59 | + ContentHash::hash_bytes(b"hello bytes").unwrap() |
| 60 | + ); |
| 61 | + } |
| 62 | + |
| 63 | + #[test] |
| 64 | + fn debug_does_not_dump_bytes() { |
| 65 | + // Bytes may be large (or sensitive). The Debug impl deliberately omits |
| 66 | + // them — this regression guard catches an accidental `derive(Debug)` |
| 67 | + // that would expose the full payload. |
| 68 | + let blob = Blob::from_bytes(vec![0xAB, 0xCD, 0xEF]).unwrap(); |
| 69 | + let dbg = format!("{:?}", blob); |
| 70 | + assert!(dbg.contains("digest")); |
| 71 | + assert!(!dbg.contains("bytes")); |
| 72 | + } |
| 73 | +} |
0 commit comments