42 #include <visp3/core/vpConfig.h>
44 #if defined(VISP_HAVE_NLOHMANN_JSON) && defined(VISP_HAVE_CATCH2)
47 #include <visp3/core/vpArray2D.h>
48 #include <visp3/core/vpIoTools.h>
50 #include <nlohmann/json.hpp>
51 using json = nlohmann::json;
53 #define CATCH_CONFIG_RUNNER
58 using StringMatcherBase = Catch::Matchers::StdString::StringMatcherBase;
59 class vpExceptionMatcher :
public Catch::Matchers::Impl::MatcherBase<vpException>
62 const StringMatcherBase &m_messageMatcher;
66 : m_type(type), m_messageMatcher(messageMatcher)
71 return m_type == in.getCode() && m_messageMatcher.match(in.getStringMessage());
74 std::string describe() const vp_override
76 std::ostringstream ss;
77 ss <<
"vpException has type " << m_type <<
" and message " << m_messageMatcher.describe();
82 class vpRandomArray2DGenerator :
public Catch::Generators::IGenerator<vpArray2D<double> >
85 std::minstd_rand m_rand;
86 std::uniform_real_distribution<> m_val_dist;
87 std::uniform_int_distribution<> m_dim_dist;
92 vpRandomArray2DGenerator(
double valueRange,
int minSize,
int maxSize)
93 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
96 static_cast<void>(next());
100 bool next() vp_override
102 const unsigned nCols = m_dim_dist(m_rand);
103 const unsigned nRows = m_dim_dist(m_rand);
104 current.
resize(nRows, nCols);
105 for (
unsigned i = 0; i < nRows; ++i) {
106 for (
unsigned j = 0; j < nCols; ++j) {
107 current[i][j] = m_val_dist(m_rand);
113 class vpRandomColVectorGenerator :
public Catch::Generators::IGenerator<vpColVector>
116 std::minstd_rand m_rand;
117 std::uniform_real_distribution<> m_val_dist;
118 std::uniform_int_distribution<> m_dim_dist;
123 vpRandomColVectorGenerator(
double valueRange,
int minSize,
int maxSize)
124 : m_rand(std::random_device {}()), m_val_dist(-valueRange, valueRange), m_dim_dist(minSize, maxSize)
127 static_cast<void>(next());
130 const vpColVector &get() const vp_override {
return current; }
131 bool next() vp_override
133 const unsigned nRows = m_dim_dist(m_rand);
135 for (
unsigned i = 0; i < nRows; ++i) {
136 current[i] = m_val_dist(m_rand);
141 Catch::Generators::GeneratorWrapper<vpArray2D<double> > randomArray(
double v,
int minSize,
int maxSize)
143 return Catch::Generators::GeneratorWrapper<vpArray2D<double> >(
144 std::unique_ptr<Catch::Generators::IGenerator<vpArray2D<double> > >(
145 new vpRandomArray2DGenerator(v, minSize, maxSize)));
147 Catch::Generators::GeneratorWrapper<vpColVector> randomColVector(
double v,
int minSize,
int maxSize)
149 return Catch::Generators::GeneratorWrapper<vpColVector>(
150 std::unique_ptr<Catch::Generators::IGenerator<vpColVector> >(
new vpRandomColVectorGenerator(v, minSize, maxSize)));
154 return vpExceptionMatcher(type, matcher);
157 SCENARIO(
"Serializing a vpArray2D",
"[json]")
159 GIVEN(
"A random vpArray2D<double>")
162 WHEN(
"Serializing to a JSON object")
164 const json j = array;
165 THEN(
"JSON object is a dictionary") { REQUIRE(j.is_object()); }
166 THEN(
"JSON object contains correct number of columns")
168 REQUIRE(j.at(
"cols").get<
unsigned int>() == array.
getCols());
170 THEN(
"JSON object contains correct number of rows")
172 REQUIRE(j.at(
"rows").get<
unsigned int>() == array.
getRows());
174 THEN(
"JSON object contains the array values")
176 const json jData = j.at(
"data");
177 THEN(
"The data field is an array") { REQUIRE(jData.is_array()); }
178 THEN(
"The data field contains the correct number of values") { REQUIRE(jData.size() == array.
size()); }
179 THEN(
"The data field contains the correct number of values")
181 const double *
const start = array[0];
182 const std::vector<double> vec(start, start + array.
size());
183 REQUIRE(vec == jData.get<std::vector<double> >());
190 SCENARIO(
"Trying to instantiate a vpArray with a wrong type of object",
"[json]")
192 GIVEN(
"A random scalar converted to a JSON representation")
195 std::minstd_rand rand;
196 std::uniform_real_distribution<> dist;
197 const json j = GENERATE(take(50, random(-200.0, 200.0)));
198 THEN(
"An exception is thrown")
200 const auto matcher = Catch::Matchers::Contains(
"is not an array or object");
206 SCENARIO(
"Recovering a vpArray2D from a JSON array",
"[json]")
208 GIVEN(
"An empty array")
210 const json j = json::array_t();
211 WHEN(
"Converting to a vpArray2D")
214 THEN(
"The resulting array is empty") { REQUIRE(array.
size() == 0); }
219 const json j = { 10.0, 20.0, 30.0 };
220 WHEN(
"Converting to a vpArray2D")
222 THEN(
"An exception is thrown, since this is an ambiguous array")
225 const auto matcher = Catch::Matchers::Contains(
"is not an array of array");
230 GIVEN(
"A vpArray2D converted to a json 2D array")
234 for (
unsigned i = 0; i < array.
getRows(); ++i) {
236 for (
unsigned j = 0; j < array.
getCols(); ++j) {
237 jRow.push_back(array[i][j]);
241 WHEN(
"Converting back to a vpArray2D")
244 THEN(
"The values are correct") { REQUIRE(array == array2); }
246 WHEN(
"Removing elements from rows so that they do not have the same size")
249 THEN(
"An exception is thrown")
251 const auto matcher = Catch::Matchers::Contains(
"row arrays that are not of the same size");
258 SCENARIO(
"Recovering a vpArray2D from a JSON object as serialized by ViSP",
"[json]")
260 GIVEN(
"A vpArray2D converted to JSON format")
264 WHEN(
"Converting back to a vpArray2D")
267 THEN(
"The 2 arrays are equal") { REQUIRE(array == array2); }
269 WHEN(
"Removing or adding some values from the data field so that its size does not match the expected array size")
271 j.at(
"data").erase(0);
272 THEN(
"An exception is thrown")
275 const auto matcher = Catch::Matchers::Contains(
"must be an array of size");
282 SCENARIO(
"Serializing and deserializing a vpColVector",
"[json]")
284 GIVEN(
"A random vpColVector")
286 const vpColVector v = GENERATE(take(100, randomColVector(100.0, 1, 50)));
287 WHEN(
"Serializing to JSON")
290 THEN(
"There is only one column") { REQUIRE(j.at(
"cols") == 1); }
291 THEN(
"The type is vpColVector") { REQUIRE(j.at(
"type") ==
"vpColVector"); }
292 WHEN(
"Deserializing back to a vpColVector")
295 THEN(
"The 2 vectors are the same") { REQUIRE(v == v2); }
299 GIVEN(
"A random 2D array with number of cols > 1")
302 WHEN(
"Serializing this array to JSON")
304 const json j = array;
305 THEN(
"Serializing back to a vpColVector throws an exception")
308 const auto matcher = Catch::Matchers::Contains(
"tried to read a 2D array into a vpColVector");
313 GIVEN(
"A random 2D array with number of cols = 1")
315 const vpColVector v = GENERATE(take(10, randomColVector(100.0, 1, 50)));
317 WHEN(
"Serializing this array to JSON")
319 const json j = array;
320 THEN(
"Serializing back to a vpColVector is ok and gives the same vector")
329 int main(
int argc,
char *argv[])
331 Catch::Session session;
332 session.applyCommandLine(argc, argv);
334 int numFailed = session.run();
340 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.