tests_dicom_dicomWriter.test.js

// namespace
var dwv = dwv || {};
dwv.test = dwv.test || {};

/**
 * Tests for the 'dicom/dicomWriter.js' file.
 */
// Do not warn if these variables were not defined before.
/* global QUnit */

/**
 * Tests getUID.
 *
 * @function module:tests/dicom~getUID
 */
QUnit.test('Test getUID', function (assert) {
  // check size
  var uid00 = dwv.dicom.getUID('mytag');
  assert.ok(uid00.length <= 64, 'uid length #0');
  var uid01 = dwv.dicom.getUID('mysuperlongtagthatneverfinishes');
  assert.ok(uid01.length <= 64, 'uid length #1');

  // consecutive for same tag are different
  var uid10 = dwv.dicom.getUID('mytag');
  var uid11 = dwv.dicom.getUID('mytag');
  assert.notEqual(uid10, uid11, 'Consecutive getUID');

  // groups do not start with 0
  var parts = uid10.split('.');
  var count = 0;
  for (var i = 0; i < parts.length; ++i) {
    var part = parts[i];
    if (part[0] === '0' && part.length !== 1) {
      ++count;
    }
  }
  assert.ok(count === 0, 'Zero at start of part');
});

/**
 * Tests for {@link dwv.dicom.DicomWriter} using simple DICOM data.
 * Using remote file for CI integration.
 *
 * @function module:tests/dicom~dicomWriterSimpleDicom
 */
QUnit.test('Test multiframe writer support.', function (assert) {
  var done = assert.async();

  var request = new XMLHttpRequest();
  var url = '/tests/data/multiframe-test1.dcm';
  request.open('GET', url, true);
  request.responseType = 'arraybuffer';
  request.onerror = function (event) {
    console.log(event);
  };
  request.onload = function (/*event*/) {
    assert.ok((this.response.byteLength !== 0), 'Got a response.');

    // parse DICOM
    var dicomParser = new dwv.dicom.DicomParser();
    dicomParser.parse(this.response);

    var numCols = 256;
    var numRows = 256;
    var numFrames = 16;
    var bufferSize = numCols * numRows * numFrames;

    // raw tags
    var rawTags = dicomParser.getRawDicomElements();
    // check values
    assert.equal(rawTags.x00280008.value[0], numFrames, 'Number of frames');
    assert.equal(rawTags.x00280011.value[0], numCols, 'Number of columns');
    assert.equal(rawTags.x00280010.value[0], numRows, 'Number of rows');
    // length of value array for pixel data
    assert.equal(
      rawTags.x7FE00010.value[0].length,
      bufferSize,
      'Length of value array for pixel data');

    var dicomWriter = new dwv.dicom.DicomWriter();
    var buffer = dicomWriter.getBuffer(rawTags);

    dicomParser = new dwv.dicom.DicomParser();
    dicomParser.parse(buffer);

    rawTags = dicomParser.getRawDicomElements();

    // check values
    assert.equal(rawTags.x00280008.value[0], numFrames, 'Number of frames');
    assert.equal(rawTags.x00280011.value[0], numCols, 'Number of columns');
    assert.equal(rawTags.x00280010.value[0], numRows, 'Number of rows');
    // length of value array for pixel data
    assert.equal(
      rawTags.x7FE00010.value[0].length,
      bufferSize,
      'Length of value array for pixel data');

    // finish async test
    done();
  };
  request.send(null);
});

/**
 * Tests for {@link dwv.dicom.DicomWriter} anomnymisation.
 * Using remote file for CI integration.
 *
 * @function module:tests/dicom~dicomWriterAnonymise
 */
