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)
49using json = nlohmann::json;
51#include <catch_amalgamated.hpp>
53#ifdef ENABLE_VISP_NAMESPACE
59using StringMatcherBase = Catch::Matchers::StringMatcherBase;
60class vpExceptionMatcher :
public Catch::Matchers::MatcherBase<vpException>
63 const StringMatcherBase &m_messageMatcher;
67 : m_type(
type), m_messageMatcher(messageMatcher)
70 bool match(vpException
const &in)
const VP_OVERRIDE
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();
83class 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;
90 vpArray2D<double> current;
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());
100 vpArray2D<double>
const &get() const VP_OVERRIDE {
return current; }
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);
114class 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);
142Catch::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));
146Catch::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);
155SCENARIO(
"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> >());
188SCENARIO(
"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");
203SCENARIO(
"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");
255SCENARIO(
"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");
279SCENARIO(
"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")
326int main(
int argc,
char *argv[])
328 Catch::Session session;
329 session.applyCommandLine(argc, argv);
330 int numFailed = session.run();
336int main() {
return EXIT_SUCCESS; }
Implementation of a generic 2D array used as base class for matrices and vectors.
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.