public async Task GivenOneDifferentStudyInstanceUID_WhenStoringWithProvidedStudyInstanceUID_TheServerShouldReturnAccepted()
        {
            var studyInstanceUID1 = TestUidGenerator.Generate();
            var studyInstanceUID2 = TestUidGenerator.Generate();

            try
            {
                DicomFile dicomFile1 = Samples.CreateRandomDicomFile(studyInstanceUid: studyInstanceUID1);
                DicomFile dicomFile2 = Samples.CreateRandomDicomFile(studyInstanceUid: studyInstanceUID2);

                using DicomWebResponse <DicomDataset> response = await _instancesManager.StoreAsync(new[] { dicomFile1, dicomFile2 }, studyInstanceUid : studyInstanceUID1);

                Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);

                DicomDataset dataset = await response.GetValueAsync();

                Assert.NotNull(dataset);
                Assert.True(dataset.Count() == 3);

                Assert.EndsWith($"studies/{studyInstanceUID1}", dataset.GetSingleValue <string>(DicomTag.RetrieveURL));

                await ValidateReferencedSopSequenceAsync(
                    response,
                    ConvertToReferencedSopSequenceEntry(dicomFile1.Dataset));

                ValidationHelpers.ValidateFailedSopSequence(
                    dataset,
                    ConvertToFailedSopSequenceEntry(dicomFile2.Dataset, MismatchStudyInstanceUidFailureCode));
            }
            finally
            {
                await _client.DeleteStudyAsync(studyInstanceUID1);
            }
        }
        public void BsonRoundTrip_BlacklistedVrs_ConvertedCorrectly()
        {
            var ds = new DicomDataset
            {
                new DicomOtherByte(DicomTag.SelectorOBValue, byte.MinValue),
                new DicomOtherWord(DicomTag.SelectorOWValue, byte.MinValue),
                new DicomUnknown(DicomTag.SelectorUNValue, byte.MinValue)
            };

            // Ensure this test fails if we update the blacklist later
            Assert.True(
                ds.Select(x => x.ValueRepresentation).All(DicomTypeTranslater.DicomVrBlacklist.Contains) &&
                ds.Count() == DicomTypeTranslater.DicomVrBlacklist.Length);

            BsonDocument doc = DicomTypeTranslaterReader.BuildBsonDocument(ds);

            Assert.NotNull(doc);
            Assert.True(doc.All(x => x.Value.IsBsonNull));

            DicomDataset recoDs = DicomTypeTranslaterWriter.BuildDicomDataset(doc);

            Assert.AreEqual(3, recoDs.Count());
            foreach (DicomItem item in recoDs)
            {
                Assert.Zero(((DicomElement)item).Count);
            }
        }
Exemplo n.º 3
0
        private async Task ValidateResponseMetadataDatasetAsync(
            DicomWebAsyncEnumerableResponse <DicomDataset> response,
            DicomDataset storedInstance1,
            DicomDataset storedInstance2)
        {
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal("application/dicom+json", response.ContentHeaders.ContentType.MediaType);

            DicomDataset[] datasets = await response.ToArrayAsync();

            Assert.Equal(2, datasets.Length);

            // Trim the stored dataset to the expected items in the response metadata dataset (remove non-supported value representations).
            DicomDataset expectedDataset1 = storedInstance1.CopyWithoutBulkDataItems();
            DicomDataset expectedDataset2 = storedInstance2.CopyWithoutBulkDataItems();

            DicomDataset retrievedDataset1 = datasets[0];
            DicomDataset retrievedDataset2 = datasets[1];

            // Compare result datasets by serializing.
            var jsonDicomConverter = new JsonDicomConverter();

            string serializedExpectedDataset1 = JsonConvert.SerializeObject(expectedDataset1, jsonDicomConverter);
            string serializedExpectedDataset2 = JsonConvert.SerializeObject(expectedDataset2, jsonDicomConverter);

            string serializedRetrievedDataset1 = JsonConvert.SerializeObject(retrievedDataset1, jsonDicomConverter);
            string serializedRetrievedDataset2 = JsonConvert.SerializeObject(retrievedDataset2, jsonDicomConverter);

            if (string.Equals(serializedExpectedDataset1, serializedRetrievedDataset1, StringComparison.InvariantCultureIgnoreCase) && string.Equals(serializedExpectedDataset2, serializedRetrievedDataset2, StringComparison.InvariantCultureIgnoreCase))
            {
                Assert.Equal(expectedDataset1.Count(), retrievedDataset1.Count());
                Assert.Equal(expectedDataset2.Count(), retrievedDataset2.Count());
                return;
            }
            else if (string.Equals(serializedExpectedDataset2, serializedRetrievedDataset1, StringComparison.InvariantCultureIgnoreCase) && string.Equals(serializedExpectedDataset1, serializedRetrievedDataset2, StringComparison.InvariantCultureIgnoreCase))
            {
                Assert.Equal(expectedDataset2.Count(), retrievedDataset1.Count());
                Assert.Equal(expectedDataset1.Count(), retrievedDataset2.Count());
                return;
            }

            Assert.False(true, "Retrieved dataset doesnot match the stored dataset");
        }
