1#[cfg(feature = "meta-code")]
10use crate::gen_meta_code_v0;
11#[cfg(feature = "text-processing")]
12use crate::gen_text_code_v0;
13use crate::{
14 gen_audio_code_v0, gen_data_code_v0, gen_image_code_v0, gen_instance_code_v0, gen_iscc_code_v0,
15 gen_mixed_code_v0, gen_video_code_v0,
16};
17
18const TEST_DATA: &str = include_str!("../tests/data.json");
20
21pub fn conformance_selftest() -> bool {
30 let data: serde_json::Value = match serde_json::from_str(TEST_DATA) {
31 Ok(v) => v,
32 Err(e) => {
33 eprintln!("FAILED: could not parse conformance data: {e}");
34 return false;
35 }
36 };
37
38 let mut passed = true;
39
40 #[cfg(feature = "meta-code")]
41 {
42 passed &= run_meta_tests(&data);
43 }
44 #[cfg(feature = "text-processing")]
45 {
46 passed &= run_text_tests(&data);
47 }
48 passed &= run_image_tests(&data);
49 passed &= run_audio_tests(&data);
50 passed &= run_video_tests(&data);
51 passed &= run_mixed_tests(&data);
52 passed &= run_data_tests(&data);
53 passed &= run_instance_tests(&data);
54 passed &= run_iscc_tests(&data);
55
56 passed
57}
58
59#[cfg(feature = "meta-code")]
61fn run_meta_tests(data: &serde_json::Value) -> bool {
62 let mut passed = true;
63 let section = &data["gen_meta_code_v0"];
64 let cases = match section.as_object() {
65 Some(c) => c,
66 None => {
67 eprintln!("FAILED: gen_meta_code_v0 section missing from conformance data");
68 return false;
69 }
70 };
71
72 for (tc_name, tc) in cases {
73 let func_name = "gen_meta_code_v0";
74 let result = (|| {
75 let inputs = tc["inputs"].as_array()?;
76 let name = inputs[0].as_str()?;
77 let desc_str = inputs[1].as_str()?;
78 let meta_val = &inputs[2];
79 let bits = inputs[3].as_u64()? as u32;
80
81 let meta_arg: Option<String> = match meta_val {
82 serde_json::Value::Null => None,
83 serde_json::Value::String(s) => Some(s.clone()),
84 serde_json::Value::Object(_) => serde_json::to_string(meta_val).ok(),
85 _ => None,
86 };
87
88 let desc = if desc_str.is_empty() {
89 None
90 } else {
91 Some(desc_str)
92 };
93
94 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
95 match gen_meta_code_v0(name, desc, meta_arg.as_deref(), bits) {
96 Ok(result) if result.iscc == expected_iscc => Some(true),
97 Ok(result) => {
98 eprintln!(
99 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
100 result.iscc
101 );
102 Some(false)
103 }
104 Err(e) => {
105 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
106 Some(false)
107 }
108 }
109 })();
110
111 match result {
112 Some(true) => {}
113 Some(false) => passed = false,
114 None => {
115 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
116 passed = false;
117 }
118 }
119 }
120 passed
121}
122
123#[cfg(feature = "text-processing")]
125fn run_text_tests(data: &serde_json::Value) -> bool {
126 let mut passed = true;
127 let section = &data["gen_text_code_v0"];
128 let cases = match section.as_object() {
129 Some(c) => c,
130 None => {
131 eprintln!("FAILED: gen_text_code_v0 section missing from conformance data");
132 return false;
133 }
134 };
135
136 for (tc_name, tc) in cases {
137 let func_name = "gen_text_code_v0";
138 let result = (|| {
139 let inputs = tc["inputs"].as_array()?;
140 let text = inputs[0].as_str()?;
141 let bits = inputs[1].as_u64()? as u32;
142 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
143
144 match gen_text_code_v0(text, bits) {
145 Ok(result) if result.iscc == expected_iscc => Some(true),
146 Ok(result) => {
147 eprintln!(
148 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
149 result.iscc
150 );
151 Some(false)
152 }
153 Err(e) => {
154 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
155 Some(false)
156 }
157 }
158 })();
159
160 match result {
161 Some(true) => {}
162 Some(false) => passed = false,
163 None => {
164 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
165 passed = false;
166 }
167 }
168 }
169 passed
170}
171
172fn run_image_tests(data: &serde_json::Value) -> bool {
174 let mut passed = true;
175 let section = &data["gen_image_code_v0"];
176 let cases = match section.as_object() {
177 Some(c) => c,
178 None => {
179 eprintln!("FAILED: gen_image_code_v0 section missing from conformance data");
180 return false;
181 }
182 };
183
184 for (tc_name, tc) in cases {
185 let func_name = "gen_image_code_v0";
186 let result = (|| {
187 let inputs = tc["inputs"].as_array()?;
188 let pixels_json = inputs[0].as_array()?;
189 let bits = inputs[1].as_u64()? as u32;
190 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
191
192 let pixels: Vec<u8> = pixels_json
193 .iter()
194 .map(|v| v.as_u64().map(|n| n as u8))
195 .collect::<Option<Vec<u8>>>()?;
196
197 match gen_image_code_v0(&pixels, bits) {
198 Ok(result) if result.iscc == expected_iscc => Some(true),
199 Ok(result) => {
200 eprintln!(
201 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
202 result.iscc
203 );
204 Some(false)
205 }
206 Err(e) => {
207 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
208 Some(false)
209 }
210 }
211 })();
212
213 match result {
214 Some(true) => {}
215 Some(false) => passed = false,
216 None => {
217 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
218 passed = false;
219 }
220 }
221 }
222 passed
223}
224
225fn run_audio_tests(data: &serde_json::Value) -> bool {
227 let mut passed = true;
228 let section = &data["gen_audio_code_v0"];
229 let cases = match section.as_object() {
230 Some(c) => c,
231 None => {
232 eprintln!("FAILED: gen_audio_code_v0 section missing from conformance data");
233 return false;
234 }
235 };
236
237 for (tc_name, tc) in cases {
238 let func_name = "gen_audio_code_v0";
239 let result = (|| {
240 let inputs = tc["inputs"].as_array()?;
241 let cv_json = inputs[0].as_array()?;
242 let bits = inputs[1].as_u64()? as u32;
243 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
244
245 let cv: Vec<i32> = cv_json
246 .iter()
247 .map(|v| v.as_i64().map(|n| n as i32))
248 .collect::<Option<Vec<i32>>>()?;
249
250 match gen_audio_code_v0(&cv, bits) {
251 Ok(result) if result.iscc == expected_iscc => Some(true),
252 Ok(result) => {
253 eprintln!(
254 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
255 result.iscc
256 );
257 Some(false)
258 }
259 Err(e) => {
260 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
261 Some(false)
262 }
263 }
264 })();
265
266 match result {
267 Some(true) => {}
268 Some(false) => passed = false,
269 None => {
270 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
271 passed = false;
272 }
273 }
274 }
275 passed
276}
277
278fn run_video_tests(data: &serde_json::Value) -> bool {
280 let mut passed = true;
281 let section = &data["gen_video_code_v0"];
282 let cases = match section.as_object() {
283 Some(c) => c,
284 None => {
285 eprintln!("FAILED: gen_video_code_v0 section missing from conformance data");
286 return false;
287 }
288 };
289
290 for (tc_name, tc) in cases {
291 let func_name = "gen_video_code_v0";
292 let result = (|| {
293 let inputs = tc["inputs"].as_array()?;
294 let frames_json = inputs[0].as_array()?;
295 let bits = inputs[1].as_u64()? as u32;
296 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
297
298 let frame_sigs: Option<Vec<Vec<i32>>> = frames_json
299 .iter()
300 .map(|frame| {
301 frame
302 .as_array()?
303 .iter()
304 .map(|v| v.as_i64().map(|n| n as i32))
305 .collect::<Option<Vec<i32>>>()
306 })
307 .collect();
308 let frame_sigs = frame_sigs?;
309
310 match gen_video_code_v0(&frame_sigs, bits) {
311 Ok(result) if result.iscc == expected_iscc => Some(true),
312 Ok(result) => {
313 eprintln!(
314 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
315 result.iscc
316 );
317 Some(false)
318 }
319 Err(e) => {
320 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
321 Some(false)
322 }
323 }
324 })();
325
326 match result {
327 Some(true) => {}
328 Some(false) => passed = false,
329 None => {
330 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
331 passed = false;
332 }
333 }
334 }
335 passed
336}
337
338fn run_mixed_tests(data: &serde_json::Value) -> bool {
340 let mut passed = true;
341 let section = &data["gen_mixed_code_v0"];
342 let cases = match section.as_object() {
343 Some(c) => c,
344 None => {
345 eprintln!("FAILED: gen_mixed_code_v0 section missing from conformance data");
346 return false;
347 }
348 };
349
350 for (tc_name, tc) in cases {
351 let func_name = "gen_mixed_code_v0";
352 let result = (|| {
353 let inputs = tc["inputs"].as_array()?;
354 let codes_json = inputs[0].as_array()?;
355 let bits = inputs[1].as_u64()? as u32;
356 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
357
358 let codes_owned: Vec<String> = codes_json
359 .iter()
360 .filter_map(|v| v.as_str().map(String::from))
361 .collect();
362 let codes: Vec<&str> = codes_owned.iter().map(|s| s.as_str()).collect();
363
364 match gen_mixed_code_v0(&codes, bits) {
365 Ok(result) if result.iscc == expected_iscc => Some(true),
366 Ok(result) => {
367 eprintln!(
368 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
369 result.iscc
370 );
371 Some(false)
372 }
373 Err(e) => {
374 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
375 Some(false)
376 }
377 }
378 })();
379
380 match result {
381 Some(true) => {}
382 Some(false) => passed = false,
383 None => {
384 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
385 passed = false;
386 }
387 }
388 }
389 passed
390}
391
392fn decode_stream(s: &str) -> Option<Vec<u8>> {
394 let hex_data = s.strip_prefix("stream:")?;
395 hex::decode(hex_data).ok()
396}
397
398fn run_data_tests(data: &serde_json::Value) -> bool {
400 let mut passed = true;
401 let section = &data["gen_data_code_v0"];
402 let cases = match section.as_object() {
403 Some(c) => c,
404 None => {
405 eprintln!("FAILED: gen_data_code_v0 section missing from conformance data");
406 return false;
407 }
408 };
409
410 for (tc_name, tc) in cases {
411 let func_name = "gen_data_code_v0";
412 let result = (|| {
413 let inputs = tc["inputs"].as_array()?;
414 let stream_str = inputs[0].as_str()?;
415 let bits = inputs[1].as_u64()? as u32;
416 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
417 let input_bytes = decode_stream(stream_str)?;
418
419 match gen_data_code_v0(&input_bytes, bits) {
420 Ok(result) if result.iscc == expected_iscc => Some(true),
421 Ok(result) => {
422 eprintln!(
423 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
424 result.iscc
425 );
426 Some(false)
427 }
428 Err(e) => {
429 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
430 Some(false)
431 }
432 }
433 })();
434
435 match result {
436 Some(true) => {}
437 Some(false) => passed = false,
438 None => {
439 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
440 passed = false;
441 }
442 }
443 }
444 passed
445}
446
447fn run_instance_tests(data: &serde_json::Value) -> bool {
449 let mut passed = true;
450 let section = &data["gen_instance_code_v0"];
451 let cases = match section.as_object() {
452 Some(c) => c,
453 None => {
454 eprintln!("FAILED: gen_instance_code_v0 section missing from conformance data");
455 return false;
456 }
457 };
458
459 for (tc_name, tc) in cases {
460 let func_name = "gen_instance_code_v0";
461 let result = (|| {
462 let inputs = tc["inputs"].as_array()?;
463 let stream_str = inputs[0].as_str()?;
464 let bits = inputs[1].as_u64()? as u32;
465 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
466 let input_bytes = decode_stream(stream_str)?;
467
468 match gen_instance_code_v0(&input_bytes, bits) {
469 Ok(result) if result.iscc == expected_iscc => Some(true),
470 Ok(result) => {
471 eprintln!(
472 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
473 result.iscc
474 );
475 Some(false)
476 }
477 Err(e) => {
478 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
479 Some(false)
480 }
481 }
482 })();
483
484 match result {
485 Some(true) => {}
486 Some(false) => passed = false,
487 None => {
488 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
489 passed = false;
490 }
491 }
492 }
493 passed
494}
495
496fn run_iscc_tests(data: &serde_json::Value) -> bool {
498 let mut passed = true;
499 let section = &data["gen_iscc_code_v0"];
500 let cases = match section.as_object() {
501 Some(c) => c,
502 None => {
503 eprintln!("FAILED: gen_iscc_code_v0 section missing from conformance data");
504 return false;
505 }
506 };
507
508 for (tc_name, tc) in cases {
509 let func_name = "gen_iscc_code_v0";
510 let result = (|| {
511 let inputs = tc["inputs"].as_array()?;
512 let codes_json = inputs[0].as_array()?;
513 let expected_iscc = tc["outputs"]["iscc"].as_str()?;
514
515 let codes_owned: Vec<String> = codes_json
516 .iter()
517 .filter_map(|v| v.as_str().map(String::from))
518 .collect();
519 let codes: Vec<&str> = codes_owned.iter().map(|s| s.as_str()).collect();
520
521 match gen_iscc_code_v0(&codes, false) {
523 Ok(result) if result.iscc == expected_iscc => Some(true),
524 Ok(result) => {
525 eprintln!(
526 "FAILED: {func_name}.{tc_name} — expected {expected_iscc}, got {}",
527 result.iscc
528 );
529 Some(false)
530 }
531 Err(e) => {
532 eprintln!("FAILED: {func_name}.{tc_name} — error: {e}");
533 Some(false)
534 }
535 }
536 })();
537
538 match result {
539 Some(true) => {}
540 Some(false) => passed = false,
541 None => {
542 eprintln!("FAILED: {func_name}.{tc_name} — could not parse test inputs");
543 passed = false;
544 }
545 }
546 }
547 passed
548}
549
550#[cfg(test)]
551mod tests {
552 use super::*;
553
554 #[test]
555 fn test_conformance_selftest_passes() {
556 assert!(conformance_selftest());
557 }
558}