QUnit.test('Test patient anonymisation', function (assert) {
  var done = assert.async();

  var request = new XMLHttpRequest();
  var url = '/tests/data/dwv-test-anonymise.dcm';
  request.open('GET', url, true);
  request.responseType = 'arraybuffer';
  request.onerror = function (event) {
    console.log(event);
  };
  request.onload = function (/*event*/) {
    assert.ok((this.response.byteLength !== 0), 'Got a response.');

    // parse DICOM
    var dicomParser = new dwv.dicom.DicomParser();
    dicomParser.parse(this.response);

    var patientsNameAnonymised = 'anonymise-name';
    var patientsIdAnonymised = 'anonymise-id';
    // rules with different levels: full tag, tag name and group name
    var rules = {
      default: {
        action: 'copy', value: null
      },
      x00100010: {
        action: 'replace', value: patientsNameAnonymised
      },
      PatientID: {
        action: 'replace', value: patientsIdAnonymised
      },
      Patient: {
        action: 'remove', value: null
      }
    };

    var patientsName = 'dwv^PatientName';
    var patientID = 'dwv-patient-id123';
    var patientsBirthDate = '19830101';
    var patientsSex = 'M';

    // raw tags
    var rawTags = dicomParser.getRawDicomElements();
    // check values
    assert.equal(
      rawTags.x00100010.value[0].trim(),
      patientsName,
      'patientsName');
    assert.equal(
      rawTags.x00100020.value[0].trim(),
      patientID,
      'patientID');
    assert.equal(
      rawTags.x00100030.value[0].trim(),
      patientsBirthDate,
      'patientsBirthDate');
    assert.equal(
      rawTags.x00100040.value[0].trim(),
      patientsSex,
      'patientsSex');

    var dicomWriter = new dwv.dicom.DicomWriter();
    dicomWriter.rules = rules;
    var buffer = dicomWriter.getBuffer(rawTags);

    dicomParser = new dwv.dicom.DicomParser();

    dicomParser.parse(buffer);

    rawTags = dicomParser.getRawDicomElements();

    // check values
    assert.equal(
      rawTags.x00100010.value[0],
      patientsNameAnonymised,
      'patientName');
    assert.equal(
      rawTags.x00100020.value[0],
      patientsIdAnonymised,
      'patientID');
    assert.notOk(rawTags.x00100030, 'patientsBirthDate');
    assert.notOk(rawTags.x00100040, 'patientsSex');

    // finish async test
    done();
  };
  request.send(null);
});

/**
 * Compare JSON tags and DICOM elements
 *
 * @param {object} jsonTags The JSON tags.
 * @param {object} dicomElements The DICOM elements
 * @param {string} name The name of the test.
 * @param {object} comparator An object with an equal function (such as
 *   Qunit assert).
 */
dwv.test.compare = function (jsonTags, dicomElements, name, comparator) {
  // check content
  if (jsonTags === null || jsonTags === 0) {
    return;
  }
  var keys = Object.keys(jsonTags);
  for (var k = 0; k < keys.length; ++k) {
    var tagName = keys[k];
    var tag = dwv.dicom.getTagFromDictionary(tagName);
    var tagKey = tag.getKey();
    var element = dicomElements.getDEFromKey(tagKey);
    var value = dicomElements.getFromKey(tagKey, true);
    if (element.vr !== 'SQ') {
      var jsonTag = jsonTags[tagName];
      // stringify possible array
      if (Array.isArray(jsonTag)) {
        jsonTag = jsonTag.join();
      }
      comparator.equal(
        dwv.dicom.cleanString(value.join()),
        jsonTag,
        name + ' - ' + tagName);
    } else {
      // check content
      if (jsonTags[tagName] === null || jsonTags[tagName] === 0) {
        continue;
      }
      var sqValue = jsonTags[tagName].value;
      if (typeof sqValue === 'undefined' ||
      sqValue === null) {
        continue;
      }
      // supposing same order of subkeys and indices...
      for (var i = 0; i < sqValue.length; ++i) {
        if (sqValue[i] !== 'undefinedLength') {
          var wrap = new dwv.dicom.DicomElementsWrapper(value[i]);
          dwv.test.compare(
            sqValue[i], wrap, name, comparator);
        }
      }
    }
  }
};

/**
 * Test a JSON config: write a DICOM file and read it back.
 *
 * @param {object} config A JSON config representing DICOM tags.
 * @param {object} assert A Qunit assert.
 */
