wsi-dicom-annotations 0.2.1

DICOM WSI ANN, SEG, SR, and Parametric Map interoperability
Documentation
use std::fs;

use super::*;

#[test]
fn single_publication_never_replaces_a_destination_created_after_staging() {
    let directory = tempfile::tempdir().unwrap();
    let destination = directory.path().join("output.dcm");
    let publication = DicomSinglePublication::new(&destination, "staged.dcm", &[]).unwrap();
    fs::write(publication.staged_file(), b"candidate").unwrap();
    fs::write(&destination, b"winner").unwrap();

    let error = publication.publish().unwrap_err();

    assert_eq!(error.code(), "OUTPUT_PUBLICATION_FAILED");
    assert_eq!(fs::read(&destination).unwrap(), b"winner");
}

#[test]
fn bundle_publication_rechecks_destination_before_rename() {
    let directory = tempfile::tempdir().unwrap();
    let destination = directory.path().join("bundle");
    let publication = DicomBundlePublication::new(&destination, &[]).unwrap();
    fs::write(publication.staging_path().join("pm-0001.dcm"), b"candidate").unwrap();
    fs::create_dir(&destination).unwrap();

    let error = publication.publish().unwrap_err();

    assert_eq!(error.code(), "OUTPUT_EXISTS");
    assert!(destination.is_dir());
    assert!(fs::read_dir(destination).unwrap().next().is_none());
}

#[test]
fn bundle_publication_publishes_a_synced_staging_directory() {
    let directory = tempfile::tempdir().unwrap();
    let destination = directory.path().join("bundle");
    let publication = DicomBundlePublication::new(&destination, &[]).unwrap();
    let manifest = publication.staging_path().join("manifest.json");
    fs::write(&manifest, b"{}").unwrap();
    publication.sync_staged_file(&manifest).unwrap();

    let published = publication.publish().unwrap();

    assert_eq!(
        published,
        directory.path().canonicalize().unwrap().join("bundle")
    );
    assert_eq!(fs::read(published.join("manifest.json")).unwrap(), b"{}");
}

#[cfg(unix)]
#[test]
fn publication_rejects_symlinked_parent_escape_and_existing_aliases() {
    use std::os::unix::fs::symlink;

    let directory = tempfile::tempdir().unwrap();
    let protected = directory.path().join("input.zarr");
    let apparent_parent = directory.path().join("apparent");
    fs::create_dir(&protected).unwrap();
    symlink(&protected, &apparent_parent).unwrap();
    let error = match DicomSinglePublication::new(
        &apparent_parent.join("output.dcm"),
        "staged.dcm",
        &[&protected],
    ) {
        Ok(_) => panic!("output inside a protected directory should be rejected"),
        Err(error) => error,
    };
    assert_eq!(error.code(), "UNSAFE_OUTPUT_PATH");

    let source = directory.path().join("source.dcm");
    let hardlink = directory.path().join("hardlink.dcm");
    let symlink_path = directory.path().join("symlink.dcm");
    fs::write(&source, b"source").unwrap();
    fs::hard_link(&source, &hardlink).unwrap();
    symlink(&source, &symlink_path).unwrap();
    for destination in [&hardlink, &symlink_path] {
        let error = match DicomSinglePublication::new(destination, "staged.dcm", &[&source]) {
            Ok(_) => panic!("an existing alias should be rejected"),
            Err(error) => error,
        };
        assert_eq!(error.code(), "OUTPUT_EXISTS");
    }
}