Exemplo n.º 4
0
        private static void ValidateResponseMetadataDataset(DicomDataset storedDataset, DicomDataset retrievedDataset)
        {
            // Trim the stored dataset to the expected items in the response metadata dataset (remove non-supported value representations).
            DicomDataset expectedDataset = storedDataset.CopyWithoutBulkDataItems();

            // Compare result datasets by serializing.
            Assert.Equal(
                JsonSerializer.Serialize(expectedDataset, AppSerializerOptions.Json),
                JsonSerializer.Serialize(retrievedDataset, AppSerializerOptions.Json));
            Assert.Equal(expectedDataset.Count(), retrievedDataset.Count());
        }
Exemplo n.º 5
0
        private static void ValidateResponseMetadataDataset(DicomDataset storedDataset, DicomDataset retrievedDataset)
        {
            // Trim the stored dataset to the expected items in the response metadata dataset (remove non-supported value representations).
            DicomDataset expectedDataset = storedDataset.CopyWithoutBulkDataItems();

            // Compare result datasets by serializing.
            var jsonDicomConverter = new JsonDicomConverter();

            Assert.Equal(
                JsonConvert.SerializeObject(expectedDataset, jsonDicomConverter),
                JsonConvert.SerializeObject(retrievedDataset, jsonDicomConverter));
            Assert.Equal(expectedDataset.Count(), retrievedDataset.Count());
        }
        public void TestWriteMultiplicity()
        {
            DicomTag stringMultiTag = DicomTag.SpecimenShortDescription;

            string[] values = { "this", "is", "a", "multi", "element", "" };

            var ds = new DicomDataset();

            DicomTypeTranslaterWriter.SetDicomTag(ds, stringMultiTag, values);

            Assert.AreEqual(1, ds.Count());
            Assert.AreEqual(6, ds.GetDicomItem <DicomElement>(stringMultiTag).Count);
            Assert.AreEqual("this\\is\\a\\multi\\element\\", ds.GetString(stringMultiTag));
        }
        private void ValidateResponseMetadataDataset(DicomWebResponse <IReadOnlyList <DicomDataset> > response, DicomDataset storedInstance1, DicomDataset storedInstance2)
        {
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal("application/dicom+json", response.Content.Headers.ContentType.MediaType);
            Assert.Equal(2, response.Value.Count());

            // Trim the stored dataset to the expected items in the response metadata dataset (remove non-supported value representations).
            DicomDataset expectedDataset1 = storedInstance1.CopyWithoutBulkDataItems();
            DicomDataset expectedDataset2 = storedInstance2.CopyWithoutBulkDataItems();

            DicomDataset retrievedDataset1 = response.Value.First();
            DicomDataset retrievedDataset2 = response.Value.Last();

            // Compare result datasets by serializing.
            var jsonDicomConverter = new JsonDicomConverter();

            string serializedExpectedDataset1 = JsonConvert.SerializeObject(expectedDataset1, jsonDicomConverter);
            string serializedExpectedDataset2 = JsonConvert.SerializeObject(expectedDataset2, jsonDicomConverter);

            string serializedRetrievedDataset1 = JsonConvert.SerializeObject(retrievedDataset1, jsonDicomConverter);
            string serializedRetrievedDataset2 = JsonConvert.SerializeObject(retrievedDataset2, jsonDicomConverter);

            if (string.Equals(serializedExpectedDataset1, serializedRetrievedDataset1, StringComparison.InvariantCultureIgnoreCase) && string.Equals(serializedExpectedDataset2, serializedRetrievedDataset2, StringComparison.InvariantCultureIgnoreCase))
            {
                Assert.Equal(expectedDataset1.Count(), retrievedDataset1.Count());
                Assert.Equal(expectedDataset2.Count(), retrievedDataset2.Count());
                return;
            }
            else if (string.Equals(serializedExpectedDataset2, serializedRetrievedDataset1, StringComparison.InvariantCultureIgnoreCase) && string.Equals(serializedExpectedDataset1, serializedRetrievedDataset2, StringComparison.InvariantCultureIgnoreCase))
            {
                Assert.Equal(expectedDataset2.Count(), retrievedDataset1.Count());
                Assert.Equal(expectedDataset1.Count(), retrievedDataset2.Count());
                return;
            }

            Assert.False(true, "Retrieved dataset doesnot match the stored dataset");
        }
        public void DicomToBson_EmptyPrivateElements_StoredAsBsonNull()
        {
            DicomDataset ds  = TranslationTestHelpers.BuildAllTypesNullDataset();
            BsonDocument doc = DicomTypeTranslaterReader.BuildBsonDocument(ds);

            Assert.AreEqual(ds.Count(), doc.Count());

            foreach (BsonElement element in doc)
            {
                BsonDocument asBsonDoc = element.Value.AsBsonDocument;
                Assert.NotNull(asBsonDoc);

                Assert.True(asBsonDoc.GetValue("val").IsBsonNull); // Private elements
            }
        }
        public void BsonRoundTrip_MaskedTags_ConvertedCorrectly()
        {
            const string rawJson = "{\"60000010\":{\"vr\":\"US\",\"val\":[128]},\"60000011\":{\"vr\":\"US\",\"val\":[614]},\"60000040\":" +
                                   "{\"vr\":\"CS\",\"val\":\"G\"},\"60000050\":{\"vr\":\"SS\",\"val\":[0,0]},\"60000100\":{\"vr\":\"US\",\"val\":[1]}," +
                                   "\"60000102\":{\"vr\":\"US\",\"val\":[0]},\"60020010\":{\"vr\":\"US\",\"val\":[512]},\"60020011\":{\"vr\":\"US\",\"val\":[613]}," +
                                   "\"60020040\":{\"vr\":\"CS\",\"val\":\"H\"},\"60020050\":{\"vr\":\"SS\",\"val\":[1,2]},\"60020100\":{\"vr\":\"US\",\"val\":[3]}," +
                                   "\"60020102\":{\"vr\":\"US\",\"val\":[4]}}";

            DicomDataset maskDataset = DicomTypeTranslater.DeserializeJsonToDataset(rawJson);

            Assert.AreEqual(12, maskDataset.Count());

            foreach (DicomItem item in maskDataset.Where(x => x.Tag.DictionaryEntry.Keyword == DicomTag.OverlayRows.DictionaryEntry.Keyword))
            {
                _logger.Debug("{0} {1} - Val: {2}", item.Tag, item.Tag.DictionaryEntry.Keyword, maskDataset.GetString(item.Tag));
            }

            VerifyBsonTripleTrip(maskDataset);
        }