dwv.test.testWriteReadDataFromConfig = function (config, assert) {
  // add private tags to dict if present
  var useUnVrForPrivateSq = false;
  if (typeof config.privateDictionary !== 'undefined') {
    var keys = Object.keys(config.privateDictionary);
    for (var i = 0; i < keys.length; ++i) {
      var group = keys[i];
      var tags = config.privateDictionary[group];
      dwv.dicom.dictionary[group] = tags;
    }
    if (typeof config.useUnVrForPrivateSq !== 'undefined') {
      useUnVrForPrivateSq = config.useUnVrForPrivateSq;
    }
  }
  // pass tags clone to avoid modifications (for ex by padElement)
  // TODO: find another way
  var jsonTags = JSON.parse(JSON.stringify(config.tags));
  // convert JSON to DICOM element object
  var dicomElements = dwv.dicom.getElementsFromJSONTags(jsonTags);
  // pixels (if possible): small gradient square
  if (dwv.dicom.checkTags(config.tags, dwv.dicom.requiredPixelTags)) {
    dicomElements.x7FE00010 =
      dwv.dicom.generatePixelDataFromJSONTags(config.tags);
  }

  // create DICOM buffer
  var writer = new dwv.dicom.DicomWriter();
  writer.useUnVrForPrivateSq = useUnVrForPrivateSq;
  var dicomBuffer = null;
  try {
    dicomBuffer = writer.getBuffer(dicomElements);
  } catch (error) {
    assert.ok(false, 'Caught error: ' + error);
    return;
  }

  // parse the buffer
  var dicomParser = new dwv.dicom.DicomParser();
  dicomParser.parse(dicomBuffer);
  var elements = dicomParser.getDicomElements();

  // compare contents
  dwv.test.compare(config.tags, elements, config.name, assert);
};

/**
 * Tests write/read DICOM data from config file: explicit encoding.
 * Using remote file for CI integration.
 *
 * @function module:tests/dicom~dicomExplicitWriteReadFromConfig
 */
QUnit.test('Test synthetic dicom explicit', function (assert) {
  var done = assert.async();

  // get the list of configs
  var request = new XMLHttpRequest();
  var url = '/tests/dicom/synthetic-data_explicit.json';
  request.open('GET', url, true);
  request.onerror = function (event) {
    console.error(event);
  };
  request.onload = function (/*event*/) {
    var configs = JSON.parse(this.responseText);
    for (var i = 0; i < configs.length; ++i) {
      dwv.test.testWriteReadDataFromConfig(configs[i], assert);
    }
    // finish async test
    done();
  };
  request.send(null);
});

/**
 * Tests write/read DICOM data from config file: implicit encoding.
 * Using remote file for CI integration.
 *
 * @function module:tests/dicom~dicomImplicitWriteReadFromConfig
 */
QUnit.test('Test synthetic dicom implicit', function (assert) {
  var done = assert.async();

  // get the list of configs
  var request = new XMLHttpRequest();
  var url = '/tests/dicom/synthetic-data_implicit.json';
  request.open('GET', url, true);
  request.onerror = function (event) {
    console.error(event);
  };
  request.onload = function (/*event*/) {
    var configs = JSON.parse(this.responseText);
    for (var i = 0; i < configs.length; ++i) {
      dwv.test.testWriteReadDataFromConfig(configs[i], assert);
    }
    // finish async test
    done();
  };
  request.send(null);
});

/**
 * Tests write/read DICOM data from config file: explicit big endian encoding.
 * Using remote file for CI integration.
 *
 * @function module:tests/dicom~dicomExplicitBigEndianWriteReadFromConfig
 */
QUnit.test('Test synthetic dicom explicit big endian', function (assert) {
  var done = assert.async();

  // get the list of configs
  var request = new XMLHttpRequest();
  var url = '/tests/dicom/synthetic-data_explicit_big-endian.json';
  request.open('GET', url, true);
  request.onerror = function (event) {
    console.error(event);
  };
  request.onload = function (/*event*/) {
    var configs = JSON.parse(this.responseText);
    for (var i = 0; i < configs.length; ++i) {
      dwv.test.testWriteReadDataFromConfig(configs[i], assert);
    }
    // finish async test
    done();
  };
  request.send(null);
});