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 Lesser General Public License
9  * as published by the Free Software Foundation, either version 3 of
10  * the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program. If not, see
19  * <http://www.gnu.org/licenses/>.
20  **/
21 
22 
23 #if ORTHANC_UNIT_TESTS_LINK_FRAMEWORK == 1
24 // Must be the first to be sure to use the Orthanc framework shared library
25 #  include <OrthancFramework.h>
26 #endif
27 
28 #include <gtest/gtest.h>
29 
30 #include "../Sources/Compatibility.h"
31 #include "../Sources/IDynamicObject.h"
32 #include "../Sources/OrthancException.h"
33 #include "../Sources/Toolbox.h"
34 
35 using namespace Orthanc;
36 
TEST(Toolbox,Json)37 TEST(Toolbox, Json)
38 {
39   Json::Value a = Json::objectValue;
40   a["hello"] = "world";
41 
42   std::string b = "{\"hello\"    :   \"world\"}";
43 
44   Json::Value c;
45   ASSERT_TRUE(Toolbox::ReadJson(c, b));
46 
47   std::string d, e;
48   Toolbox::WriteFastJson(d, a);
49   Toolbox::WriteFastJson(e, c);
50   ASSERT_EQ(d, e);
51 
52   std::string f, g;
53   Toolbox::WriteStyledJson(f, a);
54   Toolbox::WriteStyledJson(g, c);
55   ASSERT_EQ(f, g);
56 
57   /**
58    * Check compatibility with the serialized string generated by
59    * JsonCpp 1.7.4 (Ubuntu 18.04). "StripSpaces()" removes the
60    * trailing end-of-line character that was not present in the
61    * deprecated serialization classes of JsonCpp.
62    **/
63   ASSERT_EQ(Toolbox::StripSpaces(d), "{\"hello\":\"world\"}");
64   ASSERT_EQ(Toolbox::StripSpaces(f), "{\n   \"hello\" : \"world\"\n}");
65 }
66 
TEST(Toolbox,JsonComments)67 TEST(Toolbox, JsonComments)
68 {
69   std::string a = "/* a */ { /* b */ \"hello\" : /* c */ \"world\" /* d */ } // e";
70 
71   Json::Value b;
72   ASSERT_TRUE(Toolbox::ReadJsonWithoutComments(b, a));
73 
74   std::string c;
75   Toolbox::WriteFastJson(c, b);
76   ASSERT_EQ(Toolbox::StripSpaces(c), "{\"hello\":\"world\"}");
77 
78   Toolbox::WriteStyledJson(c, b);
79   ASSERT_EQ(Toolbox::StripSpaces(c), "{\n   \"hello\" : \"world\"\n}");
80 }
81 
TEST(Toolbox,Base64_allByteValues)82 TEST(Toolbox, Base64_allByteValues)
83 {
84   std::string toEncode;
85   std::string base64Result;
86   std::string decodedResult;
87 
88   size_t size = 2*256;
89   toEncode.reserve(size);
90   for (size_t i = 0; i < size; i++)
91     toEncode.push_back(i % 256);
92 
93   Toolbox::EncodeBase64(base64Result, toEncode);
94   Toolbox::DecodeBase64(decodedResult, base64Result);
95 
96   ASSERT_EQ(toEncode, decodedResult);
97 }
98 
TEST(Toolbox,Base64_multipleSizes)99 TEST(Toolbox, Base64_multipleSizes)
100 {
101   std::string toEncode;
102   std::string base64Result;
103   std::string decodedResult;
104 
105   for (size_t size = 0; size <= 5; size++)
106   {
107     printf("base64, testing size %zu\n", size);
108     toEncode.clear();
109     toEncode.reserve(size);
110     for (size_t i = 0; i < size; i++)
111       toEncode.push_back(i % 256);
112 
113     Toolbox::EncodeBase64(base64Result, toEncode);
114     Toolbox::DecodeBase64(decodedResult, base64Result);
115 
116     ASSERT_EQ(toEncode, decodedResult);
117   }
118 }
119 
EncodeBase64Bis(const std::string & s)120 static std::string EncodeBase64Bis(const std::string& s)
121 {
122   std::string result;
123   Toolbox::EncodeBase64(result, s);
124   return result;
125 }
126 
127 
TEST(Toolbox,Base64)128 TEST(Toolbox, Base64)
129 {
130   ASSERT_EQ("", EncodeBase64Bis(""));
131   ASSERT_EQ("YQ==", EncodeBase64Bis("a"));
132 
133   const std::string hello = "SGVsbG8gd29ybGQ=";
134   ASSERT_EQ(hello, EncodeBase64Bis("Hello world"));
135 
136   std::string decoded;
137   Toolbox::DecodeBase64(decoded, hello);
138   ASSERT_EQ("Hello world", decoded);
139 
140   // Invalid character
141   ASSERT_THROW(Toolbox::DecodeBase64(decoded, "?"), OrthancException);
142 
143   // All the allowed characters
144   Toolbox::DecodeBase64(decoded, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=");
145 }
146 
147 
148 #if 0 // enable only when compiling in Release with a C++ 11 compiler
149 #include <chrono> // I had troubles to link with boost::chrono ...
150 
151 TEST(Toolbox, Base64_largeString)
152 {
153   std::string toEncode;
154   std::string base64Result;
155   std::string decodedResult;
156 
157   size_t size = 10 * 1024 * 1024;
158   toEncode.reserve(size);
159   for (size_t i = 0; i < size; i++)
160     toEncode.push_back(i % 256);
161 
162   std::chrono::high_resolution_clock::time_point start;
163   std::chrono::high_resolution_clock::time_point afterEncoding;
164   std::chrono::high_resolution_clock::time_point afterDecoding;
165 
166   start = std::chrono::high_resolution_clock::now();
167   Orthanc::Toolbox::EncodeBase64(base64Result, toEncode);
168   afterEncoding = std::chrono::high_resolution_clock::now();
169   Orthanc::Toolbox::DecodeBase64(decodedResult, base64Result);
170   afterDecoding = std::chrono::high_resolution_clock::now();
171 
172   ASSERT_EQ(toEncode, decodedResult);
173 
174   printf("encoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterEncoding - start)));
175   printf("decoding took %zu ms\n", (std::chrono::duration_cast<std::chrono::milliseconds>(afterDecoding - afterEncoding)));
176 }
177 #endif
178 
179 
TEST(Toolbox,LargeHexadecimalToDecimal)180 TEST(Toolbox, LargeHexadecimalToDecimal)
181 {
182   // https://stackoverflow.com/a/16967286/881731
183   ASSERT_EQ(
184     "166089946137986168535368849184301740204613753693156360462575217560130904921953976324839782808018277000296027060873747803291797869684516494894741699267674246881622658654267131250470956587908385447044319923040838072975636163137212887824248575510341104029461758594855159174329892125993844566497176102668262139513",
185     Toolbox::LargeHexadecimalToDecimal("EC851A69B8ACD843164E10CFF70CF9E86DC2FEE3CF6F374B43C854E3342A2F1AC3E30C741CC41E679DF6D07CE6FA3A66083EC9B8C8BF3AF05D8BDBB0AA6Cb3ef8c5baa2a5e531ba9e28592f99e0fe4f95169a6c63f635d0197e325c5ec76219b907e4ebdcd401fb1986e4e3ca661ff73e7e2b8fd9988e753b7042b2bbca76679"));
186 
187   ASSERT_EQ("0", Toolbox::LargeHexadecimalToDecimal(""));
188   ASSERT_EQ("0", Toolbox::LargeHexadecimalToDecimal("0"));
189   ASSERT_EQ("0", Toolbox::LargeHexadecimalToDecimal("0000"));
190   ASSERT_EQ("255", Toolbox::LargeHexadecimalToDecimal("00000ff"));
191 
192   ASSERT_THROW(Toolbox::LargeHexadecimalToDecimal("g"), Orthanc::OrthancException);
193 }
194 
195 
TEST(Toolbox,GenerateDicomPrivateUniqueIdentifier)196 TEST(Toolbox, GenerateDicomPrivateUniqueIdentifier)
197 {
198   std::string s = Toolbox::GenerateDicomPrivateUniqueIdentifier();
199   ASSERT_EQ("2.25.", s.substr(0, 5));
200 }
201 
202 
TEST(Toolbox,UniquePtr)203 TEST(Toolbox, UniquePtr)
204 {
205   std::unique_ptr<int> i(new int(42));
206   ASSERT_EQ(42, *i);
207 
208   std::unique_ptr<SingleValueObject<int> > j(new SingleValueObject<int>(42));
209   ASSERT_EQ(42, j->GetValue());
210 }
211