40 #include <visp3/core/vpConfig.h>
42 #if defined(VISP_HAVE_NLOHMANN_JSON) && defined(VISP_HAVE_CATCH2)
45 #include <visp3/core/vpArray2D.h>
46 #include <visp3/core/vpIoTools.h>
48 #include VISP_NLOHMANN_JSON(json.hpp)
49 using json = nlohmann::json;
51 #include <catch_amalgamated.hpp>
53 #ifdef ENABLE_VISP_NAMESPACE
59 using StringMatcherBase = Catch::Matchers::StringMatcherBase;
60 class vpExceptionMatcher :
public Catch::Matchers::MatcherBase<vpException>
63 const StringMatcherBase &m_messageMatcher;
67 : m_type(type), m_messageMatcher(messageMatcher)
72 return m_type == in.getCode() && m_messageMatcher.match(in.getStringMessage());
75 std::string describe() const VP_OVERRIDE
77 std::ostringstream ss;
78 ss <<
"vpException has type " << m_type <<
" and message " << m_messageMatcher.describe();
83 class vpRandomArray2DGenerator :
public Catch::Generators::IGenerator<vpArray2D<double> >
86 std::minstd_rand m_rand;
87 std::uniform_real_distribution<> m_val_dist;
88 std::uniform_int_distribution<> m_dim_dist;
93 vpRandomArray2DGenerator(
double valueRange,
int minSize,
int maxSize)
94 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
97 static_cast<void>(next());
101 bool next() VP_OVERRIDE
103 const unsigned nCols = m_dim_dist(m_rand);
104 const unsigned nRows = m_dim_dist(m_rand);
105 current.
resize(nRows, nCols);
106 for (
unsigned i = 0; i < nRows; ++i) {
107 for (
unsigned j = 0; j < nCols; ++j) {
108 current[i][j] = m_val_dist(m_rand);
114 class vpRandomColVectorGenerator :
public Catch::Generators::IGenerator<vpColVector>
117 std::minstd_rand m_rand;
118 std::uniform_real_distribution<> m_val_dist;
119 std::uniform_int_distribution<> m_dim_dist;
124 vpRandomColVectorGenerator(
double valueRange,
int minSize,
int maxSize)
125 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
128 static_cast<void>(next());
131 const vpColVector &get() const VP_OVERRIDE {
return current; }
132 bool next() VP_OVERRIDE
134 const unsigned nRows = m_dim_dist(m_rand);
136 for (
unsigned i = 0; i < nRows; ++i) {
137 current[i] = m_val_dist(m_rand);
142 Catch::Generators::GeneratorWrapper<vpArray2D<double> > randomArray(
double v,
int minSize,
int maxSize)
144 return Catch::Generators::GeneratorWrapper<vpArray2D<double> >(Catch::Detail::make_unique<vpRandomArray2DGenerator>(v, minSize, maxSize));
146 Catch::Generators::GeneratorWrapper<vpColVector> randomColVector(
double v,
int minSize,
int maxSize)
148 return Catch::Generators::GeneratorWrapper<vpColVector>(Catch::Detail::make_unique<vpRandomColVectorGenerator>(v, minSize, maxSize));
152 return vpExceptionMatcher(type, matcher);
155 SCENARIO(
"Serializing a vpArray2D",
"[json]")
157 GIVEN(
"A random vpArray2D<double>")
160 WHEN(
"Serializing to a JSON object")
162 const json j = array;
163 THEN(
"JSON object is a dictionary") { REQUIRE(j.is_object()); }
164 THEN(
"JSON object contains correct number of columns")
166 REQUIRE(j.at(
"cols").get<
unsigned int>() == array.
getCols());
168 THEN(
"JSON object contains correct number of rows")
170 REQUIRE(j.at(
"rows").get<
unsigned int>() == array.
getRows());
172 THEN(
"JSON object contains the array values")
174 const json jData = j.at(
"data");
175 THEN(
"The data field is an array") { REQUIRE(jData.is_array()); }
176 THEN(
"The data field contains the correct number of values") { REQUIRE(jData.size() == array.
size()); }
177 THEN(
"The data field contains the correct number of values")
179 const double *
const start = array[0];
180 const std::vector<double> vec(start, start + array.
size());
181 REQUIRE(vec == jData.get<std::vector<double> >());
188 SCENARIO(
"Trying to instantiate a vpArray with a wrong type of object",
"[json]")
190 GIVEN(
"A random scalar converted to a JSON representation")
193 std::uniform_real_distribution<> dist;
194 const json j = GENERATE(take(50, random(-200.0, 200.0)));
195 THEN(
"An exception is thrown")
197 const auto matcher = Catch::Matchers::ContainsSubstring(
"is not an array or object");
203 SCENARIO(
"Recovering a vpArray2D from a JSON array",
"[json]")
205 GIVEN(
"An empty array")
207 const json j = json::array_t();
208 WHEN(
"Converting to a vpArray2D")
211 THEN(
"The resulting array is empty") { REQUIRE(array.
size() == 0); }
216 const json j = { 10.0, 20.0, 30.0 };
217 WHEN(
"Converting to a vpArray2D")
219 THEN(
"An exception is thrown, since this is an ambiguous array")
222 const auto matcher = Catch::Matchers::ContainsSubstring(
"is not an array of array");
227 GIVEN(
"A vpArray2D converted to a json 2D array")
231 for (
unsigned i = 0; i < array.
getRows(); ++i) {
233 for (
unsigned j = 0; j < array.
getCols(); ++j) {
234 jRow.push_back(array[i][j]);
238 WHEN(
"Converting back to a vpArray2D")
241 THEN(
"The values are correct") { REQUIRE(array == array2); }
243 WHEN(
"Removing elements from rows so that they do not have the same size")
246 THEN(
"An exception is thrown")
248 const auto matcher = Catch::Matchers::ContainsSubstring(
"row arrays that are not of the same size");
255 SCENARIO(
"Recovering a vpArray2D from a JSON object as serialized by ViSP",
"[json]")
257 GIVEN(
"A vpArray2D converted to JSON format")
261 WHEN(
"Converting back to a vpArray2D")
264 THEN(
"The 2 arrays are equal") { REQUIRE(array == array2); }
266 WHEN(
"Removing or adding some values from the data field so that its size does not match the expected array size")
268 j.at(
"data").erase(0);
269 THEN(
"An exception is thrown")
272 const auto matcher = Catch::Matchers::ContainsSubstring(
"must be an array of size");
279 SCENARIO(
"Serializing and deserializing a vpColVector",
"[json]")
281 GIVEN(
"A random vpColVector")
283 const vpColVector v = GENERATE(take(100, randomColVector(100.0, 1, 50)));
284 WHEN(
"Serializing to JSON")
287 THEN(
"There is only one column") { REQUIRE(j.at(
"cols") == 1); }
288 THEN(
"The type is vpColVector") { REQUIRE(j.at(
"type") ==
"vpColVector"); }
289 WHEN(
"Deserializing back to a vpColVector")
292 THEN(
"The 2 vectors are the same") { REQUIRE(v == v2); }
296 GIVEN(
"A random 2D array with number of cols > 1")
299 WHEN(
"Serializing this array to JSON")
301 const json j = array;
302 THEN(
"Serializing back to a vpColVector throws an exception")
305 const auto matcher = Catch::Matchers::ContainsSubstring(
"tried to read a 2D array into a vpColVector");
310 GIVEN(
"A random 2D array with number of cols = 1")
312 const vpColVector v = GENERATE(take(10, randomColVector(100.0, 1, 50)));
314 WHEN(
"Serializing this array to JSON")
316 const json j = array;
317 THEN(
"Serializing back to a vpColVector is ok and gives the same vector")
326 int main(
int argc,
char *argv[])
328 Catch::Session session;
329 session.applyCommandLine(argc, argv);
330 int numFailed = session.run();
336 int main() {
return EXIT_SUCCESS; }
unsigned int getCols() const
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
unsigned int size() const
Return the number of elements of the 2D array.
unsigned int getRows() const
Implementation of column vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)
error that can be emitted by ViSP classes.
@ badValue
Used to indicate that a value is not in the allowed range.