1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "PrecompiledHeadersUnitTests.h"
35 #include <gtest/gtest.h>
36
37 #include "../../OrthancFramework/Sources/OrthancException.h"
38
39 #include "../Sources/Search/DatabaseLookup.h"
40
41 using namespace Orthanc;
42
43
TEST(DatabaseLookup,SingleConstraint)44 TEST(DatabaseLookup, SingleConstraint)
45 {
46 {
47 ASSERT_THROW(DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Equal,
48 "HEL*LO", true, true), OrthancException);
49 ASSERT_THROW(DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Equal,
50 "HEL?LO", true, true), OrthancException);
51 ASSERT_THROW(DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Equal,
52 true, true), OrthancException);
53
54 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Equal, "HELLO", true, true);
55 ASSERT_TRUE(tag.IsMatch("HELLO"));
56 ASSERT_FALSE(tag.IsMatch("hello"));
57
58 ASSERT_TRUE(tag.IsCaseSensitive());
59 ASSERT_EQ(ConstraintType_Equal, tag.GetConstraintType());
60
61 DicomMap m;
62 ASSERT_FALSE(tag.IsMatch(m));
63 m.SetNullValue(DICOM_TAG_PATIENT_NAME);
64 ASSERT_FALSE(tag.IsMatch(m));
65 m.SetValue(DICOM_TAG_PATIENT_NAME, "HELLO", true /* binary */);
66 ASSERT_FALSE(tag.IsMatch(m));
67 m.SetValue(DICOM_TAG_PATIENT_NAME, "HELLO", false /* string */);
68 ASSERT_TRUE(tag.IsMatch(m));
69 }
70
71 {
72 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Equal, "HELlo", false, true);
73 ASSERT_TRUE(tag.IsMatch("HELLO"));
74 ASSERT_TRUE(tag.IsMatch("hello"));
75
76 ASSERT_EQ("HELlo", tag.GetValue());
77 }
78
79 {
80 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Wildcard, "HE*L?O", true, true);
81 ASSERT_TRUE(tag.IsMatch("HELLO"));
82 ASSERT_TRUE(tag.IsMatch("HELLLLLO"));
83 ASSERT_TRUE(tag.IsMatch("HELxO"));
84 ASSERT_FALSE(tag.IsMatch("hello"));
85 }
86
87 {
88 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_Wildcard, "HE*l?o", false, true);
89 ASSERT_TRUE(tag.IsMatch("HELLO"));
90 ASSERT_TRUE(tag.IsMatch("HELLLLLO"));
91 ASSERT_TRUE(tag.IsMatch("HELxO"));
92 ASSERT_TRUE(tag.IsMatch("hello"));
93
94 ASSERT_FALSE(tag.IsCaseSensitive());
95 ASSERT_EQ(ConstraintType_Wildcard, tag.GetConstraintType());
96 }
97
98 {
99 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_SmallerOrEqual, "123", true, true);
100 ASSERT_TRUE(tag.IsMatch("120"));
101 ASSERT_TRUE(tag.IsMatch("123"));
102 ASSERT_FALSE(tag.IsMatch("124"));
103 ASSERT_TRUE(tag.IsMandatory());
104 }
105
106 {
107 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_GreaterOrEqual, "123", true, false);
108 ASSERT_FALSE(tag.IsMatch("122"));
109 ASSERT_TRUE(tag.IsMatch("123"));
110 ASSERT_TRUE(tag.IsMatch("124"));
111 ASSERT_FALSE(tag.IsMandatory());
112 }
113
114 {
115 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_List, true, true);
116 ASSERT_FALSE(tag.IsMatch("CT"));
117 ASSERT_FALSE(tag.IsMatch("MR"));
118
119 tag.AddValue("CT");
120 ASSERT_TRUE(tag.IsMatch("CT"));
121 ASSERT_FALSE(tag.IsMatch("MR"));
122
123 tag.AddValue("MR");
124 ASSERT_TRUE(tag.IsMatch("CT"));
125 ASSERT_TRUE(tag.IsMatch("MR"));
126 ASSERT_FALSE(tag.IsMatch("ct"));
127 ASSERT_FALSE(tag.IsMatch("mr"));
128
129 ASSERT_THROW(tag.GetValue(), OrthancException);
130 ASSERT_EQ(2u, tag.GetValues().size());
131 }
132
133 {
134 DicomTagConstraint tag(DICOM_TAG_PATIENT_NAME, ConstraintType_List, false, true);
135
136 tag.AddValue("ct");
137 tag.AddValue("mr");
138
139 ASSERT_TRUE(tag.IsMatch("CT"));
140 ASSERT_TRUE(tag.IsMatch("MR"));
141 ASSERT_TRUE(tag.IsMatch("ct"));
142 ASSERT_TRUE(tag.IsMatch("mr"));
143 }
144 }
145
146
147
TEST(DatabaseLookup,FromDicom)148 TEST(DatabaseLookup, FromDicom)
149 {
150 {
151 DatabaseLookup lookup;
152 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_ID, "HELLO", true, true);
153 ASSERT_EQ(1u, lookup.GetConstraintsCount());
154 ASSERT_EQ(ConstraintType_Equal, lookup.GetConstraint(0).GetConstraintType());
155 ASSERT_EQ("HELLO", lookup.GetConstraint(0).GetValue());
156 ASSERT_TRUE(lookup.GetConstraint(0).IsCaseSensitive());
157
158 ASSERT_TRUE(lookup.HasTag(DICOM_TAG_PATIENT_ID));
159 ASSERT_FALSE(lookup.HasTag(DICOM_TAG_PATIENT_NAME));
160 }
161
162 {
163 DatabaseLookup lookup;
164 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_ID, "HELLO", false, true);
165 ASSERT_EQ(1u, lookup.GetConstraintsCount());
166
167 // This is *not* a PN VR => "false" above is *not* used
168 ASSERT_TRUE(lookup.GetConstraint(0).IsCaseSensitive());
169 }
170
171 {
172 DatabaseLookup lookup;
173 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_NAME, "HELLO", true, true);
174 ASSERT_EQ(1u, lookup.GetConstraintsCount());
175 ASSERT_TRUE(lookup.GetConstraint(0).IsCaseSensitive());
176 }
177
178 {
179 DatabaseLookup lookup;
180 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_NAME, "HELLO", false, true);
181 ASSERT_EQ(1u, lookup.GetConstraintsCount());
182
183 // This is a PN VR => "false" above is used
184 ASSERT_FALSE(lookup.GetConstraint(0).IsCaseSensitive());
185 }
186
187 {
188 DatabaseLookup lookup;
189 lookup.AddDicomConstraint(DICOM_TAG_SERIES_DESCRIPTION, "2012-2016", false, true);
190
191 // This is not a data VR
192 ASSERT_EQ(ConstraintType_Equal, lookup.GetConstraint(0).GetConstraintType());
193 }
194
195 {
196 DatabaseLookup lookup;
197 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_BIRTH_DATE, "2012-2016", false, true);
198
199 // This is a data VR => range is effective
200 ASSERT_EQ(2u, lookup.GetConstraintsCount());
201
202 ASSERT_TRUE(lookup.GetConstraint(0).GetConstraintType() != lookup.GetConstraint(1).GetConstraintType());
203
204 for (size_t i = 0; i < 2; i++)
205 {
206 ASSERT_TRUE(lookup.GetConstraint(i).GetConstraintType() == ConstraintType_SmallerOrEqual ||
207 lookup.GetConstraint(i).GetConstraintType() == ConstraintType_GreaterOrEqual);
208 }
209 }
210
211 {
212 DatabaseLookup lookup;
213 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_BIRTH_DATE, "2012-", false, true);
214
215 ASSERT_EQ(1u, lookup.GetConstraintsCount());
216 ASSERT_EQ(ConstraintType_GreaterOrEqual, lookup.GetConstraint(0).GetConstraintType());
217 ASSERT_EQ("2012", lookup.GetConstraint(0).GetValue());
218 }
219
220 {
221 DatabaseLookup lookup;
222 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_BIRTH_DATE, "-2016", false, true);
223
224 ASSERT_EQ(1u, lookup.GetConstraintsCount());
225 ASSERT_EQ(DICOM_TAG_PATIENT_BIRTH_DATE, lookup.GetConstraint(0).GetTag());
226 ASSERT_EQ(ConstraintType_SmallerOrEqual, lookup.GetConstraint(0).GetConstraintType());
227 ASSERT_EQ("2016", lookup.GetConstraint(0).GetValue());
228 }
229
230 {
231 DatabaseLookup lookup;
232 lookup.AddDicomConstraint(DICOM_TAG_MODALITIES_IN_STUDY, "CT\\MR", false, true);
233
234 ASSERT_EQ(1u, lookup.GetConstraintsCount());
235 ASSERT_EQ(DICOM_TAG_MODALITIES_IN_STUDY, lookup.GetConstraint(0).GetTag());
236 ASSERT_EQ(ConstraintType_List, lookup.GetConstraint(0).GetConstraintType());
237
238 const std::set<std::string>& values = lookup.GetConstraint(0).GetValues();
239 ASSERT_EQ(2u, values.size());
240 ASSERT_TRUE(values.find("CT") != values.end());
241 ASSERT_TRUE(values.find("MR") != values.end());
242 ASSERT_TRUE(values.find("nope") == values.end());
243 }
244
245 {
246 DatabaseLookup lookup;
247 lookup.AddDicomConstraint(DICOM_TAG_STUDY_DESCRIPTION, "CT\\MR", false, true);
248
249 ASSERT_EQ(1u, lookup.GetConstraintsCount());
250 ASSERT_EQ(DICOM_TAG_STUDY_DESCRIPTION, lookup.GetConstraint(0).GetTag());
251 ASSERT_EQ(ConstraintType_List, lookup.GetConstraint(0).GetConstraintType());
252
253 const std::set<std::string>& values = lookup.GetConstraint(0).GetValues();
254 ASSERT_EQ(2u, values.size());
255 ASSERT_TRUE(values.find("CT") != values.end());
256 ASSERT_TRUE(values.find("MR") != values.end());
257 ASSERT_TRUE(values.find("nope") == values.end());
258 }
259
260 {
261 DatabaseLookup lookup;
262 lookup.AddDicomConstraint(DICOM_TAG_STUDY_DESCRIPTION, "HE*O", false, true);
263
264 ASSERT_EQ(1u, lookup.GetConstraintsCount());
265 ASSERT_EQ(ConstraintType_Wildcard, lookup.GetConstraint(0).GetConstraintType());
266 }
267
268 {
269 DatabaseLookup lookup;
270 lookup.AddDicomConstraint(DICOM_TAG_STUDY_DESCRIPTION, "HE?O", false, true);
271
272 ASSERT_EQ(1u, lookup.GetConstraintsCount());
273 ASSERT_EQ(ConstraintType_Wildcard, lookup.GetConstraint(0).GetConstraintType());
274 }
275
276 {
277 DatabaseLookup lookup;
278 lookup.AddDicomConstraint(DICOM_TAG_RELATED_FRAME_OF_REFERENCE_UID, "TEST", false, true);
279 lookup.AddDicomConstraint(DICOM_TAG_PATIENT_NAME, "TEST2", false, false);
280 ASSERT_TRUE(lookup.GetConstraint(0).IsMandatory());
281 ASSERT_FALSE(lookup.GetConstraint(1).IsMandatory());
282 }
283 }
284