changeset 1645:bc7bd8ee13f8

making private two potentially dangerous methods in SortedFrames
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 10 Nov 2020 21:07:05 +0100
parents 4796fb60999e
children 4e14735e98f8
files OrthancStone/Sources/Toolbox/SortedFrames.h UnitTestsSources/SortedFramesTests.cpp
diffstat 2 files changed, 219 insertions(+), 207 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Toolbox/SortedFrames.h	Tue Nov 10 18:08:16 2020 +0100
+++ b/OrthancStone/Sources/Toolbox/SortedFrames.h	Tue Nov 10 21:07:05 2020 +0100
@@ -30,6 +30,14 @@
 {
   class SortedFrames : public boost::noncopyable
   {
+#if defined(FRIEND_TEST)
+    // We're compiling the unit tests
+    FRIEND_TEST(SortedFrames, Basic);
+    FRIEND_TEST(SortedFrames, SortSopInstanceUid);
+    FRIEND_TEST(SortedFrames, SortInstanceNumber);
+    FRIEND_TEST(SortedFrames, SortInstanceNumberAndImageIndex);
+#endif
+    
   private:
     struct Frame
     {
@@ -68,6 +76,11 @@
     InstancesIndex                         instancesIndex_;
     FramesIndex                            framesIndex_;
 
+    const DicomInstanceParameters& GetInstance(size_t instanceIndex) const;
+
+    bool LookupSopInstanceUid(size_t& instanceIndex,
+                              const std::string& sopInstanceUid) const;
+
     const Frame& GetFrame(size_t frameIndex) const;
 
     void AddFramesOfInstance(std::set<size_t>& remainingInstances,
@@ -110,12 +123,6 @@
       return instances_.size();
     }
 
-    // TODO - REMOVE THIS DANGEROUS FUNCTION (might be taken for GetInstanceOfFrame())
-    const DicomInstanceParameters& GetInstance(size_t instanceIndex) const;
-
-    bool LookupSopInstanceUid(size_t& instanceIndex,
-                              const std::string& sopInstanceUid) const;
-
     bool IsSorted() const
     {
       return sorted_;
--- a/UnitTestsSources/SortedFramesTests.cpp	Tue Nov 10 18:08:16 2020 +0100
+++ b/UnitTestsSources/SortedFramesTests.cpp	Tue Nov 10 21:07:05 2020 +0100
@@ -19,6 +19,7 @@
  **/
 
 
+// Make sure to define FRIEND_TEST before including "SortedFrames.h"
 #include <gtest/gtest.h>
 
 #include "../OrthancStone/Sources/Toolbox/SortedFrames.h"
@@ -26,222 +27,226 @@
 #include <OrthancException.h>
 
 
-TEST(SortedFrames, Basic)
-{
-  OrthancStone::SortedFrames f;
-  ASSERT_TRUE(f.GetStudyInstanceUid().empty());
-  ASSERT_TRUE(f.GetSeriesInstanceUid().empty());
-  ASSERT_EQ(0u, f.GetInstancesCount());
-  ASSERT_THROW(f.GetInstance(0).GetTags(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstance(0).GetSopInstanceUid(), Orthanc::OrthancException);
-  ASSERT_TRUE(f.IsSorted());
-  ASSERT_EQ(0u, f.GetFramesCount());
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetTags(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetSopInstanceUid(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetNumberOfFrames(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetFrameNumberInInstance(0), Orthanc::OrthancException);
-
-  Orthanc::DicomMap tags;
-  ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
-  tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
-  ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
-  tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
-  ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop", false);
-  f.AddInstance(tags);
-
-  ASSERT_EQ("study", f.GetStudyInstanceUid());
-  ASSERT_EQ("series", f.GetSeriesInstanceUid());
-  ASSERT_EQ(1u, f.GetInstancesCount());
-  std::string s;
-  ASSERT_TRUE(f.GetInstance(0).GetTags().LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false));
-  ASSERT_EQ("sop", s);
-  ASSERT_EQ("sop", f.GetInstance(0).GetSopInstanceUid());
-  ASSERT_FALSE(f.IsSorted());
-  ASSERT_THROW(f.GetFramesCount(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetTags(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetSopInstanceUid(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetInstanceOfFrame(0).GetNumberOfFrames(), Orthanc::OrthancException);
-  ASSERT_THROW(f.GetFrameNumberInInstance(0), Orthanc::OrthancException);
-
-  f.Sort();
-  ASSERT_TRUE(f.IsSorted());
-  ASSERT_EQ(1u, f.GetFramesCount());
-  ASSERT_TRUE(f.GetInstanceOfFrame(0).GetTags().LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false));
-  ASSERT_EQ("sop", s);
-  ASSERT_EQ("sop", f.GetInstanceOfFrame(0).GetSopInstanceUid());
-  ASSERT_EQ(1u, f.GetInstanceOfFrame(0).GetNumberOfFrames());
-  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
-  ASSERT_THROW(f.GetInstanceOfFrame(1).GetTags(), Orthanc::OrthancException);
-}
-
-
-TEST(SortedFrames, SortSopInstanceUid)
+// Namespace is necessary for FRIEND_TEST() to work in "SortedFrames.h"
+namespace OrthancStone
 {
-  Orthanc::DicomMap tags;
-  tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
-  tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
-    
-  OrthancStone::SortedFrames f;
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
-  tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "1", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
-  tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "3", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
-  tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "2", false);
-  f.AddInstance(tags);
+  TEST(SortedFrames, Basic)
+  {
+    SortedFrames f;
+    ASSERT_TRUE(f.GetStudyInstanceUid().empty());
+    ASSERT_TRUE(f.GetSeriesInstanceUid().empty());
+    ASSERT_EQ(0u, f.GetInstancesCount());
+    ASSERT_THROW(f.GetInstance(0).GetTags(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstance(0).GetSopInstanceUid(), Orthanc::OrthancException);
+    ASSERT_TRUE(f.IsSorted());
+    ASSERT_EQ(0u, f.GetFramesCount());
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetTags(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetSopInstanceUid(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetNumberOfFrames(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetFrameNumberInInstance(0), Orthanc::OrthancException);
 
-  size_t i;
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(0u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(2u, i);
-  ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
+    Orthanc::DicomMap tags;
+    ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
+    tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
+    ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
+    tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
+    ASSERT_THROW(f.AddInstance(tags), Orthanc::OrthancException);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop", false);
+    f.AddInstance(tags);
 
-  ASSERT_THROW(f.LookupFrame(i, "sop3", 0), Orthanc::OrthancException);  // Not sorted yet
-  
-  f.Sort();
-  ASSERT_EQ(3u, f.GetInstancesCount());
-  ASSERT_EQ("sop3", f.GetInstance(0).GetSopInstanceUid());
-  ASSERT_EQ("sop1", f.GetInstance(1).GetSopInstanceUid());
-  ASSERT_EQ("sop2", f.GetInstance(2).GetSopInstanceUid());
-  ASSERT_EQ(6u, f.GetFramesCount());
-  ASSERT_EQ("sop1", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
-  ASSERT_EQ("sop1", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(1u, f.GetFrameNumberInInstance(1));
-  ASSERT_EQ("sop1", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(2u, f.GetFrameNumberInInstance(2));
-  ASSERT_EQ("sop2", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
-  ASSERT_EQ("sop2", f.GetInstanceOfFrame(4).GetSopInstanceUid());  ASSERT_EQ(1u, f.GetFrameNumberInInstance(4));
-  ASSERT_EQ("sop3", f.GetInstanceOfFrame(5).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(5));
+    ASSERT_EQ("study", f.GetStudyInstanceUid());
+    ASSERT_EQ("series", f.GetSeriesInstanceUid());
+    ASSERT_EQ(1u, f.GetInstancesCount());
+    std::string s;
+    ASSERT_TRUE(f.GetInstance(0).GetTags().LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false));
+    ASSERT_EQ("sop", s);
+    ASSERT_EQ("sop", f.GetInstance(0).GetSopInstanceUid());
+    ASSERT_FALSE(f.IsSorted());
+    ASSERT_THROW(f.GetFramesCount(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetTags(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetSopInstanceUid(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetInstanceOfFrame(0).GetNumberOfFrames(), Orthanc::OrthancException);
+    ASSERT_THROW(f.GetFrameNumberInInstance(0), Orthanc::OrthancException);
 
-  // The instances must not have been reordered, only the frames
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(2u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(0u, i);
-  ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
-
-  ASSERT_TRUE(f.LookupFrame(i, "sop1", 0));  ASSERT_EQ(0u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop1", 1));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop1", 2));  ASSERT_EQ(2u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop2", 0));  ASSERT_EQ(3u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop2", 1));  ASSERT_EQ(4u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop3", 0));  ASSERT_EQ(5u, i);
-
-  ASSERT_FALSE(f.LookupFrame(i, "nope", 0));
-  ASSERT_FALSE(f.LookupFrame(i, "sop1", 3));
-  ASSERT_FALSE(f.LookupFrame(i, "sop2", 2));
-  ASSERT_FALSE(f.LookupFrame(i, "sop3", 1));
-}
+    f.Sort();
+    ASSERT_TRUE(f.IsSorted());
+    ASSERT_EQ(1u, f.GetFramesCount());
+    ASSERT_TRUE(f.GetInstanceOfFrame(0).GetTags().LookupStringValue(s, Orthanc::DICOM_TAG_SOP_INSTANCE_UID, false));
+    ASSERT_EQ("sop", s);
+    ASSERT_EQ("sop", f.GetInstanceOfFrame(0).GetSopInstanceUid());
+    ASSERT_EQ(1u, f.GetInstanceOfFrame(0).GetNumberOfFrames());
+    ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
+    ASSERT_THROW(f.GetInstanceOfFrame(1).GetTags(), Orthanc::OrthancException);
+  }
 
 
-TEST(SortedFrames, SortInstanceNumber)
-{
-  Orthanc::DicomMap tags;
-  tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
-  tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
+  TEST(SortedFrames, SortSopInstanceUid)
+  {
+    Orthanc::DicomMap tags;
+    tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
+    tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
     
-  OrthancStone::SortedFrames f;
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "20", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "-20", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2a", false);
-  tags.Remove(Orthanc::DICOM_TAG_INSTANCE_NUMBER);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop4", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop5", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
-  f.AddInstance(tags);
-    
-  size_t i;
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(0u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2a")); ASSERT_EQ(2u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop4"));  ASSERT_EQ(3u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(4u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop5"));  ASSERT_EQ(5u, i);
-  ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
+    SortedFrames f;
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
+    tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "1", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
+    tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "3", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
+    tags.SetValue(Orthanc::DICOM_TAG_NUMBER_OF_FRAMES, "2", false);
+    f.AddInstance(tags);
+
+    size_t i;
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(0u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(2u, i);
+    ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
 
-  ASSERT_THROW(f.LookupFrame(i, "sop1", 0), Orthanc::OrthancException);  // Not sorted yet
-
-  f.Sort();
-  ASSERT_EQ(6u, f.GetInstancesCount());
-  ASSERT_EQ("sop1", f.GetInstance(0).GetSopInstanceUid());
-  ASSERT_EQ("sop2", f.GetInstance(1).GetSopInstanceUid());
-  ASSERT_EQ("sop2a", f.GetInstance(2).GetSopInstanceUid());
-  ASSERT_EQ("sop4", f.GetInstance(3).GetSopInstanceUid());
-  ASSERT_EQ("sop3", f.GetInstance(4).GetSopInstanceUid());
-  ASSERT_EQ("sop5", f.GetInstance(5).GetSopInstanceUid());
-  ASSERT_EQ(6u, f.GetFramesCount());
-  ASSERT_EQ("sop2", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
-  ASSERT_EQ("sop3", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(1));
-  ASSERT_EQ("sop4", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(2));
-  ASSERT_EQ("sop5", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
-  ASSERT_EQ("sop1", f.GetInstanceOfFrame(4).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(4));
-  ASSERT_EQ("sop2a", f.GetInstanceOfFrame(5).GetSopInstanceUid()); ASSERT_EQ(0u, f.GetFrameNumberInInstance(5));
+    ASSERT_THROW(f.LookupFrame(i, "sop3", 0), Orthanc::OrthancException);  // Not sorted yet
+  
+    f.Sort();
+    ASSERT_EQ(3u, f.GetInstancesCount());
+    ASSERT_EQ("sop3", f.GetInstance(0).GetSopInstanceUid());
+    ASSERT_EQ("sop1", f.GetInstance(1).GetSopInstanceUid());
+    ASSERT_EQ("sop2", f.GetInstance(2).GetSopInstanceUid());
+    ASSERT_EQ(6u, f.GetFramesCount());
+    ASSERT_EQ("sop1", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
+    ASSERT_EQ("sop1", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(1u, f.GetFrameNumberInInstance(1));
+    ASSERT_EQ("sop1", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(2u, f.GetFrameNumberInInstance(2));
+    ASSERT_EQ("sop2", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
+    ASSERT_EQ("sop2", f.GetInstanceOfFrame(4).GetSopInstanceUid());  ASSERT_EQ(1u, f.GetFrameNumberInInstance(4));
+    ASSERT_EQ("sop3", f.GetInstanceOfFrame(5).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(5));
 
-  // The instances must not have been reordered, only the frames
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(0u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2a")); ASSERT_EQ(2u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop4"));  ASSERT_EQ(3u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(4u, i);
-  ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop5"));  ASSERT_EQ(5u, i);
-  ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
+    // The instances must not have been reordered, only the frames
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(2u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(0u, i);
+    ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
 
-  ASSERT_TRUE(f.LookupFrame(i, "sop2", 0));  ASSERT_EQ(0u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop3", 0));  ASSERT_EQ(1u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop4", 0));  ASSERT_EQ(2u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop5", 0));  ASSERT_EQ(3u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop1", 0));  ASSERT_EQ(4u, i);
-  ASSERT_TRUE(f.LookupFrame(i, "sop2a", 0)); ASSERT_EQ(5u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop1", 0));  ASSERT_EQ(0u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop1", 1));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop1", 2));  ASSERT_EQ(2u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop2", 0));  ASSERT_EQ(3u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop2", 1));  ASSERT_EQ(4u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop3", 0));  ASSERT_EQ(5u, i);
 
-  ASSERT_FALSE(f.LookupFrame(i, "nope", 0));
-  ASSERT_FALSE(f.LookupFrame(i, "sop1", 1));
-}
+    ASSERT_FALSE(f.LookupFrame(i, "nope", 0));
+    ASSERT_FALSE(f.LookupFrame(i, "sop1", 3));
+    ASSERT_FALSE(f.LookupFrame(i, "sop2", 2));
+    ASSERT_FALSE(f.LookupFrame(i, "sop3", 1));
+  }
 
 
-TEST(SortedFrames, SortInstanceNumberAndImageIndex)
-{
-  Orthanc::DicomMap tags;
-  tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
-  tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
+  TEST(SortedFrames, SortInstanceNumber)
+  {
+    Orthanc::DicomMap tags;
+    tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
+    tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
+    
+    SortedFrames f;
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "20", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "-20", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2a", false);
+    tags.Remove(Orthanc::DICOM_TAG_INSTANCE_NUMBER);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop4", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop5", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "10", false);
+    f.AddInstance(tags);
     
-  OrthancStone::SortedFrames f;
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "20", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
-  tags.Remove(Orthanc::DICOM_TAG_INSTANCE_NUMBER);
-  tags.SetValue(Orthanc::DICOM_TAG_IMAGE_INDEX, "20", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
-  tags.SetValue(Orthanc::DICOM_TAG_IMAGE_INDEX, "30", false);
-  f.AddInstance(tags);
-  tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop4", false);
-  tags.Remove(Orthanc::DICOM_TAG_IMAGE_INDEX);
-  tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "30", false);
-  f.AddInstance(tags);
+    size_t i;
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(0u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2a")); ASSERT_EQ(2u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop4"));  ASSERT_EQ(3u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(4u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop5"));  ASSERT_EQ(5u, i);
+    ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
+
+    ASSERT_THROW(f.LookupFrame(i, "sop1", 0), Orthanc::OrthancException);  // Not sorted yet
+
+    f.Sort();
+    ASSERT_EQ(6u, f.GetInstancesCount());
+    ASSERT_EQ("sop1", f.GetInstance(0).GetSopInstanceUid());
+    ASSERT_EQ("sop2", f.GetInstance(1).GetSopInstanceUid());
+    ASSERT_EQ("sop2a", f.GetInstance(2).GetSopInstanceUid());
+    ASSERT_EQ("sop4", f.GetInstance(3).GetSopInstanceUid());
+    ASSERT_EQ("sop3", f.GetInstance(4).GetSopInstanceUid());
+    ASSERT_EQ("sop5", f.GetInstance(5).GetSopInstanceUid());
+    ASSERT_EQ(6u, f.GetFramesCount());
+    ASSERT_EQ("sop2", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
+    ASSERT_EQ("sop3", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(1));
+    ASSERT_EQ("sop4", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(2));
+    ASSERT_EQ("sop5", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
+    ASSERT_EQ("sop1", f.GetInstanceOfFrame(4).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(4));
+    ASSERT_EQ("sop2a", f.GetInstanceOfFrame(5).GetSopInstanceUid()); ASSERT_EQ(0u, f.GetFrameNumberInInstance(5));
+
+    // The instances must not have been reordered, only the frames
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop1"));  ASSERT_EQ(0u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2"));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop2a")); ASSERT_EQ(2u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop4"));  ASSERT_EQ(3u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop3"));  ASSERT_EQ(4u, i);
+    ASSERT_TRUE(f.LookupSopInstanceUid(i, "sop5"));  ASSERT_EQ(5u, i);
+    ASSERT_FALSE(f.LookupSopInstanceUid(i, "nope"));
 
-  f.Sort();
-  ASSERT_EQ(4u, f.GetInstancesCount());
-  ASSERT_EQ("sop1", f.GetInstance(0).GetSopInstanceUid());
-  ASSERT_EQ("sop2", f.GetInstance(1).GetSopInstanceUid());
-  ASSERT_EQ("sop3", f.GetInstance(2).GetSopInstanceUid());
-  ASSERT_EQ("sop4", f.GetInstance(3).GetSopInstanceUid());
-  ASSERT_EQ(4u, f.GetFramesCount());
-  // First instance number, then image index
-  ASSERT_EQ("sop1", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
-  ASSERT_EQ("sop4", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(1));
-  ASSERT_EQ("sop2", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(2));
-  ASSERT_EQ("sop3", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
+    ASSERT_TRUE(f.LookupFrame(i, "sop2", 0));  ASSERT_EQ(0u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop3", 0));  ASSERT_EQ(1u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop4", 0));  ASSERT_EQ(2u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop5", 0));  ASSERT_EQ(3u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop1", 0));  ASSERT_EQ(4u, i);
+    ASSERT_TRUE(f.LookupFrame(i, "sop2a", 0)); ASSERT_EQ(5u, i);
+
+    ASSERT_FALSE(f.LookupFrame(i, "nope", 0));
+    ASSERT_FALSE(f.LookupFrame(i, "sop1", 1));
+  }
+
+
+  TEST(SortedFrames, SortInstanceNumberAndImageIndex)
+  {
+    Orthanc::DicomMap tags;
+    tags.SetValue(Orthanc::DICOM_TAG_STUDY_INSTANCE_UID, "study", false);
+    tags.SetValue(Orthanc::DICOM_TAG_SERIES_INSTANCE_UID, "series", false);
+    
+    SortedFrames f;
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop1", false);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "20", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop2", false);
+    tags.Remove(Orthanc::DICOM_TAG_INSTANCE_NUMBER);
+    tags.SetValue(Orthanc::DICOM_TAG_IMAGE_INDEX, "20", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop3", false);
+    tags.SetValue(Orthanc::DICOM_TAG_IMAGE_INDEX, "30", false);
+    f.AddInstance(tags);
+    tags.SetValue(Orthanc::DICOM_TAG_SOP_INSTANCE_UID, "sop4", false);
+    tags.Remove(Orthanc::DICOM_TAG_IMAGE_INDEX);
+    tags.SetValue(Orthanc::DICOM_TAG_INSTANCE_NUMBER, "30", false);
+    f.AddInstance(tags);
+
+    f.Sort();
+    ASSERT_EQ(4u, f.GetInstancesCount());
+    ASSERT_EQ("sop1", f.GetInstance(0).GetSopInstanceUid());
+    ASSERT_EQ("sop2", f.GetInstance(1).GetSopInstanceUid());
+    ASSERT_EQ("sop3", f.GetInstance(2).GetSopInstanceUid());
+    ASSERT_EQ("sop4", f.GetInstance(3).GetSopInstanceUid());
+    ASSERT_EQ(4u, f.GetFramesCount());
+    // First instance number, then image index
+    ASSERT_EQ("sop1", f.GetInstanceOfFrame(0).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(0));
+    ASSERT_EQ("sop4", f.GetInstanceOfFrame(1).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(1));
+    ASSERT_EQ("sop2", f.GetInstanceOfFrame(2).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(2));
+    ASSERT_EQ("sop3", f.GetInstanceOfFrame(3).GetSopInstanceUid());  ASSERT_EQ(0u, f.GetFrameNumberInInstance(3));
+  }
 }