Exemplo n.º 10
0
        /// <summary>
        /// 转换DicomDataset为日志字符串
        /// </summary>
        /// <param name="ddt">DicomDataset</param>
        /// <param name="lev">级别</param>
        /// <returns></returns>
        public static string LogToConsole(DicomDataset ddt, int lev = 0)
        {
            string           log        = string.Empty;
            List <DicomItem> dicomItems = ddt.ToList();
            int    ddtCount             = ddt.Count();
            string sLev = " ";

            for (int i = 0; i < lev; i++)
            {
                sLev += "\t";
            }
            for (int i = 0; i < ddtCount; i++)
            {
                DicomItem dicomItem = dicomItems[i];
                if (dicomItem is Dicom.DicomSequence)
                {
                    //log = $"  Tag: \"{dicomItem.Tag.DictionaryEntry.Name}\" \"{dicomItem.Tag.DictionaryEntry.Tag.ToString()}\", VR: \"{dicomItem.ValueRepresentation.ToString()}\", VM: {ddt.GetSequence(dicomItem.Tag).Items.Count.ToString()}";
                    log = log + "\r\n" + $"{sLev}{dicomItem.Tag.DictionaryEntry.Tag.ToString().PadRight(12)} {dicomItem.ValueRepresentation.Code.ToString().PadRight(5)} ({ddt.GetSequence(dicomItem.Tag).Items.Count.ToString().PadLeft(3)}) {dicomItem.Tag.DictionaryEntry.Name}";
                    foreach (DicomDataset ddts in ddt.GetSequence(dicomItem.Tag).Items)
                    {
                        log = log + LogToConsole(ddts, lev + 1);
                    }
                }
                else
                {
                    if (ddt.GetValueCount(dicomItem.Tag) > 0)
                    {
                        //log = $"{sLev}Tag: \"{dicomItem.Tag.DictionaryEntry.Name}\" \"{dicomItem.Tag.DictionaryEntry.Tag.ToString()}\", VR: \"{dicomItem.ValueRepresentation.Code.ToString()}\", VM: {((Dicom.DicomMultiStringElement)dicomItem).Count.ToString()}, Value: \"{ddt.GetValue<string>(dicomItem.Tag, 0)}\"";

                        log = log + "\r\n" + $"{sLev}{dicomItem.Tag.DictionaryEntry.Tag.ToString().PadRight(12)} {dicomItem.ValueRepresentation.Code.ToString().PadRight(5)} {($"|{ddt.GetValue<string>(dicomItem.Tag, 0)}|").PadRight(20)} ({((Dicom.DicomMultiStringElement)dicomItem).Count.ToString().PadLeft(3)}) {dicomItem.Tag.DictionaryEntry.Name}";
                    }
                    else
                    {
                        //log = $"{sLev}Tag: \"{dicomItem.Tag.DictionaryEntry.Name}\" \"{dicomItem.Tag.DictionaryEntry.Tag.ToString()}\", VR: \"{dicomItem.ValueRepresentation.Code.ToString()}\", VM: {((Dicom.DicomMultiStringElement)dicomItem).Count.ToString()}, Value: \"\"";

                        log = log + "\r\n" + $"{sLev}{dicomItem.Tag.DictionaryEntry.Tag.ToString().PadRight(12)} {dicomItem.ValueRepresentation.Code.ToString().PadRight(5)} {($"|<null>|").PadRight(20)} ({((Dicom.DicomMultiStringElement)dicomItem).Count.ToString().PadLeft(3)}) {dicomItem.Tag.DictionaryEntry.Name}";
                    }
                }
            }

            return(log);
        }
        public void DicomToBson_EmptyElements_StoredAsBsonNull()
        {
            var ds = new DicomDataset
            {
                new DicomAttributeTag(DicomTag.SelectorATValue),
                new DicomLongString(DicomTag.SelectorLOValue),
                new DicomOtherLong(DicomTag.SelectorOLValue),
                new DicomOtherWord(DicomTag.SelectorOWValue),
                new DicomSequence(DicomTag.SelectorCodeSequenceValue)
            };

            BsonDocument doc = DicomTypeTranslaterReader.BuildBsonDocument(ds);

            Assert.AreEqual(ds.Count(), doc.Count());

            foreach (BsonElement element in doc)
            {
                Assert.True(element.Value.IsBsonNull);
            }
        }
        public void TestSetDicomTagWithNullElement()
        {
            var dataset = new DicomDataset();

            // Test with a string element and a value element
            var asTag = DicomTag.SelectorASValue;
            var flTag = DicomTag.SelectorFLValue;

            DicomTypeTranslaterWriter.SetDicomTag(dataset, asTag, null);
            DicomTypeTranslaterWriter.SetDicomTag(dataset, flTag, null);

            Assert.True(dataset.Count() == 2);

            var asElement = dataset.GetDicomItem <DicomElement>(DicomTag.SelectorASValue);

            Assert.True(asElement.Buffer.Size == 0);

            var flElement = dataset.GetDicomItem <DicomElement>(DicomTag.SelectorFLValue);

            Assert.True(flElement.Buffer.Size == 0);
        }
Exemplo n.º 13
0
        public async Task GivenAllDifferentStudyInstanceUIDs_WhenStoringWithProvidedStudyInstanceUID_TheServerShouldReturnConflict()
        {
            DicomFile dicomFile1 = Samples.CreateRandomDicomFile();
            DicomFile dicomFile2 = Samples.CreateRandomDicomFile();

            var studyInstanceUID = TestUidGenerator.Generate();

            DicomWebException exception = await Assert.ThrowsAsync <DicomWebException>(() => _instancesManager.StoreAsync(
                                                                                           new[] { dicomFile1, dicomFile2 }, studyInstanceUid: studyInstanceUID));

            Assert.Equal(HttpStatusCode.Conflict, exception.StatusCode);

            DicomDataset dataset = exception.ResponseDataset;

            Assert.NotNull(dataset);
            Assert.True(dataset.Count() == 1);

            ValidationHelpers.ValidateFailedSopSequence(
                dataset,
                ConvertToFailedSopSequenceEntry(dicomFile1.Dataset, MismatchStudyInstanceUidFailureCode),
                ConvertToFailedSopSequenceEntry(dicomFile2.Dataset, MismatchStudyInstanceUidFailureCode));
        }
Exemplo n.º 14
0
        private DicomNGetResponse GetPrinter(DicomNGetRequest request)
        {
            var ds = new DicomDataset();

            var sb = new System.Text.StringBuilder();

            if (request.Attributes != null && request.Attributes.Length > 0)
            {
                foreach (var item in request.Attributes)
                {
                    sb.AppendFormat("GetPrinter attribute {0} requested", item);
                    sb.AppendLine();
                    var value = Printer.Get(item, "");
                    ds.Add(item, value);
                }

                Logger.Info(sb.ToString());
            }
            if (ds.Count() == 0)
            {
                ds.Add(DicomTag.PrinterStatus, Printer.PrinterStatus);
                ds.Add(DicomTag.PrinterStatusInfo, Printer.PrinterStatusInfo);
                ds.Add(DicomTag.PrinterName, Printer.PrinterName);
                ds.Add(DicomTag.Manufacturer, Printer.Manufacturer);
                ds.Add(DicomTag.DateOfLastCalibration, Printer.DateTimeOfLastCalibration.Date);
                ds.Add(DicomTag.TimeOfLastCalibration, Printer.DateTimeOfLastCalibration);
                ds.Add(DicomTag.ManufacturerModelName, Printer.ManufacturerModelName);
                ds.Add(DicomTag.DeviceSerialNumber, Printer.DeviceSerialNumber);
                ds.Add(DicomTag.SoftwareVersions, Printer.SoftwareVersions);
            }

            var response = new DicomNGetResponse(request, DicomStatus.Success)
            {
                Dataset = ds
            };

            Logger.Info(response.ToString(true));
            return(response);
        }
        public void JsonSerialization_SerializeBinaryFalse_ContainsEmptyTags()
        {
            if (_jsonDicomConverter.GetType().Name != "SmiLazyJsonDicomConverter")
            {
                Assert.Pass("Only applicable for SmiLazyJsonDicomConverter");
            }

            var ds = new DicomDataset
            {
                new DicomOtherByte(DicomTag.SelectorOBValue, byte.MinValue),
                new DicomOtherWord(DicomTag.SelectorOWValue, byte.MinValue),
                new DicomUnknown(DicomTag.SelectorUNValue, byte.MinValue)
            };

            DicomTypeTranslater.SerializeBinaryData = false;
            string json = DicomTypeTranslater.SerializeDatasetToJson(ds);

            Assert.DoesNotThrow(() => JToken.Parse(json));

            DicomDataset recoDs = DicomTypeTranslater.DeserializeJsonToDataset(json);

            Assert.AreEqual(ds.Count(), recoDs.Count());
            AssertBlacklistedNulls(recoDs);
        }
Exemplo n.º 16
0
        private DicomNGetResponse GetPrinter(DicomNGetRequest request)
        {

            var ds = new DicomDataset();

            var sb = new System.Text.StringBuilder();
            if (request.Attributes != null && request.Attributes.Length > 0)
            {
                foreach (var item in request.Attributes)
                {
                    sb.AppendFormat("GetPrinter attribute {0} requested", item);
                    sb.AppendLine();
                    var value = Printer.Get(item, "");
                    ds.Add(item, value);
                }

                Logger.Info(sb.ToString());
            }
            if (ds.Count() == 0)
            {

                ds.Add(DicomTag.PrinterStatus, Printer.PrinterStatus);
                ds.Add(DicomTag.PrinterStatusInfo, "");
                ds.Add(DicomTag.PrinterName, Printer.PrinterName);
                ds.Add(DicomTag.Manufacturer, Printer.Manufacturer);
                ds.Add(DicomTag.DateOfLastCalibration, Printer.DateTimeOfLastCalibration.Date);
                ds.Add(DicomTag.TimeOfLastCalibration, Printer.DateTimeOfLastCalibration);
                ds.Add(DicomTag.ManufacturerModelName, Printer.ManufacturerModelName);
                ds.Add(DicomTag.DeviceSerialNumber, Printer.DeviceSerialNumber);
                ds.Add(DicomTag.SoftwareVersions, Printer.SoftwareVersions);
            }

            var response = new DicomNGetResponse(request, DicomStatus.Success);
            response.Dataset = ds;

            this.Logger.Info(response.ToString(true));
            return response;
        }
        private void ValidateResponseDataset(
            QueryResource resource,
            DicomDataset storedInstance,
            DicomDataset responseInstance)
        {
            DicomDataset       expectedDataset = storedInstance.Clone();
            HashSet <DicomTag> levelTags       = new HashSet <DicomTag>();

            switch (resource)
            {
            case QueryResource.AllStudies:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.PatientID);
                levelTags.Add(DicomTag.PatientName);
                levelTags.Add(DicomTag.StudyDate);
                break;

            case QueryResource.AllSeries:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.PatientID);
                levelTags.Add(DicomTag.PatientName);
                levelTags.Add(DicomTag.StudyDate);
                levelTags.Add(DicomTag.SeriesInstanceUID);
                levelTags.Add(DicomTag.Modality);
                break;

            case QueryResource.AllInstances:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.PatientID);
                levelTags.Add(DicomTag.PatientName);
                levelTags.Add(DicomTag.StudyDate);
                levelTags.Add(DicomTag.SeriesInstanceUID);
                levelTags.Add(DicomTag.Modality);
                levelTags.Add(DicomTag.SOPInstanceUID);
                levelTags.Add(DicomTag.SOPClassUID);
                levelTags.Add(DicomTag.BitsAllocated);
                break;

            case QueryResource.StudySeries:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.SeriesInstanceUID);
                levelTags.Add(DicomTag.Modality);
                break;

            case QueryResource.StudyInstances:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.SeriesInstanceUID);
                levelTags.Add(DicomTag.Modality);
                levelTags.Add(DicomTag.SOPInstanceUID);
                levelTags.Add(DicomTag.SOPClassUID);
                levelTags.Add(DicomTag.BitsAllocated);
                break;

            case QueryResource.StudySeriesInstances:
                levelTags.Add(DicomTag.StudyInstanceUID);
                levelTags.Add(DicomTag.SeriesInstanceUID);
                levelTags.Add(DicomTag.SOPInstanceUID);
                levelTags.Add(DicomTag.SOPClassUID);
                levelTags.Add(DicomTag.BitsAllocated);
                break;
            }

            expectedDataset.Remove((di) =>
            {
                return(!levelTags.Contains(di.Tag));
            });

            // Compare result datasets by serializing.
            var jsonDicomConverter = new JsonDicomConverter();

            Assert.Equal(
                JsonConvert.SerializeObject(expectedDataset, jsonDicomConverter),
                JsonConvert.SerializeObject(responseInstance, jsonDicomConverter));
            Assert.Equal(expectedDataset.Count(), responseInstance.Count());
        }
        public static IEnumerable <string> Compare(DicomDataset a, DicomDataset b, bool ignoreTrailingNull = false)
        {
            if (a == null || b == null)
            {
                throw new ArgumentException("Dataset " + (a == null ? "A" : "B") + " was null");
            }

            var differences = new List <string>();

            if (!a.Any())
            {
                if (!b.Any())
                {
                    return(differences);
                }

                differences.Add("A contained no elements, but B did");
                return(differences);
            }

            if (!b.Any())
            {
                differences.Add("B contained no elements, but A did");
                return(differences);
            }

            if (a.Count() != b.Count())
            {
                differences.Add("A and B did not contain the same number of elements");
            }

            foreach (DicomItem item in a)
            {
                if (!b.Contains(item.Tag))
                {
                    differences.Add($"B did not contain tag {item.Tag} {item.Tag.DictionaryEntry.Keyword} from A");
                    continue;
                }

                if (item.ValueRepresentation.IsString)
                {
                    string before = a.GetString(item.Tag);
                    string after  = b.GetString(item.Tag);

                    if (string.Equals(before, after))
                    {
                        continue;
                    }

                    if (ignoreTrailingNull && Math.Abs(before.Length - after.Length) == 1)
                    {
                        string longest = before.Length > after.Length ? before : after;

                        // Check for a single trailing NUL character (int value == 0)
                        if (longest[longest.Length - 1] == 0)
                        {
                            continue;
                        }
                    }

                    differences.Add(string.Format("Tag {0} {1} {2} had value \"{3}\" in A and \"{4}\" in B",
                                                  item.Tag, item.ValueRepresentation, item.Tag.DictionaryEntry.Keyword, before, after));
                }
                else if (item.ValueRepresentation == DicomVR.SQ)
                {
                    DicomSequence seqA = a.GetSequence(item.Tag);
                    DicomSequence seqB = b.GetSequence(item.Tag);

                    if (seqA.Count() != seqB.Count())
                    {
                        differences.Add(string.Format("Sequence of tag {0} {1} had {2} elements in A, but {3} in B",
                                                      item.Tag, item.Tag.DictionaryEntry.Keyword, seqA.Count(), seqB.Count()));
                        continue;
                    }

                    for (var i = 0; i < seqA.Count(); ++i)
                    {
                        differences.AddRange(Compare(seqA.Items[i], seqB.Items[i]));
                    }
                }
                else
                {
                    object[] valA = a.GetValues <object>(item.Tag);
                    object[] valB = b.GetValues <object>(item.Tag);

                    if (!(valA.Any() || valB.Any()))
                    {
                        continue;
                    }

                    if (valA.Length != valB.Length)
                    {
                        differences.Add(string.Format("Tag {0} {1} {2} had {3} values in A and {4} values in B",
                                                      item.Tag, item.ValueRepresentation, item.Tag.DictionaryEntry.Keyword, valA.Length, valB.Length));
                    }

                    List <object> diffs = valA.Except(valB).ToList();

                    if (!diffs.Any())
                    {
                        continue;
                    }

                    differences.Add("\tDifferent values were: " + string.Join(", ", diffs));
                }
            }

            return(differences);
        }