add_subdirectory(samples)\r
endif()\r
\r
-if(BUILD_TESTS)\r
- enable_testing()\r
- add_subdirectory(tests)\r
-endif()\r
+#if(BUILD_TESTS)\r
+# enable_testing()\r
+# add_subdirectory(tests)\r
+#endif()\r
\r
add_subdirectory(3rdparty)\r
\r
DESTINATION include/opencv2/${name}
COMPONENT main)
- if(BUILD_TESTS AND NOT ANDROID AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test)
+ if(BUILD_TESTS AND NOT ANDROID AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test)
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/test"
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${CMAKE_SOURCE_DIR}/modules/gtest/include")
+ "${CMAKE_CURRENT_BINARY_DIR}")
- foreach(d ${ARGN})
+ set(test_deps opencv_${name} ${ARGN} opencv_ts opencv_highgui ${EXTRA_${the_target}_DEPS})
+ foreach(d ${test_deps})
if(${d} MATCHES "opencv_")
if(${d} MATCHES "opencv_lapack")
else()
file(GLOB test_srcs "test/*.cpp")
file(GLOB test_hdrs "test/*.h*")
- set(the_target "opencv_gtest_${name}")
+ set(the_target "opencv_test_${name}")
add_executable(${the_target} ${test_srcs} ${test_hdrs})
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
)
- add_dependencies(${the_target} ${ARGN} opencv_gtest)
+ add_dependencies(${the_target} ${test_deps})
# Add the required libraries for linking:
- target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${ARGN} opencv_gtest)
+ target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${test_deps})
enable_testing()
get_target_property(LOC ${the_target} LOCATION)
endif()
endmacro()
-
-if(0)
-macro(define_opencv_test name)
-
- if(BUILD_TESTS AND NOT ANDROID AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test)
- include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include"
- "${CMAKE_CURRENT_SOURCE_DIR}/test"
- "${CMAKE_CURRENT_BINARY_DIR}"
- "${CMAKE_SOURCE_DIR}/modules/gtest/include")
-
- foreach(d ${ARGN})
- if(${d} MATCHES "opencv_")
- if(${d} MATCHES "opencv_lapack")
- else()
- string(REPLACE "opencv_" "${CMAKE_CURRENT_SOURCE_DIR}/../" d_dir ${d})
- include_directories("${d_dir}/include")
- endif()
- endif()
- endforeach()
-
- file(GLOB test_srcs "test/*.cpp")
- file(GLOB test_hdrs "test/*.h*")
-
- set(the_target "opencv_gtest_${name}")
-
- add_executable(${the_target} ${test_srcs} ${test_hdrs})
-
- if(PCHSupport_FOUND)
- set(pch_header ${CMAKE_CURRENT_SOURCE_DIR}/test/precomp.hpp)
- if(${CMAKE_GENERATOR} MATCHES "Visual*" OR ${CMAKE_GENERATOR} MATCHES "Xcode*")
- if(${CMAKE_GENERATOR} MATCHES "Visual*")
- set(${the_target}_pch "test/precomp.cpp")
- endif()
- add_native_precompiled_header(${the_target} ${pch_header})
- elseif(CMAKE_COMPILER_IS_GNUCXX AND ${CMAKE_GENERATOR} MATCHES ".*Makefiles")
- add_precompiled_header(${the_target} ${pch_header})
- endif()
- endif()
-
- # Additional target properties
- set_target_properties(${the_target} PROPERTIES
- DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}"
- RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/"
- )
-
- add_dependencies(${the_target} ${ARGN} opencv_gtest)
-
- # Add the required libraries for linking:
- target_link_libraries(${the_target} ${OPENCV_LINKER_LIBS} ${ARGN} opencv_gtest)
-
- enable_testing()
- get_target_property(LOC ${the_target} LOCATION)
- add_test(${the_target} "${LOC}")
-
- if(WIN32)
- install(TARGETS ${the_target} RUNTIME DESTINATION bin COMPONENT main)
- endif()
- endif()
-
-endmacro()
-endif()
-
-
endif()
endif()
-add_subdirectory(gtest)
+add_subdirectory(ts)
add_subdirectory(highgui)
add_subdirectory(imgproc)
add_subdirectory(legacy)
int flags=CALIB_CB_ADAPTIVE_THRESH+
CALIB_CB_NORMALIZE_IMAGE );
+//! finds subpixel-accurate positions of the chessboard corners
+CV_EXPORTS bool find4QuadCornerSubpix(const Mat& img, std::vector<Point2f>& corners,
+ Size region_size);
+
//! draws the checkerboard pattern (found or partly found) in the image
CV_EXPORTS_W void drawChessboardCorners( Mat& image, Size patternSize,
const Mat& corners,
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+class CV_Affine3D_EstTest : public cvtest::BaseTest
+{
+public:
+ CV_Affine3D_EstTest();
+ ~CV_Affine3D_EstTest();
+protected:
+ void run(int);
+
+ bool test4Points();
+ bool testNPoints();
+};
+
+CV_Affine3D_EstTest::CV_Affine3D_EstTest()
+{
+}
+CV_Affine3D_EstTest::~CV_Affine3D_EstTest() {}
+
+
+float rngIn(float from, float to) { return from + (to-from) * (float)theRNG(); }
+
+
+struct WrapAff
+{
+ const double *F;
+ WrapAff(const Mat& aff) : F(aff.ptr<double>()) {}
+ Point3f operator()(const Point3f& p)
+ {
+ return Point3d( p.x * F[0] + p.y * F[1] + p.z * F[2] + F[3],
+ p.x * F[4] + p.y * F[5] + p.z * F[6] + F[7],
+ p.x * F[8] + p.y * F[9] + p.z * F[10] + F[11] );
+ }
+};
+
+bool CV_Affine3D_EstTest::test4Points()
+{
+ Mat aff(3, 4, CV_64F);
+ cv::randu(aff, Scalar(1), Scalar(3));
+
+ // setting points that are no in the same line
+
+ Mat fpts(1, 4, CV_32FC3);
+ Mat tpts(1, 4, CV_32FC3);
+
+ fpts.ptr<Point3f>()[0] = Point3f( rngIn(1,2), rngIn(1,2), rngIn(5, 6) );
+ fpts.ptr<Point3f>()[1] = Point3f( rngIn(3,4), rngIn(3,4), rngIn(5, 6) );
+ fpts.ptr<Point3f>()[2] = Point3f( rngIn(1,2), rngIn(3,4), rngIn(5, 6) );
+ fpts.ptr<Point3f>()[3] = Point3f( rngIn(3,4), rngIn(1,2), rngIn(5, 6) );
+
+ transform(fpts.ptr<Point3f>(), fpts.ptr<Point3f>() + 4, tpts.ptr<Point3f>(), WrapAff(aff));
+
+ Mat aff_est;
+ vector<uchar> outliers;
+ estimateAffine3D(fpts, tpts, aff_est, outliers);
+
+ const double thres = 1e-3;
+ if (norm(aff_est, aff, NORM_INF) > thres)
+ {
+ //cout << norm(aff_est, aff, NORM_INF) << endl;
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+struct Noise
+{
+ float l;
+ Noise(float level) : l(level) {}
+ Point3f operator()(const Point3f& p)
+ {
+ RNG& rng = theRNG();
+ return Point3f( p.x + l * (float)rng, p.y + l * (float)rng, p.z + l * (float)rng);
+ }
+};
+
+bool CV_Affine3D_EstTest::testNPoints()
+{
+ Mat aff(3, 4, CV_64F);
+ cv::randu(aff, Scalar(-2), Scalar(2));
+
+ // setting points that are no in the same line
+
+ const int n = 100;
+ const int m = 3*n/5;
+ const Point3f shift_outl = Point3f(15, 15, 15);
+ const float noise_level = 20.f;
+
+ Mat fpts(1, n, CV_32FC3);
+ Mat tpts(1, n, CV_32FC3);
+
+ randu(fpts, Scalar::all(0), Scalar::all(100));
+ transform(fpts.ptr<Point3f>(), fpts.ptr<Point3f>() + n, tpts.ptr<Point3f>(), WrapAff(aff));
+
+ /* adding noise*/
+ transform(tpts.ptr<Point3f>() + m, tpts.ptr<Point3f>() + n, tpts.ptr<Point3f>() + m, bind2nd(plus<Point3f>(), shift_outl));
+ transform(tpts.ptr<Point3f>() + m, tpts.ptr<Point3f>() + n, tpts.ptr<Point3f>() + m, Noise(noise_level));
+
+ Mat aff_est;
+ vector<uchar> outl;
+ int res = estimateAffine3D(fpts, tpts, aff_est, outl);
+
+ if (!res)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+
+ const double thres = 1e-4;
+ if (norm(aff_est, aff, NORM_INF) > thres)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+
+ bool outl_good = count(outl.begin(), outl.end(), 1) == m &&
+ m == accumulate(outl.begin(), outl.begin() + m, 0);
+
+ if (!outl_good)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+
+void CV_Affine3D_EstTest::run( int /* start_from */)
+{
+ cvtest::DefaultRngAuto dra;
+
+ if (!test4Points())
+ return;
+
+ if (!testNPoints())
+ return;
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Calib3d_EstimateAffineTransform, accuracy) { CV_Affine3D_EstTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <limits>
+
+#if 0
+class CV_ProjectPointsTest : public cvtest::ArrayTest
+{
+public:
+ CV_ProjectPointsTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+ int prepare_test_case( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ bool calc_jacobians;
+};
+
+
+CV_ProjectPointsTest::CV_ProjectPointsTest()
+ : cvtest::ArrayTest( "3d-ProjectPoints", "cvProjectPoints2", "" )
+{
+ test_array[INPUT].push_back(NULL); // rotation vector
+ test_array[OUTPUT].push_back(NULL); // rotation matrix
+ test_array[OUTPUT].push_back(NULL); // jacobian (J)
+ test_array[OUTPUT].push_back(NULL); // rotation vector (backward transform result)
+ test_array[OUTPUT].push_back(NULL); // inverse transform jacobian (J1)
+ test_array[OUTPUT].push_back(NULL); // J*J1 (or J1*J) == I(3x3)
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+
+ element_wise_relative_error = false;
+ calc_jacobians = false;
+}
+
+
+int CV_ProjectPointsTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_ProjectPointsTest::get_test_array_types_and_sizes(
+ int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ int i, code;
+
+ code = cvtest::randInt(rng) % 3;
+ types[INPUT][0] = CV_MAKETYPE(depth, 1);
+
+ if( code == 0 )
+ {
+ sizes[INPUT][0] = cvSize(1,1);
+ types[INPUT][0] = CV_MAKETYPE(depth, 3);
+ }
+ else if( code == 1 )
+ sizes[INPUT][0] = cvSize(3,1);
+ else
+ sizes[INPUT][0] = cvSize(1,3);
+
+ sizes[OUTPUT][0] = cvSize(3, 3);
+ types[OUTPUT][0] = CV_MAKETYPE(depth, 1);
+
+ types[OUTPUT][1] = CV_MAKETYPE(depth, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][1] = cvSize(3,9);
+ else
+ sizes[OUTPUT][1] = cvSize(9,3);
+
+ types[OUTPUT][2] = types[INPUT][0];
+ sizes[OUTPUT][2] = sizes[INPUT][0];
+
+ types[OUTPUT][3] = types[OUTPUT][1];
+ sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width);
+
+ types[OUTPUT][4] = types[OUTPUT][1];
+ sizes[OUTPUT][4] = cvSize(3,3);
+
+ calc_jacobians = 1;//cvtest::randInt(rng) % 3 != 0;
+ if( !calc_jacobians )
+ sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0);
+
+ for( i = 0; i < 5; i++ )
+ {
+ types[REF_OUTPUT][i] = types[OUTPUT][i];
+ sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
+ }
+}
+
+
+double CV_ProjectPointsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
+{
+ return j == 4 ? 1e-2 : 1e-2;
+}
+
+
+void CV_ProjectPointsTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, CvMat* arr )
+{
+ double r[3], theta0, theta1, f;
+ CvMat _r = cvMat( arr->rows, arr->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(arr->type)), r );
+ RNG& rng = ts->get_rng();
+
+ r[0] = cvtest::randReal(rng)*CV_PI*2;
+ r[1] = cvtest::randReal(rng)*CV_PI*2;
+ r[2] = cvtest::randReal(rng)*CV_PI*2;
+
+ theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
+ theta1 = fmod(theta0, CV_PI*2);
+
+ if( theta1 > CV_PI )
+ theta1 = -(CV_PI*2 - theta1);
+
+ f = theta1/(theta0 ? theta0 : 1);
+ r[0] *= f;
+ r[1] *= f;
+ r[2] *= f;
+
+ cvTsConvert( &_r, arr );
+}
+
+
+int CV_ProjectPointsTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ return code;
+}
+
+
+void CV_ProjectPointsTest::run_func()
+{
+ CvMat *v2m_jac = 0, *m2v_jac = 0;
+ if( calc_jacobians )
+ {
+ v2m_jac = &test_mat[OUTPUT][1];
+ m2v_jac = &test_mat[OUTPUT][3];
+ }
+
+ cvProjectPoints2( &test_mat[INPUT][0], &test_mat[OUTPUT][0], v2m_jac );
+ cvProjectPoints2( &test_mat[OUTPUT][0], &test_mat[OUTPUT][2], m2v_jac );
+}
+
+
+void CV_ProjectPointsTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const CvMat* vec = &test_mat[INPUT][0];
+ CvMat* m = &test_mat[REF_OUTPUT][0];
+ CvMat* vec2 = &test_mat[REF_OUTPUT][2];
+ CvMat* v2m_jac = 0, *m2v_jac = 0;
+ double theta0, theta1;
+
+ if( calc_jacobians )
+ {
+ v2m_jac = &test_mat[REF_OUTPUT][1];
+ m2v_jac = &test_mat[REF_OUTPUT][3];
+ }
+
+
+ cvTsProjectPoints( vec, m, v2m_jac );
+ cvTsProjectPoints( m, vec2, m2v_jac );
+ cvTsCopy( vec, vec2 );
+
+ theta0 = cvNorm( vec2, 0, CV_L2 );
+ theta1 = fmod( theta0, CV_PI*2 );
+
+ if( theta1 > CV_PI )
+ theta1 = -(CV_PI*2 - theta1);
+ cvScale( vec2, vec2, theta1/(theta0 ? theta0 : 1) );
+
+ if( calc_jacobians )
+ {
+ //cvInvert( v2m_jac, m2v_jac, CV_SVD );
+ if( cvNorm(&test_mat[OUTPUT][3],0,CV_C) < 1000 )
+ {
+ cvTsGEMM( &test_mat[OUTPUT][1], &test_mat[OUTPUT][3],
+ 1, 0, 0, &test_mat[OUTPUT][4],
+ v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T );
+ }
+ else
+ {
+ cvTsSetIdentity( &test_mat[OUTPUT][4], cvScalarAll(1.) );
+ cvTsCopy( &test_mat[REF_OUTPUT][2], &test_mat[OUTPUT][2] );
+ }
+ cvTsSetIdentity( &test_mat[REF_OUTPUT][4], cvScalarAll(1.) );
+ }
+}
+
+
+CV_ProjectPointsTest ProjectPoints_test;
+
+#endif
+
+using namespace cv;
+
+// --------------------------------- CV_CameraCalibrationTest --------------------------------------------
+
+class CV_CameraCalibrationTest : public cvtest::BaseTest
+{
+public:
+ CV_CameraCalibrationTest();
+ ~CV_CameraCalibrationTest();
+ void clear();
+protected:
+ int compare(double* val, double* refVal, int len,
+ double eps, const char* paramName);
+ virtual void calibrate( int imageCount, int* pointCounts,
+ CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
+ double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
+ double* rotationMatrices, int flags ) = 0;
+ virtual void project( int pointCount, CvPoint3D64f* objectPoints,
+ double* rotationMatrix, double* translationVector,
+ double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints ) = 0;
+
+ void run(int);
+};
+
+CV_CameraCalibrationTest::CV_CameraCalibrationTest()
+{
+}
+
+CV_CameraCalibrationTest::~CV_CameraCalibrationTest()
+{
+ clear();
+}
+
+void CV_CameraCalibrationTest::clear()
+{
+ cvtest::BaseTest::clear();
+}
+
+int CV_CameraCalibrationTest::compare(double* val, double* ref_val, int len,
+ double eps, const char* param_name )
+{
+ return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name );
+}
+
+void CV_CameraCalibrationTest::run( int start_from )
+{
+ int code = cvtest::TS::OK;
+ char filepath[200];
+ char filename[200];
+
+ CvSize imageSize;
+ CvSize etalonSize;
+ int numImages;
+
+ CvPoint2D64f* imagePoints;
+ CvPoint3D64f* objectPoints;
+ CvPoint2D64f* reprojectPoints;
+
+ double* transVects;
+ double* rotMatrs;
+
+ double* goodTransVects;
+ double* goodRotMatrs;
+
+ double cameraMatrix[3*3];
+ double distortion[5]={0,0,0,0,0};
+
+ double goodDistortion[4];
+
+ int* numbers;
+ FILE* file = 0;
+ FILE* datafile = 0;
+ int i,j;
+ int currImage;
+ int currPoint;
+
+ int calibFlags;
+ char i_dat_file[100];
+ int numPoints;
+ int numTests;
+ int currTest;
+
+ imagePoints = 0;
+ objectPoints = 0;
+ reprojectPoints = 0;
+ numbers = 0;
+
+ transVects = 0;
+ rotMatrs = 0;
+ goodTransVects = 0;
+ goodRotMatrs = 0;
+ int progress = 0;
+
+ sprintf( filepath, "%scameracalibration/", ts->get_data_path().c_str() );
+ sprintf( filename, "%sdatafiles.txt", filepath );
+ datafile = fopen( filename, "r" );
+ if( datafile == 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Could not open file with list of test files: %s\n", filename );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ fscanf(datafile,"%d",&numTests);
+
+ for( currTest = start_from; currTest < numTests; currTest++ )
+ {
+ fscanf(datafile,"%s",i_dat_file);
+ sprintf(filename, "%s%s", filepath, i_dat_file);
+ file = fopen(filename,"r");
+
+ ts->update_context( this, currTest, true );
+
+ if( file == 0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Can't open current test file: %s\n",filename);
+ if( numTests == 1 )
+ {
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+ continue; // if there is more than one test, just skip the test
+ }
+
+ fscanf(file,"%d %d\n",&(imageSize.width),&(imageSize.height));
+ if( imageSize.width <= 0 || imageSize.height <= 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Image size in test file is incorrect\n" );
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ goto _exit_;
+ }
+
+ /* Read etalon size */
+ fscanf(file,"%d %d\n",&(etalonSize.width),&(etalonSize.height));
+ if( etalonSize.width <= 0 || etalonSize.height <= 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Pattern size in test file is incorrect\n" );
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ goto _exit_;
+ }
+
+ numPoints = etalonSize.width * etalonSize.height;
+
+ /* Read number of images */
+ fscanf(file,"%d\n",&numImages);
+ if( numImages <=0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Number of images in test file is incorrect\n");
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ goto _exit_;
+ }
+
+ /* Need to allocate memory */
+ imagePoints = (CvPoint2D64f*)cvAlloc( numPoints *
+ numImages * sizeof(CvPoint2D64f));
+
+ objectPoints = (CvPoint3D64f*)cvAlloc( numPoints *
+ numImages * sizeof(CvPoint3D64f));
+
+ reprojectPoints = (CvPoint2D64f*)cvAlloc( numPoints *
+ numImages * sizeof(CvPoint2D64f));
+
+ /* Alloc memory for numbers */
+ numbers = (int*)cvAlloc( numImages * sizeof(int));
+
+ /* Fill it by numbers of points of each image*/
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ numbers[currImage] = etalonSize.width * etalonSize.height;
+ }
+
+ /* Allocate memory for translate vectors and rotmatrixs*/
+ transVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
+ rotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
+
+ goodTransVects = (double*)cvAlloc(3 * 1 * numImages * sizeof(double));
+ goodRotMatrs = (double*)cvAlloc(3 * 3 * numImages * sizeof(double));
+
+ /* Read object points */
+ i = 0;/* shift for current point */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ double x,y,z;
+ fscanf(file,"%lf %lf %lf\n",&x,&y,&z);
+
+ (objectPoints+i)->x = x;
+ (objectPoints+i)->y = y;
+ (objectPoints+i)->z = z;
+ i++;
+ }
+ }
+
+ /* Read image points */
+ i = 0;/* shift for current point */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( currPoint = 0; currPoint < numPoints; currPoint++ )
+ {
+ double x,y;
+ fscanf(file,"%lf %lf\n",&x,&y);
+
+ (imagePoints+i)->x = x;
+ (imagePoints+i)->y = y;
+ i++;
+ }
+ }
+
+ /* Read good data computed before */
+
+ /* Focal lengths */
+ double goodFcx,goodFcy;
+ fscanf(file,"%lf %lf",&goodFcx,&goodFcy);
+
+ /* Principal points */
+ double goodCx,goodCy;
+ fscanf(file,"%lf %lf",&goodCx,&goodCy);
+
+ /* Read distortion */
+
+ fscanf(file,"%lf",goodDistortion+0);
+ fscanf(file,"%lf",goodDistortion+1);
+ fscanf(file,"%lf",goodDistortion+2);
+ fscanf(file,"%lf",goodDistortion+3);
+
+ /* Read good Rot matrixes */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( i = 0; i < 3; i++ )
+ for( j = 0; j < 3; j++ )
+ fscanf(file, "%lf", goodRotMatrs + currImage * 9 + j * 3 + i);
+ }
+
+ /* Read good Trans vectors */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( i = 0; i < 3; i++ )
+ fscanf(file, "%lf", goodTransVects + currImage * 3 + i);
+ }
+
+ calibFlags = 0
+ // + CV_CALIB_FIX_PRINCIPAL_POINT
+ // + CV_CALIB_ZERO_TANGENT_DIST
+ // + CV_CALIB_FIX_ASPECT_RATIO
+ // + CV_CALIB_USE_INTRINSIC_GUESS
+ + CV_CALIB_FIX_K3
+ + CV_CALIB_FIX_K4+CV_CALIB_FIX_K5
+ + CV_CALIB_FIX_K6
+ ;
+ memset( cameraMatrix, 0, 9*sizeof(cameraMatrix[0]) );
+ cameraMatrix[0] = cameraMatrix[4] = 807.;
+ cameraMatrix[2] = (imageSize.width - 1)*0.5;
+ cameraMatrix[5] = (imageSize.height - 1)*0.5;
+ cameraMatrix[8] = 1.;
+
+ /* Now we can calibrate camera */
+ calibrate( numImages,
+ numbers,
+ imageSize,
+ imagePoints,
+ objectPoints,
+ distortion,
+ cameraMatrix,
+ transVects,
+ rotMatrs,
+ calibFlags );
+
+ /* ---- Reproject points to the image ---- */
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ int numPoints = etalonSize.width * etalonSize.height;
+ project( numPoints,
+ objectPoints + currImage * numPoints,
+ rotMatrs + currImage * 9,
+ transVects + currImage * 3,
+ cameraMatrix,
+ distortion,
+ reprojectPoints + currImage * numPoints);
+ }
+
+ /* ----- Compute reprojection error ----- */
+ i = 0;
+ double dx,dy;
+ double rx,ry;
+ double meanDx,meanDy;
+ double maxDx = 0.0;
+ double maxDy = 0.0;
+
+ meanDx = 0;
+ meanDy = 0;
+ for( currImage = 0; currImage < numImages; currImage++ )
+ {
+ for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ )
+ {
+ rx = reprojectPoints[i].x;
+ ry = reprojectPoints[i].y;
+ dx = rx - imagePoints[i].x;
+ dy = ry - imagePoints[i].y;
+
+ meanDx += dx;
+ meanDy += dy;
+
+ dx = fabs(dx);
+ dy = fabs(dy);
+
+ if( dx > maxDx )
+ maxDx = dx;
+
+ if( dy > maxDy )
+ maxDy = dy;
+ i++;
+ }
+ }
+
+ meanDx /= numImages * etalonSize.width * etalonSize.height;
+ meanDy /= numImages * etalonSize.width * etalonSize.height;
+
+ /* ========= Compare parameters ========= */
+
+ /* ----- Compare focal lengths ----- */
+ code = compare(cameraMatrix+0,&goodFcx,1,0.1,"fx");
+ if( code < 0 )
+ goto _exit_;
+
+ code = compare(cameraMatrix+4,&goodFcy,1,0.1,"fy");
+ if( code < 0 )
+ goto _exit_;
+
+ /* ----- Compare principal points ----- */
+ code = compare(cameraMatrix+2,&goodCx,1,0.1,"cx");
+ if( code < 0 )
+ goto _exit_;
+
+ code = compare(cameraMatrix+5,&goodCy,1,0.1,"cy");
+ if( code < 0 )
+ goto _exit_;
+
+ /* ----- Compare distortion ----- */
+ code = compare(distortion,goodDistortion,4,0.1,"[k1,k2,p1,p2]");
+ if( code < 0 )
+ goto _exit_;
+
+ /* ----- Compare rot matrixs ----- */
+ code = compare(rotMatrs,goodRotMatrs, 9*numImages,0.05,"rotation matrices");
+ if( code < 0 )
+ goto _exit_;
+
+ /* ----- Compare rot matrixs ----- */
+ code = compare(transVects,goodTransVects, 3*numImages,0.1,"translation vectors");
+ if( code < 0 )
+ goto _exit_;
+
+ if( maxDx > 1.0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Error in reprojection maxDx=%f > 1.0\n",maxDx);
+ code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_;
+ }
+
+ if( maxDy > 1.0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Error in reprojection maxDy=%f > 1.0\n",maxDy);
+ code = cvtest::TS::FAIL_BAD_ACCURACY; goto _exit_;
+ }
+
+ progress = update_progress( progress, currTest, numTests, 0 );
+
+ cvFree(&imagePoints);
+ cvFree(&objectPoints);
+ cvFree(&reprojectPoints);
+ cvFree(&numbers);
+
+ cvFree(&transVects);
+ cvFree(&rotMatrs);
+ cvFree(&goodTransVects);
+ cvFree(&goodRotMatrs);
+
+ fclose(file);
+ file = 0;
+ }
+
+_exit_:
+
+ if( file )
+ fclose(file);
+
+ if( datafile )
+ fclose(datafile);
+
+ /* Free all allocated memory */
+ cvFree(&imagePoints);
+ cvFree(&objectPoints);
+ cvFree(&reprojectPoints);
+ cvFree(&numbers);
+
+ cvFree(&transVects);
+ cvFree(&rotMatrs);
+ cvFree(&goodTransVects);
+ cvFree(&goodRotMatrs);
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+// --------------------------------- CV_CameraCalibrationTest_C --------------------------------------------
+
+class CV_CameraCalibrationTest_C : public CV_CameraCalibrationTest
+{
+public:
+ CV_CameraCalibrationTest_C(){}
+protected:
+ virtual void calibrate( int imageCount, int* pointCounts,
+ CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
+ double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
+ double* rotationMatrices, int flags );
+ virtual void project( int pointCount, CvPoint3D64f* objectPoints,
+ double* rotationMatrix, double* translationVector,
+ double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
+};
+
+void CV_CameraCalibrationTest_C::calibrate( int imageCount, int* pointCounts,
+ CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
+ double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
+ double* rotationMatrices, int flags )
+{
+ int i, total = 0;
+ for( i = 0; i < imageCount; i++ )
+ total += pointCounts[i];
+
+ CvMat _objectPoints = cvMat(1, total, CV_64FC3, objectPoints);
+ CvMat _imagePoints = cvMat(1, total, CV_64FC2, imagePoints);
+ CvMat _pointCounts = cvMat(1, imageCount, CV_32S, pointCounts);
+ CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix);
+ CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortionCoeffs);
+ CvMat _rotationMatrices = cvMat(imageCount, 9, CV_64F, rotationMatrices);
+ CvMat _translationVectors = cvMat(imageCount, 3, CV_64F, translationVectors);
+
+ cvCalibrateCamera2(&_objectPoints, &_imagePoints, &_pointCounts, imageSize,
+ &_cameraMatrix, &_distCoeffs, &_rotationMatrices, &_translationVectors,
+ flags);
+}
+
+void CV_CameraCalibrationTest_C::project( int pointCount, CvPoint3D64f* objectPoints,
+ double* rotationMatrix, double* translationVector,
+ double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints )
+{
+ CvMat _objectPoints = cvMat(1, pointCount, CV_64FC3, objectPoints);
+ CvMat _imagePoints = cvMat(1, pointCount, CV_64FC2, imagePoints);
+ CvMat _cameraMatrix = cvMat(3, 3, CV_64F, cameraMatrix);
+ CvMat _distCoeffs = cvMat(4, 1, CV_64F, distortion);
+ CvMat _rotationMatrix = cvMat(3, 3, CV_64F, rotationMatrix);
+ CvMat _translationVector = cvMat(1, 3, CV_64F, translationVector);
+
+ cvProjectPoints2(&_objectPoints, &_rotationMatrix, &_translationVector, &_cameraMatrix, &_distCoeffs, &_imagePoints);
+}
+
+// --------------------------------- CV_CameraCalibrationTest_CPP --------------------------------------------
+
+class CV_CameraCalibrationTest_CPP : public CV_CameraCalibrationTest
+{
+public:
+ CV_CameraCalibrationTest_CPP(){}
+protected:
+ virtual void calibrate( int imageCount, int* pointCounts,
+ CvSize imageSize, CvPoint2D64f* imagePoints, CvPoint3D64f* objectPoints,
+ double* distortionCoeffs, double* cameraMatrix, double* translationVectors,
+ double* rotationMatrices, int flags );
+ virtual void project( int pointCount, CvPoint3D64f* objectPoints,
+ double* rotationMatrix, double* translationVector,
+ double* cameraMatrix, double* distortion, CvPoint2D64f* imagePoints );
+};
+
+void CV_CameraCalibrationTest_CPP::calibrate( int imageCount, int* pointCounts,
+ CvSize _imageSize, CvPoint2D64f* _imagePoints, CvPoint3D64f* _objectPoints,
+ double* _distortionCoeffs, double* _cameraMatrix, double* translationVectors,
+ double* rotationMatrices, int flags )
+{
+ vector<vector<Point3f> > objectPoints( imageCount );
+ vector<vector<Point2f> > imagePoints( imageCount );
+ Size imageSize = _imageSize;
+ Mat cameraMatrix, distCoeffs(1,4,CV_64F,Scalar::all(0));
+ vector<Mat> rvecs, tvecs;
+
+ CvPoint3D64f* op = _objectPoints;
+ CvPoint2D64f* ip = _imagePoints;
+ vector<vector<Point3f> >::iterator objectPointsIt = objectPoints.begin();
+ vector<vector<Point2f> >::iterator imagePointsIt = imagePoints.begin();
+ for( int i = 0; i < imageCount; ++objectPointsIt, ++imagePointsIt, i++ )
+ {
+ int num = pointCounts[i];
+ objectPointsIt->resize( num );
+ imagePointsIt->resize( num );
+ vector<Point3f>::iterator oIt = objectPointsIt->begin();
+ vector<Point2f>::iterator iIt = imagePointsIt->begin();
+ for( int j = 0; j < num; ++oIt, ++iIt, j++, op++, ip++)
+ {
+ oIt->x = (float)op->x, oIt->y = (float)op->y, oIt->z = (float)op->z;
+ iIt->x = (float)ip->x, iIt->y = (float)ip->y;
+ }
+ }
+
+ calibrateCamera( objectPoints,
+ imagePoints,
+ imageSize,
+ cameraMatrix,
+ distCoeffs,
+ rvecs,
+ tvecs,
+ flags );
+
+ assert( cameraMatrix.type() == CV_64FC1 );
+ memcpy( _cameraMatrix, cameraMatrix.data, 9*sizeof(double) );
+
+ assert( cameraMatrix.type() == CV_64FC1 );
+ memcpy( _distortionCoeffs, distCoeffs.data, 4*sizeof(double) );
+
+ vector<Mat>::iterator rvecsIt = rvecs.begin();
+ vector<Mat>::iterator tvecsIt = tvecs.begin();
+ double *rm = rotationMatrices,
+ *tm = translationVectors;
+ assert( rvecsIt->type() == CV_64FC1 );
+ assert( tvecsIt->type() == CV_64FC1 );
+ for( int i = 0; i < imageCount; ++rvecsIt, ++tvecsIt, i++, rm+=9, tm+=3 )
+ {
+ Mat r9( 3, 3, CV_64FC1 );
+ Rodrigues( *rvecsIt, r9 );
+ memcpy( rm, r9.data, 9*sizeof(double) );
+ memcpy( tm, tvecsIt->data, 3*sizeof(double) );
+ }
+}
+
+void CV_CameraCalibrationTest_CPP::project( int pointCount, CvPoint3D64f* _objectPoints,
+ double* rotationMatrix, double* translationVector,
+ double* _cameraMatrix, double* distortion, CvPoint2D64f* _imagePoints )
+{
+ Mat objectPoints( pointCount, 3, CV_64FC1, _objectPoints );
+ Mat rmat( 3, 3, CV_64FC1, rotationMatrix ),
+ rvec( 1, 3, CV_64FC1 ),
+ tvec( 1, 3, CV_64FC1, translationVector );
+ Mat cameraMatrix( 3, 3, CV_64FC1, _cameraMatrix );
+ Mat distCoeffs( 1, 4, CV_64FC1, distortion );
+ vector<Point2f> imagePoints;
+ Rodrigues( rmat, rvec );
+
+ objectPoints.convertTo( objectPoints, CV_32FC1 );
+ projectPoints( objectPoints, rvec, tvec,
+ cameraMatrix, distCoeffs, imagePoints );
+ vector<Point2f>::const_iterator it = imagePoints.begin();
+ for( int i = 0; it != imagePoints.end(); ++it, i++ )
+ {
+ _imagePoints[i] = cvPoint2D64f( it->x, it->y );
+ }
+}
+
+
+//----------------------------------------- CV_CalibrationMatrixValuesTest --------------------------------
+
+class CV_CalibrationMatrixValuesTest : public cvtest::BaseTest
+{
+public:
+ CV_CalibrationMatrixValuesTest() {}
+protected:
+ void run(int);
+ virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
+ Point2d& principalPoint, double& aspectRatio ) = 0;
+};
+
+void CV_CalibrationMatrixValuesTest::run(int)
+{
+ int code = cvtest::TS::OK;
+ const double fcMinVal = 1e-5;
+ const double fcMaxVal = 1000;
+ const double apertureMaxVal = 0.01;
+
+ RNG rng = ts->get_rng();
+
+ double fx, fy, cx, cy, nx, ny;
+ Mat cameraMatrix( 3, 3, CV_64FC1 );
+ cameraMatrix.setTo( Scalar(0) );
+ fx = cameraMatrix.at<double>(0,0) = rng.uniform( fcMinVal, fcMaxVal );
+ fy = cameraMatrix.at<double>(1,1) = rng.uniform( fcMinVal, fcMaxVal );
+ cx = cameraMatrix.at<double>(0,2) = rng.uniform( fcMinVal, fcMaxVal );
+ cy = cameraMatrix.at<double>(1,2) = rng.uniform( fcMinVal, fcMaxVal );
+ cameraMatrix.at<double>(2,2) = 1;
+
+ Size imageSize( 600, 400 );
+
+ double apertureWidth = (double)rng * apertureMaxVal,
+ apertureHeight = (double)rng * apertureMaxVal;
+
+ double fovx, fovy, focalLength, aspectRatio,
+ goodFovx, goodFovy, goodFocalLength, goodAspectRatio;
+ Point2d principalPoint, goodPrincipalPoint;
+
+
+ calibMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight,
+ fovx, fovy, focalLength, principalPoint, aspectRatio );
+
+ // calculate calibration matrix values
+ goodAspectRatio = fy / fx;
+
+ if( apertureWidth != 0.0 && apertureHeight != 0.0 )
+ {
+ nx = imageSize.width / apertureWidth;
+ ny = imageSize.height / apertureHeight;
+ }
+ else
+ {
+ nx = 1.0;
+ ny = goodAspectRatio;
+ }
+
+ goodFovx = 2 * atan( imageSize.width / (2 * fx)) * 180.0 / CV_PI;
+ goodFovy = 2 * atan( imageSize.height / (2 * fy)) * 180.0 / CV_PI;
+
+ goodFocalLength = fx / nx;
+
+ goodPrincipalPoint.x = cx / nx;
+ goodPrincipalPoint.y = cy / ny;
+
+ // check results
+ if( fabs(fovx - goodFovx) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "bad fovx (real=%f, good = %f\n", fovx, goodFovx );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ if( fabs(fovy - goodFovy) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "bad fovy (real=%f, good = %f\n", fovy, goodFovy );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ if( fabs(focalLength - goodFocalLength) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "bad focalLength (real=%f, good = %f\n", focalLength, goodFocalLength );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ if( fabs(aspectRatio - goodAspectRatio) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "bad aspectRatio (real=%f, good = %f\n", aspectRatio, goodAspectRatio );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ if( norm( principalPoint - goodPrincipalPoint ) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "bad principalPoint\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+ RNG& _rng = ts->get_rng();
+ _rng = rng;
+ ts->set_failed_test_info( code );
+}
+
+//----------------------------------------- CV_CalibrationMatrixValuesTest_C --------------------------------
+
+class CV_CalibrationMatrixValuesTest_C : public CV_CalibrationMatrixValuesTest
+{
+public:
+ CV_CalibrationMatrixValuesTest_C(){}
+protected:
+ virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
+ Point2d& principalPoint, double& aspectRatio );
+};
+
+void CV_CalibrationMatrixValuesTest_C::calibMatrixValues( const Mat& _cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight,
+ double& fovx, double& fovy, double& focalLength,
+ Point2d& principalPoint, double& aspectRatio )
+{
+ CvMat cameraMatrix = _cameraMatrix;
+ CvPoint2D64f pp;
+ cvCalibrationMatrixValues( &cameraMatrix, imageSize, apertureWidth, apertureHeight,
+ &fovx, &fovy, &focalLength, &pp, &aspectRatio );
+ principalPoint.x = pp.x;
+ principalPoint.y = pp.y;
+}
+
+
+//----------------------------------------- CV_CalibrationMatrixValuesTest_CPP --------------------------------
+
+class CV_CalibrationMatrixValuesTest_CPP : public CV_CalibrationMatrixValuesTest
+{
+public:
+ CV_CalibrationMatrixValuesTest_CPP() {}
+protected:
+ virtual void calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight, double& fovx, double& fovy, double& focalLength,
+ Point2d& principalPoint, double& aspectRatio );
+};
+
+void CV_CalibrationMatrixValuesTest_CPP::calibMatrixValues( const Mat& cameraMatrix, Size imageSize,
+ double apertureWidth, double apertureHeight,
+ double& fovx, double& fovy, double& focalLength,
+ Point2d& principalPoint, double& aspectRatio )
+{
+ calibrationMatrixValues( cameraMatrix, imageSize, apertureWidth, apertureHeight,
+ fovx, fovy, focalLength, principalPoint, aspectRatio );
+}
+
+
+//----------------------------------------- CV_ProjectPointsTest --------------------------------
+void calcdfdx( const vector<vector<Point2f> >& leftF, const vector<vector<Point2f> >& rightF, double eps, Mat& dfdx )
+{
+ const int fdim = 2;
+ CV_Assert( !leftF.empty() && !rightF.empty() && !leftF[0].empty() && !rightF[0].empty() );
+ CV_Assert( leftF[0].size() == rightF[0].size() );
+ CV_Assert( fabs(eps) > std::numeric_limits<double>::epsilon() );
+ int fcount = (int)leftF[0].size(), xdim = (int)leftF.size();
+
+ dfdx.create( fcount*fdim, xdim, CV_64FC1 );
+
+ vector<vector<Point2f> >::const_iterator arrLeftIt = leftF.begin();
+ vector<vector<Point2f> >::const_iterator arrRightIt = rightF.begin();
+ for( int xi = 0; xi < xdim; xi++, ++arrLeftIt, ++arrRightIt )
+ {
+ CV_Assert( (int)arrLeftIt->size() == fcount );
+ CV_Assert( (int)arrRightIt->size() == fcount );
+ vector<Point2f>::const_iterator lIt = arrLeftIt->begin();
+ vector<Point2f>::const_iterator rIt = arrRightIt->begin();
+ for( int fi = 0; fi < dfdx.rows; fi+=fdim, ++lIt, ++rIt )
+ {
+ dfdx.at<double>(fi, xi ) = 0.5 * ((double)(rIt->x - lIt->x)) / eps;
+ dfdx.at<double>(fi+1, xi ) = 0.5 * ((double)(rIt->y - lIt->y)) / eps;
+ }
+ }
+}
+
+class CV_ProjectPointsTest : public cvtest::BaseTest
+{
+public:
+ CV_ProjectPointsTest() {}
+protected:
+ void run(int);
+ virtual void project( const Mat& objectPoints,
+ const Mat& rvec, const Mat& tvec,
+ const Mat& cameraMatrix,
+ const Mat& distCoeffs,
+ vector<Point2f>& imagePoints,
+ Mat& dpdrot, Mat& dpdt, Mat& dpdf,
+ Mat& dpdc, Mat& dpddist,
+ double aspectRatio=0 ) = 0;
+};
+
+void CV_ProjectPointsTest::run(int)
+{
+ //typedef float matType;
+
+ int code = cvtest::TS::OK;
+ const int pointCount = 100;
+
+ const float zMinVal = 10.0f, zMaxVal = 100.0f,
+ rMinVal = -0.3f, rMaxVal = 0.3f,
+ tMinVal = -2.0f, tMaxVal = 2.0f;
+
+ const float imgPointErr = 1e-3f,
+ dEps = 1e-3f;
+
+ double err;
+
+ Size imgSize( 600, 800 );
+ Mat_<float> objPoints( pointCount, 3), rvec( 1, 3), rmat, tvec( 1, 3 ), cameraMatrix( 3, 3 ), distCoeffs( 1, 4 ),
+ leftRvec, rightRvec, leftTvec, rightTvec, leftCameraMatrix, rightCameraMatrix, leftDistCoeffs, rightDistCoeffs;
+
+ RNG rng = ts->get_rng();
+
+ // generate data
+ cameraMatrix << 300.f, 0.f, imgSize.width/2.f,
+ 0.f, 300.f, imgSize.height/2.f,
+ 0.f, 0.f, 1.f;
+ distCoeffs << 0.1, 0.01, 0.001, 0.001;
+
+ rvec(0,0) = rng.uniform( rMinVal, rMaxVal );
+ rvec(0,1) = rng.uniform( rMinVal, rMaxVal );
+ rvec(0,2) = rng.uniform( rMinVal, rMaxVal );
+ Rodrigues( rvec, rmat );
+
+ tvec(0,0) = rng.uniform( tMinVal, tMaxVal );
+ tvec(0,1) = rng.uniform( tMinVal, tMaxVal );
+ tvec(0,2) = rng.uniform( tMinVal, tMaxVal );
+
+ for( int y = 0; y < objPoints.rows; y++ )
+ {
+ Mat point(1, 3, CV_32FC1, objPoints.ptr(y) );
+ float z = rng.uniform( zMinVal, zMaxVal );
+ point.at<float>(0,2) = z;
+ point.at<float>(0,0) = (rng.uniform(2.f,(float)(imgSize.width-2)) - cameraMatrix(0,2)) / cameraMatrix(0,0) * z;
+ point.at<float>(0,1) = (rng.uniform(2.f,(float)(imgSize.height-2)) - cameraMatrix(1,2)) / cameraMatrix(1,1) * z;
+ point = (point - tvec) * rmat;
+ }
+
+ vector<Point2f> imgPoints;
+ vector<vector<Point2f> > leftImgPoints;
+ vector<vector<Point2f> > rightImgPoints;
+ Mat dpdrot, dpdt, dpdf, dpdc, dpddist,
+ valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist;
+
+ project( objPoints, rvec, tvec, cameraMatrix, distCoeffs,
+ imgPoints, dpdrot, dpdt, dpdf, dpdc, dpddist, 0 );
+
+ // calculate and check image points
+ assert( (int)imgPoints.size() == pointCount );
+ vector<Point2f>::const_iterator it = imgPoints.begin();
+ for( int i = 0; i < pointCount; i++, ++it )
+ {
+ Point3d p( objPoints(i,0), objPoints(i,1), objPoints(i,2) );
+ double z = p.x*rmat(2,0) + p.y*rmat(2,1) + p.z*rmat(2,2) + tvec(0,2),
+ x = (p.x*rmat(0,0) + p.y*rmat(0,1) + p.z*rmat(0,2) + tvec(0,0)) / z,
+ y = (p.x*rmat(1,0) + p.y*rmat(1,1) + p.z*rmat(1,2) + tvec(0,1)) / z,
+ r2 = x*x + y*y,
+ r4 = r2*r2;
+ Point2f validImgPoint;
+ double a1 = 2*x*y,
+ a2 = r2 + 2*x*x,
+ a3 = r2 + 2*y*y,
+ cdist = 1+distCoeffs(0,0)*r2+distCoeffs(0,1)*r4;
+ validImgPoint.x = static_cast<float>((double)cameraMatrix(0,0)*(x*cdist + (double)distCoeffs(0,2)*a1 + (double)distCoeffs(0,3)*a2)
+ + (double)cameraMatrix(0,2));
+ validImgPoint.y = static_cast<float>((double)cameraMatrix(1,1)*(y*cdist + (double)distCoeffs(0,2)*a3 + distCoeffs(0,3)*a1)
+ + (double)cameraMatrix(1,2));
+
+ Point2f ssdfp = *it;
+ if( fabs(it->x - validImgPoint.x) > imgPointErr ||
+ fabs(it->y - validImgPoint.y) > imgPointErr )
+ {
+ ts->printf( cvtest::TS::LOG, "bad image point\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ }
+
+ // check derivatives
+ // 1. rotation
+ leftImgPoints.resize(3);
+ rightImgPoints.resize(3);
+ for( int i = 0; i < 3; i++ )
+ {
+ rvec.copyTo( leftRvec ); leftRvec(0,i) -= dEps;
+ project( objPoints, leftRvec, tvec, cameraMatrix, distCoeffs,
+ leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ rvec.copyTo( rightRvec ); rightRvec(0,i) += dEps;
+ project( objPoints, rightRvec, tvec, cameraMatrix, distCoeffs,
+ rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ }
+ calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdrot );
+ err = norm( dpdrot, valDpdrot, NORM_INF );
+ if( err > 3 )
+ {
+ ts->printf( cvtest::TS::LOG, "bad dpdrot: too big difference = %g\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // 2. translation
+ for( int i = 0; i < 3; i++ )
+ {
+ tvec.copyTo( leftTvec ); leftTvec(0,i) -= dEps;
+ project( objPoints, rvec, leftTvec, cameraMatrix, distCoeffs,
+ leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ tvec.copyTo( rightTvec ); rightTvec(0,i) += dEps;
+ project( objPoints, rvec, rightTvec, cameraMatrix, distCoeffs,
+ rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ }
+ calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdt );
+ if( norm( dpdt, valDpdt, NORM_INF ) > 0.2 )
+ {
+ ts->printf( cvtest::TS::LOG, "bad dpdtvec\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // 3. camera matrix
+ // 3.1. focus
+ leftImgPoints.resize(2);
+ rightImgPoints.resize(2);
+ cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,0) -= dEps;
+ project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
+ leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,1) -= dEps;
+ project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
+ leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,0) += dEps;
+ project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
+ rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,1) += dEps;
+ project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
+ rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdf );
+ if ( norm( dpdf, valDpdf ) > 0.2 )
+ {
+ ts->printf( cvtest::TS::LOG, "bad dpdf\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ // 3.2. principal point
+ leftImgPoints.resize(2);
+ rightImgPoints.resize(2);
+ cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(0,2) -= dEps;
+ project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
+ leftImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( leftCameraMatrix ); leftCameraMatrix(1,2) -= dEps;
+ project( objPoints, rvec, tvec, leftCameraMatrix, distCoeffs,
+ leftImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(0,2) += dEps;
+ project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
+ rightImgPoints[0], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ cameraMatrix.copyTo( rightCameraMatrix ); rightCameraMatrix(1,2) += dEps;
+ project( objPoints, rvec, tvec, rightCameraMatrix, distCoeffs,
+ rightImgPoints[1], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpdc );
+ if ( norm( dpdc, valDpdc ) > 0.2 )
+ {
+ ts->printf( cvtest::TS::LOG, "bad dpdc\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // 4. distortion
+ leftImgPoints.resize(distCoeffs.cols);
+ rightImgPoints.resize(distCoeffs.cols);
+ for( int i = 0; i < distCoeffs.cols; i++ )
+ {
+ distCoeffs.copyTo( leftDistCoeffs ); leftDistCoeffs(0,i) -= dEps;
+ project( objPoints, rvec, tvec, cameraMatrix, leftDistCoeffs,
+ leftImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ distCoeffs.copyTo( rightDistCoeffs ); rightDistCoeffs(0,i) += dEps;
+ project( objPoints, rvec, tvec, cameraMatrix, rightDistCoeffs,
+ rightImgPoints[i], valDpdrot, valDpdt, valDpdf, valDpdc, valDpddist, 0 );
+ }
+ calcdfdx( leftImgPoints, rightImgPoints, dEps, valDpddist );
+ if( norm( dpddist, valDpddist ) > 0.3 )
+ {
+ ts->printf( cvtest::TS::LOG, "bad dpddist\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+_exit_:
+ RNG& _rng = ts->get_rng();
+ _rng = rng;
+ ts->set_failed_test_info( code );
+}
+
+//----------------------------------------- CV_ProjectPointsTest_C --------------------------------
+class CV_ProjectPointsTest_C : public CV_ProjectPointsTest
+{
+public:
+ CV_ProjectPointsTest_C() {}
+protected:
+ virtual void project( const Mat& objectPoints,
+ const Mat& rvec, const Mat& tvec,
+ const Mat& cameraMatrix,
+ const Mat& distCoeffs,
+ vector<Point2f>& imagePoints,
+ Mat& dpdrot, Mat& dpdt, Mat& dpdf,
+ Mat& dpdc, Mat& dpddist,
+ double aspectRatio=0 );
+};
+
+void CV_ProjectPointsTest_C::project( const Mat& opoints, const Mat& rvec, const Mat& tvec,
+ const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& ipoints,
+ Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio)
+{
+ int npoints = opoints.cols*opoints.rows*opoints.channels()/3;
+ ipoints.resize(npoints);
+ dpdrot.create(npoints*2, 3, CV_64F);
+ dpdt.create(npoints*2, 3, CV_64F);
+ dpdf.create(npoints*2, 2, CV_64F);
+ dpdc.create(npoints*2, 2, CV_64F);
+ dpddist.create(npoints*2, distCoeffs.rows + distCoeffs.cols - 1, CV_64F);
+ CvMat _objectPoints = opoints, _imagePoints = Mat(ipoints);
+ CvMat _rvec = rvec, _tvec = tvec, _cameraMatrix = cameraMatrix, _distCoeffs = distCoeffs;
+ CvMat _dpdrot = dpdrot, _dpdt = dpdt, _dpdf = dpdf, _dpdc = dpdc, _dpddist = dpddist;
+
+ cvProjectPoints2( &_objectPoints, &_rvec, &_tvec, &_cameraMatrix, &_distCoeffs,
+ &_imagePoints, &_dpdrot, &_dpdt, &_dpdf, &_dpdc, &_dpddist, aspectRatio );
+}
+
+
+//----------------------------------------- CV_ProjectPointsTest_CPP --------------------------------
+class CV_ProjectPointsTest_CPP : public CV_ProjectPointsTest
+{
+public:
+ CV_ProjectPointsTest_CPP() {}
+protected:
+ virtual void project( const Mat& objectPoints,
+ const Mat& rvec, const Mat& tvec,
+ const Mat& cameraMatrix,
+ const Mat& distCoeffs,
+ vector<Point2f>& imagePoints,
+ Mat& dpdrot, Mat& dpdt, Mat& dpdf,
+ Mat& dpdc, Mat& dpddist,
+ double aspectRatio=0 );
+};
+
+void CV_ProjectPointsTest_CPP::project( const Mat& objectPoints, const Mat& rvec, const Mat& tvec,
+ const Mat& cameraMatrix, const Mat& distCoeffs, vector<Point2f>& imagePoints,
+ Mat& dpdrot, Mat& dpdt, Mat& dpdf, Mat& dpdc, Mat& dpddist, double aspectRatio)
+{
+ projectPoints( objectPoints, rvec, tvec, cameraMatrix, distCoeffs, imagePoints,
+ dpdrot, dpdt, dpdf, dpdc, dpddist, aspectRatio );
+}
+
+///////////////////////////////// Stereo Calibration /////////////////////////////////////
+
+class CV_StereoCalibrationTest : public cvtest::BaseTest
+{
+public:
+ CV_StereoCalibrationTest();
+ ~CV_StereoCalibrationTest();
+ void clear();
+protected:
+ bool checkPandROI( int test_case_idx,
+ const Mat& M, const Mat& D, const Mat& R,
+ const Mat& P, Size imgsize, Rect roi );
+
+ // covers of tested functions
+ virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
+ const vector<vector<Point2f> >& imagePoints1,
+ const vector<vector<Point2f> >& imagePoints2,
+ Mat& cameraMatrix1, Mat& distCoeffs1,
+ Mat& cameraMatrix2, Mat& distCoeffs2,
+ Size imageSize, Mat& R, Mat& T,
+ Mat& E, Mat& F, TermCriteria criteria, int flags ) = 0;
+ virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
+ const Mat& cameraMatrix2, const Mat& distCoeffs2,
+ Size imageSize, const Mat& R, const Mat& T,
+ Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
+ double alpha, Size newImageSize,
+ Rect* validPixROI1, Rect* validPixROI2, int flags ) = 0;
+ virtual bool rectifyUncalibrated( const Mat& points1,
+ const Mat& points2, const Mat& F, Size imgSize,
+ Mat& H1, Mat& H2, double threshold=5 ) = 0;
+
+ void run(int);
+};
+
+
+CV_StereoCalibrationTest::CV_StereoCalibrationTest()
+{
+}
+
+
+CV_StereoCalibrationTest::~CV_StereoCalibrationTest()
+{
+ clear();
+}
+
+void CV_StereoCalibrationTest::clear()
+{
+ cvtest::BaseTest::clear();
+}
+
+bool CV_StereoCalibrationTest::checkPandROI( int test_case_idx, const Mat& M, const Mat& D, const Mat& R,
+ const Mat& P, Size imgsize, Rect roi )
+{
+ const double eps = 0.05;
+ const int N = 21;
+ int x, y, k;
+ vector<Point2f> pts, upts;
+
+ // step 1. check that all the original points belong to the destination image
+ for( y = 0; y < N; y++ )
+ for( x = 0; x < N; x++ )
+ pts.push_back(Point2f((float)x*imgsize.width/(N-1), (float)y*imgsize.height/(N-1)));
+
+ undistortPoints(Mat(pts), upts, M, D, R, P );
+ for( k = 0; k < N*N; k++ )
+ if( upts[k].x < -imgsize.width*eps || upts[k].x > imgsize.width*(1+eps) ||
+ upts[k].y < -imgsize.height*eps || upts[k].y > imgsize.height*(1+eps) )
+ {
+ ts->printf(cvtest::TS::LOG, "Test #%d. The point (%g, %g) was mapped to (%g, %g) which is out of image\n",
+ test_case_idx, pts[k].x, pts[k].y, upts[k].x, upts[k].y);
+ return false;
+ }
+
+ // step 2. check that all the points inside ROI belong to the original source image
+ Mat temp(imgsize, CV_8U), utemp, map1, map2;
+ temp = Scalar::all(1);
+ initUndistortRectifyMap(M, D, R, P, imgsize, CV_16SC2, map1, map2);
+ remap(temp, utemp, map1, map2, INTER_LINEAR);
+
+ if(roi.x < 0 || roi.y < 0 || roi.x + roi.width > imgsize.width || roi.y + roi.height > imgsize.height)
+ {
+ ts->printf(cvtest::TS::LOG, "Test #%d. The ROI=(%d, %d, %d, %d) is outside of the imge rectangle\n",
+ test_case_idx, roi.x, roi.y, roi.width, roi.height);
+ return false;
+ }
+ double s = sum(utemp(roi))[0];
+ if( s > roi.area() || roi.area() - s > roi.area()*(1-eps) )
+ {
+ ts->printf(cvtest::TS::LOG, "Test #%d. The ratio of black pixels inside the valid ROI (~%g%%) is too large\n",
+ test_case_idx, s*100./roi.area());
+ return false;
+ }
+
+ return true;
+}
+
+void CV_StereoCalibrationTest::run( int )
+{
+ const int ntests = 1;
+ const double maxReprojErr = 2;
+ const double maxScanlineDistErr_c = 3;
+ const double maxScanlineDistErr_uc = 4;
+ FILE* f = 0;
+
+ for(int testcase = 1; testcase <= ntests; testcase++)
+ {
+ char filepath[1000];
+ char buf[1000];
+ sprintf( filepath, "%sstereo/case%d/stereo_calib.txt", ts->get_data_path().c_str(), testcase );
+ f = fopen(filepath, "rt");
+ Size patternSize;
+ vector<string> imglist;
+
+ if( !f || !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &patternSize.width, &patternSize.height) != 2 )
+ {
+ ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath );
+ ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA );
+ return;
+ }
+
+ for(;;)
+ {
+ if( !fgets( buf, sizeof(buf)-3, f ))
+ break;
+ size_t len = strlen(buf);
+ while( len > 0 && isspace(buf[len-1]))
+ buf[--len] = '\0';
+ if( buf[0] == '#')
+ continue;
+ sprintf(filepath, "%sstereo/case%d/%s", ts->get_data_path().c_str(), testcase, buf );
+ imglist.push_back(string(filepath));
+ }
+ fclose(f);
+
+ if( imglist.size() == 0 || imglist.size() % 2 != 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "The number of images is 0 or an odd number in the case #%d\n", testcase );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ int nframes = (int)(imglist.size()/2);
+ int npoints = patternSize.width*patternSize.height;
+ vector<vector<Point3f> > objpt(nframes);
+ vector<vector<Point2f> > imgpt1(nframes);
+ vector<vector<Point2f> > imgpt2(nframes);
+ Size imgsize;
+ int total = 0;
+
+ for( int i = 0; i < nframes; i++ )
+ {
+ Mat left = imread(imglist[i*2]);
+ Mat right = imread(imglist[i*2+1]);
+ if(!left.data || !right.data)
+ {
+ ts->printf( cvtest::TS::LOG, "Can not load images %s and %s, testcase %d\n",
+ imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
+ return;
+ }
+ imgsize = left.size();
+ bool found1 = findChessboardCorners(left, patternSize, imgpt1[i]);
+ bool found2 = findChessboardCorners(right, patternSize, imgpt2[i]);
+ if(!found1 || !found2)
+ {
+ ts->printf( cvtest::TS::LOG, "The function could not detect boards on the images %s and %s, testcase %d\n",
+ imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ total += (int)imgpt1[i].size();
+ for( int j = 0; j < npoints; j++ )
+ objpt[i].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
+ }
+
+ // rectify (calibrated)
+ Mat M1 = Mat::eye(3,3,CV_64F), M2 = Mat::eye(3,3,CV_64F), D1(5,1,CV_64F), D2(5,1,CV_64F), R, T, E, F;
+ M1.at<double>(0,2) = M2.at<double>(0,2)=(imgsize.width-1)*0.5;
+ M1.at<double>(1,2) = M2.at<double>(1,2)=(imgsize.height-1)*0.5;
+ D1 = Scalar::all(0);
+ D2 = Scalar::all(0);
+ double err = calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R, T, E, F,
+ TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
+ CV_CALIB_SAME_FOCAL_LENGTH
+ //+ CV_CALIB_FIX_ASPECT_RATIO
+ + CV_CALIB_FIX_PRINCIPAL_POINT
+ + CV_CALIB_ZERO_TANGENT_DIST
+ + CV_CALIB_FIX_K3
+ + CV_CALIB_FIX_K4 + CV_CALIB_FIX_K5 //+ CV_CALIB_FIX_K6
+ );
+ err /= nframes*npoints;
+ if( err > maxReprojErr )
+ {
+ ts->printf( cvtest::TS::LOG, "The average reprojection error is too big (=%g), testcase %d\n", err, testcase);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ Mat R1, R2, P1, P2, Q;
+ Rect roi1, roi2;
+ rectify(M1, D1, M2, D2, imgsize, R, T, R1, R2, P1, P2, Q, 1, imgsize, &roi1, &roi2, 0);
+ Mat eye33 = Mat::eye(3,3,CV_64F);
+ Mat R1t = R1.t(), R2t = R2.t();
+
+ if( norm(R1t*R1 - eye33) > 0.01 ||
+ norm(R2t*R2 - eye33) > 0.01 ||
+ abs(determinant(F)) > 0.01)
+ {
+ ts->printf( cvtest::TS::LOG, "The computed (by rectify) R1 and R2 are not orthogonal,"
+ "or the computed (by calibrate) F is not singular, testcase %d\n", testcase);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ if(!checkPandROI(testcase, M1, D1, R1, P1, imgsize, roi1))
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+
+ if(!checkPandROI(testcase, M2, D2, R2, P2, imgsize, roi2))
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+
+ // rectifyUncalibrated
+ CV_Assert( imgpt1.size() == imgpt2.size() );
+ Mat _imgpt1( total, 1, CV_32FC2 ), _imgpt2( total, 1, CV_32FC2 );
+ vector<vector<Point2f> >::const_iterator iit1 = imgpt1.begin();
+ vector<vector<Point2f> >::const_iterator iit2 = imgpt2.begin();
+ for( int pi = 0; iit1 != imgpt1.end(); ++iit1, ++iit2 )
+ {
+ vector<Point2f>::const_iterator pit1 = iit1->begin();
+ vector<Point2f>::const_iterator pit2 = iit2->begin();
+ CV_Assert( iit1->size() == iit2->size() );
+ for( ; pit1 != iit1->end(); ++pit1, ++pit2, pi++ )
+ {
+ _imgpt1.at<Point2f>(pi,0) = Point2f( pit1->x, pit1->y );
+ _imgpt2.at<Point2f>(pi,0) = Point2f( pit2->x, pit2->y );
+ }
+ }
+
+ Mat _M1, _M2, _D1, _D2;
+ vector<Mat> _R1, _R2, _T1, _T2;
+ calibrateCamera( objpt, imgpt1, imgsize, _M1, _D1, _R1, _T1, 0 );
+ calibrateCamera( objpt, imgpt2, imgsize, _M2, _D2, _R2, _T1, 0 );
+ undistortPoints( _imgpt1, _imgpt1, _M1, _D1, Mat(), _M1 );
+ undistortPoints( _imgpt2, _imgpt2, _M2, _D2, Mat(), _M2 );
+
+ Mat matF, _H1, _H2;
+ matF = findFundamentalMat( _imgpt1, _imgpt2 );
+ rectifyUncalibrated( _imgpt1, _imgpt2, matF, imgsize, _H1, _H2 );
+
+ Mat rectifPoints1, rectifPoints2;
+ perspectiveTransform( _imgpt1, rectifPoints1, _H1 );
+ perspectiveTransform( _imgpt2, rectifPoints2, _H2 );
+
+ bool verticalStereo = abs(P2.at<double>(0,3)) < abs(P2.at<double>(1,3));
+ double maxDiff_c = 0, maxDiff_uc = 0;
+ for( int i = 0, k = 0; i < nframes; i++ )
+ {
+ vector<Point2f> temp[2];
+ undistortPoints(Mat(imgpt1[i]), temp[0], M1, D1, R1, P1);
+ undistortPoints(Mat(imgpt2[i]), temp[1], M2, D2, R2, P2);
+
+ for( int j = 0; j < npoints; j++, k++ )
+ {
+ double diff_c = verticalStereo ? abs(temp[0][j].x - temp[1][j].x) : abs(temp[0][j].y - temp[1][j].y);
+ Point2f d = rectifPoints1.at<Point2f>(k,0) - rectifPoints2.at<Point2f>(k,0);
+ double diff_uc = verticalStereo ? abs(d.x) : abs(d.y);
+ maxDiff_c = max(maxDiff_c, diff_c);
+ maxDiff_uc = max(maxDiff_uc, diff_uc);
+ if( maxDiff_c > maxScanlineDistErr_c )
+ {
+ ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used calibrated stereo), testcase %d\n",
+ verticalStereo ? "x" : "y", diff_c, testcase);
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+ if( maxDiff_uc > maxScanlineDistErr_uc )
+ {
+ ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used uncalibrated stereo), testcase %d\n",
+ verticalStereo ? "x" : "y", diff_uc, testcase);
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+ }
+ }
+
+ ts->printf( cvtest::TS::LOG, "Testcase %d. Max distance (calibrated) =%g\n"
+ "Max distance (uncalibrated) =%g\n", testcase, maxDiff_c, maxDiff_uc );
+ }
+}
+
+//-------------------------------- CV_StereoCalibrationTest_C ------------------------------
+
+class CV_StereoCalibrationTest_C : public CV_StereoCalibrationTest
+{
+public:
+ CV_StereoCalibrationTest_C() {}
+protected:
+ virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
+ const vector<vector<Point2f> >& imagePoints1,
+ const vector<vector<Point2f> >& imagePoints2,
+ Mat& cameraMatrix1, Mat& distCoeffs1,
+ Mat& cameraMatrix2, Mat& distCoeffs2,
+ Size imageSize, Mat& R, Mat& T,
+ Mat& E, Mat& F, TermCriteria criteria, int flags );
+ virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
+ const Mat& cameraMatrix2, const Mat& distCoeffs2,
+ Size imageSize, const Mat& R, const Mat& T,
+ Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
+ double alpha, Size newImageSize,
+ Rect* validPixROI1, Rect* validPixROI2, int flags );
+ virtual bool rectifyUncalibrated( const Mat& points1,
+ const Mat& points2, const Mat& F, Size imgSize,
+ Mat& H1, Mat& H2, double threshold=5 );
+};
+
+double CV_StereoCalibrationTest_C::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
+ const vector<vector<Point2f> >& imagePoints1,
+ const vector<vector<Point2f> >& imagePoints2,
+ Mat& cameraMatrix1, Mat& distCoeffs1,
+ Mat& cameraMatrix2, Mat& distCoeffs2,
+ Size imageSize, Mat& R, Mat& T,
+ Mat& E, Mat& F, TermCriteria criteria, int flags )
+{
+ cameraMatrix1.create( 3, 3, CV_64F );
+ cameraMatrix2.create( 3, 3, CV_64F);
+ distCoeffs1.create( 1, 5, CV_64F);
+ distCoeffs2.create( 1, 5, CV_64F);
+ R.create(3, 3, CV_64F);
+ T.create(3, 1, CV_64F);
+ E.create(3, 3, CV_64F);
+ F.create(3, 3, CV_64F);
+
+ int nimages = (int)objectPoints.size(), total = 0;
+ for( int i = 0; i < nimages; i++ )
+ {
+ total += (int)objectPoints[i].size();
+ }
+
+ Mat npoints( 1, nimages, CV_32S ),
+ objPt( 1, total, DataType<Point3f>::type ),
+ imgPt( 1, total, DataType<Point2f>::type ),
+ imgPt2( 1, total, DataType<Point2f>::type );
+
+ Point2f* imgPtData2 = imgPt2.ptr<Point2f>();
+ Point3f* objPtData = objPt.ptr<Point3f>();
+ Point2f* imgPtData = imgPt.ptr<Point2f>();
+ for( int i = 0, ni = 0, j = 0; i < nimages; i++, j += ni )
+ {
+ ni = (int)objectPoints[i].size();
+ ((int*)npoints.data)[i] = ni;
+ std::copy(objectPoints[i].begin(), objectPoints[i].end(), objPtData + j);
+ std::copy(imagePoints1[i].begin(), imagePoints1[i].end(), imgPtData + j);
+ std::copy(imagePoints2[i].begin(), imagePoints2[i].end(), imgPtData2 + j);
+ }
+ CvMat _objPt = objPt, _imgPt = imgPt, _imgPt2 = imgPt2, _npoints = npoints;
+ CvMat _cameraMatrix1 = cameraMatrix1, _distCoeffs1 = distCoeffs1;
+ CvMat _cameraMatrix2 = cameraMatrix2, _distCoeffs2 = distCoeffs2;
+ CvMat matR = R, matT = T, matE = E, matF = F;
+
+ return cvStereoCalibrate(&_objPt, &_imgPt, &_imgPt2, &_npoints, &_cameraMatrix1,
+ &_distCoeffs1, &_cameraMatrix2, &_distCoeffs2, imageSize,
+ &matR, &matT, &matE, &matF, criteria, flags );
+}
+
+void CV_StereoCalibrationTest_C::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
+ const Mat& cameraMatrix2, const Mat& distCoeffs2,
+ Size imageSize, const Mat& R, const Mat& T,
+ Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
+ double alpha, Size newImageSize,
+ Rect* validPixROI1, Rect* validPixROI2, int flags )
+{
+ int rtype = CV_64F;
+ R1.create(3, 3, rtype);
+ R2.create(3, 3, rtype);
+ P1.create(3, 4, rtype);
+ P2.create(3, 4, rtype);
+ Q.create(4, 4, rtype);
+ CvMat _cameraMatrix1 = cameraMatrix1, _distCoeffs1 = distCoeffs1;
+ CvMat _cameraMatrix2 = cameraMatrix2, _distCoeffs2 = distCoeffs2;
+ CvMat matR = R, matT = T, _R1 = R1, _R2 = R2, _P1 = P1, _P2 = P2, matQ = Q;
+ cvStereoRectify( &_cameraMatrix1, &_cameraMatrix2, &_distCoeffs1, &_distCoeffs2,
+ imageSize, &matR, &matT, &_R1, &_R2, &_P1, &_P2, &matQ, flags,
+ alpha, newImageSize, (CvRect*)validPixROI1, (CvRect*)validPixROI2);
+}
+
+bool CV_StereoCalibrationTest_C::rectifyUncalibrated( const Mat& points1,
+ const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
+{
+ H1.create(3, 3, CV_64F);
+ H2.create(3, 3, CV_64F);
+ CvMat _pt1 = points1, _pt2 = points2, matF, *pF=0, _H1 = H1, _H2 = H2;
+ if( F.size() == Size(3, 3) )
+ pF = &(matF = F);
+ return cvStereoRectifyUncalibrated(&_pt1, &_pt2, pF, imgSize, &_H1, &_H2, threshold) > 0;
+}
+
+
+//-------------------------------- CV_StereoCalibrationTest_CPP ------------------------------
+
+class CV_StereoCalibrationTest_CPP : public CV_StereoCalibrationTest
+{
+public:
+ CV_StereoCalibrationTest_CPP() {}
+protected:
+ virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
+ const vector<vector<Point2f> >& imagePoints1,
+ const vector<vector<Point2f> >& imagePoints2,
+ Mat& cameraMatrix1, Mat& distCoeffs1,
+ Mat& cameraMatrix2, Mat& distCoeffs2,
+ Size imageSize, Mat& R, Mat& T,
+ Mat& E, Mat& F, TermCriteria criteria, int flags );
+ virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
+ const Mat& cameraMatrix2, const Mat& distCoeffs2,
+ Size imageSize, const Mat& R, const Mat& T,
+ Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
+ double alpha, Size newImageSize,
+ Rect* validPixROI1, Rect* validPixROI2, int flags );
+ virtual bool rectifyUncalibrated( const Mat& points1,
+ const Mat& points2, const Mat& F, Size imgSize,
+ Mat& H1, Mat& H2, double threshold=5 );
+};
+
+double CV_StereoCalibrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
+ const vector<vector<Point2f> >& imagePoints1,
+ const vector<vector<Point2f> >& imagePoints2,
+ Mat& cameraMatrix1, Mat& distCoeffs1,
+ Mat& cameraMatrix2, Mat& distCoeffs2,
+ Size imageSize, Mat& R, Mat& T,
+ Mat& E, Mat& F, TermCriteria criteria, int flags )
+{
+ return stereoCalibrate( objectPoints, imagePoints1, imagePoints2,
+ cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
+ imageSize, R, T, E, F, criteria, flags );
+}
+
+void CV_StereoCalibrationTest_CPP::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
+ const Mat& cameraMatrix2, const Mat& distCoeffs2,
+ Size imageSize, const Mat& R, const Mat& T,
+ Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
+ double alpha, Size newImageSize,
+ Rect* validPixROI1, Rect* validPixROI2, int flags )
+{
+ stereoRectify( cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
+ imageSize, R, T, R1, R2, P1, P2, Q, alpha, newImageSize,validPixROI1, validPixROI2, flags );
+}
+
+bool CV_StereoCalibrationTest_CPP::rectifyUncalibrated( const Mat& points1,
+ const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
+{
+ return stereoRectifyUncalibrated( points1, points2, F, imgSize, H1, H2, threshold );
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST(Calib3d_CalibrateCamera_C, regression) { CV_CameraCalibrationTest_C test; test.safe_run(); }
+TEST(Calib3d_CalibrateCamera_CPP, regression) { CV_CameraCalibrationTest_CPP test; test.safe_run(); }
+TEST(Calib3d_CalibrationMatrixValues_C, accuracy) { CV_CalibrationMatrixValuesTest_C test; test.safe_run(); }
+TEST(Calib3d_CalibrationMatrixValues_CPP, accuracy) { CV_CalibrationMatrixValuesTest_CPP test; test.safe_run(); }
+TEST(Calib3d_ProjectPoints_C, accuracy) { CV_ProjectPointsTest_C test; test.safe_run(); }
+TEST(Calib3d_ProjectPoints_CPP, regression) { CV_ProjectPointsTest_CPP test; test.safe_run(); }
+TEST(Calib3d_StereoCalibrate_C, regression) { CV_StereoCalibrationTest_C test; test.safe_run(); }
+TEST(Calib3d_StereoCalibrate_CPP, regression) { CV_StereoCalibrationTest_CPP test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <limits>
+#include <vector>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#include "test_chessboardgenerator.hpp"
+
+using namespace cv;
+using namespace std;
+
+//template<class T> ostream& operator<<(ostream& out, const Mat_<T>& mat)
+//{
+// for(Mat_<T>::const_iterator pos = mat.begin(), end = mat.end(); pos != end; ++pos)
+// out << *pos << " ";
+// return out;
+//}
+//ostream& operator<<(ostream& out, const Mat& mat) { return out << Mat_<double>(mat); }
+
+Mat calcRvec(const vector<Point3f>& points, const Size& cornerSize)
+{
+ Point3f p00 = points[0];
+ Point3f p10 = points[1];
+ Point3f p01 = points[cornerSize.width];
+
+ Vec3d ex(p10.x - p00.x, p10.y - p00.y, p10.z - p00.z);
+ Vec3d ey(p01.x - p00.x, p01.y - p00.y, p01.z - p00.z);
+ Vec3d ez = ex.cross(ey);
+
+ Mat rot(3, 3, CV_64F);
+ *rot.ptr<Vec3d>(0) = ex;
+ *rot.ptr<Vec3d>(1) = ey;
+ *rot.ptr<Vec3d>(2) = ez * (1.0/norm(ez));
+
+ Mat res;
+ Rodrigues(rot.t(), res);
+ return res.reshape(1, 1);
+}
+
+class CV_CalibrateCameraArtificialTest : public cvtest::BaseTest
+{
+public:
+ CV_CalibrateCameraArtificialTest()
+ {
+ }
+ ~CV_CalibrateCameraArtificialTest() {}
+protected:
+ int r;
+
+ const static int JUST_FIND_CORNERS = 0;
+ const static int USE_CORNERS_SUBPIX = 1;
+ const static int USE_4QUAD_CORNERS = 2;
+ const static int ARTIFICIAL_CORNERS = 4;
+
+
+ bool checkErr(double a, double a0, double eps, double delta)
+ {
+ return fabs(a - a0) > eps * (fabs(a0) + delta);
+ }
+
+ void compareCameraMatrs(const Mat_<double>& camMat, const Mat& camMat_est)
+ {
+ if ( camMat_est.at<double>(0, 1) != 0 || camMat_est.at<double>(1, 0) != 0 ||
+ camMat_est.at<double>(2, 0) != 0 || camMat_est.at<double>(2, 1) != 0 ||
+ camMat_est.at<double>(2, 2) != 1)
+ {
+ ts->printf( cvtest::TS::LOG, "Bad shape of camera matrix returned \n");
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ }
+
+ double fx_e = camMat_est.at<double>(0, 0), fy_e = camMat_est.at<double>(1, 1);
+ double cx_e = camMat_est.at<double>(0, 2), cy_e = camMat_est.at<double>(1, 2);
+
+ double fx = camMat(0, 0), fy = camMat(1, 1), cx = camMat(0, 2), cy = camMat(1, 2);
+
+ const double eps = 1e-2;
+ const double dlt = 1e-5;
+
+ bool fail = checkErr(fx_e, fx, eps, dlt) || checkErr(fy_e, fy, eps, dlt) ||
+ checkErr(cx_e, cx, eps, dlt) || checkErr(cy_e, cy, eps, dlt);
+
+ if (fail)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+ ts->printf( cvtest::TS::LOG, "%d) Expected [Fx Fy Cx Cy] = [%.3f %.3f %.3f %.3f]\n", r, fx, fy, cx, cy);
+ ts->printf( cvtest::TS::LOG, "%d) Estimated [Fx Fy Cx Cy] = [%.3f %.3f %.3f %.3f]\n", r, fx_e, fy_e, cx_e, cy_e);
+ }
+
+ void compareDistCoeffs(const Mat_<double>& distCoeffs, const Mat& distCoeffs_est)
+ {
+ const double *dt_e = distCoeffs_est.ptr<double>();
+
+ double k1_e = dt_e[0], k2_e = dt_e[1], k3_e = dt_e[4];
+ double p1_e = dt_e[2], p2_e = dt_e[3];
+
+ double k1 = distCoeffs(0, 0), k2 = distCoeffs(0, 1), k3 = distCoeffs(0, 4);
+ double p1 = distCoeffs(0, 2), p2 = distCoeffs(0, 3);
+
+ const double eps = 5e-2;
+ const double dlt = 1e-3;
+
+ const double eps_k3 = 5;
+ const double dlt_k3 = 1e-3;
+
+ bool fail = checkErr(k1_e, k1, eps, dlt) || checkErr(k2_e, k2, eps, dlt) || checkErr(k3_e, k3, eps_k3, dlt_k3) ||
+ checkErr(p1_e, p1, eps, dlt) || checkErr(p2_e, p2, eps, dlt);
+
+ if (fail)
+ {
+ // commented according to vp123's recomendation. TODO - improve accuaracy
+ //ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY); ss
+ }
+ ts->printf( cvtest::TS::LOG, "%d) DistCoeff exp=(%.2f, %.2f, %.4f, %.4f %.2f)\n", r, k1, k2, p1, p2, k3);
+ ts->printf( cvtest::TS::LOG, "%d) DistCoeff est=(%.2f, %.2f, %.4f, %.4f %.2f)\n", r, k1_e, k2_e, p1_e, p2_e, k3_e);
+ ts->printf( cvtest::TS::LOG, "%d) AbsError = [%.5f %.5f %.5f %.5f %.5f]\n", r, fabs(k1-k1_e), fabs(k2-k2_e), fabs(p1-p1_e), fabs(p2-p2_e), fabs(k3-k3_e));
+ }
+
+ void compareShiftVecs(const vector<Mat>& tvecs, const vector<Mat>& tvecs_est)
+ {
+ const double eps = 1e-2;
+ const double dlt = 1e-4;
+
+ int err_count = 0;
+ const int errMsgNum = 4;
+ for(size_t i = 0; i < tvecs.size(); ++i)
+ {
+ const Point3d& tvec = *tvecs[i].ptr<Point3d>();
+ const Point3d& tvec_est = *tvecs_est[i].ptr<Point3d>();
+
+ if (norm(tvec_est - tvec) > eps* (norm(tvec) + dlt))
+ {
+ if (err_count++ < errMsgNum)
+ {
+ if (err_count == errMsgNum)
+ ts->printf( cvtest::TS::LOG, "%d) ...\n", r);
+ else
+ {
+ ts->printf( cvtest::TS::LOG, "%d) Bad accuracy in returned tvecs. Index = %d\n", r, i);
+ ts->printf( cvtest::TS::LOG, "%d) norm(tvec_est - tvec) = %f, norm(tvec_exp) = %f \n", r, norm(tvec_est - tvec), norm(tvec));
+ }
+ }
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+ }
+ }
+
+ void compareRotationVecs(const vector<Mat>& rvecs, const vector<Mat>& rvecs_est)
+ {
+ const double eps = 2e-2;
+ const double dlt = 1e-4;
+
+ Mat rmat, rmat_est;
+ int err_count = 0;
+ const int errMsgNum = 4;
+ for(size_t i = 0; i < rvecs.size(); ++i)
+ {
+ Rodrigues(rvecs[i], rmat);
+ Rodrigues(rvecs_est[i], rmat_est);
+
+ if (norm(rmat_est, rmat) > eps* (norm(rmat) + dlt))
+ {
+ if (err_count++ < errMsgNum)
+ {
+ if (err_count == errMsgNum)
+ ts->printf( cvtest::TS::LOG, "%d) ...\n", r);
+ else
+ {
+ ts->printf( cvtest::TS::LOG, "%d) Bad accuracy in returned rvecs (rotation matrs). Index = %d\n", r, i);
+ ts->printf( cvtest::TS::LOG, "%d) norm(rot_mat_est - rot_mat_exp) = %f, norm(rot_mat_exp) = %f \n", r, norm(rmat_est, rmat), norm(rmat));
+
+ }
+ }
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+ }
+ }
+
+ double reprojectErrorWithoutIntrinsics(const vector<Point3f>& cb3d, const vector<Mat>& rvecs_exp, const vector<Mat>& tvecs_exp,
+ const vector<Mat>& rvecs_est, const vector<Mat>& tvecs_est)
+ {
+ const static Mat eye33 = Mat::eye(3, 3, CV_64F);
+ const static Mat zero15 = Mat::zeros(1, 5, CV_64F);
+ Mat chessboard3D(cb3d);
+ vector<Point2f> uv_exp, uv_est;
+ double res = 0;
+
+ for(size_t i = 0; i < rvecs_exp.size(); ++i)
+ {
+ projectPoints(chessboard3D, rvecs_exp[i], tvecs_exp[i], eye33, zero15, uv_exp);
+ projectPoints(chessboard3D, rvecs_est[i], tvecs_est[i], eye33, zero15, uv_est);
+ for(size_t j = 0; j < cb3d.size(); ++j)
+ res += norm(uv_exp[i] - uv_est[i]);
+ }
+ return res;
+ }
+
+ Size2f sqSile;
+
+ vector<Point3f> chessboard3D;
+ vector<Mat> boards, rvecs_exp, tvecs_exp, rvecs_spnp, tvecs_spnp;
+ vector< vector<Point3f> > objectPoints;
+ vector< vector<Point2f> > imagePoints_art;
+ vector< vector<Point2f> > imagePoints_findCb;
+
+
+ void prepareForTest(const Mat& bg, const Mat& camMat, const Mat& distCoeffs, size_t brdsNum, const ChessBoardGenerator& cbg)
+ {
+ sqSile = Size2f(1.f, 1.f);
+ Size cornersSize = cbg.cornersSize();
+
+ chessboard3D.clear();
+ for(int j = 0; j < cornersSize.height; ++j)
+ for(int i = 0; i < cornersSize.width; ++i)
+ chessboard3D.push_back(Point3f(sqSile.width * i, sqSile.height * j, 0));
+
+ boards.resize(brdsNum);
+ rvecs_exp.resize(brdsNum);
+ tvecs_exp.resize(brdsNum);
+ objectPoints.clear();
+ objectPoints.resize(brdsNum, chessboard3D);
+ imagePoints_art.clear();
+ imagePoints_findCb.clear();
+
+ vector<Point2f> corners_art, corners_fcb;
+ for(size_t i = 0; i < brdsNum; ++i)
+ {
+ for(;;)
+ {
+ boards[i] = cbg(bg, camMat, distCoeffs, sqSile, corners_art);
+ if(findChessboardCorners(boards[i], cornersSize, corners_fcb))
+ break;
+ }
+
+ //cv::namedWindow("CB"); imshow("CB", boards[i]); cv::waitKey();
+
+ imagePoints_art.push_back(corners_art);
+ imagePoints_findCb.push_back(corners_fcb);
+
+ tvecs_exp[i].create(1, 3, CV_64F);
+ *tvecs_exp[i].ptr<Point3d>() = cbg.corners3d[0];
+ rvecs_exp[i] = calcRvec(cbg.corners3d, cbg.cornersSize());
+ }
+
+ }
+
+ void runTest(const Size& imgSize, const Mat_<double>& camMat, const Mat_<double>& distCoeffs, size_t brdsNum, const Size& cornersSize, int flag = 0)
+ {
+ const TermCriteria tc(TermCriteria::EPS|TermCriteria::MAX_ITER, 30, 0.1);
+
+ vector< vector<Point2f> > imagePoints;
+
+ switch(flag)
+ {
+ case JUST_FIND_CORNERS: imagePoints = imagePoints_findCb; break;
+ case ARTIFICIAL_CORNERS: imagePoints = imagePoints_art; break;
+
+ case USE_CORNERS_SUBPIX:
+ for(size_t i = 0; i < brdsNum; ++i)
+ {
+ Mat gray;
+ cvtColor(boards[i], gray, CV_BGR2GRAY);
+ vector<Point2f> tmp = imagePoints_findCb[i];
+ cornerSubPix(gray, tmp, Size(5, 5), Size(-1,-1), tc);
+ imagePoints.push_back(tmp);
+ }
+ break;
+ case USE_4QUAD_CORNERS:
+ for(size_t i = 0; i < brdsNum; ++i)
+ {
+ Mat gray;
+ cvtColor(boards[i], gray, CV_BGR2GRAY);
+ vector<Point2f> tmp = imagePoints_findCb[i];
+ find4QuadCornerSubpix(gray, tmp, Size(5, 5));
+ imagePoints.push_back(tmp);
+ }
+ break;
+ default:
+ throw std::exception();
+ }
+
+ Mat camMat_est = Mat::eye(3, 3, CV_64F), distCoeffs_est = Mat::zeros(1, 5, CV_64F);
+ vector<Mat> rvecs_est, tvecs_est;
+
+ int flags = /*CV_CALIB_FIX_K3|*/CV_CALIB_FIX_K4|CV_CALIB_FIX_K5|CV_CALIB_FIX_K6; //CALIB_FIX_K3; //CALIB_FIX_ASPECT_RATIO | | CALIB_ZERO_TANGENT_DIST;
+ double rep_error = calibrateCamera(objectPoints, imagePoints, imgSize, camMat_est, distCoeffs_est, rvecs_est, tvecs_est, flags);
+ rep_error /= brdsNum * cornersSize.area();
+
+ const double thres = 1;
+ if (rep_error > thres)
+ {
+ ts->printf( cvtest::TS::LOG, "%d) Too big reproject error = %f\n", r, rep_error);
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+
+ compareCameraMatrs(camMat, camMat_est);
+ compareDistCoeffs(distCoeffs, distCoeffs_est);
+ compareShiftVecs(tvecs_exp, tvecs_est);
+ compareRotationVecs(rvecs_exp, rvecs_est);
+
+ double rep_errorWOI = reprojectErrorWithoutIntrinsics(chessboard3D, rvecs_exp, tvecs_exp, rvecs_est, tvecs_est);
+ rep_errorWOI /= brdsNum * cornersSize.area();
+
+ const double thres2 = 0.01;
+ if (rep_errorWOI > thres2)
+ {
+ ts->printf( cvtest::TS::LOG, "%d) Too big reproject error without intrinsics = %f\n", r, rep_errorWOI);
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+
+ ts->printf( cvtest::TS::LOG, "%d) Testing solvePnP...\n", r);
+ rvecs_spnp.resize(brdsNum);
+ tvecs_spnp.resize(brdsNum);
+ for(size_t i = 0; i < brdsNum; ++i)
+ solvePnP(Mat(objectPoints[i]), Mat(imagePoints[i]), camMat, distCoeffs, rvecs_spnp[i], tvecs_spnp[i]);
+
+ compareShiftVecs(tvecs_exp, tvecs_spnp);
+ compareRotationVecs(rvecs_exp, rvecs_spnp);
+ }
+
+ void run(int)
+ {
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+ RNG& rng = theRNG();
+
+ int progress = 0;
+ int repeat_num = 3;
+ for(r = 0; r < repeat_num; ++r)
+ {
+ const int brds_num = 20;
+
+ Mat bg(Size(640, 480), CV_8UC3);
+ randu(bg, Scalar::all(32), Scalar::all(255));
+ GaussianBlur(bg, bg, Size(5, 5), 2);
+
+ double fx = 300 + (20 * (double)rng - 10);
+ double fy = 300 + (20 * (double)rng - 10);
+
+ double cx = bg.cols/2 + (40 * (double)rng - 20);
+ double cy = bg.rows/2 + (40 * (double)rng - 20);
+
+ Mat_<double> camMat(3, 3);
+ camMat << fx, 0., cx, 0, fy, cy, 0., 0., 1.;
+
+ double k1 = 0.5 + (double)rng/5;
+ double k2 = (double)rng/5;
+ double k3 = (double)rng/5;
+
+ double p1 = 0.001 + (double)rng/10;
+ double p2 = 0.001 + (double)rng/10;
+
+ Mat_<double> distCoeffs(1, 5, 0.0);
+ distCoeffs << k1, k2, p1, p2, k3;
+
+ ChessBoardGenerator cbg(Size(9, 8));
+ cbg.min_cos = 0.9;
+ cbg.cov = 0.8;
+
+ progress = update_progress(progress, r, repeat_num, 0);
+ ts->printf( cvtest::TS::LOG, "\n");
+ prepareForTest(bg, camMat, distCoeffs, brds_num, cbg);
+
+ ts->printf( cvtest::TS::LOG, "artificial corners\n");
+ runTest(bg.size(), camMat, distCoeffs, brds_num, cbg.cornersSize(), ARTIFICIAL_CORNERS);
+ progress = update_progress(progress, r, repeat_num, 0);
+
+ ts->printf( cvtest::TS::LOG, "findChessboard corners\n");
+ runTest(bg.size(), camMat, distCoeffs, brds_num, cbg.cornersSize(), JUST_FIND_CORNERS);
+ progress = update_progress(progress, r, repeat_num, 0);
+
+ ts->printf( cvtest::TS::LOG, "cornersSubPix corners\n");
+ runTest(bg.size(), camMat, distCoeffs, brds_num, cbg.cornersSize(), USE_CORNERS_SUBPIX);
+ progress = update_progress(progress, r, repeat_num, 0);
+
+ ts->printf( cvtest::TS::LOG, "4quad corners\n");
+ runTest(bg.size(), camMat, distCoeffs, brds_num, cbg.cornersSize(), USE_4QUAD_CORNERS);
+ progress = update_progress(progress, r, repeat_num, 0);
+ }
+ }
+};
+
+TEST(Calib3d_CalibrateCamera_CPP, accuracy_on_artificial_data) { CV_CalibrateCameraArtificialTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "test_chessboardgenerator.hpp"
+
+#include <iostream>
+
+using namespace cv;
+using namespace std;
+
+class CV_CameraCalibrationBadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_CameraCalibrationBadArgTest() : imgSize(800, 600) {}
+ ~CV_CameraCalibrationBadArgTest() {}
+protected:
+ void run(int);
+ void run_func(void) {};
+
+ const static int M = 1;
+
+ Size imgSize;
+ Size corSize;
+ Mat chessBoard;
+ Mat corners;
+
+ struct C_Caller
+ {
+ CvMat* objPts;
+ CvMat* imgPts;
+ CvMat* npoints;
+ Size imageSize;
+ CvMat *cameraMatrix;
+ CvMat *distCoeffs;
+ CvMat *rvecs;
+ CvMat *tvecs;
+ int flags;
+
+ void operator()() const
+ {
+ cvCalibrateCamera2(objPts, imgPts, npoints, imageSize,
+ cameraMatrix, distCoeffs, rvecs, tvecs, flags );
+ }
+ };
+};
+
+
+void CV_CameraCalibrationBadArgTest::run( int /* start_from */ )
+{
+ Mat_<float> camMat(3, 3);
+ Mat_<float> distCoeffs0(1, 5);
+
+ camMat << 300.f, 0.f, imgSize.width/2.f, 0, 300.f, imgSize.height/2.f, 0.f, 0.f, 1.f;
+ distCoeffs0 << 1.2f, 0.2f, 0.f, 0.f, 0.f;
+
+ ChessBoardGenerator cbg(Size(8,6));
+ corSize = cbg.cornersSize();
+ vector<Point2f> exp_corn;
+ chessBoard = cbg(Mat(imgSize, CV_8U, Scalar(0)), camMat, distCoeffs0, exp_corn);
+ Mat_<Point2f>(corSize.height, corSize.width, (Point2f*)&exp_corn[0]).copyTo(corners);
+
+ CvMat objPts, imgPts, npoints, cameraMatrix, distCoeffs, rvecs, tvecs;
+ Mat zeros(1, sizeof(CvMat), CV_8U, Scalar(0));
+
+ C_Caller caller, bad_caller;
+ caller.imageSize = imgSize;
+ caller.objPts = &objPts;
+ caller.imgPts = &imgPts;
+ caller.npoints = &npoints;
+ caller.cameraMatrix = &cameraMatrix;
+ caller.distCoeffs = &distCoeffs;
+ caller.rvecs = &rvecs;
+ caller.tvecs = &tvecs;
+
+ /////////////////////////////
+ Mat objPts_cpp;
+ Mat imgPts_cpp;
+ Mat npoints_cpp;
+ Mat cameraMatrix_cpp;
+ Mat distCoeffs_cpp;
+ Mat rvecs_cpp;
+ Mat tvecs_cpp;
+
+ objPts_cpp.create(corSize, CV_32FC3);
+ for(int j = 0; j < corSize.height; ++j)
+ for(int i = 0; i < corSize.width; ++i)
+ objPts_cpp.at<Point3f>(j, i) = Point3i(i, j, 0);
+ objPts_cpp = objPts_cpp.reshape(3, 1);
+
+ imgPts_cpp = corners.clone().reshape(2, 1);
+ npoints_cpp = Mat_<int>(M, 1, corSize.width * corSize.height);
+ cameraMatrix_cpp.create(3, 3, CV_32F);
+ distCoeffs_cpp.create(5, 1, CV_32F);
+ rvecs_cpp.create(M, 1, CV_32FC3);
+ tvecs_cpp.create(M, 1, CV_32FC3);
+
+ caller.flags = 0;
+ //CV_CALIB_USE_INTRINSIC_GUESS; //CV_CALIB_FIX_ASPECT_RATIO
+ //CV_CALIB_USE_INTRINSIC_GUESS //CV_CALIB_FIX_ASPECT_RATIO
+ //CV_CALIB_FIX_PRINCIPAL_POINT //CV_CALIB_ZERO_TANGENT_DIST
+ //CV_CALIB_FIX_FOCAL_LENGTH //CV_CALIB_FIX_K1 //CV_CALIB_FIX_K2 //CV_CALIB_FIX_K3
+
+ objPts = objPts_cpp;
+ imgPts = imgPts_cpp;
+ npoints = npoints_cpp;
+ cameraMatrix = cameraMatrix_cpp;
+ distCoeffs = distCoeffs_cpp;
+ rvecs = rvecs_cpp;
+ tvecs = tvecs_cpp;
+
+ /* /*//*/ */
+ int errors = 0;
+
+ bad_caller = caller;
+ bad_caller.objPts = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero passed in objPts", bad_caller);
+
+ bad_caller = caller;
+ bad_caller.imgPts = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero passed in imgPts", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.npoints = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero passed in npoints", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.cameraMatrix = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero passed in cameraMatrix", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero passed in distCoeffs", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.imageSize.width = -1;
+ errors += run_test_case( CV_StsOutOfRange, "Bad image width", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.imageSize.height = -1;
+ errors += run_test_case( CV_StsOutOfRange, "Bad image height", bad_caller );
+
+ Mat bad_nts_cpp1 = Mat_<float>(M, 1, 1.f);
+ Mat bad_nts_cpp2 = Mat_<int>(3, 3, corSize.width * corSize.height);
+ CvMat bad_npts_c1 = bad_nts_cpp1;
+ CvMat bad_npts_c2 = bad_nts_cpp2;
+
+ bad_caller = caller;
+ bad_caller.npoints = &bad_npts_c1;
+ errors += run_test_case( CV_StsUnsupportedFormat, "Bad npoints format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.npoints = &bad_npts_c2;
+ errors += run_test_case( CV_StsUnsupportedFormat, "Bad npoints size", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.rvecs = (CvMat*)zeros.ptr();
+ errors += run_test_case( CV_StsBadArg, "Bad rvecs header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.tvecs = (CvMat*)zeros.ptr();
+ errors += run_test_case( CV_StsBadArg, "Bad tvecs header", bad_caller );
+
+ Mat bad_rvecs_cpp1(M+1, 1, CV_32FC3); CvMat bad_rvecs_c1 = bad_rvecs_cpp1;
+ Mat bad_tvecs_cpp1(M+1, 1, CV_32FC3); CvMat bad_tvecs_c1 = bad_tvecs_cpp1;
+
+
+
+ Mat bad_rvecs_cpp2(M, 2, CV_32FC3); CvMat bad_rvecs_c2 = bad_rvecs_cpp2;
+ Mat bad_tvecs_cpp2(M, 2, CV_32FC3); CvMat bad_tvecs_c2 = bad_tvecs_cpp2;
+
+ bad_caller = caller;
+ bad_caller.rvecs = &bad_rvecs_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad tvecs header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.rvecs = &bad_rvecs_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad tvecs header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.tvecs = &bad_tvecs_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad tvecs header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.tvecs = &bad_tvecs_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad tvecs header", bad_caller );
+
+ Mat bad_cameraMatrix_cpp1(3, 3, CV_32S); CvMat bad_cameraMatrix_c1 = bad_cameraMatrix_cpp1;
+ Mat bad_cameraMatrix_cpp2(2, 3, CV_32F); CvMat bad_cameraMatrix_c2 = bad_cameraMatrix_cpp2;
+ Mat bad_cameraMatrix_cpp3(3, 2, CV_64F); CvMat bad_cameraMatrix_c3 = bad_cameraMatrix_cpp3;
+
+
+
+ bad_caller = caller;
+ bad_caller.cameraMatrix = &bad_cameraMatrix_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad camearaMatrix header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.cameraMatrix = &bad_cameraMatrix_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad camearaMatrix header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.cameraMatrix = &bad_cameraMatrix_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad camearaMatrix header", bad_caller );
+
+ Mat bad_distCoeffs_cpp1(1, 5, CV_32S); CvMat bad_distCoeffs_c1 = bad_distCoeffs_cpp1;
+ Mat bad_distCoeffs_cpp2(2, 2, CV_64F); CvMat bad_distCoeffs_c2 = bad_distCoeffs_cpp2;
+ Mat bad_distCoeffs_cpp3(1, 6, CV_64F); CvMat bad_distCoeffs_c3 = bad_distCoeffs_cpp3;
+
+
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs header", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs header", bad_caller );
+
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs header", bad_caller );
+
+ double CM[] = {0, 0, 0, /**/0, 0, 0, /**/0, 0, 0};
+ Mat bad_cameraMatrix_cpp4(3, 3, CV_64F, CM); CvMat bad_cameraMatrix_c4 = bad_cameraMatrix_cpp4;
+
+ bad_caller = caller;
+ bad_caller.flags |= CV_CALIB_USE_INTRINSIC_GUESS;
+ bad_caller.cameraMatrix = &bad_cameraMatrix_c4;
+ CM[0] = 0; //bad fx
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 0; //bad fy
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 500; CM[2] = -1; //bad cx
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 500; CM[2] = imgSize.width*2; //bad cx
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 500; CM[2] = imgSize.width/2; CM[5] = -1; //bad cy
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 500; CM[2] = imgSize.width/2; CM[5] = imgSize.height*2; //bad cy
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[0] = 500; CM[4] = 500; CM[2] = imgSize.width/2; CM[5] = imgSize.height/2;
+ CM[1] = 0.1; //Non-zero skew
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[1] = 0;
+ CM[3] = 0.1; /* mad matrix shape */
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[3] = 0; CM[6] = 0.1; /* mad matrix shape */
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[3] = 0; CM[6] = 0; CM[7] = 0.1; /* mad matrix shape */
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+
+ CM[3] = 0; CM[6] = 0; CM[7] = 0; CM[8] = 1.1; /* mad matrix shape */
+ errors += run_test_case( CV_StsOutOfRange, "Bad camearaMatrix data", bad_caller );
+ CM[8] = 1.0;
+
+ /////////////////////////////////////////////////////////////////////////////////////
+ bad_caller = caller;
+ Mat bad_objPts_cpp5 = objPts_cpp.clone(); CvMat bad_objPts_c5 = bad_objPts_cpp5;
+ bad_caller.objPts = &bad_objPts_c5;
+
+ cv::RNG& rng = theRNG();
+ for(int i = 0; i < bad_objPts_cpp5.rows; ++i)
+ bad_objPts_cpp5.at<Point3f>(0, i).z += ((float)rng - 0.5f);
+
+ errors += run_test_case( CV_StsBadArg, "Bad objPts data", bad_caller );
+
+ if (errors)
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ else
+ ts->set_failed_test_info(cvtest::TS::OK);
+
+ //try { caller(); }
+ //catch (...)
+ //{
+ // ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ // printf("+!");
+ //}
+}
+
+
+class CV_Rodrigues2BadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_Rodrigues2BadArgTest() {}
+ ~CV_Rodrigues2BadArgTest() {}
+protected:
+ void run_func(void) {};
+
+ struct C_Caller
+ {
+ CvMat* src;
+ CvMat* dst;
+ CvMat* jacobian;
+
+ void operator()() { cvRodrigues2(src, dst, jacobian); }
+ };
+
+ void run(int /* start_from */ )
+ {
+ Mat zeros(1, sizeof(CvMat), CV_8U, Scalar(0));
+ CvMat src_c, dst_c, jacobian_c;
+
+ Mat src_cpp(3, 1, CV_32F); src_c = src_cpp;
+ Mat dst_cpp(3, 3, CV_32F); dst_c = dst_cpp;
+ Mat jacobian_cpp(3, 9, CV_32F); jacobian_c = jacobian_cpp;
+
+ C_Caller caller, bad_caller;
+ caller.src = &src_c;
+ caller.dst = &dst_c;
+ caller.jacobian = &jacobian_c;
+
+ /* try { caller(); }
+ catch (...)
+ {
+ printf("badasfas");
+ }*/
+
+ /*/*//*/*/
+ int errors = 0;
+
+ bad_caller = caller;
+ bad_caller.src = 0;
+ errors += run_test_case( CV_StsNullPtr, "Src is zero pointer", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dst = 0;
+ errors += run_test_case( CV_StsNullPtr, "Dst is zero pointer", bad_caller );
+
+ Mat bad_src_cpp1(3, 1, CV_8U); CvMat bad_src_c1 = bad_src_cpp1;
+ Mat bad_dst_cpp1(3, 1, CV_8U); CvMat bad_dst_c1 = bad_dst_cpp1;
+ Mat bad_jac_cpp1(3, 1, CV_8U); CvMat bad_jac_c1 = bad_jac_cpp1;
+ Mat bad_jac_cpp2(3, 1, CV_32FC2); CvMat bad_jac_c2 = bad_jac_cpp2;
+ Mat bad_jac_cpp3(3, 1, CV_32F); CvMat bad_jac_c3 = bad_jac_cpp3;
+
+ bad_caller = caller;
+ bad_caller.src = &bad_src_c1;
+ errors += run_test_case( CV_StsUnsupportedFormat, "Bad src formart", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dst = &bad_dst_c1;
+ errors += run_test_case( CV_StsUnmatchedFormats, "Bad dst formart", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.jacobian = (CvMat*)zeros.ptr();
+ errors += run_test_case( CV_StsBadArg, "Bad jacobian ", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.jacobian = &bad_jac_c1;
+ errors += run_test_case( CV_StsUnmatchedFormats, "Bad jacobian format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.jacobian = &bad_jac_c2;
+ errors += run_test_case( CV_StsUnmatchedFormats, "Bad jacobian format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.jacobian = &bad_jac_c3;
+ errors += run_test_case( CV_StsBadSize, "Bad jacobian format", bad_caller );
+
+ Mat bad_src_cpp2(1, 1, CV_32F); CvMat bad_src_c2 = bad_src_cpp2;
+
+ bad_caller = caller;
+ bad_caller.src = &bad_src_c2;
+ errors += run_test_case( CV_StsBadSize, "Bad src format", bad_caller );
+
+ Mat bad_dst_cpp2(2, 1, CV_32F); CvMat bad_dst_c2 = bad_dst_cpp2;
+ Mat bad_dst_cpp3(3, 2, CV_32F); CvMat bad_dst_c3 = bad_dst_cpp3;
+ Mat bad_dst_cpp4(3, 3, CV_32FC2); CvMat bad_dst_c4 = bad_dst_cpp4;
+
+ bad_caller = caller;
+ bad_caller.dst = &bad_dst_c2;
+ errors += run_test_case( CV_StsBadSize, "Bad dst format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dst = &bad_dst_c3;
+ errors += run_test_case( CV_StsBadSize, "Bad dst format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dst = &bad_dst_c4;
+ errors += run_test_case( CV_StsBadSize, "Bad dst format", bad_caller );
+
+
+ /********/
+ src_cpp.create(3, 3, CV_32F); src_c = src_cpp;
+ dst_cpp.create(3, 1, CV_32F); dst_c = dst_cpp;
+
+
+ Mat bad_dst_cpp5(5, 5, CV_32F); CvMat bad_dst_c5 = bad_dst_cpp5;
+
+ bad_caller = caller;
+ bad_caller.dst = &bad_dst_c5;
+ errors += run_test_case( CV_StsBadSize, "Bad dst format", bad_caller );
+
+
+ if (errors)
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ else
+ ts->set_failed_test_info(cvtest::TS::OK);
+ }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+class CV_ProjectPoints2BadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_ProjectPoints2BadArgTest() : camMat(3, 3), distCoeffs(1, 5)
+ {
+ Size imsSize(800, 600);
+ camMat << 300.f, 0.f, imsSize.width/2.f, 0, 300.f, imsSize.height/2.f, 0.f, 0.f, 1.f;
+ distCoeffs << 1.2f, 0.2f, 0.f, 0.f, 0.f;
+ };
+ ~CV_ProjectPoints2BadArgTest() {} ;
+protected:
+ void run_func(void) {};
+
+ Mat_<float> camMat;
+ Mat_<float> distCoeffs;
+
+ struct C_Caller
+ {
+ CvMat* objectPoints;
+ CvMat* r_vec;
+ CvMat* t_vec;
+ CvMat* A;
+ CvMat* distCoeffs;
+ CvMat* imagePoints;
+ CvMat* dpdr;
+ CvMat* dpdt;
+ CvMat* dpdf;
+ CvMat* dpdc;
+ CvMat* dpdk;
+ double aspectRatio;
+
+ void operator()()
+ {
+ cvProjectPoints2( objectPoints, r_vec, t_vec, A, distCoeffs, imagePoints,
+ dpdr, dpdt, dpdf, dpdc, dpdk, aspectRatio );
+ }
+ };
+
+ void run(int /* start_from */ )
+ {
+ CvMat zeros;
+ memset(&zeros, 0, sizeof(zeros));
+
+ C_Caller caller, bad_caller;
+ CvMat objectPoints_c, r_vec_c, t_vec_c, A_c, distCoeffs_c, imagePoints_c,
+ dpdr_c, dpdt_c, dpdf_c, dpdc_c, dpdk_c;
+
+ const int n = 10;
+
+ Mat imagePoints_cpp(1, n, CV_32FC2); imagePoints_c = imagePoints_cpp;
+
+ Mat objectPoints_cpp(1, n, CV_32FC3);
+ randu(objectPoints_cpp, Scalar::all(1), Scalar::all(10));
+ objectPoints_c = objectPoints_cpp;
+
+ Mat t_vec_cpp(Mat::zeros(1, 3, CV_32F)); t_vec_c = t_vec_cpp;
+ Mat r_vec_cpp;
+ Rodrigues(Mat::eye(3, 3, CV_32F), r_vec_cpp); r_vec_c = r_vec_cpp;
+
+ Mat A_cpp = camMat.clone(); A_c = A_cpp;
+ Mat distCoeffs_cpp = distCoeffs.clone(); distCoeffs_c = distCoeffs_cpp;
+
+ Mat dpdr_cpp(2*n, 3, CV_32F); dpdr_c = dpdr_cpp;
+ Mat dpdt_cpp(2*n, 3, CV_32F); dpdt_c = dpdt_cpp;
+ Mat dpdf_cpp(2*n, 2, CV_32F); dpdf_c = dpdf_cpp;
+ Mat dpdc_cpp(2*n, 2, CV_32F); dpdc_c = dpdc_cpp;
+ Mat dpdk_cpp(2*n, 4, CV_32F); dpdk_c = dpdk_cpp;
+
+ caller.aspectRatio = 1.0;
+ caller.objectPoints = &objectPoints_c;
+ caller.r_vec = &r_vec_c;
+ caller.t_vec = &t_vec_c;
+ caller.A = &A_c;
+ caller.distCoeffs = &distCoeffs_c;
+ caller.imagePoints = &imagePoints_c;
+ caller.dpdr = &dpdr_c;
+ caller.dpdt = &dpdt_c;
+ caller.dpdf = &dpdf_c;
+ caller.dpdc = &dpdc_c;
+ caller.dpdk = &dpdk_c;
+
+ /********************/
+ int errors = 0;
+
+
+ bad_caller = caller;
+ bad_caller.objectPoints = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero objectPoints", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.r_vec = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero r_vec", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.t_vec = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero t_vec", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.A = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero camMat", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.imagePoints = 0;
+ errors += run_test_case( CV_StsBadArg, "Zero imagePoints", bad_caller );
+
+ /****************************/
+ Mat bad_r_vec_cpp1(r_vec_cpp.size(), CV_32S); CvMat bad_r_vec_c1 = bad_r_vec_cpp1;
+ Mat bad_r_vec_cpp2(2, 2, CV_32F); CvMat bad_r_vec_c2 = bad_r_vec_cpp2;
+ Mat bad_r_vec_cpp3(r_vec_cpp.size(), CV_32FC2); CvMat bad_r_vec_c3 = bad_r_vec_cpp3;
+
+ bad_caller = caller;
+ bad_caller.r_vec = &bad_r_vec_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad rvec format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.r_vec = &bad_r_vec_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad rvec format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.r_vec = &bad_r_vec_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad rvec format", bad_caller );
+
+ /****************************/
+ Mat bad_t_vec_cpp1(t_vec_cpp.size(), CV_32S); CvMat bad_t_vec_c1 = bad_t_vec_cpp1;
+ Mat bad_t_vec_cpp2(2, 2, CV_32F); CvMat bad_t_vec_c2 = bad_t_vec_cpp2;
+ Mat bad_t_vec_cpp3(1, 1, CV_32FC2); CvMat bad_t_vec_c3 = bad_t_vec_cpp3;
+
+ bad_caller = caller;
+ bad_caller.t_vec = &bad_t_vec_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad tvec format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.t_vec = &bad_t_vec_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad tvec format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.t_vec = &bad_t_vec_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad tvec format", bad_caller );
+
+ /****************************/
+ Mat bad_A_cpp1(A_cpp.size(), CV_32S); CvMat bad_A_c1 = bad_A_cpp1;
+ Mat bad_A_cpp2(2, 2, CV_32F); CvMat bad_A_c2 = bad_A_cpp2;
+
+ bad_caller = caller;
+ bad_caller.A = &bad_A_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad A format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.A = &bad_A_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad A format", bad_caller );
+
+ /****************************/
+ Mat bad_distCoeffs_cpp1(distCoeffs_cpp.size(), CV_32S); CvMat bad_distCoeffs_c1 = bad_distCoeffs_cpp1;
+ Mat bad_distCoeffs_cpp2(2, 2, CV_32F); CvMat bad_distCoeffs_c2 = bad_distCoeffs_cpp2;
+ Mat bad_distCoeffs_cpp3(1, 7, CV_32F); CvMat bad_distCoeffs_c3 = bad_distCoeffs_cpp3;
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = &bad_distCoeffs_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad distCoeffs format", bad_caller );
+
+
+ /****************************/
+ Mat bad_dpdr_cpp1(dpdr_cpp.size(), CV_32S); CvMat bad_dpdr_c1 = bad_dpdr_cpp1;
+ Mat bad_dpdr_cpp2(dpdr_cpp.cols+1, 3, CV_32F); CvMat bad_dpdr_c2 = bad_dpdr_cpp2;
+ Mat bad_dpdr_cpp3(dpdr_cpp.cols, 7, CV_32F); CvMat bad_dpdr_c3 = bad_dpdr_cpp3;
+
+ bad_caller = caller;
+ bad_caller.dpdr = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdr format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdr = &bad_dpdr_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdr format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdr = &bad_dpdr_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdr format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdr = &bad_dpdr_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdr format", bad_caller );
+
+ /****************************/
+
+ bad_caller = caller;
+ bad_caller.dpdt = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdt format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdt = &bad_dpdr_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdt format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdt = &bad_dpdr_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdt format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdt = &bad_dpdr_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdt format", bad_caller );
+
+ /****************************/
+
+ Mat bad_dpdf_cpp2(dpdr_cpp.cols+1, 2, CV_32F); CvMat bad_dpdf_c2 = bad_dpdf_cpp2;
+
+ bad_caller = caller;
+ bad_caller.dpdf = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdf format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdf = &bad_dpdr_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdf format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdf = &bad_dpdf_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdf format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdf = &bad_dpdr_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdf format", bad_caller );
+
+ /****************************/
+
+ bad_caller = caller;
+ bad_caller.dpdc = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdc format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdc = &bad_dpdr_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdc format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdc = &bad_dpdf_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdc format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdc = &bad_dpdr_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdc format", bad_caller );
+
+ /****************************/
+
+ bad_caller = caller;
+ bad_caller.dpdk = &zeros;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdk format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdk = &bad_dpdr_c1;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdk format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdk = &bad_dpdf_c2;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdk format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.dpdk = &bad_dpdr_c3;
+ errors += run_test_case( CV_StsBadArg, "Bad dpdk format", bad_caller );
+
+ bad_caller = caller;
+ bad_caller.distCoeffs = 0;
+ errors += run_test_case( CV_StsNullPtr, "distCoeffs is NULL while dpdk is not", bad_caller );
+
+
+ if (errors)
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ else
+ ts->set_failed_test_info(cvtest::TS::OK);
+ }
+};
+
+
+TEST(Calib3d_CalibrateCamera_C, badarg) { CV_CameraCalibrationBadArgTest test; test.safe_run(); }
+TEST(Calib3d_Rodrigues_C, badarg) { CV_Rodrigues2BadArgTest test; test.safe_run(); }
+TEST(Calib3d_ProjectPoints_C, badarg) { CV_ProjectPoints2BadArgTest test; test.safe_run(); }
+
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ // By downloading, copying, installing or using the software you agree to this license.
+ // If you do not agree to this license, do not download, install,
+ // copy or use the software.
+ //
+ //
+ // License Agreement
+ // For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+ // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ // * Redistribution's of source code must retain the above copyright notice,
+ // this list of conditions and the following disclaimer.
+ //
+ // * Redistribution's in binary form must reproduce the above copyright notice,
+ // this list of conditions and the following disclaimer in the documentation
+ // and/or other materials provided with the distribution.
+ //
+ // * The name of the copyright holders may not be used to endorse or promote products
+ // derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "test_chessboardgenerator.hpp"
+
+#include <vector>
+#include <iterator>
+#include <algorithm>
+
+using namespace cv;
+using namespace std;
+
+ChessBoardGenerator::ChessBoardGenerator(const Size& _patternSize) : sensorWidth(32), sensorHeight(24),
+ squareEdgePointsNum(200), min_cos(sqrt(2.f)*0.5f), cov(0.5),
+ patternSize(_patternSize), rendererResolutionMultiplier(4), tvec(Mat::zeros(1, 3, CV_32F))
+{
+ Rodrigues(Mat::eye(3, 3, CV_32F), rvec);
+}
+
+void cv::ChessBoardGenerator::generateEdge(const Point3f& p1, const Point3f& p2, vector<Point3f>& out) const
+{
+ Point3f step = (p2 - p1) * (1.f/squareEdgePointsNum);
+ for(size_t n = 0; n < squareEdgePointsNum; ++n)
+ out.push_back( p1 + step * (float)n);
+}
+
+Size cv::ChessBoardGenerator::cornersSize() const
+{
+ return Size(patternSize.width-1, patternSize.height-1);
+}
+
+struct Mult
+{
+ float m;
+ Mult(int mult) : m((float)mult) {}
+ Point2f operator()(const Point2f& p)const { return p * m; }
+};
+
+void cv::ChessBoardGenerator::generateBasis(Point3f& pb1, Point3f& pb2) const
+{
+ RNG& rng = theRNG();
+
+ Vec3f n;
+ for(;;)
+ {
+ n[0] = rng.uniform(-1.f, 1.f);
+ n[1] = rng.uniform(-1.f, 1.f);
+ n[2] = rng.uniform(-1.f, 1.f);
+ float len = (float)norm(n);
+ n[0]/=len;
+ n[1]/=len;
+ n[2]/=len;
+
+ if (n[2] > min_cos)
+ break;
+ }
+
+ Vec3f n_temp = n; n_temp[0] += 100;
+ Vec3f b1 = n.cross(n_temp);
+ Vec3f b2 = n.cross(b1);
+ float len_b1 = (float)norm(b1);
+ float len_b2 = (float)norm(b2);
+
+ pb1 = Point3f(b1[0]/len_b1, b1[1]/len_b1, b1[2]/len_b1);
+ pb2 = Point3f(b2[0]/len_b1, b2[1]/len_b2, b2[2]/len_b2);
+}
+
+
+Mat cv::ChessBoardGenerator::generateChessBoard(const Mat& bg, const Mat& camMat, const Mat& distCoeffs,
+ const Point3f& zero, const Point3f& pb1, const Point3f& pb2,
+ float sqWidth, float sqHeight, const vector<Point3f>& whole,
+ vector<Point2f>& corners) const
+{
+ vector< vector<Point> > squares_black;
+ for(int i = 0; i < patternSize.width; ++i)
+ for(int j = 0; j < patternSize.height; ++j)
+ if ( (i % 2 == 0 && j % 2 == 0) || (i % 2 != 0 && j % 2 != 0) )
+ {
+ vector<Point3f> pts_square3d;
+ vector<Point2f> pts_square2d;
+
+ Point3f p1 = zero + (i + 0) * sqWidth * pb1 + (j + 0) * sqHeight * pb2;
+ Point3f p2 = zero + (i + 1) * sqWidth * pb1 + (j + 0) * sqHeight * pb2;
+ Point3f p3 = zero + (i + 1) * sqWidth * pb1 + (j + 1) * sqHeight * pb2;
+ Point3f p4 = zero + (i + 0) * sqWidth * pb1 + (j + 1) * sqHeight * pb2;
+ generateEdge(p1, p2, pts_square3d);
+ generateEdge(p2, p3, pts_square3d);
+ generateEdge(p3, p4, pts_square3d);
+ generateEdge(p4, p1, pts_square3d);
+
+ projectPoints(Mat(pts_square3d), rvec, tvec, camMat, distCoeffs, pts_square2d);
+ squares_black.resize(squares_black.size() + 1);
+ vector<Point2f> temp;
+ approxPolyDP(Mat(pts_square2d), temp, 1.0, true);
+ transform(temp.begin(), temp.end(), back_inserter(squares_black.back()), Mult(rendererResolutionMultiplier));
+ }
+
+ /* calculate corners */
+ corners3d.clear();
+ for(int j = 0; j < patternSize.height - 1; ++j)
+ for(int i = 0; i < patternSize.width - 1; ++i)
+ corners3d.push_back(zero + (i + 1) * sqWidth * pb1 + (j + 1) * sqHeight * pb2);
+ corners.clear();
+ projectPoints(Mat(corners3d), rvec, tvec, camMat, distCoeffs, corners);
+
+ vector<Point3f> whole3d;
+ vector<Point2f> whole2d;
+ generateEdge(whole[0], whole[1], whole3d);
+ generateEdge(whole[1], whole[2], whole3d);
+ generateEdge(whole[2], whole[3], whole3d);
+ generateEdge(whole[3], whole[0], whole3d);
+ projectPoints(Mat(whole3d), rvec, tvec, camMat, distCoeffs, whole2d);
+ vector<Point2f> temp_whole2d;
+ approxPolyDP(Mat(whole2d), temp_whole2d, 1.0, true);
+
+ vector< vector<Point > > whole_contour(1);
+ transform(temp_whole2d.begin(), temp_whole2d.end(),
+ back_inserter(whole_contour.front()), Mult(rendererResolutionMultiplier));
+
+ Mat result;
+ if (rendererResolutionMultiplier == 1)
+ {
+ result = bg.clone();
+ drawContours(result, whole_contour, -1, Scalar::all(255), CV_FILLED, CV_AA);
+ drawContours(result, squares_black, -1, Scalar::all(0), CV_FILLED, CV_AA);
+ }
+ else
+ {
+ Mat tmp;
+ resize(bg, tmp, bg.size() * rendererResolutionMultiplier);
+ drawContours(tmp, whole_contour, -1, Scalar::all(255), CV_FILLED, CV_AA);
+ drawContours(tmp, squares_black, -1, Scalar::all(0), CV_FILLED, CV_AA);
+ resize(tmp, result, bg.size(), 0, 0, INTER_AREA);
+ }
+
+ return result;
+}
+
+Mat cv::ChessBoardGenerator::operator ()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs, vector<Point2f>& corners) const
+{
+ cov = min(cov, 0.8);
+ double fovx, fovy, focalLen;
+ Point2d principalPoint;
+ double aspect;
+ calibrationMatrixValues( camMat, bg.size(), sensorWidth, sensorHeight,
+ fovx, fovy, focalLen, principalPoint, aspect);
+
+ RNG& rng = theRNG();
+
+ float d1 = static_cast<float>(rng.uniform(0.1, 10.0));
+ float ah = static_cast<float>(rng.uniform(-fovx/2 * cov, fovx/2 * cov) * CV_PI / 180);
+ float av = static_cast<float>(rng.uniform(-fovy/2 * cov, fovy/2 * cov) * CV_PI / 180);
+
+ Point3f p;
+ p.z = cos(ah) * d1;
+ p.x = sin(ah) * d1;
+ p.y = p.z * tan(av);
+
+ Point3f pb1, pb2;
+ generateBasis(pb1, pb2);
+
+ float cbHalfWidth = static_cast<float>(norm(p) * sin( min(fovx, fovy) * 0.5 * CV_PI / 180));
+ float cbHalfHeight = cbHalfWidth * patternSize.height / patternSize.width;
+
+ float cbHalfWidthEx = cbHalfWidth * ( patternSize.width + 1) / patternSize.width;
+ float cbHalfHeightEx = cbHalfHeight * (patternSize.height + 1) / patternSize.height;
+
+ vector<Point3f> pts3d(4);
+ vector<Point2f> pts2d(4);
+ for(;;)
+ {
+ pts3d[0] = p + pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+ pts3d[1] = p + pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[2] = p - pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[3] = p - pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+
+ /* can remake with better perf */
+ projectPoints(Mat(pts3d), rvec, tvec, camMat, distCoeffs, pts2d);
+
+ bool inrect1 = pts2d[0].x < bg.cols && pts2d[0].y < bg.rows && pts2d[0].x > 0 && pts2d[0].y > 0;
+ bool inrect2 = pts2d[1].x < bg.cols && pts2d[1].y < bg.rows && pts2d[1].x > 0 && pts2d[1].y > 0;
+ bool inrect3 = pts2d[2].x < bg.cols && pts2d[2].y < bg.rows && pts2d[2].x > 0 && pts2d[2].y > 0;
+ bool inrect4 = pts2d[3].x < bg.cols && pts2d[3].y < bg.rows && pts2d[3].x > 0 && pts2d[3].y > 0;
+
+ if (inrect1 && inrect2 && inrect3 && inrect4)
+ break;
+
+ cbHalfWidth*=0.8f;
+ cbHalfHeight = cbHalfWidth * patternSize.height / patternSize.width;
+
+ cbHalfWidthEx = cbHalfWidth * ( patternSize.width + 1) / patternSize.width;
+ cbHalfHeightEx = cbHalfHeight * (patternSize.height + 1) / patternSize.height;
+ }
+
+ Point3f zero = p - pb1 * cbHalfWidth - cbHalfHeight * pb2;
+ float sqWidth = 2 * cbHalfWidth/patternSize.width;
+ float sqHeight = 2 * cbHalfHeight/patternSize.height;
+
+ return generateChessBoard(bg, camMat, distCoeffs, zero, pb1, pb2, sqWidth, sqHeight, pts3d, corners);
+}
+
+
+Mat cv::ChessBoardGenerator::operator ()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs,
+ const Size2f& squareSize, vector<Point2f>& corners) const
+{
+ cov = min(cov, 0.8);
+ double fovx, fovy, focalLen;
+ Point2d principalPoint;
+ double aspect;
+ calibrationMatrixValues( camMat, bg.size(), sensorWidth, sensorHeight,
+ fovx, fovy, focalLen, principalPoint, aspect);
+
+ RNG& rng = theRNG();
+
+ float d1 = static_cast<float>(rng.uniform(0.1, 10.0));
+ float ah = static_cast<float>(rng.uniform(-fovx/2 * cov, fovx/2 * cov) * CV_PI / 180);
+ float av = static_cast<float>(rng.uniform(-fovy/2 * cov, fovy/2 * cov) * CV_PI / 180);
+
+ Point3f p;
+ p.z = cos(ah) * d1;
+ p.x = sin(ah) * d1;
+ p.y = p.z * tan(av);
+
+ Point3f pb1, pb2;
+ generateBasis(pb1, pb2);
+
+ float cbHalfWidth = squareSize.width * patternSize.width * 0.5f;
+ float cbHalfHeight = squareSize.height * patternSize.height * 0.5f;
+
+ float cbHalfWidthEx = cbHalfWidth * ( patternSize.width + 1) / patternSize.width;
+ float cbHalfHeightEx = cbHalfHeight * (patternSize.height + 1) / patternSize.height;
+
+ vector<Point3f> pts3d(4);
+ vector<Point2f> pts2d(4);
+ for(;;)
+ {
+ pts3d[0] = p + pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+ pts3d[1] = p + pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[2] = p - pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[3] = p - pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+
+ /* can remake with better perf */
+ projectPoints(Mat(pts3d), rvec, tvec, camMat, distCoeffs, pts2d);
+
+ bool inrect1 = pts2d[0].x < bg.cols && pts2d[0].y < bg.rows && pts2d[0].x > 0 && pts2d[0].y > 0;
+ bool inrect2 = pts2d[1].x < bg.cols && pts2d[1].y < bg.rows && pts2d[1].x > 0 && pts2d[1].y > 0;
+ bool inrect3 = pts2d[2].x < bg.cols && pts2d[2].y < bg.rows && pts2d[2].x > 0 && pts2d[2].y > 0;
+ bool inrect4 = pts2d[3].x < bg.cols && pts2d[3].y < bg.rows && pts2d[3].x > 0 && pts2d[3].y > 0;
+
+ if ( inrect1 && inrect2 && inrect3 && inrect4)
+ break;
+
+ p.z *= 1.1f;
+ }
+
+ Point3f zero = p - pb1 * cbHalfWidth - cbHalfHeight * pb2;
+
+ return generateChessBoard(bg, camMat, distCoeffs, zero, pb1, pb2,
+ squareSize.width, squareSize.height, pts3d, corners);
+}
+
+Mat cv::ChessBoardGenerator::operator ()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs,
+ const Size2f& squareSize, const Point3f& pos, vector<Point2f>& corners) const
+{
+ cov = min(cov, 0.8);
+ Point3f p = pos;
+ Point3f pb1, pb2;
+ generateBasis(pb1, pb2);
+
+ float cbHalfWidth = squareSize.width * patternSize.width * 0.5f;
+ float cbHalfHeight = squareSize.height * patternSize.height * 0.5f;
+
+ float cbHalfWidthEx = cbHalfWidth * ( patternSize.width + 1) / patternSize.width;
+ float cbHalfHeightEx = cbHalfHeight * (patternSize.height + 1) / patternSize.height;
+
+ vector<Point3f> pts3d(4);
+ vector<Point2f> pts2d(4);
+
+ pts3d[0] = p + pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+ pts3d[1] = p + pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[2] = p - pb1 * cbHalfWidthEx - cbHalfHeightEx * pb2;
+ pts3d[3] = p - pb1 * cbHalfWidthEx + cbHalfHeightEx * pb2;
+
+ /* can remake with better perf */
+ projectPoints(Mat(pts3d), rvec, tvec, camMat, distCoeffs, pts2d);
+
+ Point3f zero = p - pb1 * cbHalfWidth - cbHalfHeight * pb2;
+
+ return generateChessBoard(bg, camMat, distCoeffs, zero, pb1, pb2,
+ squareSize.width, squareSize.height, pts3d, corners);
+}
+
--- /dev/null
+#ifndef CV_CHESSBOARDGENERATOR_H143KJTVYM389YTNHKFDHJ89NYVMO3VLMEJNTBGUEIYVCM203P
+#define CV_CHESSBOARDGENERATOR_H143KJTVYM389YTNHKFDHJ89NYVMO3VLMEJNTBGUEIYVCM203P
+
+#include "opencv2/calib3d/calib3d.hpp"
+
+namespace cv
+{
+
+class ChessBoardGenerator
+{
+public:
+ double sensorWidth;
+ double sensorHeight;
+ size_t squareEdgePointsNum;
+ double min_cos;
+ mutable double cov;
+ Size patternSize;
+ int rendererResolutionMultiplier;
+
+ ChessBoardGenerator(const Size& patternSize = Size(8, 6));
+ Mat operator()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs, vector<Point2f>& corners) const;
+ Mat operator()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs, const Size2f& squareSize, vector<Point2f>& corners) const;
+ Mat operator()(const Mat& bg, const Mat& camMat, const Mat& distCoeffs, const Size2f& squareSize, const Point3f& pos, vector<Point2f>& corners) const;
+ Size cornersSize() const;
+
+ mutable vector<Point3f> corners3d;
+private:
+ void generateEdge(const Point3f& p1, const Point3f& p2, vector<Point3f>& out) const;
+ Mat generateChessBoard(const Mat& bg, const Mat& camMat, const Mat& distCoeffs,
+ const Point3f& zero, const Point3f& pb1, const Point3f& pb2,
+ float sqWidth, float sqHeight, const vector<Point3f>& whole, vector<Point2f>& corners) const;
+ void generateBasis(Point3f& pb1, Point3f& pb2) const;
+
+ Mat rvec, tvec;
+};
+
+};
+
+
+#endif
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "test_chessboardgenerator.hpp"
+
+#include <limits>
+#include <numeric>
+
+using namespace std;
+using namespace cv;
+
+#define _L2_ERR
+
+void show_points( const Mat& gray, const Mat& u, const vector<Point2f>& v, Size pattern_size, bool was_found )
+{
+ Mat rgb( gray.size(), CV_8U);
+ merge(vector<Mat>(3, gray), rgb);
+
+ for(size_t i = 0; i < v.size(); i++ )
+ circle( rgb, v[i], 3, CV_RGB(255, 0, 0), CV_FILLED);
+
+ if( !u.empty() )
+ {
+ const Point2f* u_data = u.ptr<Point2f>();
+ size_t count = u.cols * u.rows;
+ for(size_t i = 0; i < count; i++ )
+ circle( rgb, u_data[i], 3, CV_RGB(0, 255, 0), CV_FILLED);
+ }
+ if (!v.empty())
+ {
+ Mat corners((int)v.size(), 1, CV_32FC2, (void*)&v[0]);
+ drawChessboardCorners( rgb, pattern_size, corners, was_found );
+ }
+ //namedWindow( "test", 0 ); imshow( "test", rgb ); waitKey(0);
+}
+
+
+enum Pattern { CHESSBOARD, CIRCLES_GRID };
+
+class CV_ChessboardDetectorTest : public cvtest::BaseTest
+{
+public:
+ CV_ChessboardDetectorTest( Pattern pattern );
+protected:
+ void run(int);
+ void run_batch(const string& filename);
+ bool checkByGenerator();
+
+ Pattern pattern;
+};
+
+CV_ChessboardDetectorTest::CV_ChessboardDetectorTest( Pattern _pattern )
+{
+ pattern = _pattern;
+}
+
+double calcError(const vector<Point2f>& v, const Mat& u)
+{
+ int count_exp = u.cols * u.rows;
+ const Point2f* u_data = u.ptr<Point2f>();
+
+ double err = numeric_limits<double>::max();
+ for( int k = 0; k < 2; ++k )
+ {
+ double err1 = 0;
+ for( int j = 0; j < count_exp; ++j )
+ {
+ int j1 = k == 0 ? j : count_exp - j - 1;
+ double dx = fabs( v[j].x - u_data[j1].x );
+ double dy = fabs( v[j].y - u_data[j1].y );
+
+#if defined(_L2_ERR)
+ err1 += dx*dx + dy*dy;
+#else
+ dx = MAX( dx, dy );
+ if( dx > err1 )
+ err1 = dx;
+#endif //_L2_ERR
+ //printf("dx = %f\n", dx);
+ }
+ //printf("\n");
+ err = min(err, err1);
+ }
+
+#if defined(_L2_ERR)
+ err = sqrt(err/count_exp);
+#endif //_L2_ERR
+
+ return err;
+}
+
+const double rough_success_error_level = 2.5;
+const double precise_success_error_level = 2;
+
+
+/* ///////////////////// chess_corner_test ///////////////////////// */
+void CV_ChessboardDetectorTest::run( int /*start_from */)
+{
+ /*if (!checkByGenerator())
+ return;*/
+ switch( pattern )
+ {
+ case CHESSBOARD:
+ checkByGenerator();
+ run_batch("chessboard_list.dat");
+ run_batch("chessboard_list_subpixel.dat");
+ break;
+ case CIRCLES_GRID:
+ run_batch("circles_list.dat");
+ break;
+ }
+}
+
+void CV_ChessboardDetectorTest::run_batch( const string& filename )
+{
+ cvtest::TS& ts = *this->ts;
+ ts.set_failed_test_info( cvtest::TS::OK );
+
+ ts.printf(cvtest::TS::LOG, "\nRunning batch %s\n", filename.c_str());
+//#define WRITE_POINTS 1
+#ifndef WRITE_POINTS
+ double max_rough_error = 0, max_precise_error = 0;
+#endif
+ string folder;
+ switch( pattern )
+ {
+ case CHESSBOARD:
+ folder = string(ts.get_data_path()) + "cameracalibration/";
+ break;
+ case CIRCLES_GRID:
+ folder = string(ts.get_data_path()) + "cameracalibration/circles/";
+ break;
+ }
+
+ FileStorage fs( folder + filename, FileStorage::READ );
+ FileNode board_list = fs["boards"];
+
+ if( !fs.isOpened() || board_list.empty() || !board_list.isSeq() || board_list.size() % 2 != 0 )
+ {
+ ts.printf( cvtest::TS::LOG, "%s can not be readed or is not valid\n", (folder + filename).c_str() );
+ ts.printf( cvtest::TS::LOG, "fs.isOpened=%d, board_list.empty=%d, board_list.isSeq=%d,board_list.size()%2=%d\n",
+ fs.isOpened(), (int)board_list.empty(), board_list.isSeq(), board_list.size()%2);
+ ts.set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
+ return;
+ }
+
+ int progress = 0;
+ int max_idx = board_list.node->data.seq->total/2;
+ double sum_error = 0.0;
+ int count = 0;
+
+ for(int idx = 0; idx < max_idx; ++idx )
+ {
+ ts.update_context( this, idx, true );
+
+ /* read the image */
+ string img_file = board_list[idx * 2];
+ Mat gray = imread( folder + img_file, 0);
+
+ if( gray.empty() )
+ {
+ ts.printf( cvtest::TS::LOG, "one of chessboard images can't be read: %s\n", img_file.c_str() );
+ ts.set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
+ continue;
+ }
+
+ string filename = folder + (string)board_list[idx * 2 + 1];
+ Mat expected;
+ {
+ CvMat *u = (CvMat*)cvLoad( filename.c_str() );
+ if(!u )
+ {
+ ts.printf( cvtest::TS::LOG, "one of chessboard corner files can't be read: %s\n", filename.c_str() );
+ ts.set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
+ continue;
+ }
+ expected = Mat(u, true);
+ cvReleaseMat( &u );
+ }
+ size_t count_exp = static_cast<size_t>(expected.cols * expected.rows);
+ Size pattern_size = expected.size();
+
+ vector<Point2f> v;
+ bool result = false;
+ switch( pattern )
+ {
+ case CHESSBOARD:
+ result = findChessboardCorners(gray, pattern_size, v, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE);
+ break;
+ case CIRCLES_GRID:
+ result = findCirclesGrid(gray, pattern_size, v);
+ break;
+ }
+ show_points( gray, Mat(), v, pattern_size, result );
+ if( !result || v.size() != count_exp )
+ {
+ ts.printf( cvtest::TS::LOG, "chessboard is not found in %s\n", img_file.c_str() );
+ ts.set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ continue;
+ }
+
+#ifndef WRITE_POINTS
+ double err = calcError(v, expected);
+#if 0
+ if( err > rough_success_error_level )
+ {
+ ts.printf( cvtest::TS::LOG, "bad accuracy of corner guesses\n" );
+ ts.set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ continue;
+ }
+#endif
+ max_rough_error = MAX( max_rough_error, err );
+#endif
+ if( pattern == CHESSBOARD )
+ cornerSubPix( gray, v, Size(5, 5), Size(-1,-1), TermCriteria(TermCriteria::EPS|TermCriteria::MAX_ITER, 30, 0.1));
+ //find4QuadCornerSubpix(gray, v, Size(5, 5));
+ show_points( gray, expected, v, pattern_size, result );
+
+#ifndef WRITE_POINTS
+// printf("called find4QuadCornerSubpix\n");
+ err = calcError(v, expected);
+ sum_error += err;
+ count++;
+#if 1
+ if( err > precise_success_error_level )
+ {
+ ts.printf( cvtest::TS::LOG, "Image %s: bad accuracy of adjusted corners %f\n", img_file.c_str(), err );
+ ts.set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ continue;
+ }
+#endif
+ ts.printf(cvtest::TS::LOG, "Error on %s is %f\n", img_file.c_str(), err);
+ max_precise_error = MAX( max_precise_error, err );
+#else
+ Mat mat_v(pattern_size, CV_32FC2, (void*)&v[0]);
+ CvMat cvmat_v = mat_v;
+ cvSave( filename.c_str(), &cvmat_v );
+#endif
+ progress = update_progress( progress, idx, max_idx, 0 );
+ }
+
+ sum_error /= count;
+ ts.printf(cvtest::TS::LOG, "Average error is %f\n", sum_error);
+}
+
+double calcErrorMinError(const Size& cornSz, const vector<Point2f>& corners_found, const vector<Point2f>& corners_generated)
+{
+ Mat m1(cornSz, CV_32FC2, (Point2f*)&corners_generated[0]);
+ Mat m2; flip(m1, m2, 0);
+
+ Mat m3; flip(m1, m3, 1); m3 = m3.t(); flip(m3, m3, 1);
+
+ Mat m4 = m1.t(); flip(m4, m4, 1);
+
+ double min1 = min(calcError(corners_found, m1), calcError(corners_found, m2));
+ double min2 = min(calcError(corners_found, m3), calcError(corners_found, m4));
+ return min(min1, min2);
+}
+
+bool validateData(const ChessBoardGenerator& cbg, const Size& imgSz,
+ const vector<Point2f>& corners_generated)
+{
+ Size cornersSize = cbg.cornersSize();
+ Mat_<Point2f> mat(cornersSize.height, cornersSize.width, (Point2f*)&corners_generated[0]);
+
+ double minNeibDist = std::numeric_limits<double>::max();
+ double tmp = 0;
+ for(int i = 1; i < mat.rows - 2; ++i)
+ for(int j = 1; j < mat.cols - 2; ++j)
+ {
+ const Point2f& cur = mat(i, j);
+
+ tmp = norm( cur - mat(i + 1, j + 1) );
+ if (tmp < minNeibDist)
+ tmp = minNeibDist;
+
+ tmp = norm( cur - mat(i - 1, j + 1 ) );
+ if (tmp < minNeibDist)
+ tmp = minNeibDist;
+
+ tmp = norm( cur - mat(i + 1, j - 1) );
+ if (tmp < minNeibDist)
+ tmp = minNeibDist;
+
+ tmp = norm( cur - mat(i - 1, j - 1) );
+ if (tmp < minNeibDist)
+ tmp = minNeibDist;
+ }
+
+ const double threshold = 0.25;
+ double cbsize = (max(cornersSize.width, cornersSize.height) + 1) * minNeibDist;
+ int imgsize = min(imgSz.height, imgSz.width);
+ return imgsize * threshold < cbsize;
+}
+
+bool CV_ChessboardDetectorTest::checkByGenerator()
+{
+ bool res = true;
+ //theRNG() = 0x58e6e895b9913160;
+ //cv::DefaultRngAuto dra;
+ //theRNG() = *ts->get_rng();
+
+ Mat bg(Size(800, 600), CV_8UC3, Scalar::all(255));
+ randu(bg, Scalar::all(0), Scalar::all(255));
+ GaussianBlur(bg, bg, Size(7,7), 3.0);
+
+ Mat_<float> camMat(3, 3);
+ camMat << 300.f, 0.f, bg.cols/2.f, 0, 300.f, bg.rows/2.f, 0.f, 0.f, 1.f;
+
+ Mat_<float> distCoeffs(1, 5);
+ distCoeffs << 1.2f, 0.2f, 0.f, 0.f, 0.f;
+
+ const Size sizes[] = { Size(6, 6), Size(8, 6), Size(11, 12), Size(5, 4) };
+ const size_t sizes_num = sizeof(sizes)/sizeof(sizes[0]);
+ const int test_num = 16;
+ int progress = 0;
+ for(int i = 0; i < test_num; ++i)
+ {
+ progress = update_progress( progress, i, test_num, 0 );
+ ChessBoardGenerator cbg(sizes[i % sizes_num]);
+
+ vector<Point2f> corners_generated;
+
+ Mat cb = cbg(bg, camMat, distCoeffs, corners_generated);
+
+ if(!validateData(cbg, cb.size(), corners_generated))
+ {
+ ts->printf( cvtest::TS::LOG, "Chess board skipped - too small" );
+ continue;
+ }
+
+ /*cb = cb * 0.8 + Scalar::all(30);
+ GaussianBlur(cb, cb, Size(3, 3), 0.8); */
+ //cv::addWeighted(cb, 0.8, bg, 0.2, 20, cb);
+ //cv::namedWindow("CB"); cv::imshow("CB", cb); cv::waitKey();
+
+ vector<Point2f> corners_found;
+ int flags = i % 8; // need to check branches for all flags
+ bool found = findChessboardCorners(cb, cbg.cornersSize(), corners_found, flags);
+ if (!found)
+ {
+ ts->printf( cvtest::TS::LOG, "Chess board corners not found\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ res = false;
+ continue;
+ }
+
+ double err = calcErrorMinError(cbg.cornersSize(), corners_found, corners_generated);
+ if( err > rough_success_error_level )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of corner guesses" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ res = false;
+ continue;
+ }
+ }
+
+ /* ***** negative ***** */
+ {
+ vector<Point2f> corners_found;
+ bool found = findChessboardCorners(bg, Size(8, 7), corners_found);
+ if (found)
+ res = false;
+
+ ChessBoardGenerator cbg(Size(8, 7));
+
+ vector<Point2f> cg;
+ Mat cb = cbg(bg, camMat, distCoeffs, cg);
+
+ found = findChessboardCorners(cb, Size(3, 4), corners_found);
+ if (found)
+ res = false;
+
+ Point2f c = std::accumulate(cg.begin(), cg.end(), Point2f(), plus<Point2f>()) * (1.f/cg.size());
+
+ Mat_<double> aff(2, 3);
+ aff << 1.0, 0.0, -(double)c.x, 0.0, 1.0, 0.0;
+ Mat sh;
+ warpAffine(cb, sh, aff, cb.size());
+
+ found = findChessboardCorners(sh, cbg.cornersSize(), corners_found);
+ if (found)
+ res = false;
+
+ vector< vector<Point> > cnts(1);
+ vector<Point>& cnt = cnts[0];
+ cnt.push_back(cg[ 0]); cnt.push_back(cg[0+2]);
+ cnt.push_back(cg[7+0]); cnt.push_back(cg[7+2]);
+ cv::drawContours(cb, cnts, -1, Scalar::all(128), CV_FILLED);
+
+ found = findChessboardCorners(cb, cbg.cornersSize(), corners_found);
+ if (found)
+ res = false;
+
+ cv::drawChessboardCorners(cb, cbg.cornersSize(), Mat(corners_found), found);
+ }
+
+ return res;
+}
+
+TEST(Calib3d_ChessboardDetector, accuracy) { CV_ChessboardDetectorTest test( CHESSBOARD ); test.safe_run(); }
+TEST(Calib3d_CirclesPatternDetector, accuracy) { CV_ChessboardDetectorTest test( CIRCLES_GRID ); test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "test_chessboardgenerator.hpp"
+
+#include <limits>
+
+using namespace std;
+using namespace cv;
+
+class CV_ChessboardDetectorBadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_ChessboardDetectorBadArgTest();
+protected:
+ void run(int);
+ bool checkByGenerator();
+
+ bool cpp;
+
+ /* cpp interface */
+ Mat img;
+ Size pattern_size;
+ int flags;
+ vector<Point2f> corners;
+
+ /* c interface */
+ CvMat arr;
+ CvPoint2D32f* out_corners;
+ int* out_corner_count;
+
+
+ /* c interface draw corners */
+ bool drawCorners;
+ CvMat drawCorImg;
+ bool was_found;
+
+ void run_func()
+ {
+ if (cpp)
+ findChessboardCorners(img, pattern_size, corners, flags);
+ else
+ if (!drawCorners)
+ cvFindChessboardCorners( &arr, pattern_size, out_corners, out_corner_count, flags );
+ else
+ cvDrawChessboardCorners( &drawCorImg, pattern_size,
+ (CvPoint2D32f*)&corners[0], (int)corners.size(), was_found);
+ }
+};
+
+CV_ChessboardDetectorBadArgTest::CV_ChessboardDetectorBadArgTest() {}
+
+/* ///////////////////// chess_corner_test ///////////////////////// */
+void CV_ChessboardDetectorBadArgTest::run( int /*start_from */)
+{
+ Mat bg(800, 600, CV_8U, Scalar(0));
+ Mat_<float> camMat(3, 3);
+ camMat << 300.f, 0.f, bg.cols/2.f, 0, 300.f, bg.rows/2.f, 0.f, 0.f, 1.f;
+ Mat_<float> distCoeffs(1, 5);
+ distCoeffs << 1.2f, 0.2f, 0.f, 0.f, 0.f;
+
+ ChessBoardGenerator cbg(Size(8,6));
+ vector<Point2f> exp_corn;
+ Mat cb = cbg(bg, camMat, distCoeffs, exp_corn);
+
+ /* /*//*/ */
+ int errors = 0;
+ flags = CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_NORMALIZE_IMAGE;
+ cpp = true;
+
+ img = cb.clone();
+ pattern_size = Size(2,2);
+ errors += run_test_case( CV_StsOutOfRange, "Invlid pattern size" );
+
+ pattern_size = cbg.cornersSize();
+ cb.convertTo(img, CV_32F);
+ errors += run_test_case( CV_StsUnsupportedFormat, "Not 8-bit image" );
+
+ cv::merge(vector<Mat>(2, cb), img);
+ errors += run_test_case( CV_StsUnsupportedFormat, "2 channel image" );
+
+ cpp = false;
+ drawCorners = false;
+
+ img = cb.clone();
+ arr = img;
+ out_corner_count = 0;
+ out_corners = 0;
+ errors += run_test_case( CV_StsNullPtr, "Null pointer to corners" );
+
+ drawCorners = true;
+ Mat cvdrawCornImg(img.size(), CV_8UC2);
+ drawCorImg = cvdrawCornImg;
+ was_found = true;
+ errors += run_test_case( CV_StsUnsupportedFormat, "2 channel image" );
+
+
+ if (errors)
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ else
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Calib3d_ChessboardDetector, badarg) { CV_ChessboardDetectorBadArgTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+class CV_ChessboardDetectorTimingTest : public cvtest::BaseTest
+{
+public:
+ CV_ChessboardDetectorTimingTest();
+protected:
+ void run(int);
+};
+
+
+CV_ChessboardDetectorTimingTest::CV_ChessboardDetectorTimingTest()
+{
+}
+
+/* ///////////////////// chess_corner_test ///////////////////////// */
+void CV_ChessboardDetectorTimingTest::run( int start_from )
+{
+ int code = cvtest::TS::OK;
+
+ /* test parameters */
+ char filepath[1000];
+ char filename[1000];
+
+ CvMat* _v = 0;
+ CvPoint2D32f* v;
+
+ IplImage* img = 0;
+ IplImage* gray = 0;
+ IplImage* thresh = 0;
+
+ int idx, max_idx;
+ int progress = 0;
+
+ sprintf( filepath, "%scameracalibration/", ts->get_data_path().c_str() );
+ sprintf( filename, "%schessboard_timing_list.dat", filepath );
+ printf("Reading file %s\n", filename);
+ CvFileStorage* fs = cvOpenFileStorage( filename, 0, CV_STORAGE_READ );
+ CvFileNode* board_list = fs ? cvGetFileNodeByName( fs, 0, "boards" ) : 0;
+
+ if( !fs || !board_list || !CV_NODE_IS_SEQ(board_list->tag) ||
+ board_list->data.seq->total % 4 != 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "chessboard_timing_list.dat can not be readed or is not valid" );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ max_idx = board_list->data.seq->total/4;
+
+ for( idx = start_from; idx < max_idx; idx++ )
+ {
+ int count0 = -1;
+ int count = 0;
+ CvSize pattern_size;
+ int result, result1 = 0;
+
+ const char* imgname = cvReadString((CvFileNode*)cvGetSeqElem(board_list->data.seq,idx*4), "dummy.txt");
+ int is_chessboard = cvReadInt((CvFileNode*)cvGetSeqElem(board_list->data.seq,idx*4+1), 0);
+ pattern_size.width = cvReadInt((CvFileNode*)cvGetSeqElem(board_list->data.seq,idx*4 + 2), -1);
+ pattern_size.height = cvReadInt((CvFileNode*)cvGetSeqElem(board_list->data.seq,idx*4 + 3), -1);
+
+ ts->update_context( this, idx-1, true );
+
+ /* read the image */
+ sprintf( filename, "%s%s", filepath, imgname );
+
+ img = cvLoadImage( filename );
+
+ if( !img )
+ {
+ ts->printf( cvtest::TS::LOG, "one of chessboard images can't be read: %s\n", filename );
+ if( max_idx == 1 )
+ {
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+ continue;
+ }
+
+ ts->printf(cvtest::TS::LOG, "%s: chessboard %d:\n", imgname, is_chessboard);
+
+ gray = cvCreateImage( cvSize( img->width, img->height ), IPL_DEPTH_8U, 1 );
+ thresh = cvCreateImage( cvSize( img->width, img->height ), IPL_DEPTH_8U, 1 );
+ cvCvtColor( img, gray, CV_BGR2GRAY );
+
+
+ count0 = pattern_size.width*pattern_size.height;
+
+ /* allocate additional buffers */
+ _v = cvCreateMat(1, count0, CV_32FC2);
+ count = count0;
+
+ v = (CvPoint2D32f*)_v->data.fl;
+
+ int64 _time0 = cvGetTickCount();
+ result = cvCheckChessboard(gray, pattern_size);
+ int64 _time01 = cvGetTickCount();
+
+ OPENCV_CALL( result1 = cvFindChessboardCorners(
+ gray, pattern_size, v, &count, 15 ));
+ int64 _time1 = cvGetTickCount();
+
+ if( result != is_chessboard )
+ {
+ ts->printf( cvtest::TS::LOG, "Error: chessboard was %sdetected in the image %s\n",
+ result ? "" : "not ", imgname );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ if(result != result1)
+ {
+ ts->printf( cvtest::TS::LOG, "Warning: results differ cvCheckChessboard %d, cvFindChessboardCorners %d\n",
+ result, result1);
+ }
+
+ int num_pixels = gray->width*gray->height;
+ float check_chessboard_time = float(_time01 - _time0)/(float)cvGetTickFrequency(); // in us
+ ts->printf(cvtest::TS::LOG, " cvCheckChessboard time s: %f, us per pixel: %f\n",
+ check_chessboard_time*1e-6, check_chessboard_time/num_pixels);
+
+ float find_chessboard_time = float(_time1 - _time01)/(float)cvGetTickFrequency();
+ ts->printf(cvtest::TS::LOG, " cvFindChessboard time s: %f, us per pixel: %f\n",
+ find_chessboard_time*1e-6, find_chessboard_time/num_pixels);
+
+ cvReleaseMat( &_v );
+ cvReleaseImage( &img );
+ cvReleaseImage( &gray );
+ cvReleaseImage( &thresh );
+ progress = update_progress( progress, idx-1, max_idx, 0 );
+ }
+
+_exit_:
+
+ /* release occupied memory */
+ cvReleaseMat( &_v );
+ cvReleaseFileStorage( &fs );
+ cvReleaseImage( &img );
+ cvReleaseImage( &gray );
+ cvReleaseImage( &thresh );
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Calib3d_ChessboardDetector, timing) { CV_ChessboardDetectorTimingTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class Differential
+{
+public:
+ typedef Mat_<double> mat_t;
+
+ Differential(double eps_, const mat_t& rv1_, const mat_t& tv1_, const mat_t& rv2_, const mat_t& tv2_)
+ : rv1(rv1_), tv1(tv1_), rv2(rv2_), tv2(tv2_), eps(eps_), ev(3, 1) {}
+
+ void dRv1(mat_t& dr3_dr1, mat_t& dt3_dr1)
+ {
+ dr3_dr1.create(3, 3); dt3_dr1.create(3, 3);
+
+ for(int i = 0; i < 3; ++i)
+ {
+ ev.setTo(Scalar(0)); ev(i, 0) = eps;
+
+ composeRT( rv1 + ev, tv1, rv2, tv2, rv3_p, tv3_p);
+ composeRT( rv1 - ev, tv1, rv2, tv2, rv3_m, tv3_m);
+
+ dr3_dr1.col(i) = rv3_p - rv3_m;
+ dt3_dr1.col(i) = tv3_p - tv3_m;
+ }
+ dr3_dr1 /= 2 * eps; dt3_dr1 /= 2 * eps;
+ }
+
+ void dRv2(mat_t& dr3_dr2, mat_t& dt3_dr2)
+ {
+ dr3_dr2.create(3, 3); dt3_dr2.create(3, 3);
+
+ for(int i = 0; i < 3; ++i)
+ {
+ ev.setTo(Scalar(0)); ev(i, 0) = eps;
+
+ composeRT( rv1, tv1, rv2 + ev, tv2, rv3_p, tv3_p);
+ composeRT( rv1, tv1, rv2 - ev, tv2, rv3_m, tv3_m);
+
+ dr3_dr2.col(i) = rv3_p - rv3_m;
+ dt3_dr2.col(i) = tv3_p - tv3_m;
+ }
+ dr3_dr2 /= 2 * eps; dt3_dr2 /= 2 * eps;
+ }
+
+ void dTv1(mat_t& drt3_dt1, mat_t& dt3_dt1)
+ {
+ drt3_dt1.create(3, 3); dt3_dt1.create(3, 3);
+
+ for(int i = 0; i < 3; ++i)
+ {
+ ev.setTo(Scalar(0)); ev(i, 0) = eps;
+
+ composeRT( rv1, tv1 + ev, rv2, tv2, rv3_p, tv3_p);
+ composeRT( rv1, tv1 - ev, rv2, tv2, rv3_m, tv3_m);
+
+ drt3_dt1.col(i) = rv3_p - rv3_m;
+ dt3_dt1.col(i) = tv3_p - tv3_m;
+ }
+ drt3_dt1 /= 2 * eps; dt3_dt1 /= 2 * eps;
+ }
+
+ void dTv2(mat_t& dr3_dt2, mat_t& dt3_dt2)
+ {
+ dr3_dt2.create(3, 3); dt3_dt2.create(3, 3);
+
+ for(int i = 0; i < 3; ++i)
+ {
+ ev.setTo(Scalar(0)); ev(i, 0) = eps;
+
+ composeRT( rv1, tv1, rv2, tv2 + ev, rv3_p, tv3_p);
+ composeRT( rv1, tv1, rv2, tv2 - ev, rv3_m, tv3_m);
+
+ dr3_dt2.col(i) = rv3_p - rv3_m;
+ dt3_dt2.col(i) = tv3_p - tv3_m;
+ }
+ dr3_dt2 /= 2 * eps; dt3_dt2 /= 2 * eps;
+ }
+
+private:
+ const mat_t& rv1, tv1, rv2, tv2;
+ double eps;
+ Mat_<double> ev;
+
+ Differential& operator=(const Differential&);
+ Mat rv3_m, tv3_m, rv3_p, tv3_p;
+};
+
+class CV_composeRT_Test : public cvtest::BaseTest
+{
+public:
+ CV_composeRT_Test() {}
+ ~CV_composeRT_Test() {}
+protected:
+
+ void run(int)
+ {
+ cvtest::TS& ts = *this->ts;
+ ts.set_failed_test_info(cvtest::TS::OK);
+
+ Mat_<double> rvec1(3, 1), tvec1(3, 1), rvec2(3, 1), tvec2(3, 1);
+
+ randu(rvec1, Scalar(0), Scalar(6.29));
+ randu(rvec2, Scalar(0), Scalar(6.29));
+
+ randu(tvec1, Scalar(-2), Scalar(2));
+ randu(tvec2, Scalar(-2), Scalar(2));
+
+ Mat rvec3, tvec3;
+ composeRT(rvec1, tvec1, rvec2, tvec2, rvec3, tvec3);
+
+ Mat rvec3_exp, tvec3_exp;
+
+ Mat rmat1, rmat2;
+ Rodrigues(rvec1, rmat1);
+ Rodrigues(rvec2, rmat2);
+ Rodrigues(rmat2 * rmat1, rvec3_exp);
+
+ tvec3_exp = rmat2 * tvec1 + tvec2;
+
+ const double thres = 1e-5;
+ if (norm(rvec3_exp, rvec3) > thres || norm(tvec3_exp, tvec3) > thres)
+ ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+
+ const double eps = 1e-3;
+ Differential diff(eps, rvec1, tvec1, rvec2, tvec2);
+
+ Mat dr3dr1, dr3dt1, dr3dr2, dr3dt2, dt3dr1, dt3dt1, dt3dr2, dt3dt2;
+
+ composeRT(rvec1, tvec1, rvec2, tvec2, rvec3, tvec3,
+ dr3dr1, dr3dt1, dr3dr2, dr3dt2, dt3dr1, dt3dt1, dt3dr2, dt3dt2);
+
+ Mat_<double> dr3_dr1, dt3_dr1;
+ diff.dRv1(dr3_dr1, dt3_dr1);
+
+ if (norm(dr3_dr1, dr3dr1) > thres || norm(dt3_dr1, dt3dr1) > thres)
+ {
+ ts.printf( cvtest::TS::LOG, "Invalid derivates by r1\n" );
+ ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+
+ Mat_<double> dr3_dr2, dt3_dr2;
+ diff.dRv2(dr3_dr2, dt3_dr2);
+
+ if (norm(dr3_dr2, dr3dr2) > thres || norm(dt3_dr2, dt3dr2) > thres)
+ {
+ ts.printf( cvtest::TS::LOG, "Invalid derivates by r2\n" );
+ ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+
+ Mat_<double> dr3_dt1, dt3_dt1;
+ diff.dTv1(dr3_dt1, dt3_dt1);
+
+ if (norm(dr3_dt1, dr3dt1) > thres || norm(dt3_dt1, dt3dt1) > thres)
+ {
+ ts.printf( cvtest::TS::LOG, "Invalid derivates by t1\n" );
+ ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+
+ Mat_<double> dr3_dt2, dt3_dt2;
+ diff.dTv2(dr3_dt2, dt3_dt2);
+
+ if (norm(dr3_dt2, dr3dt2) > thres || norm(dt3_dt2, dt3dt2) > thres)
+ {
+ ts.printf( cvtest::TS::LOG, "Invalid derivates by t2\n" );
+ ts.set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ }
+ }
+};
+
+TEST(Calib3d_ComposeRT, accuracy) { CV_composeRT_Test test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+ //
+ // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+ //
+ // By downloading, copying, installing or using the software you agree to this license.
+ // If you do not agree to this license, do not download, install,
+ // copy or use the software.
+ //
+ //
+ // Intel License Agreement
+ // For Open Source Computer Vision Library
+ //
+ // Copyright (C) 2000, Intel Corporation, all rights reserved.
+ // Third party copyrights are property of their respective owners.
+ //
+ // Redistribution and use in source and binary forms, with or without modification,
+ // are permitted provided that the following conditions are met:
+ //
+ // * Redistribution's of source code must retain the above copyright notice,
+ // this list of conditions and the following disclaimer.
+ //
+ // * Redistribution's in binary form must reproduce the above copyright notice,
+ // this list of conditions and the following disclaimer in the documentation
+ // and/or other materials provided with the distribution.
+ //
+ // * The name of Intel Corporation may not be used to endorse or promote products
+ // derived from this software without specific prior written permission.
+ //
+ // This software is provided by the copyright holders and contributors "as is" and
+ // any express or implied warranties, including, but not limited to, the implied
+ // warranties of merchantability and fitness for a particular purpose are disclaimed.
+ // In no event shall the Intel Corporation or contributors be liable for any direct,
+ // indirect, incidental, special, exemplary, or consequential damages
+ // (including, but not limited to, procurement of substitute goods or services;
+ // loss of use, data, or profits; or business interruption) however caused
+ // and on any theory of liability, whether in contract, strict liability,
+ // or tort (including negligence or otherwise) arising in any way out of
+ // the use of this software, even if advised of the possibility of such damage.
+ //
+ //M*/
+
+#include "test_precomp.hpp"
+#include <limits>
+#include "test_chessboardgenerator.hpp"
+
+using namespace cv;
+
+class CV_ChessboardSubpixelTest : public cvtest::BaseTest
+{
+public:
+ CV_ChessboardSubpixelTest();
+
+protected:
+ Mat intrinsic_matrix_;
+ Mat distortion_coeffs_;
+ Size image_size_;
+
+ void run(int);
+ void generateIntrinsicParams();
+};
+
+
+int calcDistance(const vector<Point2f>& set1, const vector<Point2f>& set2, double& mean_dist)
+{
+ if(set1.size() != set2.size())
+ {
+ return 0;
+ }
+
+ std::vector<int> indices;
+ double sum_dist = 0.0;
+ for(size_t i = 0; i < set1.size(); i++)
+ {
+ double min_dist = std::numeric_limits<double>::max();
+ int min_idx = -1;
+
+ for(int j = 0; j < (int)set2.size(); j++)
+ {
+ double dist = norm(set1[i] - set2[j]);
+ if(dist < min_dist)
+ {
+ min_idx = j;
+ min_dist = dist;
+ }
+ }
+
+ // check validity of min_idx
+ if(min_idx == -1)
+ {
+ return 0;
+ }
+ std::vector<int>::iterator it = std::find(indices.begin(), indices.end(), min_idx);
+ if(it != indices.end())
+ {
+ // there are two points in set1 corresponding to the same point in set2
+ return 0;
+ }
+ indices.push_back(min_idx);
+
+// printf("dist %d = %f\n", (int)i, min_dist);
+
+ sum_dist += min_dist*min_dist;
+ }
+
+ mean_dist = sqrt(sum_dist/set1.size());
+// printf("sum_dist = %f, set1.size() = %d, mean_dist = %f\n", sum_dist, (int)set1.size(), mean_dist);
+
+ return 1;
+}
+
+CV_ChessboardSubpixelTest::CV_ChessboardSubpixelTest() :
+ intrinsic_matrix_(Size(3, 3), CV_64FC1), distortion_coeffs_(Size(1, 4), CV_64FC1),
+ image_size_(640, 480)
+{
+}
+
+/* ///////////////////// chess_corner_test ///////////////////////// */
+void CV_ChessboardSubpixelTest::run( int )
+{
+ int code = cvtest::TS::OK;
+ int progress = 0;
+
+ RNG& rng = ts->get_rng();
+
+ const int runs_count = 20;
+ const int max_pattern_size = 8;
+ const int min_pattern_size = 5;
+ Mat bg(image_size_, CV_8UC1);
+ bg = Scalar(0);
+
+ double sum_dist = 0.0;
+ int count = 0;
+ for(int i = 0; i < runs_count; i++)
+ {
+ const int pattern_width = min_pattern_size + cvtest::randInt(rng) % (max_pattern_size - min_pattern_size);
+ const int pattern_height = min_pattern_size + cvtest::randInt(rng) % (max_pattern_size - min_pattern_size);
+ Size pattern_size;
+ if(pattern_width > pattern_height)
+ {
+ pattern_size = Size(pattern_height, pattern_width);
+ }
+ else
+ {
+ pattern_size = Size(pattern_width, pattern_height);
+ }
+ ChessBoardGenerator gen_chessboard(Size(pattern_size.width + 1, pattern_size.height + 1));
+
+ // generates intrinsic camera and distortion matrices
+ generateIntrinsicParams();
+
+ vector<Point2f> corners;
+ Mat chessboard_image = gen_chessboard(bg, intrinsic_matrix_, distortion_coeffs_, corners);
+
+ vector<Point2f> test_corners;
+ bool result = findChessboardCorners(chessboard_image, pattern_size, test_corners, 15);
+ if(!result)
+ {
+#if 0
+ ts->printf(cvtest::TS::LOG, "Warning: chessboard was not detected! Writing image to test.jpg\n");
+ ts->printf(cvtest::TS::LOG, "Size = %d, %d\n", pattern_size.width, pattern_size.height);
+ ts->printf(cvtest::TS::LOG, "Intrinsic params: fx = %f, fy = %f, cx = %f, cy = %f\n",
+ intrinsic_matrix_.at<double>(0, 0), intrinsic_matrix_.at<double>(1, 1),
+ intrinsic_matrix_.at<double>(0, 2), intrinsic_matrix_.at<double>(1, 2));
+ ts->printf(cvtest::TS::LOG, "Distortion matrix: %f, %f, %f, %f, %f\n",
+ distortion_coeffs_.at<double>(0, 0), distortion_coeffs_.at<double>(0, 1),
+ distortion_coeffs_.at<double>(0, 2), distortion_coeffs_.at<double>(0, 3),
+ distortion_coeffs_.at<double>(0, 4));
+
+ imwrite("test.jpg", chessboard_image);
+#endif
+ continue;
+ }
+
+ double dist1 = 0.0;
+ int ret = calcDistance(corners, test_corners, dist1);
+ if(ret == 0)
+ {
+ ts->printf(cvtest::TS::LOG, "findChessboardCorners returns invalid corner coordinates!\n");
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+
+ IplImage chessboard_image_header = chessboard_image;
+ cvFindCornerSubPix(&chessboard_image_header, (CvPoint2D32f*)&test_corners[0],
+ (int)test_corners.size(), cvSize(3, 3), cvSize(1, 1), cvTermCriteria(CV_TERMCRIT_EPS|CV_TERMCRIT_ITER,300,0.1));
+ find4QuadCornerSubpix(chessboard_image, test_corners, Size(5, 5));
+
+ double dist2 = 0.0;
+ ret = calcDistance(corners, test_corners, dist2);
+ if(ret == 0)
+ {
+ ts->printf(cvtest::TS::LOG, "findCornerSubpix returns invalid corner coordinates!\n");
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+
+ ts->printf(cvtest::TS::LOG, "Error after findChessboardCorners: %f, after findCornerSubPix: %f\n",
+ dist1, dist2);
+ sum_dist += dist2;
+ count++;
+
+ const double max_reduce_factor = 0.8;
+ if(dist1 < dist2*max_reduce_factor)
+ {
+ ts->printf(cvtest::TS::LOG, "findCornerSubPix increases average error!\n");
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+
+ progress = update_progress( progress, i-1, runs_count, 0 );
+ }
+ sum_dist /= count;
+ ts->printf(cvtest::TS::LOG, "Average error after findCornerSubpix: %f\n", sum_dist);
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+void CV_ChessboardSubpixelTest::generateIntrinsicParams()
+{
+ RNG& rng = ts->get_rng();
+ const double max_focus_length = 1000.0;
+ const double max_focus_diff = 5.0;
+
+ double fx = cvtest::randReal(rng)*max_focus_length;
+ double fy = fx + cvtest::randReal(rng)*max_focus_diff;
+ double cx = image_size_.width/2;
+ double cy = image_size_.height/2;
+
+ double k1 = 0.5*cvtest::randReal(rng);
+ double k2 = 0.05*cvtest::randReal(rng);
+ double p1 = 0.05*cvtest::randReal(rng);
+ double p2 = 0.05*cvtest::randReal(rng);
+ double k3 = 0.0;
+
+ intrinsic_matrix_ = (Mat_<double>(3, 3) << fx, 0.0, cx, 0.0, fy, cy, 0.0, 0.0, 1.0);
+ distortion_coeffs_ = (Mat_<double>(1, 5) << k1, k2, p1, p2, k3);
+}
+
+TEST(Calib3d_ChessboardSubPixDetector, accuracy) { CV_ChessboardSubpixelTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+int cvTsRodrigues( const CvMat* src, CvMat* dst, CvMat* jacobian )
+{
+ int depth;
+ int i;
+ float Jf[27];
+ double J[27];
+ CvMat _Jf, matJ = cvMat( 3, 9, CV_64F, J );
+
+ depth = CV_MAT_DEPTH(src->type);
+
+ if( jacobian )
+ {
+ assert( (jacobian->rows == 9 && jacobian->cols == 3) ||
+ (jacobian->rows == 3 && jacobian->cols == 9) );
+ }
+
+ if( src->cols == 1 || src->rows == 1 )
+ {
+ double r[3], theta;
+ CvMat _r = cvMat( src->rows, src->cols, CV_MAKETYPE(CV_64F,CV_MAT_CN(src->type)), r);
+
+ assert( dst->rows == 3 && dst->cols == 3 );
+
+ cvConvert( src, &_r );
+
+ theta = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
+ if( theta < DBL_EPSILON )
+ {
+ cvSetIdentity( dst );
+
+ if( jacobian )
+ {
+ memset( J, 0, sizeof(J) );
+ J[5] = J[15] = J[19] = 1;
+ J[7] = J[11] = J[21] = -1;
+ }
+ }
+ else
+ {
+ // omega = r/theta (~[w1, w2, w3])
+ double itheta = 1./theta;
+ double w1 = r[0]*itheta, w2 = r[1]*itheta, w3 = r[2]*itheta;
+ double alpha = cos(theta);
+ double beta = sin(theta);
+ double gamma = 1 - alpha;
+ double omegav[] =
+ {
+ 0, -w3, w2,
+ w3, 0, -w1,
+ -w2, w1, 0
+ };
+ double A[] =
+ {
+ w1*w1, w1*w2, w1*w3,
+ w2*w1, w2*w2, w2*w3,
+ w3*w1, w3*w2, w3*w3
+ };
+ double R[9];
+ CvMat _omegav = cvMat(3, 3, CV_64F, omegav);
+ CvMat matA = cvMat(3, 3, CV_64F, A);
+ CvMat matR = cvMat(3, 3, CV_64F, R);
+
+ cvSetIdentity( &matR, cvRealScalar(alpha) );
+ cvScaleAdd( &_omegav, cvRealScalar(beta), &matR, &matR );
+ cvScaleAdd( &matA, cvRealScalar(gamma), &matR, &matR );
+ cvConvert( &matR, dst );
+
+ if( jacobian )
+ {
+ // m3 = [r, theta]
+ double dm3din[] =
+ {
+ 1, 0, 0,
+ 0, 1, 0,
+ 0, 0, 1,
+ w1, w2, w3
+ };
+ // m2 = [omega, theta]
+ double dm2dm3[] =
+ {
+ itheta, 0, 0, -w1*itheta,
+ 0, itheta, 0, -w2*itheta,
+ 0, 0, itheta, -w3*itheta,
+ 0, 0, 0, 1
+ };
+ double t0[9*4];
+ double dm1dm2[21*4];
+ double dRdm1[9*21];
+ CvMat _dm3din = cvMat( 4, 3, CV_64FC1, dm3din );
+ CvMat _dm2dm3 = cvMat( 4, 4, CV_64FC1, dm2dm3 );
+ CvMat _dm1dm2 = cvMat( 21, 4, CV_64FC1, dm1dm2 );
+ CvMat _dRdm1 = cvMat( 9, 21, CV_64FC1, dRdm1 );
+ CvMat _dRdm1_part;
+ CvMat _t0 = cvMat( 9, 4, CV_64FC1, t0 );
+ CvMat _t1 = cvMat( 9, 4, CV_64FC1, dRdm1 );
+
+ // m1 = [alpha, beta, gamma, omegav; A]
+ memset( dm1dm2, 0, sizeof(dm1dm2) );
+ dm1dm2[3] = -beta;
+ dm1dm2[7] = alpha;
+ dm1dm2[11] = beta;
+
+ // dm1dm2(4:12,1:3) = [0 0 0 0 0 1 0 -1 0;
+ // 0 0 -1 0 0 0 1 0 0;
+ // 0 1 0 -1 0 0 0 0 0]'
+ // -------------------
+ // 0 0 0 0 0 0 0 0 0
+ dm1dm2[12 + 6] = dm1dm2[12 + 20] = dm1dm2[12 + 25] = 1;
+ dm1dm2[12 + 9] = dm1dm2[12 + 14] = dm1dm2[12 + 28] = -1;
+
+ double dm1dw[] =
+ {
+ 2*w1, w2, w3, w2, 0, 0, w3, 0, 0,
+ 0, w1, 0, w1, 2*w2, w3, 0, w3, 0,
+ 0, 0, w1, 0, 0, w2, w1, w2, 2*w3
+ };
+
+ CvMat _dm1dw = cvMat( 3, 9, CV_64FC1, dm1dw );
+ CvMat _dm1dm2_part;
+
+ cvGetSubRect( &_dm1dm2, &_dm1dm2_part, cvRect(0,12,3,9) );
+ cvTranspose( &_dm1dw, &_dm1dm2_part );
+
+ memset( dRdm1, 0, sizeof(dRdm1) );
+ dRdm1[0*21] = dRdm1[4*21] = dRdm1[8*21] = 1;
+
+ cvGetCol( &_dRdm1, &_dRdm1_part, 1 );
+ cvTranspose( &_omegav, &_omegav );
+ cvReshape( &_omegav, &_omegav, 1, 1 );
+ cvTranspose( &_omegav, &_dRdm1_part );
+
+ cvGetCol( &_dRdm1, &_dRdm1_part, 2 );
+ cvReshape( &matA, &matA, 1, 1 );
+ cvTranspose( &matA, &_dRdm1_part );
+
+ cvGetSubRect( &_dRdm1, &_dRdm1_part, cvRect(3,0,9,9) );
+ cvSetIdentity( &_dRdm1_part, cvScalarAll(beta) );
+
+ cvGetSubRect( &_dRdm1, &_dRdm1_part, cvRect(12,0,9,9) );
+ cvSetIdentity( &_dRdm1_part, cvScalarAll(gamma) );
+
+ matJ = cvMat( 9, 3, CV_64FC1, J );
+
+ cvMatMul( &_dRdm1, &_dm1dm2, &_t0 );
+ cvMatMul( &_t0, &_dm2dm3, &_t1 );
+ cvMatMul( &_t1, &_dm3din, &matJ );
+
+ _t0 = cvMat( 3, 9, CV_64FC1, t0 );
+ cvTranspose( &matJ, &_t0 );
+
+ for( i = 0; i < 3; i++ )
+ {
+ _t1 = cvMat( 3, 3, CV_64FC1, t0 + i*9 );
+ cvTranspose( &_t1, &_t1 );
+ }
+
+ cvTranspose( &_t0, &matJ );
+ }
+ }
+ }
+ else if( src->cols == 3 && src->rows == 3 )
+ {
+ double R[9], A[9], I[9], r[3], W[3], U[9], V[9];
+ double tr, alpha, beta, theta;
+ CvMat matR = cvMat( 3, 3, CV_64F, R );
+ CvMat matA = cvMat( 3, 3, CV_64F, A );
+ CvMat matI = cvMat( 3, 3, CV_64F, I );
+ CvMat _r = cvMat( dst->rows, dst->cols, CV_MAKETYPE(CV_64F, CV_MAT_CN(dst->type)), r );
+ CvMat matW = cvMat( 1, 3, CV_64F, W );
+ CvMat matU = cvMat( 3, 3, CV_64F, U );
+ CvMat matV = cvMat( 3, 3, CV_64F, V );
+
+ cvConvert( src, &matR );
+ cvSVD( &matR, &matW, &matU, &matV, CV_SVD_MODIFY_A + CV_SVD_U_T + CV_SVD_V_T );
+ cvGEMM( &matU, &matV, 1, 0, 0, &matR, CV_GEMM_A_T );
+
+ cvMulTransposed( &matR, &matA, 0 );
+ cvSetIdentity( &matI );
+
+ if( cvNorm( &matA, &matI, CV_C ) > 1e-3 ||
+ fabs( cvDet(&matR) - 1 ) > 1e-3 )
+ return 0;
+
+ tr = (cvTrace(&matR).val[0] - 1.)*0.5;
+ tr = tr > 1. ? 1. : tr < -1. ? -1. : tr;
+ theta = acos(tr);
+ alpha = cos(theta);
+ beta = sin(theta);
+
+ if( beta >= 1e-5 )
+ {
+ double dtheta_dtr = -1./sqrt(1 - tr*tr);
+ double vth = 1/(2*beta);
+
+ // om1 = [R(3,2) - R(2,3), R(1,3) - R(3,1), R(2,1) - R(1,2)]'
+ double om1[] = { R[7] - R[5], R[2] - R[6], R[3] - R[1] };
+ // om = om1*vth
+ // r = om*theta
+ double d3 = vth*theta;
+
+ r[0] = om1[0]*d3; r[1] = om1[1]*d3; r[2] = om1[2]*d3;
+ cvConvert( &_r, dst );
+
+ if( jacobian )
+ {
+ // var1 = [vth;theta]
+ // var = [om1;var1] = [om1;vth;theta]
+ double dvth_dtheta = -vth*alpha/beta;
+ double d1 = 0.5*dvth_dtheta*dtheta_dtr;
+ double d2 = 0.5*dtheta_dtr;
+ // dvar1/dR = dvar1/dtheta*dtheta/dR = [dvth/dtheta; 1] * dtheta/dtr * dtr/dR
+ double dvardR[5*9] =
+ {
+ 0, 0, 0, 0, 0, 1, 0, -1, 0,
+ 0, 0, -1, 0, 0, 0, 1, 0, 0,
+ 0, 1, 0, -1, 0, 0, 0, 0, 0,
+ d1, 0, 0, 0, d1, 0, 0, 0, d1,
+ d2, 0, 0, 0, d2, 0, 0, 0, d2
+ };
+ // var2 = [om;theta]
+ double dvar2dvar[] =
+ {
+ vth, 0, 0, om1[0], 0,
+ 0, vth, 0, om1[1], 0,
+ 0, 0, vth, om1[2], 0,
+ 0, 0, 0, 0, 1
+ };
+ double domegadvar2[] =
+ {
+ theta, 0, 0, om1[0]*vth,
+ 0, theta, 0, om1[1]*vth,
+ 0, 0, theta, om1[2]*vth
+ };
+
+ CvMat _dvardR = cvMat( 5, 9, CV_64FC1, dvardR );
+ CvMat _dvar2dvar = cvMat( 4, 5, CV_64FC1, dvar2dvar );
+ CvMat _domegadvar2 = cvMat( 3, 4, CV_64FC1, domegadvar2 );
+ double t0[3*5];
+ CvMat _t0 = cvMat( 3, 5, CV_64FC1, t0 );
+
+ cvMatMul( &_domegadvar2, &_dvar2dvar, &_t0 );
+ cvMatMul( &_t0, &_dvardR, &matJ );
+ }
+ }
+ else if( tr > 0 )
+ {
+ cvZero( dst );
+ if( jacobian )
+ {
+ memset( J, 0, sizeof(J) );
+ J[5] = J[15] = J[19] = 0.5;
+ J[7] = J[11] = J[21] = -0.5;
+ }
+ }
+ else
+ {
+ r[0] = theta*sqrt((R[0] + 1)*0.5);
+ r[1] = theta*sqrt((R[4] + 1)*0.5)*(R[1] >= 0 ? 1 : -1);
+ r[2] = theta*sqrt((R[8] + 1)*0.5)*(R[2] >= 0 ? 1 : -1);
+ cvConvert( &_r, dst );
+
+ if( jacobian )
+ memset( J, 0, sizeof(J) );
+ }
+
+ if( jacobian )
+ {
+ for( i = 0; i < 3; i++ )
+ {
+ CvMat t = cvMat( 3, 3, CV_64F, J + i*9 );
+ cvTranspose( &t, &t );
+ }
+ }
+ }
+ else
+ {
+ assert(0);
+ return 0;
+ }
+
+ if( jacobian )
+ {
+ if( depth == CV_32F )
+ {
+ if( jacobian->rows == matJ.rows )
+ cvConvert( &matJ, jacobian );
+ else
+ {
+ _Jf = cvMat( matJ.rows, matJ.cols, CV_32FC1, Jf );
+ cvConvert( &matJ, &_Jf );
+ cvTranspose( &_Jf, jacobian );
+ }
+ }
+ else if( jacobian->rows == matJ.rows )
+ cvCopy( &matJ, jacobian );
+ else
+ cvTranspose( &matJ, jacobian );
+ }
+
+ return 1;
+}
+
+
+void cvtest::Rodrigues(const Mat& src, Mat& dst, Mat* jac)
+{
+ CvMat _src = src, _dst = dst, _jac;
+ if( jac )
+ _jac = *jac;
+ cvTsRodrigues(&_src, &_dst, jac ? &_jac : 0);
+}
+
+
+static void test_convertHomogeneous( const Mat& _src, Mat& _dst )
+{
+ Mat src = _src, dst = _dst;
+ int i, count, sdims, ddims;
+ int sstep1, sstep2, dstep1, dstep2;
+
+ if( src.depth() != CV_64F )
+ _src.convertTo(src, CV_64F);
+
+ if( dst.depth() != CV_64F )
+ dst.create(dst.size(), CV_MAKETYPE(CV_64F, _dst.channels()));
+
+ if( src.rows > src.cols )
+ {
+ count = src.rows;
+ sdims = src.channels()*src.cols;
+ sstep1 = src.step/sizeof(double);
+ sstep2 = 1;
+ }
+ else
+ {
+ count = src.cols;
+ sdims = src.channels()*src.rows;
+ if( src.rows == 1 )
+ {
+ sstep1 = sdims;
+ sstep2 = 1;
+ }
+ else
+ {
+ sstep1 = 1;
+ sstep2 = src.step/sizeof(double);
+ }
+ }
+
+ if( dst.rows > dst.cols )
+ {
+ CV_Assert( count == dst.rows );
+ ddims = dst.channels()*dst.cols;
+ dstep1 = dst.step/sizeof(double);
+ dstep2 = 1;
+ }
+ else
+ {
+ assert( count == dst.cols );
+ ddims = dst.channels()*dst.rows;
+ if( dst.rows == 1 )
+ {
+ dstep1 = ddims;
+ dstep2 = 1;
+ }
+ else
+ {
+ dstep1 = 1;
+ dstep2 = dst.step/sizeof(double);
+ }
+ }
+
+ double* s = src.ptr<double>();
+ double* d = dst.ptr<double>();
+
+ if( sdims <= ddims )
+ {
+ int wstep = dstep2*(ddims - 1);
+
+ for( i = 0; i < count; i++, s += sstep1, d += dstep1 )
+ {
+ double x = s[0];
+ double y = s[sstep2];
+
+ d[wstep] = 1;
+ d[0] = x;
+ d[dstep2] = y;
+
+ if( sdims >= 3 )
+ {
+ d[dstep2*2] = s[sstep2*2];
+ if( sdims == 4 )
+ d[dstep2*3] = s[sstep2*3];
+ }
+ }
+ }
+ else
+ {
+ int wstep = sstep2*(sdims - 1);
+
+ for( i = 0; i < count; i++, s += sstep1, d += dstep1 )
+ {
+ double w = s[wstep];
+ double x = s[0];
+ double y = s[sstep2];
+
+ w = w ? 1./w : 1;
+
+ d[0] = x*w;
+ d[dstep2] = y*w;
+
+ if( ddims == 3 )
+ d[dstep2*2] = s[sstep2*2]*w;
+ }
+ }
+
+ if( dst.data != _dst.data )
+ dst.convertTo(_dst, _dst.depth());
+}
+
+
+void
+test_projectPoints( const Mat& _3d, const Mat& Rt, const Mat& A, Mat& _2d, RNG* rng, double sigma )
+{
+ CV_Assert( _3d.isContinuous() );
+
+ double p[12];
+ Mat P( 3, 4, CV_64F, p );
+ gemm(A, Rt, 1, Mat(), 0, P);
+
+ int i, count = _3d.cols;
+
+ Mat noise;
+ if( rng )
+ {
+ if( sigma == 0 )
+ rng = 0;
+ else
+ {
+ noise.create( 1, _3d.cols, CV_64FC2 );
+ rng->fill(noise, RNG::NORMAL, Scalar::all(0), Scalar::all(sigma) );
+ }
+ }
+
+ Mat temp( 1, count, CV_64FC3 );
+
+ for( i = 0; i < count; i++ )
+ {
+ const double* M = _3d.ptr<double>() + i*3;
+ double* m = temp.ptr<double>() + i*3;
+ double X = M[0], Y = M[1], Z = M[2];
+ double u = p[0]*X + p[1]*Y + p[2]*Z + p[3];
+ double v = p[4]*X + p[5]*Y + p[6]*Z + p[7];
+ double s = p[8]*X + p[9]*Y + p[10]*Z + p[11];
+
+ if( !noise.empty() )
+ {
+ u += noise.at<Point2d>(i).x*s;
+ v += noise.at<Point2d>(i).y*s;
+ }
+
+ m[0] = u;
+ m[1] = v;
+ m[2] = s;
+ }
+
+ test_convertHomogeneous( temp, _2d );
+}
+
+
+/********************************** Rodrigues transform ********************************/
+
+class CV_RodriguesTest : public cvtest::ArrayTest
+{
+public:
+ CV_RodriguesTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+ int prepare_test_case( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ bool calc_jacobians;
+ bool test_cpp;
+};
+
+
+CV_RodriguesTest::CV_RodriguesTest()
+{
+ test_array[INPUT].push_back(NULL); // rotation vector
+ test_array[OUTPUT].push_back(NULL); // rotation matrix
+ test_array[OUTPUT].push_back(NULL); // jacobian (J)
+ test_array[OUTPUT].push_back(NULL); // rotation vector (backward transform result)
+ test_array[OUTPUT].push_back(NULL); // inverse transform jacobian (J1)
+ test_array[OUTPUT].push_back(NULL); // J*J1 (or J1*J) == I(3x3)
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+
+ element_wise_relative_error = false;
+ calc_jacobians = false;
+
+ test_cpp = false;
+}
+
+
+int CV_RodriguesTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_RodriguesTest::get_test_array_types_and_sizes(
+ int /*test_case_idx*/, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ int i, code;
+
+ code = cvtest::randInt(rng) % 3;
+ types[INPUT][0] = CV_MAKETYPE(depth, 1);
+
+ if( code == 0 )
+ {
+ sizes[INPUT][0] = cvSize(1,1);
+ types[INPUT][0] = CV_MAKETYPE(depth, 3);
+ }
+ else if( code == 1 )
+ sizes[INPUT][0] = cvSize(3,1);
+ else
+ sizes[INPUT][0] = cvSize(1,3);
+
+ sizes[OUTPUT][0] = cvSize(3, 3);
+ types[OUTPUT][0] = CV_MAKETYPE(depth, 1);
+
+ types[OUTPUT][1] = CV_MAKETYPE(depth, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][1] = cvSize(3,9);
+ else
+ sizes[OUTPUT][1] = cvSize(9,3);
+
+ types[OUTPUT][2] = types[INPUT][0];
+ sizes[OUTPUT][2] = sizes[INPUT][0];
+
+ types[OUTPUT][3] = types[OUTPUT][1];
+ sizes[OUTPUT][3] = cvSize(sizes[OUTPUT][1].height, sizes[OUTPUT][1].width);
+
+ types[OUTPUT][4] = types[OUTPUT][1];
+ sizes[OUTPUT][4] = cvSize(3,3);
+
+ calc_jacobians = cvtest::randInt(rng) % 3 != 0;
+ if( !calc_jacobians )
+ sizes[OUTPUT][1] = sizes[OUTPUT][3] = sizes[OUTPUT][4] = cvSize(0,0);
+
+ for( i = 0; i < 5; i++ )
+ {
+ types[REF_OUTPUT][i] = types[OUTPUT][i];
+ sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
+ }
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+double CV_RodriguesTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
+{
+ return j == 4 ? 1e-2 : 1e-2;
+}
+
+
+void CV_RodriguesTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i == INPUT && j == 0 )
+ {
+ double r[3], theta0, theta1, f;
+ Mat _r( arr.rows, arr.cols, CV_MAKETYPE(CV_64F,arr.channels()), r );
+ RNG& rng = ts->get_rng();
+
+ r[0] = cvtest::randReal(rng)*CV_PI*2;
+ r[1] = cvtest::randReal(rng)*CV_PI*2;
+ r[2] = cvtest::randReal(rng)*CV_PI*2;
+
+ theta0 = sqrt(r[0]*r[0] + r[1]*r[1] + r[2]*r[2]);
+ theta1 = fmod(theta0, CV_PI*2);
+
+ if( theta1 > CV_PI )
+ theta1 = -(CV_PI*2 - theta1);
+
+ f = theta1/(theta0 ? theta0 : 1);
+ r[0] *= f;
+ r[1] *= f;
+ r[2] *= f;
+
+ cvtest::convert( _r, arr, arr.type() );
+ }
+ else
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+int CV_RodriguesTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ return code;
+}
+
+
+void CV_RodriguesTest::run_func()
+{
+ CvMat v2m_jac, m2v_jac;
+
+ if( calc_jacobians )
+ {
+ v2m_jac = test_mat[OUTPUT][1];
+ m2v_jac = test_mat[OUTPUT][3];
+ }
+
+ if( !test_cpp )
+ {
+ CvMat _input = test_mat[INPUT][0], _output = test_mat[OUTPUT][0], _output2 = test_mat[OUTPUT][2];
+ cvRodrigues2( &_input, &_output, calc_jacobians ? &v2m_jac : 0 );
+ cvRodrigues2( &_output, &_output2, calc_jacobians ? &m2v_jac : 0 );
+ }
+ else
+ {
+ cv::Mat v = test_mat[INPUT][0], M = test_mat[OUTPUT][0], v2 = test_mat[OUTPUT][2];
+ cv::Mat M0 = M, v2_0 = v2;
+ if( !calc_jacobians )
+ {
+ cv::Rodrigues(v, M);
+ cv::Rodrigues(M, v2);
+ }
+ else
+ {
+ cv::Mat J1 = test_mat[OUTPUT][1], J2 = test_mat[OUTPUT][3];
+ cv::Mat J1_0 = J1, J2_0 = J2;
+ cv::Rodrigues(v, M, J1);
+ cv::Rodrigues(M, v2, J2);
+ if( J1.data != J1_0.data )
+ {
+ if( J1.size() != J1_0.size() )
+ J1 = J1.t();
+ J1.convertTo(J1_0, J1_0.type());
+ }
+ if( J2.data != J2_0.data )
+ {
+ if( J2.size() != J2_0.size() )
+ J2 = J2.t();
+ J2.convertTo(J2_0, J2_0.type());
+ }
+ }
+ if( M.data != M0.data )
+ M.reshape(M0.channels(), M0.rows).convertTo(M0, M0.type());
+ if( v2.data != v2_0.data )
+ v2.reshape(v2_0.channels(), v2_0.rows).convertTo(v2_0, v2_0.type());
+ }
+}
+
+
+void CV_RodriguesTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& vec = test_mat[INPUT][0];
+ Mat& m = test_mat[REF_OUTPUT][0];
+ Mat& vec2 = test_mat[REF_OUTPUT][2];
+ Mat* v2m_jac = 0, *m2v_jac = 0;
+ double theta0, theta1;
+
+ if( calc_jacobians )
+ {
+ v2m_jac = &test_mat[REF_OUTPUT][1];
+ m2v_jac = &test_mat[REF_OUTPUT][3];
+ }
+
+
+ cvtest::Rodrigues( vec, m, v2m_jac );
+ cvtest::Rodrigues( m, vec2, m2v_jac );
+ cvtest::copy( vec, vec2 );
+
+ theta0 = norm( vec2, CV_L2 );
+ theta1 = fmod( theta0, CV_PI*2 );
+
+ if( theta1 > CV_PI )
+ theta1 = -(CV_PI*2 - theta1);
+ vec2 *= theta1/(theta0 ? theta0 : 1);
+
+ if( calc_jacobians )
+ {
+ //cvInvert( v2m_jac, m2v_jac, CV_SVD );
+ double nrm = norm(test_mat[REF_OUTPUT][3],CV_C);
+ if( FLT_EPSILON < nrm && nrm < 1000 )
+ {
+ gemm( test_mat[OUTPUT][1], test_mat[OUTPUT][3],
+ 1, Mat(), 0, test_mat[OUTPUT][4],
+ v2m_jac->rows == 3 ? 0 : CV_GEMM_A_T + CV_GEMM_B_T );
+ }
+ else
+ {
+ setIdentity(test_mat[OUTPUT][4], Scalar::all(1.));
+ cvtest::copy( test_mat[REF_OUTPUT][2], test_mat[OUTPUT][2] );
+ }
+ setIdentity(test_mat[REF_OUTPUT][4], Scalar::all(1.));
+ }
+}
+
+
+/********************************** fundamental matrix *********************************/
+
+class CV_FundamentalMatTest : public cvtest::ArrayTest
+{
+public:
+ CV_FundamentalMatTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+ int prepare_test_case( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int method;
+ int img_size;
+ int cube_size;
+ int dims;
+ int f_result;
+ double min_f, max_f;
+ double sigma;
+ bool test_cpp;
+};
+
+
+CV_FundamentalMatTest::CV_FundamentalMatTest()
+{
+ // input arrays:
+ // 0, 1 - arrays of 2d points that are passed to %func%.
+ // Can have different data type, layout, be stored in homogeneous coordinates or not.
+ // 2 - array of 3d points that are projected to both view planes
+ // 3 - [R|t] matrix for the second view plane (for the first one it is [I|0]
+ // 4, 5 - intrinsic matrices
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+
+ element_wise_relative_error = false;
+
+ method = 0;
+ img_size = 10;
+ cube_size = 10;
+ min_f = 1;
+ max_f = 3;
+ sigma = 0;//0.1;
+ f_result = 0;
+
+ test_cpp = false;
+}
+
+
+int CV_FundamentalMatTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_FundamentalMatTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int pt_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ double pt_count_exp = cvtest::randReal(rng)*6 + 1;
+ int pt_count = cvRound(exp(pt_count_exp));
+
+ dims = cvtest::randInt(rng) % 2 + 2;
+ method = 1 << (cvtest::randInt(rng) % 4);
+
+ if( method == CV_FM_7POINT )
+ pt_count = 7;
+ else
+ {
+ pt_count = MAX( pt_count, 8 + (method == CV_FM_8POINT) );
+ if( pt_count >= 8 && cvtest::randInt(rng) % 2 )
+ method |= CV_FM_8POINT;
+ }
+
+ types[INPUT][0] = CV_MAKETYPE(pt_depth, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, dims);
+ else
+ {
+ sizes[INPUT][0] = cvSize(dims, pt_count);
+ if( cvtest::randInt(rng) % 2 )
+ {
+ types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, 1);
+ else
+ sizes[INPUT][0] = cvSize(1, pt_count);
+ }
+ }
+
+ sizes[INPUT][1] = sizes[INPUT][0];
+ types[INPUT][1] = types[INPUT][0];
+
+ sizes[INPUT][2] = cvSize(pt_count, 1 );
+ types[INPUT][2] = CV_64FC3;
+
+ sizes[INPUT][3] = cvSize(4,3);
+ types[INPUT][3] = CV_64FC1;
+
+ sizes[INPUT][4] = sizes[INPUT][5] = cvSize(3,3);
+ types[INPUT][4] = types[INPUT][5] = CV_MAKETYPE(CV_64F, 1);
+
+ sizes[TEMP][0] = cvSize(3,3);
+ types[TEMP][0] = CV_64FC1;
+ sizes[TEMP][1] = cvSize(pt_count,1);
+ types[TEMP][1] = CV_8UC1;
+
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(3,1);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
+ sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(pt_count,1);
+ types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_8UC1;
+
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+double CV_FundamentalMatTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 1e-2;
+}
+
+
+void CV_FundamentalMatTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ double t[12]={0};
+ RNG& rng = ts->get_rng();
+
+ if( i != INPUT )
+ {
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+ return;
+ }
+
+ switch( j )
+ {
+ case 0:
+ case 1:
+ return; // fill them later in prepare_test_case
+ case 2:
+ {
+ double* p = arr.ptr<double>();
+ for( i = 0; i < arr.cols*3; i += 3 )
+ {
+ p[i] = cvtest::randReal(rng)*cube_size;
+ p[i+1] = cvtest::randReal(rng)*cube_size;
+ p[i+2] = cvtest::randReal(rng)*cube_size + cube_size;
+ }
+ }
+ break;
+ case 3:
+ {
+ double r[3];
+ Mat rot_vec( 3, 1, CV_64F, r );
+ Mat rot_mat( 3, 3, CV_64F, t, 4*sizeof(t[0]) );
+ r[0] = cvtest::randReal(rng)*CV_PI*2;
+ r[1] = cvtest::randReal(rng)*CV_PI*2;
+ r[2] = cvtest::randReal(rng)*CV_PI*2;
+
+ cvtest::Rodrigues( rot_vec, rot_mat );
+ t[3] = cvtest::randReal(rng)*cube_size;
+ t[7] = cvtest::randReal(rng)*cube_size;
+ t[11] = cvtest::randReal(rng)*cube_size;
+ Mat( 3, 4, CV_64F, t ).convertTo(arr, arr.type());
+ }
+ break;
+ case 4:
+ case 5:
+ t[0] = t[4] = cvtest::randReal(rng)*(max_f - min_f) + min_f;
+ t[2] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[0];
+ t[5] = (img_size*0.5 + cvtest::randReal(rng)*4. - 2.)*t[4];
+ t[8] = 1.;
+ Mat( 3, 3, CV_64F, t ).convertTo( arr, arr.type() );
+ break;
+ }
+}
+
+
+int CV_FundamentalMatTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ const Mat& _3d = test_mat[INPUT][2];
+ RNG& rng = ts->get_rng();
+ double Idata[] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 };
+ Mat I( 3, 4, CV_64F, Idata );
+ int k;
+
+ for( k = 0; k < 2; k++ )
+ {
+ const Mat& Rt = k == 0 ? I : test_mat[INPUT][3];
+ const Mat& A = test_mat[INPUT][k == 0 ? 4 : 5];
+ Mat& _2d = test_mat[INPUT][k];
+
+ test_projectPoints( _3d, Rt, A, _2d, &rng, sigma );
+ }
+ }
+
+ return code;
+}
+
+
+void CV_FundamentalMatTest::run_func()
+{
+ //if(!test_cpp)
+ {
+ CvMat _input0 = test_mat[INPUT][0], _input1 = test_mat[INPUT][1];
+ CvMat F = test_mat[TEMP][0], mask = test_mat[TEMP][1];
+ f_result = cvFindFundamentalMat( &_input0, &_input1, &F, method, MAX(sigma*3, 0.01), 0, &mask );
+ }
+ /*else
+ {
+ cv::findFundamentalMat(const Mat& points1, const Mat& points2,
+ vector<uchar>& mask, int method=FM_RANSAC,
+ double param1=3., double param2=0.99 );
+
+ CV_EXPORTS Mat findFundamentalMat( const Mat& points1, const Mat& points2,
+ int method=FM_RANSAC,
+ double param1=3., double param2=0.99 );
+ }*/
+
+}
+
+
+void CV_FundamentalMatTest::prepare_to_validation( int test_case_idx )
+{
+ const Mat& Rt = test_mat[INPUT][3];
+ const Mat& A1 = test_mat[INPUT][4];
+ const Mat& A2 = test_mat[INPUT][5];
+ double f0[9], f[9];
+ Mat F0(3, 3, CV_64FC1, f0), F(3, 3, CV_64F, f);
+
+ Mat invA1, invA2, R=Rt.colRange(0, 3), T;
+
+ cv::invert(A1, invA1, CV_SVD);
+ cv::invert(A2, invA2, CV_SVD);
+
+ double tx = Rt.at<double>(0, 3);
+ double ty = Rt.at<double>(1, 3);
+ double tz = Rt.at<double>(2, 3);
+
+ double _t_x[] = { 0, -tz, ty, tz, 0, -tx, -ty, tx, 0 };
+
+ // F = (A2^-T)*[t]_x*R*(A1^-1)
+ cv::gemm( invA2, Mat( 3, 3, CV_64F, _t_x ), 1, Mat(), 0, T, CV_GEMM_A_T );
+ cv::gemm( R, invA1, 1, Mat(), 0, invA2 );
+ cv::gemm( T, invA2, 1, Mat(), 0, F0 );
+ F0 *= 1./f0[8];
+
+ uchar* status = test_mat[TEMP][1].data;
+ double err_level = get_success_error_level( test_case_idx, OUTPUT, 1 );
+ uchar* mtfm1 = test_mat[REF_OUTPUT][1].data;
+ uchar* mtfm2 = test_mat[OUTPUT][1].data;
+ double* f_prop1 = (double*)test_mat[REF_OUTPUT][0].data;
+ double* f_prop2 = (double*)test_mat[OUTPUT][0].data;
+
+ int i, pt_count = test_mat[INPUT][2].cols;
+ Mat p1( 1, pt_count, CV_64FC2 );
+ Mat p2( 1, pt_count, CV_64FC2 );
+
+ test_convertHomogeneous( test_mat[INPUT][0], p1 );
+ test_convertHomogeneous( test_mat[INPUT][1], p2 );
+
+ cvtest::convert(test_mat[TEMP][0], F, F.type());
+
+ if( method <= CV_FM_8POINT )
+ memset( status, 1, pt_count );
+
+ for( i = 0; i < pt_count; i++ )
+ {
+ double x1 = p1.at<Point2d>(i).x;
+ double y1 = p1.at<Point2d>(i).y;
+ double x2 = p2.at<Point2d>(i).x;
+ double y2 = p2.at<Point2d>(i).y;
+ double n1 = 1./sqrt(x1*x1 + y1*y1 + 1);
+ double n2 = 1./sqrt(x2*x2 + y2*y2 + 1);
+ double t0 = fabs(f0[0]*x2*x1 + f0[1]*x2*y1 + f0[2]*x2 +
+ f0[3]*y2*x1 + f0[4]*y2*y1 + f0[5]*y2 +
+ f0[6]*x1 + f0[7]*y1 + f0[8])*n1*n2;
+ double t = fabs(f[0]*x2*x1 + f[1]*x2*y1 + f[2]*x2 +
+ f[3]*y2*x1 + f[4]*y2*y1 + f[5]*y2 +
+ f[6]*x1 + f[7]*y1 + f[8])*n1*n2;
+ mtfm1[i] = 1;
+ mtfm2[i] = !status[i] || t0 > err_level || t < err_level;
+ }
+
+ f_prop1[0] = 1;
+ f_prop1[1] = 1;
+ f_prop1[2] = 0;
+
+ f_prop2[0] = f_result != 0;
+ f_prop2[1] = f[8];
+ f_prop2[2] = cv::determinant( F );
+}
+
+
+/********************************** convert homogeneous *********************************/
+
+class CV_ConvertHomogeneousTest : public cvtest::ArrayTest
+{
+public:
+ CV_ConvertHomogeneousTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int dims1, dims2;
+ int pt_count;
+};
+
+
+CV_ConvertHomogeneousTest::CV_ConvertHomogeneousTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = false;
+
+ pt_count = dims1 = dims2 = 0;
+}
+
+
+int CV_ConvertHomogeneousTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_ConvertHomogeneousTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int pt_depth1 = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ int pt_depth2 = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ double pt_count_exp = cvtest::randReal(rng)*6 + 1;
+ int t;
+
+ pt_count = cvRound(exp(pt_count_exp));
+ pt_count = MAX( pt_count, 5 );
+
+ dims1 = 2 + (cvtest::randInt(rng) % 3);
+ dims2 = 2 + (cvtest::randInt(rng) % 3);
+
+ if( dims1 == dims2 + 2 )
+ dims1--;
+ else if( dims1 == dims2 - 2 )
+ dims1++;
+
+ if( cvtest::randInt(rng) % 2 )
+ CV_SWAP( dims1, dims2, t );
+
+ types[INPUT][0] = CV_MAKETYPE(pt_depth1, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, dims1);
+ else
+ {
+ sizes[INPUT][0] = cvSize(dims1, pt_count);
+ if( cvtest::randInt(rng) % 2 )
+ {
+ types[INPUT][0] = CV_MAKETYPE(pt_depth1, dims1);
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, 1);
+ else
+ sizes[INPUT][0] = cvSize(1, pt_count);
+ }
+ }
+
+ types[OUTPUT][0] = CV_MAKETYPE(pt_depth2, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][0] = cvSize(pt_count, dims2);
+ else
+ {
+ sizes[OUTPUT][0] = cvSize(dims2, pt_count);
+ if( cvtest::randInt(rng) % 2 )
+ {
+ types[OUTPUT][0] = CV_MAKETYPE(pt_depth2, dims2);
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][0] = cvSize(pt_count, 1);
+ else
+ sizes[OUTPUT][0] = cvSize(1, pt_count);
+ }
+ }
+
+ types[REF_OUTPUT][0] = types[OUTPUT][0];
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+}
+
+
+double CV_ConvertHomogeneousTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 1e-5;
+}
+
+
+void CV_ConvertHomogeneousTest::fill_array( int /*test_case_idx*/, int /*i*/, int /*j*/, Mat& arr )
+{
+ Mat temp( 1, pt_count, CV_MAKETYPE(CV_64FC1,dims1) );
+ RNG& rng = ts->get_rng();
+ CvScalar low = cvScalarAll(0), high = cvScalarAll(10);
+
+ if( dims1 > dims2 )
+ low.val[dims1-1] = 1.;
+
+ cvtest::randUni( rng, temp, low, high );
+ test_convertHomogeneous( temp, arr );
+}
+
+
+void CV_ConvertHomogeneousTest::run_func()
+{
+ CvMat _input = test_mat[INPUT][0], _output = test_mat[OUTPUT][0];
+ cvConvertPointsHomogeneous( &_input, &_output );
+}
+
+
+void CV_ConvertHomogeneousTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_convertHomogeneous( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
+}
+
+
+/************************** compute corresponding epipolar lines ************************/
+
+class CV_ComputeEpilinesTest : public cvtest::ArrayTest
+{
+public:
+ CV_ComputeEpilinesTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int which_image;
+ int dims;
+ int pt_count;
+};
+
+
+CV_ComputeEpilinesTest::CV_ComputeEpilinesTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = false;
+
+ pt_count = dims = which_image = 0;
+}
+
+
+int CV_ComputeEpilinesTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_ComputeEpilinesTest::get_test_array_types_and_sizes( int /*test_case_idx*/,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int fm_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ int pt_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ int ln_depth = cvtest::randInt(rng) % 2 == 0 ? CV_32F : CV_64F;
+ double pt_count_exp = cvtest::randReal(rng)*6 + 1;
+
+ which_image = 1 + (cvtest::randInt(rng) % 2);
+
+ pt_count = cvRound(exp(pt_count_exp));
+ pt_count = MAX( pt_count, 5 );
+
+ dims = 2 + (cvtest::randInt(rng) % 2);
+
+ types[INPUT][0] = CV_MAKETYPE(pt_depth, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, dims);
+ else
+ {
+ sizes[INPUT][0] = cvSize(dims, pt_count);
+ if( cvtest::randInt(rng) % 2 )
+ {
+ types[INPUT][0] = CV_MAKETYPE(pt_depth, dims);
+ if( cvtest::randInt(rng) % 2 )
+ sizes[INPUT][0] = cvSize(pt_count, 1);
+ else
+ sizes[INPUT][0] = cvSize(1, pt_count);
+ }
+ }
+
+ types[INPUT][1] = CV_MAKETYPE(fm_depth, 1);
+ sizes[INPUT][1] = cvSize(3, 3);
+
+ types[OUTPUT][0] = CV_MAKETYPE(ln_depth, 1);
+
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][0] = cvSize(pt_count, 3);
+ else
+ {
+ sizes[OUTPUT][0] = cvSize(3, pt_count);
+ if( cvtest::randInt(rng) % 2 )
+ {
+ types[OUTPUT][0] = CV_MAKETYPE(ln_depth, 3);
+ if( cvtest::randInt(rng) % 2 )
+ sizes[OUTPUT][0] = cvSize(pt_count, 1);
+ else
+ sizes[OUTPUT][0] = cvSize(1, pt_count);
+ }
+ }
+
+ types[REF_OUTPUT][0] = types[OUTPUT][0];
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+}
+
+
+double CV_ComputeEpilinesTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 1e-5;
+}
+
+
+void CV_ComputeEpilinesTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ RNG& rng = ts->get_rng();
+
+ if( i == INPUT && j == 0 )
+ {
+ Mat temp( 1, pt_count, CV_MAKETYPE(CV_64FC1,dims) );
+ cvtest::randUni( rng, temp, cvScalar(0,0,1), cvScalarAll(10) );
+ test_convertHomogeneous( temp, arr );
+ }
+ else if( i == INPUT && j == 1 )
+ cvtest::randUni( rng, arr, cvScalarAll(0), cvScalarAll(10) );
+ else
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+void CV_ComputeEpilinesTest::run_func()
+{
+ CvMat _points = test_mat[INPUT][0], _F = test_mat[INPUT][1], _lines = test_mat[OUTPUT][0];
+ cvComputeCorrespondEpilines( &_points, which_image, &_F, &_lines );
+}
+
+
+void CV_ComputeEpilinesTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat pt( 1, pt_count, CV_MAKETYPE(CV_64F, 3) );
+ Mat lines( 1, pt_count, CV_MAKETYPE(CV_64F, 3) );
+ double f[9];
+ Mat F( 3, 3, CV_64F, f );
+
+ test_convertHomogeneous( test_mat[INPUT][0], pt );
+ test_mat[INPUT][1].convertTo(F, CV_64F);
+ if( which_image == 2 )
+ cv::transpose( F, F );
+
+ for( int i = 0; i < pt_count; i++ )
+ {
+ double* p = pt.ptr<double>() + i*3;
+ double* l = lines.ptr<double>() + i*3;
+ double t0 = f[0]*p[0] + f[1]*p[1] + f[2]*p[2];
+ double t1 = f[3]*p[0] + f[4]*p[1] + f[5]*p[2];
+ double t2 = f[6]*p[0] + f[7]*p[1] + f[8]*p[2];
+ double d = sqrt(t0*t0 + t1*t1);
+ d = d ? 1./d : 1.;
+ l[0] = t0*d; l[1] = t1*d; l[2] = t2*d;
+ }
+
+ test_convertHomogeneous( lines, test_mat[REF_OUTPUT][0] );
+}
+
+
+TEST(Calib3d_Rodrigues, accuracy) { CV_RodriguesTest test; test.safe_run(); }
+TEST(Calib3d_FindFundamentalMat, accuracy) { CV_FundamentalMatTest test; test.safe_run(); }
+TEST(Calib3d_ConvertHomogeneoous, accuracy) { CV_ConvertHomogeneousTest test; test.safe_run(); }
+TEST(Calib3d_ComputeEpilines, accuracy) { CV_ComputeEpilinesTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_POSITTest : public cvtest::BaseTest
+{
+public:
+ CV_POSITTest();
+protected:
+ void run(int);
+};
+
+
+CV_POSITTest::CV_POSITTest()
+{
+ test_case_count = 20;
+}
+
+void CV_POSITTest::run( int start_from )
+{
+ int code = cvtest::TS::OK;
+
+ /* fixed parameters output */
+ /*float rot[3][3]={ 0.49010f, 0.85057f, 0.19063f,
+ -0.56948f, 0.14671f, 0.80880f,
+ 0.65997f, -0.50495f, 0.55629f };
+
+ float trans[3] = { 0.0f, 0.0f, 40.02637f };
+ */
+
+ /* Some variables */
+ int i, counter;
+
+ CvTermCriteria criteria;
+ CvPoint3D32f* obj_points;
+ CvPoint2D32f* img_points;
+ CvPOSITObject* object;
+
+ float angleX, angleY, angleZ;
+ RNG& rng = ts->get_rng();
+ int progress = 0;
+
+ CvMat* true_rotationX = cvCreateMat( 3, 3, CV_32F );
+ CvMat* true_rotationY = cvCreateMat( 3, 3, CV_32F );
+ CvMat* true_rotationZ = cvCreateMat( 3, 3, CV_32F );
+ CvMat* tmp_matrix = cvCreateMat( 3, 3, CV_32F );
+ CvMat* true_rotation = cvCreateMat( 3, 3, CV_32F );
+ CvMat* rotation = cvCreateMat( 3, 3, CV_32F );
+ CvMat* translation = cvCreateMat( 3, 1, CV_32F );
+ CvMat* true_translation = cvCreateMat( 3, 1, CV_32F );
+
+ const float flFocalLength = 760.f;
+ const float flEpsilon = 0.5f;
+
+ /* Initilization */
+ criteria.type = CV_TERMCRIT_EPS|CV_TERMCRIT_ITER;
+ criteria.epsilon = flEpsilon;
+ criteria.max_iter = 10000;
+
+ /* Allocating source arrays; */
+ obj_points = (CvPoint3D32f*)cvAlloc( 8 * sizeof(CvPoint3D32f) );
+ img_points = (CvPoint2D32f*)cvAlloc( 8 * sizeof(CvPoint2D32f) );
+
+ /* Fill points arrays with values */
+
+ /* cube model with edge size 10 */
+ obj_points[0].x = 0; obj_points[0].y = 0; obj_points[0].z = 0;
+ obj_points[1].x = 10; obj_points[1].y = 0; obj_points[1].z = 0;
+ obj_points[2].x = 10; obj_points[2].y = 10; obj_points[2].z = 0;
+ obj_points[3].x = 0; obj_points[3].y = 10; obj_points[3].z = 0;
+ obj_points[4].x = 0; obj_points[4].y = 0; obj_points[4].z = 10;
+ obj_points[5].x = 10; obj_points[5].y = 0; obj_points[5].z = 10;
+ obj_points[6].x = 10; obj_points[6].y = 10; obj_points[6].z = 10;
+ obj_points[7].x = 0; obj_points[7].y = 10; obj_points[7].z = 10;
+
+ /* Loop for test some random object positions */
+ for( counter = start_from; counter < test_case_count; counter++ )
+ {
+ ts->update_context( this, counter, true );
+ progress = update_progress( progress, counter, test_case_count, 0 );
+
+ /* set all rotation matrix to zero */
+ cvZero( true_rotationX );
+ cvZero( true_rotationY );
+ cvZero( true_rotationZ );
+
+ /* fill random rotation matrix */
+ angleX = (float)(cvtest::randReal(rng)*2*CV_PI);
+ angleY = (float)(cvtest::randReal(rng)*2*CV_PI);
+ angleZ = (float)(cvtest::randReal(rng)*2*CV_PI);
+
+ true_rotationX->data.fl[0 *3+ 0] = 1;
+ true_rotationX->data.fl[1 *3+ 1] = (float)cos(angleX);
+ true_rotationX->data.fl[2 *3+ 2] = true_rotationX->data.fl[1 *3+ 1];
+ true_rotationX->data.fl[1 *3+ 2] = -(float)sin(angleX);
+ true_rotationX->data.fl[2 *3+ 1] = -true_rotationX->data.fl[1 *3+ 2];
+
+ true_rotationY->data.fl[1 *3+ 1] = 1;
+ true_rotationY->data.fl[0 *3+ 0] = (float)cos(angleY);
+ true_rotationY->data.fl[2 *3+ 2] = true_rotationY->data.fl[0 *3+ 0];
+ true_rotationY->data.fl[0 *3+ 2] = -(float)sin(angleY);
+ true_rotationY->data.fl[2 *3+ 0] = -true_rotationY->data.fl[0 *3+ 2];
+
+ true_rotationZ->data.fl[2 *3+ 2] = 1;
+ true_rotationZ->data.fl[0 *3+ 0] = (float)cos(angleZ);
+ true_rotationZ->data.fl[1 *3+ 1] = true_rotationZ->data.fl[0 *3+ 0];
+ true_rotationZ->data.fl[0 *3+ 1] = -(float)sin(angleZ);
+ true_rotationZ->data.fl[1 *3+ 0] = -true_rotationZ->data.fl[0 *3+ 1];
+
+ cvMatMul( true_rotationX, true_rotationY, tmp_matrix);
+ cvMatMul( tmp_matrix, true_rotationZ, true_rotation);
+
+ /* fill translation vector */
+ true_translation->data.fl[2] = (float)(cvtest::randReal(rng)*(2*flFocalLength-40) + 60);
+ true_translation->data.fl[0] = (float)((cvtest::randReal(rng)*2-1)*true_translation->data.fl[2]);
+ true_translation->data.fl[1] = (float)((cvtest::randReal(rng)*2-1)*true_translation->data.fl[2]);
+
+ /* calculate perspective projection */
+ for ( i = 0; i < 8; i++ )
+ {
+ float vec[3];
+ CvMat Vec = cvMat( 3, 1, CV_32F, vec );
+ CvMat Obj_point = cvMat( 3, 1, CV_32F, &obj_points[i].x );
+
+ cvMatMul( true_rotation, &Obj_point, &Vec );
+
+ vec[0] += true_translation->data.fl[0];
+ vec[1] += true_translation->data.fl[1];
+ vec[2] += true_translation->data.fl[2];
+
+ img_points[i].x = flFocalLength * vec[0] / vec[2];
+ img_points[i].y = flFocalLength * vec[1] / vec[2];
+ }
+
+ /*img_points[0].x = 0 ; img_points[0].y = 0;
+ img_points[1].x = 80; img_points[1].y = -93;
+ img_points[2].x = 245;img_points[2].y = -77;
+ img_points[3].x = 185;img_points[3].y = 32;
+ img_points[4].x = 32; img_points[4].y = 135;
+ img_points[5].x = 99; img_points[5].y = 35;
+ img_points[6].x = 247; img_points[6].y = 62;
+ img_points[7].x = 195; img_points[7].y = 179;
+ */
+
+ object = cvCreatePOSITObject( obj_points, 8 );
+ cvPOSIT( object, img_points, flFocalLength, criteria,
+ rotation->data.fl, translation->data.fl );
+ cvReleasePOSITObject( &object );
+
+ //Mat _rotation = cvarrToMat(rotation), _true_rotation = cvarrToMat(true_rotation);
+ //Mat _translation = cvarrToMat(translation), _true_translation = cvarrToMat(true_translation);
+ code = cvtest::cmpEps2( ts, rotation, true_rotation, flEpsilon, false, "rotation matrix" );
+ if( code < 0 )
+ break;
+
+ code = cvtest::cmpEps2( ts, translation, true_translation, flEpsilon, false, "translation vector" );
+ if( code < 0 )
+ break;
+ }
+
+ cvFree( &obj_points );
+ cvFree( &img_points );
+
+ cvReleaseMat( &true_rotationX );
+ cvReleaseMat( &true_rotationY );
+ cvReleaseMat( &true_rotationZ );
+ cvReleaseMat( &tmp_matrix );
+ cvReleaseMat( &true_rotation );
+ cvReleaseMat( &rotation );
+ cvReleaseMat( &translation );
+ cvReleaseMat( &true_translation );
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Calib3d_POSIT, accuracy) { CV_POSITTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/calib3d/calib3d.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <iostream>
+
+namespace cvtest
+{
+ void Rodrigues(const Mat& src, Mat& dst, Mat* jac=0);
+}
+
+#endif
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <string>
+#include <limits>
+
+using namespace cv;
+using namespace std;
+
+template<class T> double thres() { return 1.0; }
+template<> double thres<float>() { return 1e-5; }
+
+class CV_ReprojectImageTo3DTest : public cvtest::BaseTest
+{
+public:
+ CV_ReprojectImageTo3DTest() {}
+ ~CV_ReprojectImageTo3DTest() {}
+protected:
+
+
+ void run(int)
+ {
+ ts->set_failed_test_info(cvtest::TS::OK);
+ int progress = 0;
+ int caseId = 0;
+
+ progress = update_progress( progress, 1, 14, 0 );
+ runCase<float, float>(++caseId, -100.f, 100.f);
+ progress = update_progress( progress, 2, 14, 0 );
+ runCase<int, float>(++caseId, -100, 100);
+ progress = update_progress( progress, 3, 14, 0 );
+ runCase<short, float>(++caseId, -100, 100);
+ progress = update_progress( progress, 4, 14, 0 );
+ runCase<unsigned char, float>(++caseId, 10, 100);
+ progress = update_progress( progress, 5, 14, 0 );
+
+ runCase<float, int>(++caseId, -100.f, 100.f);
+ progress = update_progress( progress, 6, 14, 0 );
+ runCase<int, int>(++caseId, -100, 100);
+ progress = update_progress( progress, 7, 14, 0 );
+ runCase<short, int>(++caseId, -100, 100);
+ progress = update_progress( progress, 8, 14, 0 );
+ runCase<unsigned char, int>(++caseId, 10, 100);
+ progress = update_progress( progress, 10, 14, 0 );
+
+ runCase<float, short>(++caseId, -100.f, 100.f);
+ progress = update_progress( progress, 11, 14, 0 );
+ runCase<int, short>(++caseId, -100, 100);
+ progress = update_progress( progress, 12, 14, 0 );
+ runCase<short, short>(++caseId, -100, 100);
+ progress = update_progress( progress, 13, 14, 0 );
+ runCase<unsigned char, short>(++caseId, 10, 100);
+ progress = update_progress( progress, 14, 14, 0 );
+ }
+
+ template<class U, class V> double error(const Vec<U, 3>& v1, const Vec<V, 3>& v2) const
+ {
+ double tmp, sum = 0;
+ double nsum = 0;
+ for(int i = 0; i < 3; ++i)
+ {
+ tmp = v1[i];
+ nsum += tmp * tmp;
+
+ tmp = tmp - v2[i];
+ sum += tmp * tmp;
+
+ }
+ return sqrt(sum)/(sqrt(nsum)+1.);
+ }
+
+ template<class InT, class OutT> void runCase(int caseId, InT min, InT max)
+ {
+ typedef Vec<OutT, 3> out3d_t;
+
+ bool handleMissingValues = (unsigned)theRNG() % 2 == 0;
+
+ Mat_<InT> disp(Size(320, 240));
+ randu(disp, Scalar(min), Scalar(max));
+
+ if (handleMissingValues)
+ disp(disp.rows/2, disp.cols/2) = min - 1;
+
+ Mat_<double> Q(4, 4);
+ randu(Q, Scalar(-5), Scalar(5));
+
+ Mat_<out3d_t> _3dImg(disp.size());
+
+ CvMat cvdisp = disp; CvMat cv_3dImg = _3dImg; CvMat cvQ = Q;
+ cvReprojectImageTo3D( &cvdisp, &cv_3dImg, &cvQ, handleMissingValues );
+
+ if (numeric_limits<OutT>::max() == numeric_limits<float>::max())
+ reprojectImageTo3D(disp, _3dImg, Q, handleMissingValues);
+
+ for(int y = 0; y < disp.rows; ++y)
+ for(int x = 0; x < disp.cols; ++x)
+ {
+ InT d = disp(y, x);
+
+ double from[4] = { x, y, d, 1 };
+ Mat_<double> res = Q * Mat_<double>(4, 1, from);
+ res /= res(3, 0);
+
+ out3d_t pixel_exp = *(Vec3d*)res.data;
+ out3d_t pixel_out = _3dImg(y, x);
+
+ const int largeZValue = 10000; /* see documentation */
+
+ if (handleMissingValues && y == disp.rows/2 && x == disp.cols/2)
+ {
+ if (pixel_out[2] == largeZValue)
+ continue;
+
+ ts->printf(cvtest::TS::LOG, "Missing values are handled improperly\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+ else
+ {
+ double err = error(pixel_out, pixel_exp), t = thres<OutT>();
+ if ( err > t )
+ {
+ ts->printf(cvtest::TS::LOG, "case %d. too big error at (%d, %d): %g vs expected %g: res = (%g, %g, %g, w=%g) vs pixel_out = (%g, %g, %g)\n",
+ caseId, x, y, err, t, res(0,0), res(1,0), res(2,0), res(3,0),
+ (double)pixel_out[0], (double)pixel_out[1], (double)pixel_out[2]);
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+ }
+ }
+ }
+};
+
+TEST(Calib3d_ReprojectImageTo3D, accuracy) { CV_ReprojectImageTo3DTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+/*
+ This is a regression test for stereo matching algorithms. This test gets some quality metrics
+ discribed in "A Taxonomy and Evaluation of Dense Two-Frame Stereo Correspondence Algorithms".
+ Daniel Scharstein, Richard Szeliski
+*/
+
+#include "test_precomp.hpp"
+#include <limits>
+#include <cstdio>
+
+using namespace std;
+using namespace cv;
+
+const float EVAL_BAD_THRESH = 1.f;
+const int EVAL_TEXTURELESS_WIDTH = 3;
+const float EVAL_TEXTURELESS_THRESH = 4.f;
+const float EVAL_DISP_THRESH = 1.f;
+const float EVAL_DISP_GAP = 2.f;
+const int EVAL_DISCONT_WIDTH = 9;
+const int EVAL_IGNORE_BORDER = 10;
+
+const int ERROR_KINDS_COUNT = 6;
+
+//============================== quality measuring functions =================================================
+
+/*
+ Calculate textureless regions of image (regions where the squared horizontal intensity gradient averaged over
+ a square window of size=evalTexturelessWidth is below a threshold=evalTexturelessThresh) and textured regions.
+*/
+void computeTextureBasedMasks( const Mat& _img, Mat* texturelessMask, Mat* texturedMask,
+ int texturelessWidth = EVAL_TEXTURELESS_WIDTH, float texturelessThresh = EVAL_TEXTURELESS_THRESH )
+{
+ if( !texturelessMask && !texturedMask )
+ return;
+ if( _img.empty() )
+ CV_Error( CV_StsBadArg, "img is empty" );
+
+ Mat img = _img;
+ if( _img.channels() > 1)
+ {
+ Mat tmp; cvtColor( _img, tmp, CV_BGR2GRAY ); img = tmp;
+ }
+ Mat dxI; Sobel( img, dxI, CV_32FC1, 1, 0, 3 );
+ Mat dxI2; pow( dxI / 8.f/*normalize*/, 2, dxI2 );
+ Mat avgDxI2; boxFilter( dxI2, avgDxI2, CV_32FC1, Size(texturelessWidth,texturelessWidth) );
+
+ if( texturelessMask )
+ *texturelessMask = avgDxI2 < texturelessThresh;
+ if( texturedMask )
+ *texturedMask = avgDxI2 >= texturelessThresh;
+}
+
+void checkTypeAndSizeOfDisp( const Mat& dispMap, const Size* sz )
+{
+ if( dispMap.empty() )
+ CV_Error( CV_StsBadArg, "dispMap is empty" );
+ if( dispMap.type() != CV_32FC1 )
+ CV_Error( CV_StsBadArg, "dispMap must have CV_32FC1 type" );
+ if( sz && (dispMap.rows != sz->height || dispMap.cols != sz->width) )
+ CV_Error( CV_StsBadArg, "dispMap has incorrect size" );
+}
+
+void checkTypeAndSizeOfMask( const Mat& mask, Size sz )
+{
+ if( mask.empty() )
+ CV_Error( CV_StsBadArg, "mask is empty" );
+ if( mask.type() != CV_8UC1 )
+ CV_Error( CV_StsBadArg, "mask must have CV_8UC1 type" );
+ if( mask.rows != sz.height || mask.cols != sz.width )
+ CV_Error( CV_StsBadArg, "mask has incorrect size" );
+}
+
+void checkDispMapsAndUnknDispMasks( const Mat& leftDispMap, const Mat& rightDispMap,
+ const Mat& leftUnknDispMask, const Mat& rightUnknDispMask )
+{
+ // check type and size of disparity maps
+ checkTypeAndSizeOfDisp( leftDispMap, 0 );
+ if( !rightDispMap.empty() )
+ {
+ Size sz = leftDispMap.size();
+ checkTypeAndSizeOfDisp( rightDispMap, &sz );
+ }
+
+ // check size and type of unknown disparity maps
+ if( !leftUnknDispMask.empty() )
+ checkTypeAndSizeOfMask( leftUnknDispMask, leftDispMap.size() );
+ if( !rightUnknDispMask.empty() )
+ checkTypeAndSizeOfMask( rightUnknDispMask, rightDispMap.size() );
+
+ // check values of disparity maps (known disparity values musy be positive)
+ double leftMinVal = 0, rightMinVal = 0;
+ if( leftUnknDispMask.empty() )
+ minMaxLoc( leftDispMap, &leftMinVal );
+ else
+ minMaxLoc( leftDispMap, &leftMinVal, 0, 0, 0, ~leftUnknDispMask );
+ if( !rightDispMap.empty() )
+ {
+ if( rightUnknDispMask.empty() )
+ minMaxLoc( rightDispMap, &rightMinVal );
+ else
+ minMaxLoc( rightDispMap, &rightMinVal, 0, 0, 0, ~rightUnknDispMask );
+ }
+ if( leftMinVal < 0 || rightMinVal < 0)
+ CV_Error( CV_StsBadArg, "known disparity values must be positive" );
+}
+
+/*
+ Calculate occluded regions of reference image (left image) (regions that are occluded in the matching image (right image),
+ i.e., where the forward-mapped disparity lands at a location with a larger (nearer) disparity) and non occluded regions.
+*/
+void computeOcclusionBasedMasks( const Mat& leftDisp, const Mat& _rightDisp,
+ Mat* occludedMask, Mat* nonOccludedMask,
+ const Mat& leftUnknDispMask = Mat(), const Mat& rightUnknDispMask = Mat(),
+ float dispThresh = EVAL_DISP_THRESH )
+{
+ if( !occludedMask && !nonOccludedMask )
+ return;
+ checkDispMapsAndUnknDispMasks( leftDisp, _rightDisp, leftUnknDispMask, rightUnknDispMask );
+
+ Mat rightDisp;
+ if( _rightDisp.empty() )
+ {
+ if( !rightUnknDispMask.empty() )
+ CV_Error( CV_StsBadArg, "rightUnknDispMask must be empty if _rightDisp is empty" );
+ rightDisp.create(leftDisp.size(), CV_32FC1);
+ rightDisp.setTo(Scalar::all(0) );
+ for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
+ {
+ for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
+ {
+ if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
+ continue;
+ float leftDispVal = leftDisp.at<float>(leftY, leftX);
+ int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
+ if( rightX >= 0)
+ rightDisp.at<float>(rightY,rightX) = max(rightDisp.at<float>(rightY,rightX), leftDispVal);
+ }
+ }
+ }
+ else
+ _rightDisp.copyTo(rightDisp);
+
+ if( occludedMask )
+ {
+ occludedMask->create(leftDisp.size(), CV_8UC1);
+ occludedMask->setTo(Scalar::all(0) );
+ }
+ if( nonOccludedMask )
+ {
+ nonOccludedMask->create(leftDisp.size(), CV_8UC1);
+ nonOccludedMask->setTo(Scalar::all(0) );
+ }
+ for( int leftY = 0; leftY < leftDisp.rows; leftY++ )
+ {
+ for( int leftX = 0; leftX < leftDisp.cols; leftX++ )
+ {
+ if( !leftUnknDispMask.empty() && leftUnknDispMask.at<uchar>(leftY,leftX) )
+ continue;
+ float leftDispVal = leftDisp.at<float>(leftY, leftX);
+ int rightX = leftX - cvRound(leftDispVal), rightY = leftY;
+ if( rightX < 0 && occludedMask )
+ occludedMask->at<uchar>(leftY, leftX) = 255;
+ else
+ {
+ if( !rightUnknDispMask.empty() && rightUnknDispMask.at<uchar>(rightY,rightX) )
+ continue;
+ float rightDispVal = rightDisp.at<float>(rightY, rightX);
+ if( rightDispVal > leftDispVal + dispThresh )
+ {
+ if( occludedMask )
+ occludedMask->at<uchar>(leftY, leftX) = 255;
+ }
+ else
+ {
+ if( nonOccludedMask )
+ nonOccludedMask->at<uchar>(leftY, leftX) = 255;
+ }
+ }
+ }
+ }
+}
+
+/*
+ Calculate depth discontinuty regions: pixels whose neiboring disparities differ by more than
+ dispGap, dilated by window of width discontWidth.
+*/
+void computeDepthDiscontMask( const Mat& disp, Mat& depthDiscontMask, const Mat& unknDispMask = Mat(),
+ float dispGap = EVAL_DISP_GAP, int discontWidth = EVAL_DISCONT_WIDTH )
+{
+ if( disp.empty() )
+ CV_Error( CV_StsBadArg, "disp is empty" );
+ if( disp.type() != CV_32FC1 )
+ CV_Error( CV_StsBadArg, "disp must have CV_32FC1 type" );
+ if( !unknDispMask.empty() )
+ checkTypeAndSizeOfMask( unknDispMask, disp.size() );
+
+ Mat curDisp; disp.copyTo( curDisp );
+ if( !unknDispMask.empty() )
+ curDisp.setTo( Scalar(numeric_limits<float>::min()), unknDispMask );
+ Mat maxNeighbDisp; dilate( curDisp, maxNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
+ if( !unknDispMask.empty() )
+ curDisp.setTo( Scalar(numeric_limits<float>::max()), unknDispMask );
+ Mat minNeighbDisp; erode( curDisp, minNeighbDisp, Mat(3, 3, CV_8UC1, Scalar(1)) );
+ depthDiscontMask = max( (Mat)(maxNeighbDisp-disp), (Mat)(disp-minNeighbDisp) ) > dispGap;
+ if( !unknDispMask.empty() )
+ depthDiscontMask &= ~unknDispMask;
+ dilate( depthDiscontMask, depthDiscontMask, Mat(discontWidth, discontWidth, CV_8UC1, Scalar(1)) );
+}
+
+/*
+ Get evaluation masks excluding a border.
+*/
+Mat getBorderedMask( Size maskSize, int border = EVAL_IGNORE_BORDER )
+{
+ CV_Assert( border >= 0 );
+ Mat mask(maskSize, CV_8UC1, Scalar(0));
+ int w = maskSize.width - 2*border, h = maskSize.height - 2*border;
+ if( w < 0 || h < 0 )
+ mask.setTo(Scalar(0));
+ else
+ mask( Rect(Point(border,border),Size(w,h)) ).setTo(Scalar(255));
+ return mask;
+}
+
+/*
+ Calculate root-mean-squared error between the computed disparity map (computedDisp) and ground truth map (groundTruthDisp).
+*/
+float dispRMS( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask )
+{
+ checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
+ Size sz = groundTruthDisp.size();
+ checkTypeAndSizeOfDisp( computedDisp, &sz );
+
+ int pointsCount = sz.height*sz.width;
+ if( !mask.empty() )
+ {
+ checkTypeAndSizeOfMask( mask, sz );
+ pointsCount = countNonZero(mask);
+ }
+ return 1.f/sqrt((float)pointsCount) * (float)norm(computedDisp, groundTruthDisp, NORM_L2, mask);
+}
+
+/*
+ Calculate fraction of bad matching pixels.
+*/
+float badMatchPxlsFraction( const Mat& computedDisp, const Mat& groundTruthDisp, const Mat& mask,
+ float _badThresh = EVAL_BAD_THRESH )
+{
+ int badThresh = cvRound(_badThresh);
+ checkTypeAndSizeOfDisp( groundTruthDisp, 0 );
+ Size sz = groundTruthDisp.size();
+ checkTypeAndSizeOfDisp( computedDisp, &sz );
+
+ Mat badPxlsMap;
+ absdiff( computedDisp, groundTruthDisp, badPxlsMap );
+ badPxlsMap = badPxlsMap > badThresh;
+ int pointsCount = sz.height*sz.width;
+ if( !mask.empty() )
+ {
+ checkTypeAndSizeOfMask( mask, sz );
+ badPxlsMap = badPxlsMap & mask;
+ pointsCount = countNonZero(mask);
+ }
+ return 1.f/pointsCount * countNonZero(badPxlsMap);
+}
+
+//===================== regression test for stereo matching algorithms ==============================
+
+const string ALGORITHMS_DIR = "stereomatching/algorithms/";
+const string DATASETS_DIR = "stereomatching/datasets/";
+const string DATASETS_FILE = "datasets.xml";
+
+const string RUN_PARAMS_FILE = "_params.xml";
+const string RESULT_FILE = "_res.xml";
+
+const string LEFT_IMG_NAME = "im2.png";
+const string RIGHT_IMG_NAME = "im6.png";
+const string TRUE_LEFT_DISP_NAME = "disp2.png";
+const string TRUE_RIGHT_DISP_NAME = "disp6.png";
+
+string ERROR_PREFIXES[] = { "borderedAll",
+ "borderedNoOccl",
+ "borderedOccl",
+ "borderedTextured",
+ "borderedTextureless",
+ "borderedDepthDiscont" }; // size of ERROR_KINDS_COUNT
+
+
+const string RMS_STR = "RMS";
+const string BAD_PXLS_FRACTION_STR = "BadPxlsFraction";
+
+class QualityEvalParams
+{
+public:
+ QualityEvalParams() { setDefaults(); }
+ QualityEvalParams( int _ignoreBorder )
+ {
+ setDefaults();
+ ignoreBorder = _ignoreBorder;
+ }
+ void setDefaults()
+ {
+ badThresh = EVAL_BAD_THRESH;
+ texturelessWidth = EVAL_TEXTURELESS_WIDTH;
+ texturelessThresh = EVAL_TEXTURELESS_THRESH;
+ dispThresh = EVAL_DISP_THRESH;
+ dispGap = EVAL_DISP_GAP;
+ discontWidth = EVAL_DISCONT_WIDTH;
+ ignoreBorder = EVAL_IGNORE_BORDER;
+ }
+ float badThresh;
+ int texturelessWidth;
+ float texturelessThresh;
+ float dispThresh;
+ float dispGap;
+ int discontWidth;
+ int ignoreBorder;
+};
+
+class CV_StereoMatchingTest : public cvtest::BaseTest
+{
+public:
+ CV_StereoMatchingTest()
+ { rmsEps.resize( ERROR_KINDS_COUNT, 0.01f ); fracEps.resize( ERROR_KINDS_COUNT, 1.e-6f ); }
+protected:
+ // assumed that left image is a reference image
+ virtual int runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rightImg,
+ Mat& leftDisp, Mat& rightDisp, int caseIdx ) = 0; // return ignored border width
+
+ int readDatasetsParams( FileStorage& fs );
+ virtual int readRunParams( FileStorage& fs );
+ void writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs = 0 );
+ void readErrors( FileNode& fn, const string& errName, vector<float>& errors );
+ int compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
+ const vector<float>& eps, const string& errName );
+ int processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
+ const Mat& leftImg, const Mat& rightImg,
+ const Mat& trueLeftDisp, const Mat& trueRightDisp,
+ const Mat& leftDisp, const Mat& rightDisp,
+ const QualityEvalParams& qualityEvalParams );
+ void run( int );
+
+ vector<float> rmsEps;
+ vector<float> fracEps;
+
+ struct DatasetParams
+ {
+ int dispScaleFactor;
+ int dispUnknVal;
+ };
+ map<string, DatasetParams> datasetsParams;
+
+ vector<string> caseNames;
+ vector<string> caseDatasets;
+};
+
+void CV_StereoMatchingTest::run(int)
+{
+ string dataPath = ts->get_data_path();
+ string algorithmName = name;
+ assert( !algorithmName.empty() );
+ if( dataPath.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "dataPath is empty" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
+ return;
+ }
+
+ FileStorage datasetsFS( dataPath + DATASETS_DIR + DATASETS_FILE, FileStorage::READ );
+ int code = readDatasetsParams( datasetsFS );
+ if( code != cvtest::TS::OK )
+ {
+ ts->set_failed_test_info( code );
+ return;
+ }
+ FileStorage runParamsFS( dataPath + ALGORITHMS_DIR + algorithmName + RUN_PARAMS_FILE, FileStorage::READ );
+ code = readRunParams( runParamsFS );
+ if( code != cvtest::TS::OK )
+ {
+ ts->set_failed_test_info( code );
+ return;
+ }
+
+ string fullResultFilename = dataPath + ALGORITHMS_DIR + algorithmName + RESULT_FILE;
+ FileStorage resFS( fullResultFilename, FileStorage::READ );
+ bool isWrite = true; // write or compare results
+ if( resFS.isOpened() )
+ isWrite = false;
+ else
+ {
+ resFS.open( fullResultFilename, FileStorage::WRITE );
+ if( !resFS.isOpened() )
+ {
+ ts->printf( cvtest::TS::LOG, "file %s can not be read or written\n", fullResultFilename.c_str() );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ARG_CHECK );
+ return;
+ }
+ resFS << "stereo_matching" << "{";
+ }
+
+ int progress = 0, caseCount = (int)caseNames.size();
+ for( int ci = 0; ci < caseCount; ci++)
+ {
+ progress = update_progress( progress, ci, caseCount, 0 );
+
+ string datasetName = caseDatasets[ci];
+ string datasetFullDirName = dataPath + DATASETS_DIR + datasetName + "/";
+ Mat leftImg = imread(datasetFullDirName + LEFT_IMG_NAME);
+ Mat rightImg = imread(datasetFullDirName + RIGHT_IMG_NAME);
+ Mat trueLeftDisp = imread(datasetFullDirName + TRUE_LEFT_DISP_NAME, 0);
+ Mat trueRightDisp = imread(datasetFullDirName + TRUE_RIGHT_DISP_NAME, 0);
+
+ if( leftImg.empty() || rightImg.empty() || trueLeftDisp.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "images or left ground-truth disparities of dataset %s can not be read", datasetName.c_str() );
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ continue;
+ }
+ int dispScaleFactor = datasetsParams[datasetName].dispScaleFactor;
+ Mat tmp; trueLeftDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueLeftDisp = tmp; tmp.release();
+ if( !trueRightDisp.empty() )
+ trueRightDisp.convertTo( tmp, CV_32FC1, 1.f/dispScaleFactor ); trueRightDisp = tmp; tmp.release();
+
+ Mat leftDisp, rightDisp;
+ int ignBorder = max(runStereoMatchingAlgorithm(leftImg, rightImg, leftDisp, rightDisp, ci), EVAL_IGNORE_BORDER);
+ leftDisp.convertTo( tmp, CV_32FC1 ); leftDisp = tmp; tmp.release();
+ rightDisp.convertTo( tmp, CV_32FC1 ); rightDisp = tmp; tmp.release();
+
+ int tempCode = processStereoMatchingResults( resFS, ci, isWrite,
+ leftImg, rightImg, trueLeftDisp, trueRightDisp, leftDisp, rightDisp, QualityEvalParams(ignBorder));
+ code = tempCode==cvtest::TS::OK ? code : tempCode;
+ }
+
+ if( isWrite )
+ resFS << "}"; // "stereo_matching"
+
+ ts->set_failed_test_info( code );
+}
+
+void calcErrors( const Mat& leftImg, const Mat& /*rightImg*/,
+ const Mat& trueLeftDisp, const Mat& trueRightDisp,
+ const Mat& trueLeftUnknDispMask, const Mat& trueRightUnknDispMask,
+ const Mat& calcLeftDisp, const Mat& /*calcRightDisp*/,
+ vector<float>& rms, vector<float>& badPxlsFractions,
+ const QualityEvalParams& qualityEvalParams )
+{
+ Mat texturelessMask, texturedMask;
+ computeTextureBasedMasks( leftImg, &texturelessMask, &texturedMask,
+ qualityEvalParams.texturelessWidth, qualityEvalParams.texturelessThresh );
+ Mat occludedMask, nonOccludedMask;
+ computeOcclusionBasedMasks( trueLeftDisp, trueRightDisp, &occludedMask, &nonOccludedMask,
+ trueLeftUnknDispMask, trueRightUnknDispMask, qualityEvalParams.dispThresh);
+ Mat depthDiscontMask;
+ computeDepthDiscontMask( trueLeftDisp, depthDiscontMask, trueLeftUnknDispMask,
+ qualityEvalParams.dispGap, qualityEvalParams.discontWidth);
+
+ Mat borderedKnownMask = getBorderedMask( leftImg.size(), qualityEvalParams.ignoreBorder ) & ~trueLeftUnknDispMask;
+
+ nonOccludedMask &= borderedKnownMask;
+ occludedMask &= borderedKnownMask;
+ texturedMask &= nonOccludedMask; // & borderedKnownMask
+ texturelessMask &= nonOccludedMask; // & borderedKnownMask
+ depthDiscontMask &= nonOccludedMask; // & borderedKnownMask
+
+ rms.resize(ERROR_KINDS_COUNT);
+ rms[0] = dispRMS( calcLeftDisp, trueLeftDisp, borderedKnownMask );
+ rms[1] = dispRMS( calcLeftDisp, trueLeftDisp, nonOccludedMask );
+ rms[2] = dispRMS( calcLeftDisp, trueLeftDisp, occludedMask );
+ rms[3] = dispRMS( calcLeftDisp, trueLeftDisp, texturedMask );
+ rms[4] = dispRMS( calcLeftDisp, trueLeftDisp, texturelessMask );
+ rms[5] = dispRMS( calcLeftDisp, trueLeftDisp, depthDiscontMask );
+
+ badPxlsFractions.resize(ERROR_KINDS_COUNT);
+ badPxlsFractions[0] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, borderedKnownMask, qualityEvalParams.badThresh );
+ badPxlsFractions[1] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, nonOccludedMask, qualityEvalParams.badThresh );
+ badPxlsFractions[2] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, occludedMask, qualityEvalParams.badThresh );
+ badPxlsFractions[3] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturedMask, qualityEvalParams.badThresh );
+ badPxlsFractions[4] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, texturelessMask, qualityEvalParams.badThresh );
+ badPxlsFractions[5] = badMatchPxlsFraction( calcLeftDisp, trueLeftDisp, depthDiscontMask, qualityEvalParams.badThresh );
+}
+
+int CV_StereoMatchingTest::processStereoMatchingResults( FileStorage& fs, int caseIdx, bool isWrite,
+ const Mat& leftImg, const Mat& rightImg,
+ const Mat& trueLeftDisp, const Mat& trueRightDisp,
+ const Mat& leftDisp, const Mat& rightDisp,
+ const QualityEvalParams& qualityEvalParams )
+{
+ // rightDisp is not used in current test virsion
+ int code = cvtest::TS::OK;
+ assert( fs.isOpened() );
+ assert( trueLeftDisp.type() == CV_32FC1 && trueRightDisp.type() == CV_32FC1 );
+ assert( leftDisp.type() == CV_32FC1 && rightDisp.type() == CV_32FC1 );
+
+ // get masks for unknown ground truth disparity values
+ Mat leftUnknMask, rightUnknMask;
+ DatasetParams params = datasetsParams[caseDatasets[caseIdx]];
+ absdiff( trueLeftDisp, Scalar(params.dispUnknVal), leftUnknMask );
+ leftUnknMask = leftUnknMask < numeric_limits<float>::epsilon();
+ assert(leftUnknMask.type() == CV_8UC1);
+ if( !trueRightDisp.empty() )
+ {
+ absdiff( trueRightDisp, Scalar(params.dispUnknVal), rightUnknMask );
+ rightUnknMask = rightUnknMask < numeric_limits<float>::epsilon();
+ assert(leftUnknMask.type() == CV_8UC1);
+ }
+
+ // calculate errors
+ vector<float> rmss, badPxlsFractions;
+ calcErrors( leftImg, rightImg, trueLeftDisp, trueRightDisp, leftUnknMask, rightUnknMask,
+ leftDisp, rightDisp, rmss, badPxlsFractions, qualityEvalParams );
+
+ if( isWrite )
+ {
+ fs << caseNames[caseIdx] << "{";
+ cvWriteComment( fs.fs, RMS_STR.c_str(), 0 );
+ writeErrors( RMS_STR, rmss, &fs );
+ cvWriteComment( fs.fs, BAD_PXLS_FRACTION_STR.c_str(), 0 );
+ writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions, &fs );
+ fs << "}"; // datasetName
+ }
+ else // compare
+ {
+ ts->printf( cvtest::TS::LOG, "\nquality of case named %s\n", caseNames[caseIdx].c_str() );
+ ts->printf( cvtest::TS::LOG, "%s\n", RMS_STR.c_str() );
+ writeErrors( RMS_STR, rmss );
+ ts->printf( cvtest::TS::LOG, "%s\n", BAD_PXLS_FRACTION_STR.c_str() );
+ writeErrors( BAD_PXLS_FRACTION_STR, badPxlsFractions );
+
+ FileNode fn = fs.getFirstTopLevelNode()[caseNames[caseIdx]];
+ vector<float> validRmss, validBadPxlsFractions;
+
+ readErrors( fn, RMS_STR, validRmss );
+ readErrors( fn, BAD_PXLS_FRACTION_STR, validBadPxlsFractions );
+ int tempCode = compareErrors( rmss, validRmss, rmsEps, RMS_STR );
+ code = tempCode==cvtest::TS::OK ? code : tempCode;
+ tempCode = compareErrors( badPxlsFractions, validBadPxlsFractions, fracEps, BAD_PXLS_FRACTION_STR );
+ code = tempCode==cvtest::TS::OK ? code : tempCode;
+ }
+ return code;
+}
+
+int CV_StereoMatchingTest::readDatasetsParams( FileStorage& fs )
+{
+ if( !fs.isOpened() )
+ {
+ ts->printf( cvtest::TS::LOG, "datasetsParams can not be read " );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ datasetsParams.clear();
+ FileNode fn = fs.getFirstTopLevelNode();
+ assert(fn.isSeq());
+ for( int i = 0; i < (int)fn.size(); i+=3 )
+ {
+ string name = fn[i];
+ DatasetParams params;
+ string sf = fn[i+1]; params.dispScaleFactor = atoi(sf.c_str());
+ string uv = fn[i+2]; params.dispUnknVal = atoi(uv.c_str());
+ datasetsParams[name] = params;
+ }
+ return cvtest::TS::OK;
+}
+
+int CV_StereoMatchingTest::readRunParams( FileStorage& fs )
+{
+ if( !fs.isOpened() )
+ {
+ ts->printf( cvtest::TS::LOG, "runParams can not be read " );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ caseNames.clear();;
+ caseDatasets.clear();
+ return cvtest::TS::OK;
+}
+
+void CV_StereoMatchingTest::writeErrors( const string& errName, const vector<float>& errors, FileStorage* fs )
+{
+ assert( (int)errors.size() == ERROR_KINDS_COUNT );
+ vector<float>::const_iterator it = errors.begin();
+ if( fs )
+ for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
+ *fs << ERROR_PREFIXES[i] + errName << *it;
+ else
+ for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
+ ts->printf( cvtest::TS::LOG, "%s = %f\n", string(ERROR_PREFIXES[i]+errName).c_str(), *it );
+}
+
+void CV_StereoMatchingTest::readErrors( FileNode& fn, const string& errName, vector<float>& errors )
+{
+ errors.resize( ERROR_KINDS_COUNT );
+ vector<float>::iterator it = errors.begin();
+ for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++it )
+ fn[ERROR_PREFIXES[i]+errName] >> *it;
+}
+
+int CV_StereoMatchingTest::compareErrors( const vector<float>& calcErrors, const vector<float>& validErrors,
+ const vector<float>& eps, const string& errName )
+{
+ assert( (int)calcErrors.size() == ERROR_KINDS_COUNT );
+ assert( (int)validErrors.size() == ERROR_KINDS_COUNT );
+ assert( (int)eps.size() == ERROR_KINDS_COUNT );
+ vector<float>::const_iterator calcIt = calcErrors.begin(),
+ validIt = validErrors.begin(),
+ epsIt = eps.begin();
+ bool ok = true;
+ for( int i = 0; i < ERROR_KINDS_COUNT; i++, ++calcIt, ++validIt, ++epsIt )
+ if( *calcIt - *validIt > *epsIt )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of %s (valid=%f; calc=%f)\n", string(ERROR_PREFIXES[i]+errName).c_str(), *validIt, *calcIt );
+ ok = false;
+ }
+ return ok ? cvtest::TS::OK : cvtest::TS::FAIL_BAD_ACCURACY;
+}
+
+//----------------------------------- StereoBM test -----------------------------------------------------
+
+class CV_StereoBMTest : public CV_StereoMatchingTest
+{
+public:
+ CV_StereoBMTest()
+ {
+ name = "stereobm";
+ fill(rmsEps.begin(), rmsEps.end(), 0.4f);
+ fill(fracEps.begin(), fracEps.end(), 0.022f);
+ }
+
+protected:
+ struct RunParams
+ {
+ int ndisp;
+ int winSize;
+ };
+ vector<RunParams> caseRunParams;
+
+ virtual int readRunParams( FileStorage& fs )
+ {
+ int code = CV_StereoMatchingTest::readRunParams( fs );
+ FileNode fn = fs.getFirstTopLevelNode();
+ assert(fn.isSeq());
+ for( int i = 0; i < (int)fn.size(); i+=4 )
+ {
+ string caseName = fn[i], datasetName = fn[i+1];
+ RunParams params;
+ string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
+ string winSize = fn[i+3]; params.winSize = atoi(winSize.c_str());
+ caseNames.push_back( caseName );
+ caseDatasets.push_back( datasetName );
+ caseRunParams.push_back( params );
+ }
+ return code;
+ }
+
+ virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg,
+ Mat& leftDisp, Mat& /*rightDisp*/, int caseIdx )
+ {
+ RunParams params = caseRunParams[caseIdx];
+ assert( params.ndisp%16 == 0 );
+ assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 );
+ Mat leftImg; cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
+ Mat rightImg; cvtColor( _rightImg, rightImg, CV_BGR2GRAY );
+
+ StereoBM bm( StereoBM::BASIC_PRESET, params.ndisp, params.winSize );
+ bm( leftImg, rightImg, leftDisp, CV_32F );
+ return params.winSize/2;
+ }
+};
+
+
+//----------------------------------- StereoGC test -----------------------------------------------------
+
+class CV_StereoGCTest : public CV_StereoMatchingTest
+{
+public:
+ CV_StereoGCTest()
+ {
+ name = "stereogc";
+ fill(rmsEps.begin(), rmsEps.end(), 3.f);
+ fracEps[0] = 0.05f; // all
+ fracEps[1] = 0.05f; // noOccl
+ fracEps[2] = 0.25f; // occl
+ fracEps[3] = 0.05f; // textured
+ fracEps[4] = 0.10f; // textureless
+ fracEps[5] = 0.10f; // borderedDepthDiscont
+ }
+protected:
+ struct RunParams
+ {
+ int ndisp;
+ int iterCount;
+ };
+ vector<RunParams> caseRunParams;
+
+ virtual int readRunParams( FileStorage& fs )
+ {
+ int code = CV_StereoMatchingTest::readRunParams(fs);
+ FileNode fn = fs.getFirstTopLevelNode();
+ assert(fn.isSeq());
+ for( int i = 0; i < (int)fn.size(); i+=4 )
+ {
+ string caseName = fn[i], datasetName = fn[i+1];
+ RunParams params;
+ string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
+ string iterCount = fn[i+3]; params.iterCount = atoi(iterCount.c_str());
+ caseNames.push_back( caseName );
+ caseDatasets.push_back( datasetName );
+ caseRunParams.push_back( params );
+ }
+ return code;
+ }
+
+ virtual int runStereoMatchingAlgorithm( const Mat& _leftImg, const Mat& _rightImg,
+ Mat& leftDisp, Mat& rightDisp, int caseIdx )
+ {
+ RunParams params = caseRunParams[caseIdx];
+ assert( _leftImg.type() == CV_8UC3 && _rightImg.type() == CV_8UC3 );
+ Mat leftImg, rightImg, tmp;
+ cvtColor( _leftImg, leftImg, CV_BGR2GRAY );
+ cvtColor( _rightImg, rightImg, CV_BGR2GRAY );
+
+ leftDisp.create( leftImg.size(), CV_16SC1 );
+ rightDisp.create( rightImg.size(), CV_16SC1 );
+
+ CvMat _limg = leftImg, _rimg = rightImg, _ldisp = leftDisp, _rdisp = rightDisp;
+ CvStereoGCState *state = cvCreateStereoGCState( params.ndisp, params.iterCount );
+ cvFindStereoCorrespondenceGC( &_limg, &_rimg, &_ldisp, &_rdisp, state );
+ cvReleaseStereoGCState( &state );
+
+ leftDisp = - leftDisp;
+ return 0;
+ }
+
+};
+
+
+//----------------------------------- StereoSGBM test -----------------------------------------------------
+
+class CV_StereoSGBMTest : public CV_StereoMatchingTest
+{
+public:
+ CV_StereoSGBMTest()
+ {
+ name = "stereosgbm";
+ fill(rmsEps.begin(), rmsEps.end(), 0.25f);
+ fill(fracEps.begin(), fracEps.end(), 0.01f);
+ }
+
+protected:
+ struct RunParams
+ {
+ int ndisp;
+ int winSize;
+ bool fullDP;
+ };
+ vector<RunParams> caseRunParams;
+
+ virtual int readRunParams( FileStorage& fs )
+ {
+ int code = CV_StereoMatchingTest::readRunParams(fs);
+ FileNode fn = fs.getFirstTopLevelNode();
+ assert(fn.isSeq());
+ for( int i = 0; i < (int)fn.size(); i+=5 )
+ {
+ string caseName = fn[i], datasetName = fn[i+1];
+ RunParams params;
+ string ndisp = fn[i+2]; params.ndisp = atoi(ndisp.c_str());
+ string winSize = fn[i+3]; params.winSize = atoi(winSize.c_str());
+ string fullDP = fn[i+4]; params.fullDP = atoi(fullDP.c_str()) == 0 ? false : true;
+ caseNames.push_back( caseName );
+ caseDatasets.push_back( datasetName );
+ caseRunParams.push_back( params );
+ }
+ return code;
+ }
+
+ virtual int runStereoMatchingAlgorithm( const Mat& leftImg, const Mat& rightImg,
+ Mat& leftDisp, Mat& /*rightDisp*/, int caseIdx )
+ {
+ RunParams params = caseRunParams[caseIdx];
+ assert( params.ndisp%16 == 0 );
+ StereoSGBM sgbm( 0, params.ndisp, params.winSize, 10*params.winSize*params.winSize, 40*params.winSize*params.winSize,
+ 1, 63, 10, 100, 32, params.fullDP );
+ sgbm( leftImg, rightImg, leftDisp );
+ assert( leftDisp.type() == CV_16SC1 );
+ leftDisp/=16;
+ return 0;
+ }
+};
+
+
+TEST(Calib3d_StereoBM, regression) { CV_StereoBMTest test; test.safe_run(); }
+TEST(Calib3d_StereoGC, regression) { CV_StereoGCTest test; test.safe_run(); }
+TEST(Calib3d_StereoSGBM, regression) { CV_StereoSGBMTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_DefaultNewCameraMatrixTest : public cvtest::ArrayTest
+{
+public:
+ CV_DefaultNewCameraMatrixTest();
+protected:
+ int prepare_test_case (int test_case_idx);
+ void prepare_to_validation( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+
+private:
+ cv::Size img_size;
+ cv::Mat camera_mat;
+ cv::Mat new_camera_mat;
+
+ int matrix_type;
+
+ bool center_principal_point;
+
+ static const int MAX_X = 2048;
+ static const int MAX_Y = 2048;
+ static const int MAX_VAL = 10000;
+};
+
+CV_DefaultNewCameraMatrixTest::CV_DefaultNewCameraMatrixTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+}
+
+void CV_DefaultNewCameraMatrixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx,sizes,types);
+ RNG& rng = ts->get_rng();
+ matrix_type = types[INPUT][0] = types[OUTPUT][0]= types[REF_OUTPUT][0] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ sizes[INPUT][0] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(3,3);
+}
+
+int CV_DefaultNewCameraMatrixTest::prepare_test_case(int test_case_idx)
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+
+ if (code <= 0)
+ return code;
+
+ RNG& rng = ts->get_rng();
+
+ img_size.width = cvtest::randInt(rng) % MAX_X + 1;
+ img_size.height = cvtest::randInt(rng) % MAX_Y + 1;
+
+ center_principal_point = ((cvtest::randInt(rng) % 2)!=0);
+
+ // Generating camera_mat matrix
+ double sz = MAX(img_size.width, img_size.height);
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ double a[9] = {0,0,0,0,0,0,0,0,1};
+ Mat _a(3,3,CV_64F,a);
+ a[2] = (img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[5] = (img_size.height - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ a[4] = aspect_ratio*a[0];
+
+ Mat& _a0 = test_mat[INPUT][0];
+ cvtest::convert(_a, _a0, _a0.type());
+ camera_mat = _a0;
+
+ return code;
+
+}
+
+void CV_DefaultNewCameraMatrixTest::run_func()
+{
+ new_camera_mat = cv::getDefaultNewCameraMatrix(camera_mat,img_size,center_principal_point);
+}
+
+void CV_DefaultNewCameraMatrixTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_OUTPUT][0];
+ Mat& test_output = test_mat[OUTPUT][0];
+ Mat& output = new_camera_mat;
+ cvtest::convert( output, test_output, test_output.type() );
+ if (!center_principal_point)
+ {
+ cvtest::copy(src, dst);
+ }
+ else
+ {
+ double a[9] = {0,0,0,0,0,0,0,0,1};
+ Mat _a(3,3,CV_64F,a);
+ if (matrix_type == CV_64F)
+ {
+ a[0] = src.at<double>(0,0);
+ a[4] = src.at<double>(1,1);
+ }
+ else
+ {
+ a[0] = src.at<float>(0,0);
+ a[4] = src.at<float>(1,1);
+ }
+ a[2] = (img_size.width - 1)*0.5;
+ a[5] = (img_size.height - 1)*0.5;
+ cvtest::convert( _a, dst, dst.type() );
+ }
+}
+
+//---------
+
+class CV_UndistortPointsTest : public cvtest::ArrayTest
+{
+public:
+ CV_UndistortPointsTest();
+protected:
+ int prepare_test_case (int test_case_idx);
+ void prepare_to_validation( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void distortPoints(const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatrix,
+ const CvMat* _distCoeffs, const CvMat* matR, const CvMat* matP);
+
+private:
+ bool useCPlus;
+ bool useDstMat;
+ static const int N_POINTS = 10;
+ static const int MAX_X = 2048;
+ static const int MAX_Y = 2048;
+
+ bool zero_new_cam;
+ bool zero_distortion;
+ bool zero_R;
+
+ cv::Size img_size;
+ cv::Mat dst_points_mat;
+
+ cv::Mat camera_mat;
+ cv::Mat R;
+ cv::Mat P;
+ cv::Mat distortion_coeffs;
+ cv::Mat src_points;
+ std::vector<cv::Point2f> dst_points;
+};
+
+CV_UndistortPointsTest::CV_UndistortPointsTest()
+{
+ test_array[INPUT].push_back(NULL); // points matrix
+ test_array[INPUT].push_back(NULL); // camera matrix
+ test_array[INPUT].push_back(NULL); // distortion coeffs
+ test_array[INPUT].push_back(NULL); // R matrix
+ test_array[INPUT].push_back(NULL); // P matrix
+ test_array[OUTPUT].push_back(NULL); // distorted dst points
+ test_array[TEMP].push_back(NULL); // dst points
+ test_array[REF_OUTPUT].push_back(NULL);
+}
+
+void CV_UndistortPointsTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx,sizes,types);
+ RNG& rng = ts->get_rng();
+ useCPlus = ((cvtest::randInt(rng) % 2)!=0);
+ //useCPlus = 0;
+ if (useCPlus)
+ {
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0]= CV_32FC2;
+ }
+ else
+ {
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0]= cvtest::randInt(rng)%2 ? CV_64FC2 : CV_32FC2;
+ }
+ types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][3] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][4] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+
+ sizes[INPUT][0] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sizes[TEMP][0]= cvtest::randInt(rng)%2 ? cvSize(1,N_POINTS) : cvSize(N_POINTS,1);
+ sizes[INPUT][1] = sizes[INPUT][3] = cvSize(3,3);
+ sizes[INPUT][4] = cvtest::randInt(rng)%2 ? cvSize(3,3) : cvSize(4,3);
+
+ if (cvtest::randInt(rng)%2)
+ {
+ if (cvtest::randInt(rng)%2)
+ {
+ sizes[INPUT][2] = cvSize(1,4);
+ }
+ else
+ {
+ sizes[INPUT][2] = cvSize(1,5);
+ }
+ }
+ else
+ {
+ if (cvtest::randInt(rng)%2)
+ {
+ sizes[INPUT][2] = cvSize(4,1);
+ }
+ else
+ {
+ sizes[INPUT][2] = cvSize(5,1);
+ }
+ }
+}
+
+int CV_UndistortPointsTest::prepare_test_case(int test_case_idx)
+{
+ RNG& rng = ts->get_rng();
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+
+ if (code <= 0)
+ return code;
+
+ useDstMat = (cvtest::randInt(rng) % 2) == 0;
+
+ img_size.width = cvtest::randInt(rng) % MAX_X + 1;
+ img_size.height = cvtest::randInt(rng) % MAX_Y + 1;
+ int dist_size = test_mat[INPUT][2].cols > test_mat[INPUT][2].rows ? test_mat[INPUT][2].cols : test_mat[INPUT][2].rows;
+ double cam[9] = {0,0,0,0,0,0,0,0,1};
+ vector<double> dist(dist_size);
+ vector<double> proj(test_mat[INPUT][4].cols * test_mat[INPUT][4].rows);
+ vector<Point2d> points(N_POINTS);
+
+ Mat _camera(3,3,CV_64F,cam);
+ Mat _distort(test_mat[INPUT][2].rows,test_mat[INPUT][2].cols,CV_64F,&dist[0]);
+ Mat _proj(test_mat[INPUT][4].size(), CV_64F, &proj[0]);
+ Mat _points(test_mat[INPUT][0].size(), CV_64FC2, &points[0]);
+
+ _proj = Scalar::all(0);
+
+ //Generating points
+ for( int i = 0; i < N_POINTS; i++ )
+ {
+ points[i].x = cvtest::randReal(rng)*img_size.width;
+ points[i].y = cvtest::randReal(rng)*img_size.height;
+ }
+
+ //Generating camera matrix
+ double sz = MAX(img_size.width,img_size.height);
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ cam[2] = (img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ cam[5] = (img_size.height - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ cam[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ cam[4] = aspect_ratio*cam[0];
+
+ //Generating distortion coeffs
+ dist[0] = cvtest::randReal(rng)*0.06 - 0.03;
+ dist[1] = cvtest::randReal(rng)*0.06 - 0.03;
+ if( dist[0]*dist[1] > 0 )
+ dist[1] = -dist[1];
+ if( cvtest::randInt(rng)%4 != 0 )
+ {
+ dist[2] = cvtest::randReal(rng)*0.004 - 0.002;
+ dist[3] = cvtest::randReal(rng)*0.004 - 0.002;
+ if (dist_size > 4)
+ dist[4] = cvtest::randReal(rng)*0.004 - 0.002;
+ }
+ else
+ {
+ dist[2] = dist[3] = 0;
+ if (dist_size > 4)
+ dist[4] = 0;
+ }
+
+ //Generating P matrix (projection)
+ if( test_mat[INPUT][4].cols != 4 )
+ {
+ proj[8] = 1;
+ if (cvtest::randInt(rng)%2 == 0) // use identity new camera matrix
+ {
+ proj[0] = 1;
+ proj[4] = 1;
+ }
+ else
+ {
+ proj[0] = cam[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[0]; //10%
+ proj[4] = cam[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[4]; //10%
+ proj[2] = cam[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.width; //15%
+ proj[5] = cam[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.height; //15%
+ }
+ }
+ else
+ {
+ proj[10] = 1;
+ proj[0] = cam[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[0]; //10%
+ proj[5] = cam[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[4]; //10%
+ proj[2] = cam[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.width; //15%
+ proj[6] = cam[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.height; //15%
+
+ proj[3] = (img_size.height + img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ proj[7] = (img_size.height + img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ proj[11] = (img_size.height + img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ }
+
+ //Generating R matrix
+ Mat _rot(3,3,CV_64F);
+ Mat rotation(1,3,CV_64F);
+ rotation.at<double>(0) = CV_PI*(cvtest::randReal(rng) - (double)0.5); // phi
+ rotation.at<double>(1) = CV_PI*(cvtest::randReal(rng) - (double)0.5); // ksi
+ rotation.at<double>(2) = CV_PI*(cvtest::randReal(rng) - (double)0.5); //khi
+ cvtest::Rodrigues(rotation, _rot);
+
+ //copying data
+ //src_points = &_points;
+ _points.convertTo(test_mat[INPUT][0], test_mat[INPUT][0].type());
+ _camera.convertTo(test_mat[INPUT][1], test_mat[INPUT][1].type());
+ _distort.convertTo(test_mat[INPUT][2], test_mat[INPUT][2].type());
+ _rot.convertTo(test_mat[INPUT][3], test_mat[INPUT][3].type());
+ _proj.convertTo(test_mat[INPUT][4], test_mat[INPUT][4].type());
+
+ zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ zero_R = (cvtest::randInt(rng)%2) == 0 ? false : true;
+
+ if (useCPlus)
+ {
+ _points.convertTo(src_points, CV_32F);
+
+ camera_mat = test_mat[INPUT][1];
+ distortion_coeffs = test_mat[INPUT][2];
+ R = test_mat[INPUT][3];
+ P = test_mat[INPUT][4];
+ }
+
+ return code;
+}
+
+void CV_UndistortPointsTest::prepare_to_validation(int /*test_case_idx*/)
+{
+ int dist_size = test_mat[INPUT][2].cols > test_mat[INPUT][2].rows ? test_mat[INPUT][2].cols : test_mat[INPUT][2].rows;
+ double cam[9] = {0,0,0,0,0,0,0,0,1};
+ double rot[9] = {1,0,0,0,1,0,0,0,1};
+
+ double* dist = new double[dist_size ];
+ double* proj = new double[test_mat[INPUT][4].cols * test_mat[INPUT][4].rows];
+ double* points = new double[N_POINTS*2];
+ double* r_points = new double[N_POINTS*2];
+ //Run reference calculations
+ CvMat ref_points= cvMat(test_mat[INPUT][0].rows,test_mat[INPUT][0].cols,CV_64FC2,r_points);
+ CvMat _camera = cvMat(3,3,CV_64F,cam);
+ CvMat _rot = cvMat(3,3,CV_64F,rot);
+ CvMat _distort = cvMat(test_mat[INPUT][2].rows,test_mat[INPUT][2].cols,CV_64F,dist);
+ CvMat _proj = cvMat(test_mat[INPUT][4].rows,test_mat[INPUT][4].cols,CV_64F,proj);
+ CvMat _points= cvMat(test_mat[TEMP][0].rows,test_mat[TEMP][0].cols,CV_64FC2,points);
+
+ Mat __camera = cvarrToMat(&_camera);
+ Mat __distort = cvarrToMat(&_distort);
+ Mat __rot = cvarrToMat(&_rot);
+ Mat __proj = cvarrToMat(&_proj);
+ Mat __points = cvarrToMat(&_points);
+ Mat _ref_points = cvarrToMat(&ref_points);
+
+ cvtest::convert(test_mat[INPUT][1], __camera, __camera.type());
+ cvtest::convert(test_mat[INPUT][2], __distort, __distort.type());
+ cvtest::convert(test_mat[INPUT][3], __rot, __rot.type());
+ cvtest::convert(test_mat[INPUT][4], __proj, __proj.type());
+
+ if (useCPlus)
+ {
+ if (useDstMat)
+ {
+ CvMat temp = dst_points_mat;
+ for (int i=0;i<N_POINTS*2;i++)
+ {
+ points[i] = temp.data.fl[i];
+ }
+ }
+ else
+ {
+ for (int i=0;i<N_POINTS;i++)
+ {
+ points[2*i] = dst_points[i].x;
+ points[2*i+1] = dst_points[i].y;
+ }
+ }
+ }
+ else
+ {
+ cvtest::convert(test_mat[TEMP][0],__points, __points.type());
+ }
+
+ CvMat* input2 = zero_distortion ? 0 : &_distort;
+ CvMat* input3 = zero_R ? 0 : &_rot;
+ CvMat* input4 = zero_new_cam ? 0 : &_proj;
+ distortPoints(&_points,&ref_points,&_camera,input2,input3,input4);
+
+ Mat& dst = test_mat[REF_OUTPUT][0];
+ cvtest::convert(_ref_points, dst, dst.type());
+
+ cvtest::copy(test_mat[INPUT][0], test_mat[OUTPUT][0]);
+
+ delete[] dist;
+ delete[] proj;
+ delete[] points;
+ delete[] r_points;
+}
+
+void CV_UndistortPointsTest::run_func()
+{
+
+ if (useCPlus)
+ {
+ cv::Mat input2,input3,input4;
+ input2 = zero_distortion ? cv::Mat() : cv::Mat(test_mat[INPUT][2]);
+ input3 = zero_R ? cv::Mat() : cv::Mat(test_mat[INPUT][3]);
+ input4 = zero_new_cam ? cv::Mat() : cv::Mat(test_mat[INPUT][4]);
+
+ if (useDstMat)
+ {
+ //cv::undistortPoints(src_points,dst_points_mat,camera_mat,distortion_coeffs,R,P);
+ cv::undistortPoints(src_points,dst_points_mat,camera_mat,input2,input3,input4);
+ }
+ else
+ {
+ //cv::undistortPoints(src_points,dst_points,camera_mat,distortion_coeffs,R,P);
+ cv::undistortPoints(src_points,dst_points,camera_mat,input2,input3,input4);
+ }
+ }
+ else
+ {
+ CvMat _input0 = test_mat[INPUT][0], _input1 = test_mat[INPUT][1], _input2, _input3, _input4;
+ CvMat _output = test_mat[TEMP][0];
+ if(!zero_distortion)
+ _input2 = test_mat[INPUT][2];
+ if(!zero_R)
+ _input3 = test_mat[INPUT][3];
+ if(!zero_new_cam)
+ _input4 = test_mat[INPUT][4];
+ cvUndistortPoints(&_input0, &_output, &_input1,
+ zero_distortion ? 0 : &_input2,
+ zero_R ? 0 : &_input3,
+ zero_new_cam ? 0 : &_input4);
+ }
+}
+
+void CV_UndistortPointsTest::distortPoints(const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatrix,
+ const CvMat* _distCoeffs,
+ const CvMat* matR, const CvMat* matP)
+{
+ double a[9];
+
+ CvMat* __P;
+ if ((!matP)||(matP->cols == 3))
+ __P = cvCreateMat(3,3,CV_64F);
+ else
+ __P = cvCreateMat(3,4,CV_64F);
+ if (matP)
+ {
+ cvTsConvert(matP,__P);
+ }
+ else
+ {
+ cvZero(__P);
+ __P->data.db[0] = 1;
+ __P->data.db[4] = 1;
+ __P->data.db[8] = 1;
+ }
+ CvMat* __R = cvCreateMat(3,3,CV_64F);;
+ if (matR)
+ {
+ cvCopy(matR,__R);
+ }
+ else
+ {
+ cvZero(__R);
+ __R->data.db[0] = 1;
+ __R->data.db[4] = 1;
+ __R->data.db[8] = 1;
+ }
+ for (int i=0;i<N_POINTS;i++)
+ {
+ int movement = __P->cols > 3 ? 1 : 0;
+ double x = (_src->data.db[2*i]-__P->data.db[2])/__P->data.db[0];
+ double y = (_src->data.db[2*i+1]-__P->data.db[5+movement])/__P->data.db[4+movement];
+ CvMat inverse = cvMat(3,3,CV_64F,a);
+ cvInvert(__R,&inverse);
+ double w1 = x*inverse.data.db[6]+y*inverse.data.db[7]+inverse.data.db[8];
+ double _x = (x*inverse.data.db[0]+y*inverse.data.db[1]+inverse.data.db[2])/w1;
+ double _y = (x*inverse.data.db[3]+y*inverse.data.db[4]+inverse.data.db[5])/w1;
+
+ //Distortions
+
+ double __x = _x;
+ double __y = _y;
+ if (_distCoeffs)
+ {
+ double r2 = _x*_x+_y*_y;
+
+ __x = _x*(1+_distCoeffs->data.db[0]*r2+_distCoeffs->data.db[1]*r2*r2)+
+ 2*_distCoeffs->data.db[2]*_x*_y+_distCoeffs->data.db[3]*(r2+2*_x*_x);
+ __y = _y*(1+_distCoeffs->data.db[0]*r2+_distCoeffs->data.db[1]*r2*r2)+
+ 2*_distCoeffs->data.db[3]*_x*_y+_distCoeffs->data.db[2]*(r2+2*_y*_y);
+ if ((_distCoeffs->cols > 4) || (_distCoeffs->rows > 4))
+ {
+ __x+=_x*_distCoeffs->data.db[4]*r2*r2*r2;
+ __y+=_y*_distCoeffs->data.db[4]*r2*r2*r2;
+ }
+ }
+
+
+ _dst->data.db[2*i] = __x*_cameraMatrix->data.db[0]+_cameraMatrix->data.db[2];
+ _dst->data.db[2*i+1] = __y*_cameraMatrix->data.db[4]+_cameraMatrix->data.db[5];
+
+ }
+
+ cvReleaseMat(&__R);
+ cvReleaseMat(&__P);
+
+}
+
+
+double CV_UndistortPointsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 5e-2;
+}
+
+//------------------------------------------------------
+
+class CV_InitUndistortRectifyMapTest : public cvtest::ArrayTest
+{
+public:
+ CV_InitUndistortRectifyMapTest();
+protected:
+ int prepare_test_case (int test_case_idx);
+ void prepare_to_validation( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+
+private:
+ bool useCPlus;
+ static const int N_POINTS = 100;
+ static const int MAX_X = 2048;
+ static const int MAX_Y = 2048;
+ bool zero_new_cam;
+ bool zero_distortion;
+ bool zero_R;
+
+
+ cv::Size img_size;
+
+ cv::Mat camera_mat;
+ cv::Mat R;
+ cv::Mat new_camera_mat;
+ cv::Mat distortion_coeffs;
+ cv::Mat mapx;
+ cv::Mat mapy;
+ CvMat* _mapx;
+ CvMat* _mapy;
+ int mat_type;
+};
+
+CV_InitUndistortRectifyMapTest::CV_InitUndistortRectifyMapTest()
+{
+ test_array[INPUT].push_back(NULL); // test points matrix
+ test_array[INPUT].push_back(NULL); // camera matrix
+ test_array[INPUT].push_back(NULL); // distortion coeffs
+ test_array[INPUT].push_back(NULL); // R matrix
+ test_array[INPUT].push_back(NULL); // new camera matrix
+ test_array[OUTPUT].push_back(NULL); // distorted dst points
+ test_array[REF_OUTPUT].push_back(NULL);
+}
+
+void CV_InitUndistortRectifyMapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ cvtest::ArrayTest::get_test_array_types_and_sizes(test_case_idx,sizes,types);
+ RNG& rng = ts->get_rng();
+ useCPlus = ((cvtest::randInt(rng) % 2)!=0);
+ //useCPlus = 0;
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC2;
+
+ types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][3] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][4] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+
+ sizes[INPUT][0] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(N_POINTS,1);
+ sizes[INPUT][1] = sizes[INPUT][3] = cvSize(3,3);
+ sizes[INPUT][4] = cvSize(3,3);
+
+ if (cvtest::randInt(rng)%2)
+ {
+ if (cvtest::randInt(rng)%2)
+ {
+ sizes[INPUT][2] = cvSize(1,4);
+ }
+ else
+ {
+ sizes[INPUT][2] = cvSize(1,5);
+ }
+ }
+ else
+ {
+ if (cvtest::randInt(rng)%2)
+ {
+ sizes[INPUT][2] = cvSize(4,1);
+ }
+ else
+ {
+ sizes[INPUT][2] = cvSize(5,1);
+ }
+ }
+}
+
+
+int CV_InitUndistortRectifyMapTest::prepare_test_case(int test_case_idx)
+{
+ RNG& rng = ts->get_rng();
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+
+ if (code <= 0)
+ return code;
+
+ img_size.width = cvtest::randInt(rng) % MAX_X + 1;
+ img_size.height = cvtest::randInt(rng) % MAX_Y + 1;
+
+ if (useCPlus)
+ {
+ mat_type = (cvtest::randInt(rng) % 2) == 0 ? CV_32FC1 : CV_16SC2;
+ if ((cvtest::randInt(rng) % 4) == 0)
+ mat_type = -1;
+ if ((cvtest::randInt(rng) % 4) == 0)
+ mat_type = CV_32FC2;
+ _mapx = 0;
+ _mapy = 0;
+ }
+ else
+ {
+ int typex = (cvtest::randInt(rng) % 2) == 0 ? CV_32FC1 : CV_16SC2;
+ //typex = CV_32FC1; ///!!!!!!!!!!!!!!!!
+ int typey = (typex == CV_32FC1) ? CV_32FC1 : CV_16UC1;
+
+ _mapx = cvCreateMat(img_size.height,img_size.width,typex);
+ _mapy = cvCreateMat(img_size.height,img_size.width,typey);
+
+
+ }
+
+ int dist_size = test_mat[INPUT][2].cols > test_mat[INPUT][2].rows ? test_mat[INPUT][2].cols : test_mat[INPUT][2].rows;
+ double cam[9] = {0,0,0,0,0,0,0,0,1};
+ vector<double> dist(dist_size);
+ vector<double> new_cam(test_mat[INPUT][4].cols * test_mat[INPUT][4].rows);
+ vector<Point2d> points(N_POINTS);
+
+ Mat _camera(3,3,CV_64F,cam);
+ Mat _distort(test_mat[INPUT][2].size(),CV_64F,&dist[0]);
+ Mat _new_cam(test_mat[INPUT][4].size(),CV_64F,&new_cam[0]);
+ Mat _points(test_mat[INPUT][0].size(),CV_64FC2, &points[0]);
+
+ //Generating points
+ for (int i=0;i<N_POINTS;i++)
+ {
+ points[i].x = cvtest::randReal(rng)*img_size.width;
+ points[i].y = cvtest::randReal(rng)*img_size.height;
+ }
+
+ //Generating camera matrix
+ double sz = MAX(img_size.width,img_size.height);
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ cam[2] = (img_size.width - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ cam[5] = (img_size.height - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ cam[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ cam[4] = aspect_ratio*cam[0];
+
+ //Generating distortion coeffs
+ dist[0] = cvtest::randReal(rng)*0.06 - 0.03;
+ dist[1] = cvtest::randReal(rng)*0.06 - 0.03;
+ if( dist[0]*dist[1] > 0 )
+ dist[1] = -dist[1];
+ if( cvtest::randInt(rng)%4 != 0 )
+ {
+ dist[2] = cvtest::randReal(rng)*0.004 - 0.002;
+ dist[3] = cvtest::randReal(rng)*0.004 - 0.002;
+ if (dist_size > 4)
+ dist[4] = cvtest::randReal(rng)*0.004 - 0.002;
+ }
+ else
+ {
+ dist[2] = dist[3] = 0;
+ if (dist_size > 4)
+ dist[4] = 0;
+ }
+
+ //Generating new camera matrix
+ _new_cam = Scalar::all(0);
+ new_cam[8] = 1;
+
+ //new_cam[0] = cam[0];
+ //new_cam[4] = cam[4];
+ //new_cam[2] = cam[2];
+ //new_cam[5] = cam[5];
+
+ new_cam[0] = cam[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[0]; //10%
+ new_cam[4] = cam[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*cam[4]; //10%
+ new_cam[2] = cam[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.width; //15%
+ new_cam[5] = cam[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*img_size.height; //15%
+
+
+ //Generating R matrix
+ Mat _rot(3,3,CV_64F);
+ Mat rotation(1,3,CV_64F);
+ rotation.at<double>(0) = CV_PI/8*(cvtest::randReal(rng) - (double)0.5); // phi
+ rotation.at<double>(1) = CV_PI/8*(cvtest::randReal(rng) - (double)0.5); // ksi
+ rotation.at<double>(2) = CV_PI/3*(cvtest::randReal(rng) - (double)0.5); //khi
+ cvtest::Rodrigues(rotation, _rot);
+
+ //cvSetIdentity(_rot);
+ //copying data
+ cvtest::convert( _points, test_mat[INPUT][0], test_mat[INPUT][0].type());
+ cvtest::convert( _camera, test_mat[INPUT][1], test_mat[INPUT][1].type());
+ cvtest::convert( _distort, test_mat[INPUT][2], test_mat[INPUT][2].type());
+ cvtest::convert( _rot, test_mat[INPUT][3], test_mat[INPUT][3].type());
+ cvtest::convert( _new_cam, test_mat[INPUT][4], test_mat[INPUT][4].type());
+
+ zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ zero_R = (cvtest::randInt(rng)%2) == 0 ? false : true;
+
+ if (useCPlus)
+ {
+ camera_mat = test_mat[INPUT][1];
+ distortion_coeffs = test_mat[INPUT][2];
+ R = test_mat[INPUT][3];
+ new_camera_mat = test_mat[INPUT][4];
+ }
+
+ return code;
+}
+
+void CV_InitUndistortRectifyMapTest::prepare_to_validation(int/* test_case_idx*/)
+{
+#if 0
+ int dist_size = test_mat[INPUT][2].cols > test_mat[INPUT][2].rows ? test_mat[INPUT][2].cols : test_mat[INPUT][2].rows;
+ double cam[9] = {0,0,0,0,0,0,0,0,1};
+ double rot[9] = {1,0,0,0,1,0,0,0,1};
+ vector<double> dist(dist_size);
+ vector<double> new_cam(test_mat[INPUT][4].cols * test_mat[INPUT][4].rows);
+ vector<Point2d> points(N_POINTS);
+ vector<Point2d> r_points(N_POINTS);
+ //Run reference calculations
+ Mat ref_points(test_mat[INPUT][0].size(),CV_64FC2,&r_points[0]);
+ Mat _camera(3,3,CV_64F,cam);
+ Mat _rot(3,3,CV_64F,rot);
+ Mat _distort(test_mat[INPUT][2].size(),CV_64F,&dist[0]);
+ Mat _new_cam(test_mat[INPUT][4].size(),CV_64F,&new_cam[0]);
+ Mat _points(test_mat[INPUT][0].size(),CV_64FC2,&points[0]);
+
+ cvtest::convert(test_mat[INPUT][1],_camera,_camera.type());
+ cvtest::convert(test_mat[INPUT][2],_distort,_distort.type());
+ cvtest::convert(test_mat[INPUT][3],_rot,_rot.type());
+ cvtest::convert(test_mat[INPUT][4],_new_cam,_new_cam.type());
+
+ //Applying precalculated undistort rectify map
+ if (!useCPlus)
+ {
+ mapx = cv::Mat(_mapx);
+ mapy = cv::Mat(_mapy);
+ }
+ cv::Mat map1,map2;
+ cv::convertMaps(mapx,mapy,map1,map2,CV_32FC1);
+ CvMat _map1 = map1;
+ CvMat _map2 = map2;
+ const Point2d* sptr = (const Point2d*)test_mat[INPUT][0].data;
+ for( int i = 0;i < N_POINTS; i++ )
+ {
+ int u = saturate_cast<int>(sptr[i].x);
+ int v = saturate_cast<int>(sptr[i].y);
+ points[i].x = _map1.data.fl[v*_map1.cols + u];
+ points[i].y = _map2.data.fl[v*_map2.cols + u];
+ }
+
+ //---
+
+ cv::undistortPoints(_points, ref_points, _camera,
+ zero_distortion ? Mat() : _distort,
+ zero_R ? Mat::eye(3,3,CV_64F) : _rot,
+ zero_new_cam ? _camera : _new_cam);
+ //cvTsDistortPoints(&_points,&ref_points,&_camera,&_distort,&_rot,&_new_cam);
+ cvtest::convert(ref_points, test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].type());
+ cvtest::copy(test_mat[INPUT][0],test_mat[OUTPUT][0]);
+
+ cvReleaseMat(&_mapx);
+ cvReleaseMat(&_mapy);
+#else
+ int dist_size = test_mat[INPUT][2].cols > test_mat[INPUT][2].rows ? test_mat[INPUT][2].cols : test_mat[INPUT][2].rows;
+ double cam[9] = {0,0,0,0,0,0,0,0,1};
+ double rot[9] = {1,0,0,0,1,0,0,0,1};
+ double* dist = new double[dist_size ];
+ double* new_cam = new double[test_mat[INPUT][4].cols * test_mat[INPUT][4].rows];
+ double* points = new double[N_POINTS*2];
+ double* r_points = new double[N_POINTS*2];
+ //Run reference calculations
+ CvMat ref_points= cvMat(test_mat[INPUT][0].rows,test_mat[INPUT][0].cols,CV_64FC2,r_points);
+ CvMat _camera = cvMat(3,3,CV_64F,cam);
+ CvMat _rot = cvMat(3,3,CV_64F,rot);
+ CvMat _distort = cvMat(test_mat[INPUT][2].rows,test_mat[INPUT][2].cols,CV_64F,dist);
+ CvMat _new_cam = cvMat(test_mat[INPUT][4].rows,test_mat[INPUT][4].cols,CV_64F,new_cam);
+ CvMat _points= cvMat(test_mat[INPUT][0].rows,test_mat[INPUT][0].cols,CV_64FC2,points);
+
+ CvMat _input1 = test_mat[INPUT][1];
+ CvMat _input2 = test_mat[INPUT][2];
+ CvMat _input3 = test_mat[INPUT][3];
+ CvMat _input4 = test_mat[INPUT][4];
+
+ cvTsConvert(&_input1,&_camera);
+ cvTsConvert(&_input2,&_distort);
+ cvTsConvert(&_input3,&_rot);
+ cvTsConvert(&_input4,&_new_cam);
+
+ //Applying precalculated undistort rectify map
+ if (!useCPlus)
+ {
+ mapx = cv::Mat(_mapx);
+ mapy = cv::Mat(_mapy);
+ }
+ cv::Mat map1,map2;
+ cv::convertMaps(mapx,mapy,map1,map2,CV_32FC1);
+ CvMat _map1 = map1;
+ CvMat _map2 = map2;
+ for (int i=0;i<N_POINTS;i++)
+ {
+ double u = test_mat[INPUT][0].ptr<double>()[2*i];
+ double v = test_mat[INPUT][0].ptr<double>()[2*i+1];
+ _points.data.db[2*i] = (double)_map1.data.fl[(int)v*_map1.cols+(int)u];
+ _points.data.db[2*i+1] = (double)_map2.data.fl[(int)v*_map2.cols+(int)u];
+ }
+
+ //---
+
+ cvUndistortPoints(&_points,&ref_points,&_camera,
+ zero_distortion ? 0 : &_distort, zero_R ? 0 : &_rot, zero_new_cam ? &_camera : &_new_cam);
+ //cvTsDistortPoints(&_points,&ref_points,&_camera,&_distort,&_rot,&_new_cam);
+ CvMat dst = test_mat[REF_OUTPUT][0];
+ cvTsConvert(&ref_points,&dst);
+
+ cvtest::copy(test_mat[INPUT][0],test_mat[OUTPUT][0]);
+
+ delete[] dist;
+ delete[] new_cam;
+ delete[] points;
+ delete[] r_points;
+ cvReleaseMat(&_mapx);
+ cvReleaseMat(&_mapy);
+#endif
+}
+
+void CV_InitUndistortRectifyMapTest::run_func()
+{
+ if (useCPlus)
+ {
+ cv::Mat input2,input3,input4;
+ input2 = zero_distortion ? cv::Mat() : test_mat[INPUT][2];
+ input3 = zero_R ? cv::Mat() : test_mat[INPUT][3];
+ input4 = zero_new_cam ? cv::Mat() : test_mat[INPUT][4];
+ cv::initUndistortRectifyMap(camera_mat,input2,input3,input4,img_size,mat_type,mapx,mapy);
+ }
+ else
+ {
+ CvMat input1 = test_mat[INPUT][1], input2, input3, input4;
+ if( !zero_distortion )
+ input2 = test_mat[INPUT][2];
+ if( !zero_R )
+ input3 = test_mat[INPUT][3];
+ if( !zero_new_cam )
+ input4 = test_mat[INPUT][4];
+ cvInitUndistortRectifyMap(&input1,
+ zero_distortion ? 0 : &input2,
+ zero_R ? 0 : &input3,
+ zero_new_cam ? 0 : &input4,
+ _mapx,_mapy);
+ }
+}
+
+double CV_InitUndistortRectifyMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 8;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST(Calib3d_DefaultNewCameraMatrix, accuracy) { CV_DefaultNewCameraMatrixTest test; test.safe_run(); }
+TEST(Calib3d_UndistortPoints, accuracy) { CV_UndistortPointsTest test; test.safe_run(); }
+TEST(Calib3d_InitUndistortRectifyMap, accuracy) { CV_InitUndistortRectifyMapTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+class CV_UndistortPointsBadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_UndistortPointsBadArgTest();
+protected:
+ void run(int);
+ void run_func();
+
+private:
+ //common
+ cv::Size img_size;
+ bool useCPlus;
+ //static const int N_POINTS = 1;
+ static const int N_POINTS2 = 2;
+
+ //C
+ CvMat* _camera_mat;
+ CvMat* matR;
+ CvMat* matP;
+ CvMat* _distortion_coeffs;
+ CvMat* _src_points;
+ CvMat* _dst_points;
+
+
+ //C++
+ cv::Mat camera_mat;
+ cv::Mat R;
+ cv::Mat P;
+ cv::Mat distortion_coeffs;
+ cv::Mat src_points;
+ std::vector<cv::Point2f> dst_points;
+
+};
+
+CV_UndistortPointsBadArgTest::CV_UndistortPointsBadArgTest ()
+{
+}
+
+void CV_UndistortPointsBadArgTest::run_func()
+{
+ if (useCPlus)
+ {
+ cv::undistortPoints(src_points,dst_points,camera_mat,distortion_coeffs,R,P);
+ }
+ else
+ {
+ cvUndistortPoints(_src_points,_dst_points,_camera_mat,_distortion_coeffs,matR,matP);
+ }
+}
+
+void CV_UndistortPointsBadArgTest::run(int)
+{
+ //RNG& rng = ts->get_rng();
+ int errcount = 0;
+ useCPlus = false;
+//initializing
+ img_size.width = 800;
+ img_size.height = 600;
+ double cam[9] = {150.f, 0.f, img_size.width/2.f, 0, 300.f, img_size.height/2.f, 0.f, 0.f, 1.f};
+ double dist[4] = {0.01,0.02,0.001,0.0005};
+ double s_points[N_POINTS2] = {img_size.width/4,img_size.height/4};
+ double d_points[N_POINTS2];
+ double p[9] = {155.f, 0.f, img_size.width/2.f+img_size.width/50.f, 0, 310.f, img_size.height/2.f+img_size.height/50.f, 0.f, 0.f, 1.f};
+ double r[9] = {1,0,0,0,1,0,0,0,1};
+
+ CvMat _camera_mat_orig = cvMat(3,3,CV_64F,cam);
+ CvMat _distortion_coeffs_orig = cvMat(1,4,CV_64F,dist);
+ CvMat _P_orig = cvMat(3,3,CV_64F,p);
+ CvMat _R_orig = cvMat(3,3,CV_64F,r);
+ CvMat _src_points_orig = cvMat(1,4,CV_64FC2,s_points);
+ CvMat _dst_points_orig = cvMat(1,4,CV_64FC2,d_points);
+
+ _camera_mat = &_camera_mat_orig;
+ _distortion_coeffs = &_distortion_coeffs_orig;
+ matP = &_P_orig;
+ matR = &_R_orig;
+ _src_points = &_src_points_orig;
+ _dst_points = &_dst_points_orig;
+
+//tests
+ CvMat* temp1;
+ CvMat* temp;
+ IplImage* temp_img = cvCreateImage(cvSize(img_size.width,img_size.height),8,3);
+
+//-----------
+ temp = (CvMat*)temp_img;
+ _src_points = temp;
+ errcount += run_test_case( CV_StsAssert, "Input data is not CvMat*" );
+ _src_points = &_src_points_orig;
+
+ temp = (CvMat*)temp_img;
+ _dst_points = temp;
+ errcount += run_test_case( CV_StsAssert, "Output data is not CvMat*" );
+ _dst_points = &_dst_points_orig;
+
+ temp = cvCreateMat(2,3,CV_64F);
+ _src_points = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid input data matrix size" );
+ _src_points = &_src_points_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(2,3,CV_64F);
+ _dst_points = temp;
+ errcount += run_test_case(CV_StsAssert, "Invalid output data matrix size" );
+ _dst_points = &_dst_points_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(1,3,CV_64F);
+ temp1 = cvCreateMat(4,1,CV_64F);
+ _dst_points = temp;
+ _src_points = temp1;
+ errcount += run_test_case(CV_StsAssert, "Output and input data sizes mismatch" );
+ _dst_points = &_dst_points_orig;
+ _src_points = &_src_points_orig;
+ cvReleaseMat(&temp);
+ cvReleaseMat(&temp1);
+
+ temp = cvCreateMat(1,3,CV_32S);
+ _dst_points = temp;
+ errcount += run_test_case(CV_StsAssert, "Invalid output data matrix type" );
+ _dst_points = &_dst_points_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(1,3,CV_32S);
+ _src_points = temp;
+ errcount += run_test_case(CV_StsAssert, "Invalid input data matrix type" );
+ _src_points = &_src_points_orig;
+ cvReleaseMat(&temp);
+//------------
+ temp = cvCreateMat(2,3,CV_64F);
+ _camera_mat = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid camera data matrix size" );
+ _camera_mat = &_camera_mat_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(3,4,CV_64F);
+ _camera_mat = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid camera data matrix size" );
+ _camera_mat = &_camera_mat_orig;
+ cvReleaseMat(&temp);
+
+ temp = (CvMat*)temp_img;
+ _camera_mat = temp;
+ errcount += run_test_case( CV_StsAssert, "Camera data is not CvMat*" );
+ _camera_mat = &_camera_mat_orig;
+//----------
+
+ temp = (CvMat*)temp_img;
+ _distortion_coeffs = temp;
+ errcount += run_test_case( CV_StsAssert, "Distortion coefficients data is not CvMat*" );
+ _distortion_coeffs = &_distortion_coeffs_orig;
+
+ temp = cvCreateMat(1,6,CV_64F);
+ _distortion_coeffs = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid distortion coefficients data matrix size" );
+ _distortion_coeffs = &_distortion_coeffs_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(3,3,CV_64F);
+ _distortion_coeffs = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid distortion coefficients data matrix size" );
+ _distortion_coeffs = &_distortion_coeffs_orig;
+ cvReleaseMat(&temp);
+//----------
+ temp = (CvMat*)temp_img;
+ matR = temp;
+ errcount += run_test_case( CV_StsAssert, "R data is not CvMat*" );
+ matR = &_R_orig;
+
+ temp = cvCreateMat(4,3,CV_64F);
+ matR = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid R data matrix size" );
+ matR = &_R_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(3,2,CV_64F);
+ matR = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid R data matrix size" );
+ matR = &_R_orig;
+ cvReleaseMat(&temp);
+
+//-----------
+ temp = (CvMat*)temp_img;
+ matP = temp;
+ errcount += run_test_case( CV_StsAssert, "P data is not CvMat*" );
+ matP = &_P_orig;
+
+ temp = cvCreateMat(4,3,CV_64F);
+ matP = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid P data matrix size" );
+ matP = &_P_orig;
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(3,2,CV_64F);
+ matP = temp;
+ errcount += run_test_case( CV_StsAssert, "Invalid P data matrix size" );
+ matP = &_P_orig;
+ cvReleaseMat(&temp);
+//------------
+ //C++ tests
+ useCPlus = true;
+
+ camera_mat = cv::Mat(&_camera_mat_orig);
+ distortion_coeffs = cv::Mat(&_distortion_coeffs_orig);
+ P = cv::Mat(&_P_orig);
+ R = cv::Mat(&_R_orig);
+ src_points = cv::Mat(&_src_points_orig);
+
+ temp = cvCreateMat(2,2,CV_32FC2);
+ src_points = cv::Mat(temp);
+ errcount += run_test_case( CV_StsAssert, "Invalid input data matrix size" );
+ src_points = cv::Mat(&_src_points_orig);
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(1,4,CV_64FC2);
+ src_points = cv::Mat(temp);
+ errcount += run_test_case( CV_StsAssert, "Invalid input data matrix type" );
+ src_points = cv::Mat(&_src_points_orig);
+ cvReleaseMat(&temp);
+
+ src_points = cv::Mat();
+ errcount += run_test_case( CV_StsAssert, "Input data matrix is not continuous" );
+ src_points = cv::Mat(&_src_points_orig);
+ cvReleaseMat(&temp);
+
+
+
+//------------
+ cvReleaseImage(&temp_img);
+ ts->set_failed_test_info(errcount > 0 ? cvtest::TS::FAIL_BAD_ARG_CHECK : cvtest::TS::OK);
+}
+
+
+//=========
+class CV_InitUndistortRectifyMapBadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_InitUndistortRectifyMapBadArgTest();
+protected:
+ void run(int);
+ void run_func();
+
+private:
+ //common
+ cv::Size img_size;
+ bool useCPlus;
+
+ //C
+ CvMat* _camera_mat;
+ CvMat* matR;
+ CvMat* _new_camera_mat;
+ CvMat* _distortion_coeffs;
+ CvMat* _mapx;
+ CvMat* _mapy;
+
+
+ //C++
+ cv::Mat camera_mat;
+ cv::Mat R;
+ cv::Mat new_camera_mat;
+ cv::Mat distortion_coeffs;
+ cv::Mat mapx;
+ cv::Mat mapy;
+ int mat_type;
+
+};
+
+CV_InitUndistortRectifyMapBadArgTest::CV_InitUndistortRectifyMapBadArgTest ()
+{
+}
+
+void CV_InitUndistortRectifyMapBadArgTest::run_func()
+{
+ if (useCPlus)
+ {
+ cv::initUndistortRectifyMap(camera_mat,distortion_coeffs,R,new_camera_mat,img_size,mat_type,mapx,mapy);
+ }
+ else
+ {
+ cvInitUndistortRectifyMap(_camera_mat,_distortion_coeffs,matR,_new_camera_mat,_mapx,_mapy);
+ }
+}
+
+void CV_InitUndistortRectifyMapBadArgTest::run(int)
+{
+ int errcount = 0;
+//initializing
+ img_size.width = 800;
+ img_size.height = 600;
+ double cam[9] = {150.f, 0.f, img_size.width/2.f, 0, 300.f, img_size.height/2.f, 0.f, 0.f, 1.f};
+ double dist[4] = {0.01,0.02,0.001,0.0005};
+ float* arr_mapx = new float[img_size.width*img_size.height];
+ float* arr_mapy = new float[img_size.width*img_size.height];
+ double arr_new_camera_mat[9] = {155.f, 0.f, img_size.width/2.f+img_size.width/50.f, 0, 310.f, img_size.height/2.f+img_size.height/50.f, 0.f, 0.f, 1.f};
+ double r[9] = {1,0,0,0,1,0,0,0,1};
+
+ CvMat _camera_mat_orig = cvMat(3,3,CV_64F,cam);
+ CvMat _distortion_coeffs_orig = cvMat(1,4,CV_64F,dist);
+ CvMat _new_camera_mat_orig = cvMat(3,3,CV_64F,arr_new_camera_mat);
+ CvMat _R_orig = cvMat(3,3,CV_64F,r);
+ CvMat _mapx_orig = cvMat(img_size.height,img_size.width,CV_32FC1,arr_mapx);
+ CvMat _mapy_orig = cvMat(img_size.height,img_size.width,CV_32FC1,arr_mapy);
+ int mat_type_orig = CV_32FC1;
+
+ _camera_mat = &_camera_mat_orig;
+ _distortion_coeffs = &_distortion_coeffs_orig;
+ _new_camera_mat = &_new_camera_mat_orig;
+ matR = &_R_orig;
+ _mapx = &_mapx_orig;
+ _mapy = &_mapy_orig;
+ mat_type = mat_type_orig;
+
+//tests
+ useCPlus = true;
+ CvMat* temp;
+
+ //C++ tests
+ useCPlus = true;
+
+ camera_mat = cv::Mat(&_camera_mat_orig);
+ distortion_coeffs = cv::Mat(&_distortion_coeffs_orig);
+ new_camera_mat = cv::Mat(&_new_camera_mat_orig);
+ R = cv::Mat(&_R_orig);
+ mapx = cv::Mat(&_mapx_orig);
+ mapy = cv::Mat(&_mapy_orig);
+
+
+ mat_type = CV_64F;
+ errcount += run_test_case( CV_StsAssert, "Invalid map matrix type" );
+ mat_type = mat_type_orig;
+
+ temp = cvCreateMat(3,2,CV_32FC1);
+ camera_mat = cv::Mat(temp);
+ errcount += run_test_case( CV_StsAssert, "Invalid camera data matrix size" );
+ camera_mat = cv::Mat(&_camera_mat_orig);
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(4,3,CV_32FC1);
+ R = cv::Mat(temp);
+ errcount += run_test_case( CV_StsAssert, "Invalid R data matrix size" );
+ R = cv::Mat(&_R_orig);
+ cvReleaseMat(&temp);
+
+ temp = cvCreateMat(6,1,CV_32FC1);
+ distortion_coeffs = cv::Mat(temp);
+ errcount += run_test_case( CV_StsAssert, "Invalid distortion coefficients data matrix size" );
+ distortion_coeffs = cv::Mat(&_distortion_coeffs_orig);
+ cvReleaseMat(&temp);
+
+//------------
+ delete[] arr_mapx;
+ delete[] arr_mapy;
+ ts->set_failed_test_info(errcount > 0 ? cvtest::TS::FAIL_BAD_ARG_CHECK : cvtest::TS::OK);
+}
+
+
+//=========
+class CV_UndistortBadArgTest : public cvtest::BadArgTest
+{
+public:
+ CV_UndistortBadArgTest();
+protected:
+ void run(int);
+ void run_func();
+
+private:
+ //common
+ cv::Size img_size;
+ bool useCPlus;
+
+ //C
+ CvMat* _camera_mat;
+ CvMat* _new_camera_mat;
+ CvMat* _distortion_coeffs;
+ CvMat* _src;
+ CvMat* _dst;
+
+
+ //C++
+ cv::Mat camera_mat;
+ cv::Mat new_camera_mat;
+ cv::Mat distortion_coeffs;
+ cv::Mat src;
+ cv::Mat dst;
+
+};
+
+CV_UndistortBadArgTest::CV_UndistortBadArgTest ()
+{
+}
+
+void CV_UndistortBadArgTest::run_func()
+{
+ if (useCPlus)
+ {
+ cv::undistort(src,dst,camera_mat,distortion_coeffs,new_camera_mat);
+ }
+ else
+ {
+ cvUndistort2(_src,_dst,_camera_mat,_distortion_coeffs,_new_camera_mat);
+ }
+}
+
+void CV_UndistortBadArgTest::run(int)
+{
+ int errcount = 0;
+//initializing
+ img_size.width = 800;
+ img_size.height = 600;
+ double cam[9] = {150.f, 0.f, img_size.width/2.f, 0, 300.f, img_size.height/2.f, 0.f, 0.f, 1.f};
+ double dist[4] = {0.01,0.02,0.001,0.0005};
+ float* arr_src = new float[img_size.width*img_size.height];
+ float* arr_dst = new float[img_size.width*img_size.height];
+ double arr_new_camera_mat[9] = {155.f, 0.f, img_size.width/2.f+img_size.width/50.f, 0, 310.f, img_size.height/2.f+img_size.height/50.f, 0.f, 0.f, 1.f};
+
+ CvMat _camera_mat_orig = cvMat(3,3,CV_64F,cam);
+ CvMat _distortion_coeffs_orig = cvMat(1,4,CV_64F,dist);
+ CvMat _new_camera_mat_orig = cvMat(3,3,CV_64F,arr_new_camera_mat);
+ CvMat _src_orig = cvMat(img_size.height,img_size.width,CV_32FC1,arr_src);
+ CvMat _dst_orig = cvMat(img_size.height,img_size.width,CV_32FC1,arr_dst);
+
+ _camera_mat = &_camera_mat_orig;
+ _distortion_coeffs = &_distortion_coeffs_orig;
+ _new_camera_mat = &_new_camera_mat_orig;
+ _src = &_src_orig;
+ _dst = &_dst_orig;
+
+//tests
+ useCPlus = true;
+ CvMat* temp;
+ CvMat* temp1;
+
+//C tests
+ useCPlus = false;
+
+ temp = cvCreateMat(800,600,CV_32F);
+ temp1 = cvCreateMat(800,601,CV_32F);
+ _src = temp;
+ _dst = temp1;
+ errcount += run_test_case( CV_StsAssert, "Input and output data matrix sizes mismatch" );
+ _src = &_src_orig;
+ _dst = &_dst_orig;
+ cvReleaseMat(&temp);
+ cvReleaseMat(&temp1);
+
+ temp = cvCreateMat(800,600,CV_32F);
+ temp1 = cvCreateMat(800,600,CV_64F);
+ _src = temp;
+ _dst = temp1;
+ errcount += run_test_case( CV_StsAssert, "Input and output data matrix types mismatch" );
+ _src = &_src_orig;
+ _dst = &_dst_orig;
+ cvReleaseMat(&temp);
+ cvReleaseMat(&temp1);
+
+ //C++ tests
+ useCPlus = true;
+
+ camera_mat = cv::Mat(&_camera_mat_orig);
+ distortion_coeffs = cv::Mat(&_distortion_coeffs_orig);
+ new_camera_mat = cv::Mat(&_new_camera_mat_orig);
+ src = cv::Mat(&_src_orig);
+ dst = cv::Mat(&_dst_orig);
+
+//------------
+ delete[] arr_src;
+ delete[] arr_dst;
+ ts->set_failed_test_info(errcount > 0 ? cvtest::TS::FAIL_BAD_ARG_CHECK : cvtest::TS::OK);
+}
+
+TEST(Calib3d_UndistortPoints, badarg) { CV_UndistortPointsBadArgTest test; test.safe_run(); }
+TEST(Calib3d_InitUndistortRectifyMap, badarg) { CV_InitUndistortRectifyMapBadArgTest test; test.safe_run(); }
+TEST(Calib3d_Undistort, badarg) { CV_UndistortBadArgTest test; test.safe_run(); }
+
+/* End of file. */
};
- CV_EXPORTS bool find4QuadCornerSubpix(const Mat& img, std::vector<Point2f>& corners, Size region_size);
-
CV_EXPORTS int chamerMatching( Mat& img, Mat& templ,
vector<vector<Point> >& results, vector<float>& cost,
double templScale=1, int maxMatches = 20,
/* ! DO NOT make it an inline function */
#define cvStackAlloc(size) cvAlignPtr( alloca((size) + CV_MALLOC_ALIGN), CV_MALLOC_ALIGN )
-#if defined _MSC_VER || defined __BORLANDC__
- #define CV_BIG_INT(n) n##I64
- #define CV_BIG_UINT(n) n##UI64
-#else
- #define CV_BIG_INT(n) n##LL
- #define CV_BIG_UINT(n) n##ULL
-#endif
-
#ifndef CV_IMPL
#define CV_IMPL CV_EXTERN_C
#endif
#if defined _MSC_VER || defined __BORLANDC__
typedef __int64 int64;
typedef unsigned __int64 uint64;
+#define CV_BIG_INT(n) n##I64
+#define CV_BIG_UINT(n) n##UI64
#else
typedef int64_t int64;
typedef uint64_t uint64;
+#define CV_BIG_INT(n) n##LL
+#define CV_BIG_UINT(n) n##ULL
#endif
#ifndef HAVE_IPL
b *= d;
a *= d;
- T z0 = saturate_cast<T>(src2[i+1] * src1[i] * b);
- T z1 = saturate_cast<T>(src2[i] * src1[i+1] * b);
- T z2 = saturate_cast<T>(src2[i+3] * src1[i+2] * a);
- T z3 = saturate_cast<T>(src2[i+2] * src1[i+3] * a);
+ T z0 = saturate_cast<T>(src2[i+1] * ((double)src1[i] * b));
+ T z1 = saturate_cast<T>(src2[i] * ((double)src1[i+1] * b));
+ T z2 = saturate_cast<T>(src2[i+3] * ((double)src1[i+2] * a));
+ T z3 = saturate_cast<T>(src2[i+2] * ((double)src1[i+3] * a));
dst[i] = z0; dst[i+1] = z1;
dst[i+2] = z2; dst[i+3] = z3;
};
MulDivFunc func = tab[src1.depth()];
- CV_Assert( src1.size() == src2.size() && src1.type() == src2.type() && func != 0 );
+ CV_Assert( src1.type() == src2.type() && func != 0 );
if( src1.dims > 2 || src2.dims > 2 )
{
addWeighted_<ushort, float>,
addWeighted_<short, float>,
addWeighted_<int, double>,
- addWeighted_<float, float>,
+ addWeighted_<float, double>,
addWeighted_<double, double>,
0
};
{
func( it.planes[0], it.planes[1], value );
if( invflag )
- bitwise_not(it.planes[2], it.planes[2]);
+ bitwise_not(it.planes[1], it.planes[1]);
}
return;
}
typedef void (*CvtFunc)( const Mat& src, Mat& dst );
typedef void (*CvtScaleFunc)( const Mat& src, Mat& dst, double scale, double shift );
-void convertScaleAbs( const Mat& src, Mat& dst, double scale, double shift )
+void convertScaleAbs( const Mat& src0, Mat& dst, double scale, double shift )
{
static CvtScaleFunc tab[] =
{
cvtScale_<double, OpCvtAbs<double, uchar> >, 0
};
- Mat src0 = src;
- dst.create( src.size(), CV_8UC(src.channels()) );
- CvtScaleFunc func = tab[src0.depth()];
+ Mat src = src0;
+ dst.create( src.dims, src.size, CV_8UC(src.channels()) );
+ CvtScaleFunc func = tab[src.depth()];
CV_Assert( func != 0 );
- func( src0, dst, scale, shift );
+
+ if( src.dims <= 2 )
+ {
+ func( src, dst, scale, shift );
+ }
+ else
+ {
+ const Mat* arrays[] = {&src, &dst, 0};
+ Mat planes[2];
+ NAryMatIterator it(arrays, planes);
+
+ for( int i = 0; i < it.nplanes; i++, ++it )
+ func(it.planes[0], it.planes[1], scale, shift);
+ }
}
-
void Mat::convertTo(Mat& dst, int _type, double alpha, double beta) const
{
static CvtFunc tab[8][8] =
cvtScaleInt_<ushort, OpCvtFixPt<int, ushort, FBITS>, OpCvt<float, ushort>, 0>,
cvtScaleInt_<ushort, OpCvtFixPt<int, short, FBITS>, OpCvt<float, short>, 0>,
cvtScale_<ushort, OpCvt<double, int> >,
- cvtScale_<ushort, OpCvt<float, float> >,
+ cvtScale_<ushort, OpCvt<double, float> >,
cvtScale_<ushort, OpCvt<double, double> >, 0,
},
cvtScaleInt_<short, OpCvtFixPt<int, ushort, FBITS>, OpCvt<float, ushort>, 1<<15>,
cvtScaleInt_<short, OpCvtFixPt<int, short, FBITS>, OpCvt<float, short>, 1<<15>,
cvtScale_<short, OpCvt<double, int> >,
- cvtScale_<short, OpCvt<float, float> >,
+ cvtScale_<short, OpCvt<double, float> >,
cvtScale_<short, OpCvt<double, double> >, 0,
},
cvtScale_<int, OpCvt<double, ushort> >,
cvtScale_<int, OpCvt<double, short> >,
cvtScale_<int, OpCvt<double, int> >,
- cvtScale_<int, OpCvt<float, float> >,
+ cvtScale_<int, OpCvt<double, float> >,
cvtScale_<int, OpCvt<double, double> >, 0,
},
{
static const int MAX_BLOCK_SIZE = 1024;
-
typedef CvStatus (CV_STDCALL * MathFunc)(const void* src, void* dst, int len);
-#define ICV_MATH_BLOCK_SIZE 256
-
-#define _CV_SQRT_MAGIC 0xbe6f0000
-
-#define _CV_SQRT_MAGIC_DBL CV_BIG_UINT(0xbfcd460000000000)
-
-#define _CV_ATAN_CF0 (-15.8131890796f)
-#define _CV_ATAN_CF1 (61.0941945596f)
-#define _CV_ATAN_CF2 0.f /*(-0.140500406322f)*/
-
-static const float icvAtanTab[8] = { 0.f + _CV_ATAN_CF2, 90.f - _CV_ATAN_CF2,
- 180.f - _CV_ATAN_CF2, 90.f + _CV_ATAN_CF2,
- 360.f - _CV_ATAN_CF2, 270.f + _CV_ATAN_CF2,
- 180.f + _CV_ATAN_CF2, 270.f - _CV_ATAN_CF2
-};
-
-static const int icvAtanSign[8] =
- { 0, 0x80000000, 0x80000000, 0, 0x80000000, 0, 0, 0x80000000 };
-
float fastAtan2( float y, float x )
{
double a, x2 = (double)x*x, y2 = (double)y*y;
if( y2 <= x2 )
{
- a = (180./CV_PI)*x*y/(x2 + 0.28*y2 + DBL_EPSILON);
+ a = (180./CV_PI)*x*y*(x2 + 0.43157974*y2)/(x2*x2 + y2*(0.76443945*x2 + 0.05831938*y2) + DBL_EPSILON);
return (float)(x < 0 ? a + 180 : y >= 0 ? a : 360+a);
}
- a = (180./CV_PI)*x*y/(y2 + 0.28*x2 + DBL_EPSILON);
+ a = (180./CV_PI)*x*y*(y2 + 0.43157974*x2)/(y2*y2 + x2*(0.76443945*y2 + 0.05831938*x2) + DBL_EPSILON);
return (float)(y >= 0 ? 90 - a : 270 - a);
}
Cv32suf iabsmask; iabsmask.i = 0x7fffffff;
__m128 eps = _mm_set1_ps((float)DBL_EPSILON), absmask = _mm_set1_ps(iabsmask.f);
__m128 _90 = _mm_set1_ps((float)(CV_PI*0.5)), _180 = _mm_set1_ps((float)CV_PI), _360 = _mm_set1_ps((float)(CV_PI*2));
- __m128 zero = _mm_setzero_ps(), _0_28 = _mm_set1_ps(0.28f), scale4 = _mm_set1_ps(scale);
+ __m128 zero = _mm_setzero_ps(), scale4 = _mm_set1_ps(scale);
+ __m128 p0 = _mm_set1_ps(0.43157974f), q0 = _mm_set1_ps(0.76443945f), q1 = _mm_set1_ps(0.05831938f);
for( ; i <= len - 4; i += 4 )
{
__m128 x4 = _mm_loadu_ps(X + i), y4 = _mm_loadu_ps(Y + i);
__m128 xq4 = _mm_mul_ps(x4, x4), yq4 = _mm_mul_ps(y4, y4);
__m128 xly = _mm_cmplt_ps(xq4, yq4);
- __m128 z4 = _mm_div_ps(_mm_mul_ps(x4, y4), _mm_add_ps(_mm_add_ps(_mm_max_ps(xq4, yq4),
- _mm_mul_ps(_mm_min_ps(xq4, yq4), _0_28)), eps));
+ __m128 t = _mm_min_ps(xq4, yq4);
+ xq4 = _mm_max_ps(xq4, yq4); yq4 = t;
+ __m128 z4 = _mm_div_ps(_mm_mul_ps(_mm_mul_ps(x4, y4), _mm_add_ps(xq4, _mm_mul_ps(yq4, p0))),
+ _mm_add_ps(eps, _mm_add_ps(_mm_mul_ps(xq4, xq4),
+ _mm_mul_ps(yq4, _mm_add_ps(_mm_mul_ps(xq4, q0),
+ _mm_mul_ps(yq4, q1))))));
// a4 <- x < y ? 90 : 0;
__m128 a4 = _mm_and_ps(xly, _90);
}
#endif
- for( ; i < len; i++ )
+ for( ; i < len; i++ )
{
- float x = X[i], y = Y[i];
- float a, x2 = x*x, y2 = y*y;
- if( y2 <= x2 )
- a = x*y/(x2 + 0.28f*y2 + (float)DBL_EPSILON) + (float)(x < 0 ? CV_PI : y >= 0 ? 0 : CV_PI*2);
- else
- a = (float)(y >= 0 ? CV_PI*0.5 : CV_PI*1.5) - x*y/(y2 + 0.28f*x2 + (float)DBL_EPSILON);
- angle[i] = a*scale;
+ double x = X[i], y = Y[i], x2 = x*x, y2 = y*y, a;
+
+ if( y2 <= x2 )
+ a = (x < 0 ? CV_PI : y >= 0 ? 0 : CV_PI*2) +
+ x*y*(x2 + 0.43157974*y2)/(x2*x2 + y2*(0.76443945*x2 + 0.05831938*y2) + (float)DBL_EPSILON);
+ else
+ {
+ a = (y >= 0 ? CV_PI*0.5 : CV_PI*1.5) -
+ x*y*(y2 + 0.43157974*x2)/(y2*y2 + x2*(0.76443945*y2 + 0.05831938*x2) + (float)DBL_EPSILON);
+ }
+ angle[i] = a*scale;
}
return CV_OK;
m.step.p = (size_t*)fastMalloc(_dims*sizeof(m.step.p[0]) + (_dims+1)*sizeof(m.size.p[0]));
m.size.p = (int*)(m.step.p + _dims) + 1;
m.size.p[-1] = _dims;
+ m.rows = m.cols = -1;
}
}
Mat Mat::reshape(int new_cn, int new_rows) const
{
- CV_Assert( dims <= 2 );
- Mat hdr = *this;
-
int cn = channels();
+ Mat hdr = *this;
+
+ if( dims > 2 && new_rows == 0 && new_cn != 0 && size[dims-1]*cn % new_cn == 0 )
+ {
+ hdr.flags = (hdr.flags & ~CV_MAT_CN_MASK) | ((new_cn-1) << CV_CN_SHIFT);
+ hdr.step[dims-1] = CV_ELEM_SIZE(hdr.flags);
+ hdr.size[dims-1] = hdr.size[dims-1]*cn / new_cn;
+ return hdr;
+ }
+
+ CV_Assert( dims <= 2 );
+
if( new_cn == 0 )
new_cn = cn;
template<class SqrOp> static void
-meanStdDev_( const Mat& srcmat, Scalar& _mean, Scalar& _stddev )
+meanStdDev_( const Mat& srcmat, Scalar& _sum, Scalar& _sqsum )
{
SqrOp sqr;
typedef typename SqrOp::type1 T;
sq += sqr(v);
}
}
-
- _mean = _stddev = Scalar();
- double scale = 1./std::max(size.width*size.height, 1);
- for( int i = 0; i < DataType<ST>::channels; i++ )
- {
- double t = ((ST1*)&s)[i]*scale;
- _mean.val[i] = t;
- _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.));
- }
+ _sum = rawToScalar(s);
+ _sqsum = rawToScalar(sq);
}
template<class SqrOp> static void
meanStdDevMask_( const Mat& srcmat, const Mat& maskmat,
- Scalar& _mean, Scalar& _stddev )
+ Scalar& _sum, Scalar& _sqsum, int& _nz )
{
SqrOp sqr;
typedef typename SqrOp::type1 T;
pix++;
}
}
- _mean = _stddev = Scalar();
- double scale = 1./std::max(pix, 1);
- for( int i = 0; i < DataType<ST>::channels; i++ )
- {
- double t = ((ST1*)&s)[i]*scale;
- _mean.val[i] = t;
- _stddev.val[i] = std::sqrt(std::max(((ST1*)&sq)[i]*scale - t*t, 0.));
- }
+ _sum = rawToScalar(s);
+ _sqsum = rawToScalar(sq);
+ _nz = pix;
}
-typedef void (*MeanStdDevFunc)(const Mat& src, Scalar& mean, Scalar& stddev);
+typedef void (*MeanStdDevFunc)(const Mat& src, Scalar& s, Scalar& sq);
typedef void (*MeanStdDevMaskFunc)(const Mat& src, const Mat& mask,
- Scalar& mean, Scalar& stddev);
+ Scalar& s, Scalar& sq, int& nz);
void meanStdDev( const Mat& m, Scalar& mean, Scalar& stddev, const Mat& mask )
{
CV_Assert( m.channels() <= 4 && (mask.empty() || mask.type() == CV_8U) );
+ Scalar sum, sqsum;
+ int total = 0;
MeanStdDevFunc func = tab[m.type()];
MeanStdDevMaskFunc mfunc = mtab[m.type()];
- CV_Assert( func != 0 || mfunc != 0 );
+ CV_Assert( func != 0 && mfunc != 0 );
if( m.dims > 2 )
{
- Scalar s, sq;
- double total = 0;
-
const Mat* arrays[] = {&m, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
- int k, cn = m.channels();
+ int nz = (int)planes[0].total();
for( int i = 0; i < it.nplanes; i++, ++it )
{
- Scalar _mean, _stddev;
- double nz = (double)(mask.data ? countNonZero(it.planes[1]) : it.planes[0].rows*it.planes[0].cols);
+ Scalar s, sq;
- if( func )
- func(it.planes[0], _mean, _stddev);
+ if( mask.empty() )
+ func(it.planes[0], s, sq);
else
- mfunc(it.planes[0], it.planes[1], _mean, _stddev);
+ mfunc(it.planes[0], it.planes[1], s, sq, nz);
total += nz;
- for( k = 0; k < cn; k++ )
- {
- s[k] += _mean[k]*nz;
- sq[k] += (_stddev[k]*_stddev[k] + _mean[k]*_mean[k])*nz;
- }
+ sum += s;
+ sqsum += sq;
}
-
- mean = stddev = Scalar();
- total = 1./std::max(total, 1.);
- for( k = 0; k < cn; k++ )
+ }
+ else
+ {
+ if( mask.data )
{
- mean[k] = s[k]*total;
- stddev[k] = std::sqrt(std::max(sq[k]*total - mean[k]*mean[k], 0.));
+ CV_Assert( mask.size() == m.size() );
+ mfunc( m, mask, sum, sqsum, total );
+ }
+ else
+ {
+ func( m, sum, sqsum );
+ total = (int)m.total();
}
- return;
}
- if( mask.data )
+ double scale = 1./std::max(total, 1);
+ for( int k = 0; k < 4; k++ )
{
- CV_Assert( mask.size() == m.size() );
- mfunc( m, mask, mean, stddev );
+ mean[k] = sum[k]*scale;
+ stddev[k] = std::sqrt(std::max(sqsum[k]*scale - mean[k]*mean[k], 0.));
}
- else
- func( m, mean, stddev );
}
* minMaxLoc *
\****************************************************************************************/
-template<typename T> static void
-minMaxIndx_( const Mat& srcmat, double* minVal, double* maxVal, int* minLoc, int* maxLoc )
+template<typename T, typename WT> static void
+minMaxIndx_( const Mat& srcmat, double* _minVal, double* _maxVal,
+ size_t startIdx, size_t* _minIdx, size_t* _maxIdx )
{
assert( DataType<T>::type == srcmat.type() );
const T* src = (const T*)srcmat.data;
size_t step = srcmat.step/sizeof(src[0]);
- T min_val = src[0], max_val = min_val;
- int min_loc = 0, max_loc = 0;
- int x, loc = 0;
+ WT minVal = saturate_cast<WT>(*_minVal), maxVal = saturate_cast<WT>(*_maxVal);
+ size_t minIdx = *_minIdx, maxIdx = *_maxIdx;
Size size = getContinuousSize( srcmat );
- for( ; size.height--; src += step, loc += size.width )
+ for( ; size.height--; src += step, startIdx += size.width )
{
- for( x = 0; x < size.width; x++ )
+ for( int x = 0; x < size.width; x++ )
{
T val = src[x];
- if( val < min_val )
+ if( val < minVal )
{
- min_val = val;
- min_loc = loc + x;
+ minVal = val;
+ minIdx = startIdx + x;
}
- else if( val > max_val )
+ if( val > maxVal )
{
- max_val = val;
- max_loc = loc + x;
+ maxVal = val;
+ maxIdx = startIdx + x;
}
}
}
- *minLoc = min_loc;
- *maxLoc = max_loc;
- *minVal = min_val;
- *maxVal = max_val;
+ *_minIdx = minIdx;
+ *_maxIdx = maxIdx;
+ *_minVal = minVal;
+ *_maxVal = maxVal;
}
-template<typename T> static void
+template<typename T, typename WT> static void
minMaxIndxMask_( const Mat& srcmat, const Mat& maskmat,
- double* minVal, double* maxVal, int* minLoc, int* maxLoc )
+ double* _minVal, double* _maxVal,
+ size_t startIdx, size_t* _minIdx, size_t* _maxIdx )
{
assert( DataType<T>::type == srcmat.type() &&
CV_8U == maskmat.type() &&
const uchar* mask = maskmat.data;
size_t step = srcmat.step/sizeof(src[0]);
size_t maskstep = maskmat.step;
- T min_val = 0, max_val = 0;
- int min_loc = -1, max_loc = -1;
- int x = 0, y, loc = 0;
+ WT minVal = saturate_cast<WT>(*_minVal), maxVal = saturate_cast<WT>(*_maxVal);
+ size_t minIdx = *_minIdx, maxIdx = *_maxIdx;
Size size = getContinuousSize( srcmat, maskmat );
- for( y = 0; y < size.height; y++, src += step, mask += maskstep, loc += size.width )
+ for( ; size.height--; src += step, mask += maskstep, startIdx += size.width )
{
- for( x = 0; x < size.width; x++ )
- if( mask[x] != 0 )
- {
- min_loc = max_loc = loc + x;
- min_val = max_val = src[x];
- break;
- }
- if( x < size.width )
- break;
- }
-
- for( ; y < size.height; x = 0, y++, src += step, mask += maskstep, loc += size.width )
- {
- for( ; x < size.width; x++ )
+ for( int x = 0; x < size.width; x++ )
{
T val = src[x];
int m = mask[x];
-
- if( val < min_val && m )
+
+ if( val < minVal && m )
{
- min_val = val;
- min_loc = loc + x;
+ minVal = val;
+ minIdx = startIdx + x;
}
- else if( val > max_val && m )
+ if( val > maxVal && m )
{
- max_val = val;
- max_loc = loc + x;
+ maxVal = val;
+ maxIdx = startIdx + x;
}
}
}
- *minLoc = min_loc;
- *maxLoc = max_loc;
- *minVal = min_val;
- *maxVal = max_val;
+ *_minIdx = minIdx;
+ *_maxIdx = maxIdx;
+ *_minVal = minVal;
+ *_maxVal = maxVal;
}
-typedef void (*MinMaxIndxFunc)(const Mat&, double*, double*, int*, int*);
+typedef void (*MinMaxIndxFunc)(const Mat&, double*, double*, size_t, size_t*, size_t*);
-typedef void (*MinMaxIndxMaskFunc)(const Mat&, const Mat&,
- double*, double*, int*, int*);
+typedef void (*MinMaxIndxMaskFunc)(const Mat&, const Mat&, double*, double*,
+ size_t, size_t*, size_t*);
void minMaxLoc( const Mat& img, double* minVal, double* maxVal,
Point* minLoc, Point* maxLoc, const Mat& mask )
CV_Assert(img.dims <= 2);
static MinMaxIndxFunc tab[] =
- {minMaxIndx_<uchar>, 0, minMaxIndx_<ushort>, minMaxIndx_<short>,
- minMaxIndx_<int>, minMaxIndx_<float>, minMaxIndx_<double>, 0};
+ {
+ minMaxIndx_<uchar, int>, 0, minMaxIndx_<ushort, int>, minMaxIndx_<short, int>,
+ minMaxIndx_<int, int>, minMaxIndx_<float, float>, minMaxIndx_<double, double>, 0
+ };
static MinMaxIndxMaskFunc tabm[] =
- {minMaxIndxMask_<uchar>, 0, minMaxIndxMask_<ushort>, minMaxIndxMask_<short>,
- minMaxIndxMask_<int>, minMaxIndxMask_<float>, minMaxIndxMask_<double>, 0};
+ {
+ minMaxIndxMask_<uchar, int>, 0, minMaxIndxMask_<ushort, int>, minMaxIndxMask_<short, int>,
+ minMaxIndxMask_<int, int>, minMaxIndxMask_<float, float>, minMaxIndxMask_<double, double>, 0
+ };
int depth = img.depth();
- double minval=0, maxval=0;
- int minloc=0, maxloc=0;
+ double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX;
+ double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX;
+ size_t minidx = 0, maxidx = 0, startidx = 1;
CV_Assert( img.channels() == 1 );
{
MinMaxIndxFunc func = tab[depth];
CV_Assert( func != 0 );
- func( img, &minval, &maxval, &minloc, &maxloc );
+ func( img, &minval, &maxval, startidx, &minidx, &maxidx );
}
else
{
CV_Assert( img.size() == mask.size() && mask.type() == CV_8U );
MinMaxIndxMaskFunc func = tabm[depth];
CV_Assert( func != 0 );
- func( img, mask, &minval, &maxval, &minloc, &maxloc );
+ func( img, mask, &minval, &maxval, startidx, &minidx, &maxidx );
}
+ if( minidx == 0 )
+ minVal = maxVal = 0;
+
if( minVal )
*minVal = minval;
if( maxVal )
*maxVal = maxval;
if( minLoc )
{
- if( minloc >= 0 )
+ if( minidx > 0 )
{
- minLoc->y = minloc/img.cols;
- minLoc->x = minloc - minLoc->y*img.cols;
+ minidx--;
+ minLoc->y = minidx/img.cols;
+ minLoc->x = minidx - minLoc->y*img.cols;
}
else
minLoc->x = minLoc->y = -1;
}
if( maxLoc )
{
- if( maxloc >= 0 )
+ if( maxidx > 0 )
{
- maxLoc->y = maxloc/img.cols;
- maxLoc->x = maxloc - maxLoc->y*img.cols;
+ maxidx--;
+ maxLoc->y = maxidx/img.cols;
+ maxLoc->x = maxidx - maxLoc->y*img.cols;
}
else
maxLoc->x = maxLoc->y = -1;
static void ofs2idx(const Mat& a, size_t ofs, int* idx)
{
int i, d = a.dims;
- for( i = 0; i < d; i++ )
+ if( ofs > 0 )
+ {
+ ofs--;
+ for( i = d-1; i >= 0; i-- )
+ {
+ int sz = a.size[i];
+ idx[i] = (int)(ofs % sz);
+ ofs /= sz;
+ }
+ }
+ else
{
- idx[i] = (int)(ofs / a.step[i]);
- ofs %= a.step[i];
+ for( i = d-1; i >= 0; i-- )
+ idx[i] = -1;
}
}
Point minLoc, maxLoc;
minMaxLoc(a, minVal, maxVal, &minLoc, &maxLoc, mask);
if( minIdx )
- minIdx[0] = minLoc.x, minIdx[1] = minLoc.y;
+ minIdx[0] = minLoc.y, minIdx[1] = minLoc.x;
if( maxIdx )
- maxIdx[0] = maxLoc.x, maxIdx[1] = maxLoc.y;
+ maxIdx[0] = maxLoc.y, maxIdx[1] = maxLoc.x;
return;
}
+
+ static MinMaxIndxFunc tab[] =
+ {
+ minMaxIndx_<uchar, int>, 0, minMaxIndx_<ushort, int>, minMaxIndx_<short, int>,
+ minMaxIndx_<int, int>, minMaxIndx_<float, float>, minMaxIndx_<double, double>, 0
+ };
+ static MinMaxIndxMaskFunc tabm[] =
+ {
+ minMaxIndxMask_<uchar, int>, 0, minMaxIndxMask_<ushort, int>, minMaxIndxMask_<short, int>,
+ minMaxIndxMask_<int, int>, minMaxIndxMask_<float, float>, minMaxIndxMask_<double, double>, 0
+ };
const Mat* arrays[] = {&a, &mask, 0};
Mat planes[2];
NAryMatIterator it(arrays, planes);
- double minval = DBL_MAX, maxval = -DBL_MAX;
- size_t minofs = 0, maxofs = 0, esz = a.elemSize();
- for( int i = 0; i < it.nplanes; i++, ++it )
+ int depth = a.depth();
+ double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX;
+ double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX;
+ size_t minidx = 0, maxidx = 0;
+ size_t startidx = 1, planeSize = planes[0].total();
+ MinMaxIndxFunc func = 0;
+ MinMaxIndxMaskFunc mfunc = 0;
+
+ if( mask.empty() )
+ func = tab[depth];
+ else
+ mfunc = tabm[depth];
+ CV_Assert( func != 0 || mfunc != 0 );
+
+ for( int i = 0; i < it.nplanes; i++, ++it, startidx += planeSize )
{
- double val0 = 0, val1 = 0;
- Point pt0, pt1;
- minMaxLoc( it.planes[0], &val0, &val1, &pt0, &pt1, it.planes[1] );
- if( val0 < minval )
- {
- minval = val0;
- minofs = (it.planes[0].data - a.data) + pt0.x*esz;
- }
- if( val1 > maxval )
- {
- maxval = val1;
- maxofs = (it.planes[0].data - a.data) + pt1.x*esz;
- }
+ if( func )
+ func( planes[0], &minval, &maxval, startidx, &minidx, &maxidx );
+ else
+ mfunc( planes[0], planes[1], &minval, &maxval, startidx, &minidx, &maxidx );
}
+ if( minidx == 0 )
+ minVal = maxVal = 0;
+
if( minVal )
*minVal = minval;
if( maxVal )
*maxVal = maxval;
if( minIdx )
- ofs2idx(a, minofs, minIdx);
+ ofs2idx(a, minidx, minIdx);
if( maxIdx )
- ofs2idx(a, maxofs, maxIdx);
+ ofs2idx(a, maxidx, maxIdx);
}
/****************************************************************************************\
ST s0 = 0;
WT s = 0;
int y, remaining = BLOCK_SIZE;
+ int cn = srcmat.channels();
for( y = 0; y < size.height; y++ )
{
int limit = std::min( remaining, size.width - x );
remaining -= limit;
limit += x;
- for( ; x <= limit - 4; x += 4 )
+ int x0 = x;
+ for( int c = 0; c < cn; c++ )
{
- if( mask[x] )
- s = update(s, (WT)f(src[x]));
- if( mask[x+1] )
- s = update(s, (WT)f(src[x+1]));
- if( mask[x+2] )
- s = update(s, (WT)f(src[x+2]));
- if( mask[x+3] )
- s = update(s, (WT)f(src[x+3]));
- }
- for( ; x < limit; x++ )
- {
- if( mask[x] )
- s = update(s, (WT)f(src[x]));
+ for( x = x0; x <= limit - 4; x += 4 )
+ {
+ if( mask[x] )
+ s = update(s, (WT)f(src[x*cn + c]));
+ if( mask[x+1] )
+ s = update(s, (WT)f(src[(x+1)*cn + c]));
+ if( mask[x+2] )
+ s = update(s, (WT)f(src[(x+2)*cn + c]));
+ if( mask[x+3] )
+ s = update(s, (WT)f(src[(x+3)*cn + c]));
+ }
+ for( ; x < limit; x++ )
+ {
+ if( mask[x] )
+ s = update(s, (WT)f(src[x*cn + c]));
+ }
}
if( remaining == 0 || (x == size.width && y == size.height-1) )
{
assert( DataType<T>::depth == srcmat.depth() );
Size size = getContinuousSize( srcmat, maskmat );
ST s = 0;
-
+ int cn = srcmat.channels();
+
for( int y = 0; y < size.height; y++ )
{
const T* src = (const T*)(srcmat.data + srcmat.step*y);
const uchar* mask = maskmat.data + maskmat.step*y;
- int x = 0;
- for( ; x <= size.width - 4; x += 4 )
+ for( int c = 0; c < cn; c++ )
{
- if( mask[x] )
- s = update(s, (ST)f(src[x]));
- if( mask[x+1] )
- s = update(s, (ST)f(src[x+1]));
- if( mask[x+2] )
- s = update(s, (ST)f(src[x+2]));
- if( mask[x+3] )
- s = update(s, (ST)f(src[x+3]));
- }
- for( ; x < size.width; x++ )
- {
- if( mask[x] )
- s = update(s, (ST)f(src[x]));
+ int x = 0;
+ for( ; x <= size.width - 4; x += 4 )
+ {
+ if( mask[x] )
+ s = update(s, (ST)f(src[x*cn + c]));
+ if( mask[x+1] )
+ s = update(s, (ST)f(src[(x+1)*cn + c]));
+ if( mask[x+2] )
+ s = update(s, (ST)f(src[(x+2)*cn + c]));
+ if( mask[x+3] )
+ s = update(s, (ST)f(src[(x+3)*cn + c]));
+ }
+ for( ; x < size.width; x++ )
+ {
+ if( mask[x] )
+ s = update(s, (ST)f(src[x*cn + c]));
+ }
}
}
return s;
ST s0 = 0;
WT s = 0;
int y, remaining = BLOCK_SIZE;
+ int cn = srcmat1.channels();
for( y = 0; y < size.height; y++ )
{
int limit = std::min( remaining, size.width - x );
remaining -= limit;
limit += x;
- for( ; x <= limit - 4; x += 4 )
+ int x0 = x;
+ for( int c = 0; c < cn; c++ )
{
- if( mask[x] )
- s = update(s, (WT)f(src1[x] - src2[x]));
- if( mask[x+1] )
- s = update(s, (WT)f(src1[x+1] - src2[x+1]));
- if( mask[x+2] )
- s = update(s, (WT)f(src1[x+2] - src2[x+2]));
- if( mask[x+3] )
- s = update(s, (WT)f(src1[x+3] - src2[x+3]));
+ for( x = x0; x <= limit - 4; x += 4 )
+ {
+ if( mask[x] )
+ s = update(s, (WT)f(src1[x*cn + c] - src2[x*cn + c]));
+ if( mask[x+1] )
+ s = update(s, (WT)f(src1[(x+1)*cn + c] - src2[(x+1)*cn + c]));
+ if( mask[x+2] )
+ s = update(s, (WT)f(src1[(x+2)*cn + c] - src2[(x+2)*cn + c]));
+ if( mask[x+3] )
+ s = update(s, (WT)f(src1[(x+3)*cn + c] - src2[(x+3)*cn + c]));
+ }
+ for( ; x < limit; x++ )
+ if( mask[x] )
+ s = update(s, (WT)f(src1[x*cn + c] - src2[x*cn + c]));
}
- for( ; x < limit; x++ )
- if( mask[x] )
- s = update(s, (WT)f(src1[x] - src2[x]));
if( remaining == 0 || (x == size.width && y == size.height-1) )
{
s0 = globUpdate(s0, (ST)s);
assert( DataType<T>::depth == srcmat1.depth() );
Size size = getContinuousSize( srcmat1, srcmat2, maskmat );
ST s = 0;
+ int cn = srcmat1.channels();
for( int y = 0; y < size.height; y++ )
{
const T* src1 = (const T*)(srcmat1.data + srcmat1.step*y);
const T* src2 = (const T*)(srcmat2.data + srcmat2.step*y);
const uchar* mask = maskmat.data + maskmat.step*y;
- int x = 0;
- for( ; x <= size.width - 4; x += 4 )
+ for( int c = 0; c < cn; c++ )
{
- if( mask[x] )
- s = update(s, (ST)f(src1[x] - src2[x]));
- if( mask[x+1] )
- s = update(s, (ST)f(src1[x+1] - src2[x+1]));
- if( mask[x+2] )
- s = update(s, (ST)f(src1[x+2] - src2[x+2]));
- if( mask[x+3] )
- s = update(s, (ST)f(src1[x+3] - src2[x+3]));
+ int x = 0;
+ for( ; x <= size.width - 4; x += 4 )
+ {
+ if( mask[x] )
+ s = update(s, (ST)f(src1[x*cn + c] - src2[x*cn + c]));
+ if( mask[x+1] )
+ s = update(s, (ST)f(src1[(x+1)*cn + c] - src2[(x+1)*cn + c]));
+ if( mask[x+2] )
+ s = update(s, (ST)f(src1[(x+2)*cn + c] - src2[(x+2)*cn + c]));
+ if( mask[x+3] )
+ s = update(s, (ST)f(src1[(x+3)*cn + c] - src2[(x+3)*cn + c]));
+ }
+ for( ; x < size.width; x++ )
+ if( mask[x] )
+ s = update(s, (ST)f(src1[x*cn + c] - src2[x*cn + c]));
}
- for( ; x < size.width; x++ )
- if( mask[x] )
- s = update(s, (ST)f(src1[x] - src2[x]));
-
}
return s;
}
return norm(a, normType);
normType &= 7;
- CV_Assert((normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) &&
- mask.type() == CV_8U && a.channels() == 1);
+ CV_Assert((normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2) && mask.type() == CV_8U);
NormMaskFunc func = tab[normType >> 1][a.depth()];
CV_Assert(func != 0);
if( !mask.data )
return norm(a, b, normType);
- CV_Assert( a.type() == b.type() && mask.type() == CV_8U && a.channels() == 1);
+ CV_Assert( a.type() == b.type() && mask.type() == CV_8U);
bool isRelative = (normType & NORM_RELATIVE) != 0;
normType &= 7;
CV_Assert(normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2);
#include "test_precomp.hpp"
-#include <iostream>
using namespace cv;
using namespace std;
+namespace cvtest
+{
+
const int ARITHM_NTESTS = 1000;
const int ARITHM_RNG_SEED = -1;
+const int ARITHM_MAX_CHANNELS = 4;
const int ARITHM_MAX_NDIMS = 4;
const int ARITHM_MAX_SIZE_LOG = 10;
-const int ARITHM_MAX_CHANNELS = 4;
-static void getArithmValueRange(int depth, double& minval, double& maxval)
+struct BaseElemWiseOp
+{
+ enum { FIX_ALPHA=1, FIX_BETA=2, FIX_GAMMA=4, REAL_GAMMA=8, SUPPORT_MASK=16, SCALAR_OUTPUT=32 };
+ BaseElemWiseOp(int _ninputs, int _flags, double _alpha, double _beta,
+ Scalar _gamma=Scalar::all(0), int _context=1)
+ : ninputs(_ninputs), flags(_flags), alpha(_alpha), beta(_beta), gamma(_gamma), context(_context) {}
+ BaseElemWiseOp() { flags = alpha = beta = 0; gamma = Scalar::all(0); }
+ virtual ~BaseElemWiseOp() {}
+ virtual void op(const vector<Mat>&, Mat&, const Mat&) {}
+ virtual void refop(const vector<Mat>&, Mat&, const Mat&) {}
+ virtual void getValueRange(int depth, double& minval, double& maxval)
+ {
+ minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
+ maxval = depth < CV_32S ? cvtest::getMaxVal(depth) : depth == CV_32S ? 1000000 : 1000.;
+ }
+
+ virtual void getRandomSize(RNG& rng, vector<int>& size)
+ {
+ cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, cvtest::ARITHM_MAX_SIZE_LOG, size);
+ }
+
+ virtual int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL_BUT_8S, 1,
+ ninputs > 1 ? ARITHM_MAX_CHANNELS : 4);
+ }
+
+ virtual int getMaxErr(int depth) { return depth < CV_32F ? 1 : 256; }
+ virtual void generateScalars(int depth, RNG& rng)
+ {
+ const double m = 3.;
+
+ if( !(flags & FIX_ALPHA) )
+ {
+ alpha = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
+ alpha *= rng.uniform(0, 2) ? 1 : -1;
+ }
+ if( !(flags & FIX_BETA) )
+ {
+ beta = exp(rng.uniform(-0.5, 0.1)*m*2*CV_LOG2);
+ beta *= rng.uniform(0, 2) ? 1 : -1;
+ }
+
+ if( !(flags & FIX_GAMMA) )
+ {
+ for( int i = 0; i < 4; i++ )
+ {
+ gamma[i] = exp(rng.uniform(-1, 6)*m*CV_LOG2);
+ gamma[i] *= rng.uniform(0, 2) ? 1 : -1;
+ }
+ if( flags & REAL_GAMMA )
+ gamma = Scalar::all(gamma[0]);
+ }
+
+ if( depth == CV_32F )
+ {
+ Mat fl, db;
+
+ db = Mat(1, 1, CV_64F, &alpha);
+ db.convertTo(fl, CV_32F);
+ fl.convertTo(db, CV_64F);
+
+ db = Mat(1, 1, CV_64F, &beta);
+ db.convertTo(fl, CV_32F);
+ fl.convertTo(db, CV_64F);
+
+ db = Mat(1, 4, CV_64F, &gamma[0]);
+ db.convertTo(fl, CV_32F);
+ fl.convertTo(db, CV_64F);
+ }
+ }
+
+ int ninputs;
+ int flags;
+ double alpha;
+ double beta;
+ Scalar gamma;
+ int maxErr;
+ int context;
+};
+
+
+struct BaseAddOp : public BaseElemWiseOp
+{
+ BaseAddOp(int _ninputs, int _flags, double _alpha, double _beta, Scalar _gamma=Scalar::all(0))
+ : BaseElemWiseOp(_ninputs, _flags, _alpha, _beta, _gamma) {}
+
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ if( !mask.empty() )
+ {
+ cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, temp, src[0].type());
+ cvtest::copy(temp, dst, mask);
+ }
+ else
+ cvtest::add(src[0], alpha, src.size() > 1 ? src[1] : Mat(), beta, gamma, dst, src[0].type());
+ }
+};
+
+
+struct AddOp : public BaseAddOp
+{
+ AddOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( mask.empty() )
+ add(src[0], src[1], dst);
+ else
+ add(src[0], src[1], dst, mask);
+ }
+};
+
+
+struct SubOp : public BaseAddOp
+{
+ SubOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, -1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( mask.empty() )
+ subtract(src[0], src[1], dst);
+ else
+ subtract(src[0], src[1], dst, mask);
+ }
+};
+
+
+struct AddSOp : public BaseAddOp
{
- minval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? -1000000 : -1000.;
- maxval = depth < CV_32S ? cvtest::getMinVal(depth) : depth == CV_32S ? 1000000 : 1000.;
+ AddSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 0, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( mask.empty() )
+ add(src[0], gamma, dst);
+ else
+ add(src[0], gamma, dst, mask);
+ }
+};
+
+
+struct SubRSOp : public BaseAddOp
+{
+ SubRSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, -1, 0, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( mask.empty() )
+ subtract(gamma, src[0], dst);
+ else
+ subtract(gamma, src[0], dst, mask);
+ }
+};
+
+
+struct ScaleAddOp : public BaseAddOp
+{
+ ScaleAddOp() : BaseAddOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ scaleAdd(src[0], alpha, src[1], dst);
+ }
+};
+
+
+struct AddWeightedOp : public BaseAddOp
+{
+ AddWeightedOp() : BaseAddOp(2, REAL_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ addWeighted(src[0], alpha, src[1], beta, gamma[0], dst);
+ }
+ int getMaxErr(int depth)
+ {
+ return depth <= CV_32S ? 2 : depth < CV_64F ? (1 << 10) : (1 << 22);
+ }
+};
+
+struct MulOp : public BaseElemWiseOp
+{
+ MulOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::multiply(src[0], src[1], dst, alpha);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::multiply(src[0], src[1], dst, alpha);
+ }
+ int getMaxErr(int depth)
+ {
+ return depth < CV_32S ? 2 : depth < CV_32F ? 4 : 16;
+ }
+};
+
+struct DivOp : public BaseElemWiseOp
+{
+ DivOp() : BaseElemWiseOp(2, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::divide(src[0], src[1], dst, alpha);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::divide(src[0], src[1], dst, alpha);
+ }
+ int getMaxErr(int depth)
+ {
+ return depth < CV_32S ? 2 : depth < CV_32F ? 4 : 16;
+ }
+};
+
+struct RecipOp : public BaseElemWiseOp
+{
+ RecipOp() : BaseElemWiseOp(1, FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::divide(alpha, src[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::divide(Mat(), src[0], dst, alpha);
+ }
+ int getMaxErr(int depth)
+ {
+ return depth < CV_32S ? 2 : depth < CV_32F ? 4 : 16;
+ }
+};
+
+struct AbsDiffOp : public BaseAddOp
+{
+ AbsDiffOp() : BaseAddOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, -1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ absdiff(src[0], src[1], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::add(src[0], 1, src[1], -1, Scalar::all(0), dst, src[0].type(), true);
+ }
+};
+
+struct AbsDiffSOp : public BaseAddOp
+{
+ AbsDiffSOp() : BaseAddOp(1, FIX_ALPHA+FIX_BETA, 1, 0, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ absdiff(src[0], gamma, dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::add(src[0], 1, Mat(), 0, -gamma, dst, src[0].type(), true);
+ }
+};
+
+struct LogicOp : public BaseElemWiseOp
+{
+ LogicOp(char _opcode) : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)), opcode(_opcode) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( opcode == '&' )
+ bitwise_and(src[0], src[1], dst, mask);
+ else if( opcode == '|' )
+ bitwise_or(src[0], src[1], dst, mask);
+ else
+ bitwise_xor(src[0], src[1], dst, mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ if( !mask.empty() )
+ {
+ cvtest::logicOp(src[0], src[1], temp, opcode);
+ cvtest::copy(temp, dst, mask);
+ }
+ else
+ cvtest::logicOp(src[0], src[1], dst, opcode);
+ }
+ int getMaxErr(int depth)
+ {
+ return 0;
+ }
+ char opcode;
+};
+
+struct LogicSOp : public BaseElemWiseOp
+{
+ LogicSOp(char _opcode)
+ : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+(_opcode != '~' ? SUPPORT_MASK : 0), 1, 1, Scalar::all(0)), opcode(_opcode) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ if( opcode == '&' )
+ bitwise_and(src[0], gamma, dst, mask);
+ else if( opcode == '|' )
+ bitwise_or(src[0], gamma, dst, mask);
+ else if( opcode == '^' )
+ bitwise_xor(src[0], gamma, dst, mask);
+ else
+ bitwise_not(src[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ if( !mask.empty() )
+ {
+ cvtest::logicOp(src[0], gamma, temp, opcode);
+ cvtest::copy(temp, dst, mask);
+ }
+ else
+ cvtest::logicOp(src[0], gamma, dst, opcode);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ char opcode;
+};
+
+struct MinOp : public BaseElemWiseOp
+{
+ MinOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::min(src[0], src[1], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::min(src[0], src[1], dst);
+ }
+ int getMaxErr(int depth)
+ {
+ return 0;
+ }
+};
+
+struct MaxOp : public BaseElemWiseOp
+{
+ MaxOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::max(src[0], src[1], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::max(src[0], src[1], dst);
+ }
+ int getMaxErr(int depth)
+ {
+ return 0;
+ }
+};
+
+struct MinSOp : public BaseElemWiseOp
+{
+ MinSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::min(src[0], gamma[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::min(src[0], gamma[0], dst);
+ }
+ int getMaxErr(int depth)
+ {
+ return 0;
+ }
+};
+
+struct MaxSOp : public BaseElemWiseOp
+{
+ MaxSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::max(src[0], gamma[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::max(src[0], gamma[0], dst);
+ }
+ int getMaxErr(int depth)
+ {
+ return 0;
+ }
+};
+
+struct CmpOp : public BaseElemWiseOp
+{
+ CmpOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void generateScalars(int depth, RNG& rng)
+ {
+ BaseElemWiseOp::generateScalars(depth, rng);
+ cmpop = rng.uniform(0, 6);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::compare(src[0], src[1], dst, cmpop);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::compare(src[0], src[1], dst, cmpop);
+ }
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL_BUT_8S, 1, 1);
+ }
+
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ int cmpop;
+};
+
+struct CmpSOp : public BaseElemWiseOp
+{
+ CmpSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
+ void generateScalars(int depth, RNG& rng)
+ {
+ BaseElemWiseOp::generateScalars(depth, rng);
+ cmpop = rng.uniform(0, 6);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::compare(src[0], gamma[0], dst, cmpop);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::compare(src[0], gamma[0], dst, cmpop);
+ }
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL_BUT_8S, 1, 1);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ int cmpop;
+};
+
+
+struct CopyOp : public BaseElemWiseOp
+{
+ CopyOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ src[0].copyTo(dst, mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ cvtest::copy(src[0], dst, mask);
+ }
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ int cmpop;
+};
+
+
+struct SetOp : public BaseElemWiseOp
+{
+ SetOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+SUPPORT_MASK, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>&, Mat& dst, const Mat& mask)
+ {
+ dst.setTo(gamma, mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ cvtest::set(dst, gamma, mask);
+ }
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+template<typename _Tp, typename _WTp> static void
+inRangeS_(const _Tp* src, const _WTp* a, const _WTp* b, uchar* dst, size_t total, int cn)
+{
+ size_t i;
+ int c;
+ for( i = 0; i < total; i++ )
+ {
+ _Tp val = src[i*cn];
+ dst[i] = a[0] <= val && val < b[0] ? 255 : 0;
+ }
+ for( c = 1; c < cn; c++ )
+ {
+ for( i = 0; i < total; i++ )
+ {
+ _Tp val = src[i*cn + c];
+ dst[i] = a[c] <= val && val < b[c] ? dst[i] : 0;
+ }
+ }
}
-static double getArithmMaxErr(int depth)
+template<typename _Tp> static void inRange_(const _Tp* src, const _Tp* a, const _Tp* b, uchar* dst, size_t total, int cn)
{
- return depth < CV_32F ? 0 : 4;
+ size_t i;
+ int c;
+ for( i = 0; i < total; i++ )
+ {
+ _Tp val = src[i*cn];
+ dst[i] = a[i*cn] <= val && val < b[i*cn] ? 255 : 0;
+ }
+ for( c = 1; c < cn; c++ )
+ {
+ for( i = 0; i < total; i++ )
+ {
+ _Tp val = src[i*cn + c];
+ dst[i] = a[i*cn + c] <= val && val < b[i*cn + c] ? dst[i] : 0;
+ }
+ }
+}
+
+
+static void inRange(const Mat& src, const Mat& lb, const Mat& rb, Mat& dst)
+{
+ CV_Assert( src.type() == lb.type() && src.type() == rb.type() &&
+ src.size == lb.size && src.size == rb.size );
+ dst.create( src.dims, &src.size[0], CV_8U );
+ const Mat *arrays[]={&src, &lb, &rb, &dst, 0};
+ Mat planes[4];
+
+ NAryMatIterator it(arrays, planes);
+ size_t total = planes[0].total();
+ int i, nplanes = it.nplanes, depth = src.depth(), cn = src.channels();
+
+ for( i = 0; i < nplanes; i++, ++it )
+ {
+ const uchar* sptr = planes[0].data;
+ const uchar* aptr = planes[1].data;
+ const uchar* bptr = planes[2].data;
+ uchar* dptr = planes[3].data;
+
+ switch( depth )
+ {
+ case CV_8U:
+ inRange_((const uchar*)sptr, (const uchar*)aptr, (const uchar*)bptr, dptr, total, cn);
+ break;
+ case CV_8S:
+ inRange_((const schar*)sptr, (const schar*)aptr, (const schar*)bptr, dptr, total, cn);
+ break;
+ case CV_16U:
+ inRange_((const ushort*)sptr, (const ushort*)aptr, (const ushort*)bptr, dptr, total, cn);
+ break;
+ case CV_16S:
+ inRange_((const short*)sptr, (const short*)aptr, (const short*)bptr, dptr, total, cn);
+ break;
+ case CV_32S:
+ inRange_((const int*)sptr, (const int*)aptr, (const int*)bptr, dptr, total, cn);
+ break;
+ case CV_32F:
+ inRange_((const float*)sptr, (const float*)aptr, (const float*)bptr, dptr, total, cn);
+ break;
+ case CV_64F:
+ inRange_((const double*)sptr, (const double*)aptr, (const double*)bptr, dptr, total, cn);
+ break;
+ default:
+ CV_Error(CV_StsUnsupportedFormat, "");
+ }
+ }
+}
+
+
+static void inRangeS(const Mat& src, const Scalar& lb, const Scalar& rb, Mat& dst)
+{
+ dst.create( src.dims, &src.size[0], CV_8U );
+ const Mat *arrays[]={&src, &dst, 0};
+ Mat planes[2];
+
+ NAryMatIterator it(arrays, planes);
+ size_t total = planes[0].total();
+ int i, nplanes = it.nplanes, depth = src.depth(), cn = src.channels();
+ double lbuf[4], rbuf[4];
+ int wtype = CV_MAKETYPE(depth <= CV_32S ? CV_32S : depth, cn);
+ scalarToRawData(lb, lbuf, wtype, cn);
+ scalarToRawData(rb, rbuf, wtype, cn);
+
+ for( i = 0; i < nplanes; i++, ++it )
+ {
+ const uchar* sptr = planes[0].data;
+ uchar* dptr = planes[1].data;
+
+ switch( depth )
+ {
+ case CV_8U:
+ inRangeS_((const uchar*)sptr, (const int*)lbuf, (const int*)rbuf, dptr, total, cn);
+ break;
+ case CV_8S:
+ inRangeS_((const schar*)sptr, (const int*)lbuf, (const int*)rbuf, dptr, total, cn);
+ break;
+ case CV_16U:
+ inRangeS_((const ushort*)sptr, (const int*)lbuf, (const int*)rbuf, dptr, total, cn);
+ break;
+ case CV_16S:
+ inRangeS_((const short*)sptr, (const int*)lbuf, (const int*)rbuf, dptr, total, cn);
+ break;
+ case CV_32S:
+ inRangeS_((const int*)sptr, (const int*)lbuf, (const int*)rbuf, dptr, total, cn);
+ break;
+ case CV_32F:
+ inRangeS_((const float*)sptr, (const float*)lbuf, (const float*)rbuf, dptr, total, cn);
+ break;
+ case CV_64F:
+ inRangeS_((const double*)sptr, (const double*)lbuf, (const double*)rbuf, dptr, total, cn);
+ break;
+ default:
+ CV_Error(CV_StsUnsupportedFormat, "");
+ }
+ }
}
+
+
+struct InRangeSOp : public BaseElemWiseOp
+{
+ InRangeSOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::inRange(src[0], gamma, gamma1, dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::inRangeS(src[0], gamma, gamma1, dst);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ void generateScalars(int depth, RNG& rng)
+ {
+ BaseElemWiseOp::generateScalars(depth, rng);
+ Scalar temp = gamma;
+ BaseElemWiseOp::generateScalars(depth, rng);
+ for( int i = 0; i < 4; i++ )
+ {
+ gamma1[i] = std::max(gamma[i], temp[i]);
+ gamma[i] = std::min(gamma[i], temp[i]);
+ }
+ }
+ Scalar gamma1;
+};
-TEST(ArithmTest, add)
+
+struct InRangeOp : public BaseElemWiseOp
{
+ InRangeOp() : BaseElemWiseOp(3, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat lb, rb;
+ cvtest::min(src[1], src[2], lb);
+ cvtest::max(src[1], src[2], rb);
+
+ cv::inRange(src[0], lb, rb, dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat lb, rb;
+ cvtest::min(src[1], src[2], lb);
+ cvtest::max(src[1], src[2], rb);
+
+ cvtest::inRange(src[0], lb, rb, dst);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+
+struct ConvertScaleOp : public BaseElemWiseOp
+{
+ ConvertScaleOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)), ddepth(0) { };
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ src[0].convertTo(dst, ddepth, alpha, gamma[0]);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::convert(src[0], dst, CV_MAKETYPE(ddepth, src[0].channels()), alpha, gamma[0]);
+ }
+ int getRandomType(RNG& rng)
+ {
+ int srctype = cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
+ ddepth = cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, 1);
+ return srctype;
+ }
+ int getMaxErr(int)
+ {
+ return ddepth <= CV_32S ? 2 : ddepth < CV_64F ? (1 << 14) : (1 << 18);
+ }
+ void generateScalars(int depth, RNG& rng)
+ {
+ if( rng.uniform(0, 2) )
+ BaseElemWiseOp::generateScalars(depth, rng);
+ else
+ {
+ alpha = 1;
+ gamma = Scalar::all(0);
+ }
+ }
+ int ddepth;
+};
+
+
+struct ConvertScaleAbsOp : public BaseElemWiseOp
+{
+ ConvertScaleAbsOp() : BaseElemWiseOp(1, FIX_BETA+REAL_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::convertScaleAbs(src[0], dst, alpha, gamma[0]);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::add(src[0], alpha, Mat(), 0, Scalar::all(gamma[0]), dst, CV_8UC(src[0].channels()), true);
+ }
+ void generateScalars(int depth, RNG& rng)
+ {
+ if( rng.uniform(0, 2) )
+ BaseElemWiseOp::generateScalars(depth, rng);
+ else
+ {
+ alpha = 1;
+ gamma = Scalar::all(0);
+ }
+ }
+};
+
+
+static void flip(const Mat& src, Mat& dst, int flipcode)
+{
+ CV_Assert(src.dims == 2);
+ dst.create(src.size(), src.type());
+ int i, j, k, esz = (int)src.elemSize(), width = src.cols*esz;
+
+ for( i = 0; i < dst.rows; i++ )
+ {
+ const uchar* sptr = src.ptr(flipcode == 1 ? i : dst.rows - i - 1);
+ uchar* dptr = dst.ptr(i);
+ if( flipcode == 0 )
+ memcpy(dptr, sptr, width);
+ else
+ {
+ for( j = 0; j < width; j += esz )
+ for( k = 0; k < esz; k++ )
+ dptr[j + k] = sptr[width - j - esz + k];
+ }
+ }
+}
+
+
+static void setIdentity(Mat& dst, const Scalar& s)
+{
+ CV_Assert( dst.dims == 2 && dst.channels() <= 4 );
+ double buf[4];
+ scalarToRawData(s, buf, dst.type(), 0);
+ int i, k, esz = (int)dst.elemSize(), width = dst.cols*esz;
+
+ for( i = 0; i < dst.rows; i++ )
+ {
+ uchar* dptr = dst.ptr(i);
+ memset( dptr, 0, width );
+ if( i < dst.cols )
+ for( k = 0; k < esz; k++ )
+ dptr[i*esz + k] = ((uchar*)buf)[k];
+ }
+}
+
+
+struct FlipOp : public BaseElemWiseOp
+{
+ FlipOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void getRandomSize(RNG& rng, vector<int>& size)
+ {
+ cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::flip(src[0], dst, flipcode);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::flip(src[0], dst, flipcode);
+ }
+ void generateScalars(int depth, RNG& rng)
+ {
+ flipcode = rng.uniform(0, 3) - 1;
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+ int flipcode;
+};
+
+struct TransposeOp : public BaseElemWiseOp
+{
+ TransposeOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void getRandomSize(RNG& rng, vector<int>& size)
+ {
+ cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::transpose(src[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::transpose(src[0], dst);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+struct SetIdentityOp : public BaseElemWiseOp
+{
+ SetIdentityOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA, 1, 1, Scalar::all(0)) {};
+ void getRandomSize(RNG& rng, vector<int>& size)
+ {
+ cvtest::randomSize(rng, 2, 2, cvtest::ARITHM_MAX_SIZE_LOG, size);
+ }
+ void op(const vector<Mat>&, Mat& dst, const Mat&)
+ {
+ cv::setIdentity(dst, gamma);
+ }
+ void refop(const vector<Mat>&, Mat& dst, const Mat&)
+ {
+ cvtest::setIdentity(dst, gamma);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+struct SetZeroOp : public BaseElemWiseOp
+{
+ SetZeroOp() : BaseElemWiseOp(0, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ void op(const vector<Mat>&, Mat& dst, const Mat&)
+ {
+ dst = Scalar::all(0);
+ }
+ void refop(const vector<Mat>&, Mat& dst, const Mat&)
+ {
+ cvtest::set(dst, Scalar::all(0));
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+
+static void exp(const Mat& src, Mat& dst)
+{
+ dst.create( src.dims, &src.size[0], src.type() );
+ const Mat *arrays[]={&src, &dst, 0};
+ Mat planes[2];
+
+ NAryMatIterator it(arrays, planes);
+ size_t j, total = planes[0].total()*src.channels();
+ int i, nplanes = it.nplanes, depth = src.depth();
+
+ for( i = 0; i < nplanes; i++, ++it )
+ {
+ const uchar* sptr = planes[0].data;
+ uchar* dptr = planes[1].data;
+
+ if( depth == CV_32F )
+ {
+ for( j = 0; j < total; j++ )
+ ((float*)dptr)[j] = std::exp(((const float*)sptr)[j]);
+ }
+ else if( depth == CV_64F )
+ {
+ for( j = 0; j < total; j++ )
+ ((double*)dptr)[j] = std::exp(((const double*)sptr)[j]);
+ }
+ }
+}
+
+static void log(const Mat& src, Mat& dst)
+{
+ dst.create( src.dims, &src.size[0], src.type() );
+ const Mat *arrays[]={&src, &dst, 0};
+ Mat planes[2];
+
+ NAryMatIterator it(arrays, planes);
+ size_t j, total = planes[0].total()*src.channels();
+ int i, nplanes = it.nplanes, depth = src.depth();
+
+ for( i = 0; i < nplanes; i++, ++it )
+ {
+ const uchar* sptr = planes[0].data;
+ uchar* dptr = planes[1].data;
+
+ if( depth == CV_32F )
+ {
+ for( j = 0; j < total; j++ )
+ ((float*)dptr)[j] = (float)std::log(fabs(((const float*)sptr)[j]));
+ }
+ else if( depth == CV_64F )
+ {
+ for( j = 0; j < total; j++ )
+ ((double*)dptr)[j] = std::log(fabs(((const double*)sptr)[j]));
+ }
+ }
+}
+
+struct ExpOp : public BaseElemWiseOp
+{
+ ExpOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
+ }
+ void getValueRange(int depth, double& minval, double& maxval)
+ {
+ maxval = depth == CV_32F ? 50 : 100;
+ minval = -maxval;
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cv::exp(src[0], dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ cvtest::exp(src[0], dst);
+ }
+ int getMaxErr(int)
+ {
+ return (1<<10);
+ }
+};
+
+
+struct LogOp : public BaseElemWiseOp
+{
+ LogOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0)) {};
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_FLT, 1, ARITHM_MAX_CHANNELS);
+ }
+ void getValueRange(int depth, double& minval, double& maxval)
+ {
+ maxval = depth == CV_32F ? 50 : 100;
+ minval = -maxval;
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat temp;
+ cvtest::exp(src[0], temp);
+ cv::log(temp, dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat temp;
+ cvtest::exp(src[0], temp);
+ cvtest::log(temp, dst);
+ }
+ int getMaxErr(int)
+ {
+ return (1<<10);
+ }
+};
+
+
+static void cartToPolar(const Mat& mx, const Mat& my, Mat& mmag, Mat& mangle, bool angleInDegrees)
+{
+ CV_Assert( (mx.type() == CV_32F || mx.type() == CV_64F) &&
+ mx.type() == my.type() && mx.size == my.size );
+ mmag.create( mx.dims, &mx.size[0], mx.type() );
+ mangle.create( mx.dims, &mx.size[0], mx.type() );
+ const Mat *arrays[]={&mx, &my, &mmag, &mangle, 0};
+ Mat planes[4];
+
+ NAryMatIterator it(arrays, planes);
+ size_t j, total = planes[0].total();
+ int i, nplanes = it.nplanes, depth = mx.depth();
+ double scale = angleInDegrees ? 180/CV_PI : 1;
+
+ for( i = 0; i < nplanes; i++, ++it )
+ {
+ if( depth == CV_32F )
+ {
+ const float* xptr = (const float*)planes[0].data;
+ const float* yptr = (const float*)planes[1].data;
+ float* mptr = (float*)planes[2].data;
+ float* aptr = (float*)planes[3].data;
+
+ for( j = 0; j < total; j++ )
+ {
+ mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
+ double a = atan2((double)yptr[j], (double)xptr[j]);
+ if( a < 0 ) a += CV_PI*2;
+ aptr[j] = (float)(a*scale);
+ }
+ }
+ else
+ {
+ const double* xptr = (const double*)planes[0].data;
+ const double* yptr = (const double*)planes[1].data;
+ double* mptr = (double*)planes[2].data;
+ double* aptr = (double*)planes[3].data;
+
+ for( j = 0; j < total; j++ )
+ {
+ mptr[j] = std::sqrt(xptr[j]*xptr[j] + yptr[j]*yptr[j]);
+ double a = atan2(yptr[j], xptr[j]);
+ if( a < 0 ) a += CV_PI*2;
+ aptr[j] = a*scale;
+ }
+ }
+ }
+}
+
+
+struct CartToPolarToCartOp : public BaseElemWiseOp
+{
+ CartToPolarToCartOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA, 1, 1, Scalar::all(0))
+ {
+ context = 3;
+ angleInDegrees = true;
+ }
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_FLT, 1, 1);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat mag, angle, x, y;
+
+ cv::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
+ cv::polarToCart(mag, angle, x, y, angleInDegrees);
+
+ Mat msrc[] = {mag, angle, x, y};
+ int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
+ dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
+ cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ Mat mag, angle;
+ cvtest::cartToPolar(src[0], src[1], mag, angle, angleInDegrees);
+ Mat msrc[] = {mag, angle, src[0], src[1]};
+ int pairs[] = {0, 0, 1, 1, 2, 2, 3, 3};
+ dst.create(src[0].dims, src[0].size, CV_MAKETYPE(src[0].depth(), 4));
+ cv::mixChannels(msrc, 4, &dst, 1, pairs, 4);
+ }
+ void generateScalars(int, RNG& rng)
+ {
+ angleInDegrees = rng.uniform(0, 2) != 0;
+ }
+ int getMaxErr(int)
+ {
+ return (1<<10);
+ }
+ bool angleInDegrees;
+};
+
+
+struct MeanOp : public BaseElemWiseOp
+{
+ MeanOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
+ {
+ context = 3;
+ };
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ dst.create(1, 1, CV_64FC4);
+ dst.at<Scalar>(0,0) = cv::mean(src[0], mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ dst.create(1, 1, CV_64FC4);
+ dst.at<Scalar>(0,0) = cvtest::mean(src[0], mask);
+ }
+ int getMaxErr(int)
+ {
+ return (1<<13);
+ }
+};
+
+
+struct SumOp : public BaseElemWiseOp
+{
+ SumOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
+ {
+ context = 3;
+ };
+ void op(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ dst.create(1, 1, CV_64FC4);
+ dst.at<Scalar>(0,0) = cv::sum(src[0]);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat&)
+ {
+ dst.create(1, 1, CV_64FC4);
+ dst.at<Scalar>(0,0) = cvtest::mean(src[0])*(double)src[0].total();
+ }
+ int getMaxErr(int)
+ {
+ return (1<<13);
+ }
+};
+
+
+struct CountNonZeroOp : public BaseElemWiseOp
+{
+ CountNonZeroOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SCALAR_OUTPUT+SUPPORT_MASK, 1, 1, Scalar::all(0))
+ {}
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, 1);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ src[0].copyTo(temp);
+ if( !mask.empty() )
+ temp.setTo(Scalar::all(0), mask);
+ dst.create(1, 1, CV_32S);
+ dst.at<int>(0,0) = cv::countNonZero(temp);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ cvtest::compare(src[0], 0, temp, CMP_NE);
+ if( !mask.empty() )
+ cvtest::set(temp, Scalar::all(0), mask);
+ dst.create(1, 1, CV_32S);
+ dst.at<int>(0,0) = saturate_cast<int>(cvtest::mean(temp)[0]/255*temp.total());
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+
+struct MeanStdDevOp : public BaseElemWiseOp
+{
+ MeanStdDevOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
+ {
+ context = 7;
+ };
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ dst.create(1, 2, CV_64FC4);
+ cv::meanStdDev(src[0], dst.at<Scalar>(0,0), dst.at<Scalar>(0,1), mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ Mat temp;
+ cvtest::convert(src[0], temp, CV_64F);
+ cvtest::multiply(temp, temp, temp);
+ Scalar mean = cvtest::mean(src[0], mask);
+ Scalar sqmean = cvtest::mean(temp, mask);
+
+ for( int c = 0; c < 4; c++ )
+ sqmean[c] = std::sqrt(std::max(sqmean[c] - mean[c]*mean[c], 0.));
+
+ dst.create(1, 2, CV_64FC4);
+ dst.at<Scalar>(0,0) = mean;
+ dst.at<Scalar>(0,1) = sqmean;
+ }
+ int getMaxErr(int)
+ {
+ return (1<<13);
+ }
+};
+
+
+struct NormOp : public BaseElemWiseOp
+{
+ NormOp() : BaseElemWiseOp(2, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
+ {
+ context = 1;
+ normType = 0;
+ };
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL_BUT_8S, 1, 4);
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ dst.create(1, 2, CV_64FC1);
+ dst.at<double>(0,0) = cv::norm(src[0], normType, mask);
+ dst.at<double>(0,1) = cv::norm(src[0], src[1], normType, mask);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ dst.create(1, 2, CV_64FC1);
+ dst.at<double>(0,0) = cvtest::norm(src[0], normType, mask);
+ dst.at<double>(0,1) = cvtest::norm(src[0], src[1], normType, mask);
+ }
+ void generateScalars(int, RNG& rng)
+ {
+ normType = 1 << rng.uniform(0, 3);
+ }
+ int getMaxErr(int)
+ {
+ return (1<<13);
+ }
+ int normType;
+};
+
+
+struct MinMaxLocOp : public BaseElemWiseOp
+{
+ MinMaxLocOp() : BaseElemWiseOp(1, FIX_ALPHA+FIX_BETA+FIX_GAMMA+SUPPORT_MASK+SCALAR_OUTPUT, 1, 1, Scalar::all(0))
+ {
+ context = ARITHM_MAX_NDIMS*2 + 2;
+ };
+ int getRandomType(RNG& rng)
+ {
+ return cvtest::randomType(rng, cvtest::TYPE_MASK_ALL_BUT_8S, 1, 1);
+ }
+ void saveOutput(const vector<int>& minidx, const vector<int>& maxidx,
+ double minval, double maxval, Mat& dst)
+ {
+ size_t i, ndims = minidx.size();
+ dst.create(1, (int)(ndims*2 + 2), CV_64FC1);
+
+ for( i = 0; i < ndims; i++ )
+ {
+ dst.at<double>(0,i) = minidx[i];
+ dst.at<double>(0,i+ndims) = maxidx[i];
+ }
+ dst.at<double>(0,ndims*2) = minval;
+ dst.at<double>(0,ndims*2+1) = maxval;
+ }
+ void op(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ int ndims = src[0].dims;
+ vector<int> minidx(ndims), maxidx(ndims);
+ double minval=0, maxval=0;
+ cv::minMaxIdx(src[0], &minval, &maxval, &minidx[0], &maxidx[0], mask);
+ saveOutput(minidx, maxidx, minval, maxval, dst);
+ }
+ void refop(const vector<Mat>& src, Mat& dst, const Mat& mask)
+ {
+ int ndims=src[0].dims;
+ vector<int> minidx(ndims), maxidx(ndims);
+ double minval=0, maxval=0;
+ cvtest::minMaxLoc(src[0], &minval, &maxval, &minidx, &maxidx, mask);
+ saveOutput(minidx, maxidx, minval, maxval, dst);
+ }
+ int getMaxErr(int)
+ {
+ return 0;
+ }
+};
+
+
+}
+
+typedef Ptr<cvtest::BaseElemWiseOp> ElemWiseOpPtr;
+class ElemWiseTest : public ::testing::TestWithParam<ElemWiseOpPtr> {};
+
+TEST_P(ElemWiseTest, accuracy)
+{
+ ElemWiseOpPtr op = GetParam();
+
int testIdx = 0;
- RNG rng(ARITHM_RNG_SEED);
- for( testIdx = 0; testIdx < ARITHM_NTESTS; testIdx++ )
+ RNG rng(cvtest::ARITHM_RNG_SEED);
+ for( testIdx = 0; testIdx < cvtest::ARITHM_NTESTS; testIdx++ )
{
- double minval, maxval;
vector<int> size;
- cvtest::randomSize(rng, 2, ARITHM_MAX_NDIMS, ARITHM_MAX_SIZE_LOG, size);
- int type = cvtest::randomType(rng, cvtest::TYPE_MASK_ALL, 1, ARITHM_MAX_CHANNELS);
+ op->getRandomSize(rng, size);
+ int type = op->getRandomType(rng);
int depth = CV_MAT_DEPTH(type);
- bool haveMask = rng.uniform(0, 4) == 0;
-
- getArithmValueRange(depth, minval, maxval);
- Mat src1 = cvtest::randomMat(rng, size, type, minval, maxval, true);
- Mat src2 = cvtest::randomMat(rng, size, type, minval, maxval, true);
- Mat dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false);
- Mat dst = cvtest::randomMat(rng, size, type, minval, maxval, true);
- Mat mask;
+ bool haveMask = (op->flags & cvtest::BaseElemWiseOp::SUPPORT_MASK) != 0 && rng.uniform(0, 4) == 0;
+
+ double minval=0, maxval=0;
+ op->getValueRange(depth, minval, maxval);
+ int i, ninputs = op->ninputs;
+ vector<Mat> src(ninputs);
+ for( i = 0; i < ninputs; i++ )
+ src[i] = cvtest::randomMat(rng, size, type, minval, maxval, true);
+ Mat dst0, dst, mask;
if( haveMask )
- {
mask = cvtest::randomMat(rng, size, CV_8U, 0, 2, true);
- cvtest::copy(dst0, dst);
- cvtest::add(src1, 1, src2, 1, Scalar::all(0), dst0, dst.type());
- cvtest::copy(dst, dst0, mask, true);
- add(src1, src2, dst, mask);
- }
- else
+
+ if( (haveMask || ninputs == 0) && !(op->flags & cvtest::BaseElemWiseOp::SCALAR_OUTPUT))
{
- cvtest::add(src1, 1, src2, 1, Scalar::all(0), dst0, dst.type());
- add(src1, src2, dst);
+ dst0 = cvtest::randomMat(rng, size, type, minval, maxval, false);
+ dst = cvtest::randomMat(rng, size, type, minval, maxval, true);
+ cvtest::copy(dst, dst0);
}
+ op->generateScalars(depth, rng);
- double maxErr = getArithmMaxErr(depth);
+ op->refop(src, dst0, mask);
+ op->op(src, dst, mask);
+
+ double maxErr = op->getMaxErr(depth);
vector<int> pos;
- ASSERT_TRUE(cvtest::cmpEps(dst0, dst, maxErr, &pos)) << "position: " << Mat(pos);
+ ASSERT_PRED_FORMAT2(cvtest::MatComparator(maxErr, op->context), dst0, dst) << "\nsrc[0] ~ " << cvtest::MatInfo(!src.empty() ? src[0] : Mat()) << "\ntestCase #" << testIdx << "\n";
}
}
+
+
+INSTANTIATE_TEST_CASE_P(Core_Copy, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CopyOp)));
+INSTANTIATE_TEST_CASE_P(Core_Set, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetOp)));
+INSTANTIATE_TEST_CASE_P(Core_SetZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetZeroOp)));
+INSTANTIATE_TEST_CASE_P(Core_ConvertScale, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleOp)));
+INSTANTIATE_TEST_CASE_P(Core_ConvertScaleAbs, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ConvertScaleAbsOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_Add, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddOp)));
+INSTANTIATE_TEST_CASE_P(Core_Sub, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubOp)));
+INSTANTIATE_TEST_CASE_P(Core_AddS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddSOp)));
+INSTANTIATE_TEST_CASE_P(Core_SubRS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SubRSOp)));
+INSTANTIATE_TEST_CASE_P(Core_ScaleAdd, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ScaleAddOp)));
+INSTANTIATE_TEST_CASE_P(Core_AddWeighted, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AddWeightedOp)));
+INSTANTIATE_TEST_CASE_P(Core_AbsDiff, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffOp)));
+INSTANTIATE_TEST_CASE_P(Core_AbsDiffS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::AbsDiffSOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_And, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('&'))));
+INSTANTIATE_TEST_CASE_P(Core_AndS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('&'))));
+INSTANTIATE_TEST_CASE_P(Core_Or, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('|'))));
+INSTANTIATE_TEST_CASE_P(Core_OrS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('|'))));
+INSTANTIATE_TEST_CASE_P(Core_Xor, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicOp('^'))));
+INSTANTIATE_TEST_CASE_P(Core_XorS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('^'))));
+INSTANTIATE_TEST_CASE_P(Core_Not, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogicSOp('~'))));
+
+INSTANTIATE_TEST_CASE_P(Core_Max, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxOp)));
+INSTANTIATE_TEST_CASE_P(Core_MaxS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MaxSOp)));
+INSTANTIATE_TEST_CASE_P(Core_Min, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinOp)));
+INSTANTIATE_TEST_CASE_P(Core_MinS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinSOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_Mul, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MulOp)));
+INSTANTIATE_TEST_CASE_P(Core_Div, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::DivOp)));
+INSTANTIATE_TEST_CASE_P(Core_Recip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::RecipOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_Cmp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpOp)));
+INSTANTIATE_TEST_CASE_P(Core_CmpS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CmpSOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_InRangeS, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeSOp)));
+INSTANTIATE_TEST_CASE_P(Core_InRange, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::InRangeOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_Flip, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::FlipOp)));
+INSTANTIATE_TEST_CASE_P(Core_Transpose, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::TransposeOp)));
+INSTANTIATE_TEST_CASE_P(Core_SetIdentity, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SetIdentityOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_Exp, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::ExpOp)));
+INSTANTIATE_TEST_CASE_P(Core_Log, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::LogOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_CountNonZero, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CountNonZeroOp)));
+INSTANTIATE_TEST_CASE_P(Core_Mean, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanOp)));
+INSTANTIATE_TEST_CASE_P(Core_MeanStdDev, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MeanStdDevOp)));
+INSTANTIATE_TEST_CASE_P(Core_Sum, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::SumOp)));
+INSTANTIATE_TEST_CASE_P(Core_Norm, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::NormOp)));
+INSTANTIATE_TEST_CASE_P(Core_MinMaxLoc, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::MinMaxLocOp)));
+
+INSTANTIATE_TEST_CASE_P(Core_CartToPolarToCart, ElemWiseTest, ::testing::Values(ElemWiseOpPtr(new cvtest::CartToPolarToCartOp)));
--- /dev/null
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+typedef struct CvTsSimpleSeq
+{
+ schar* array;
+ int count;
+ int max_count;
+ int elem_size;
+} CvTsSimpleSeq;
+
+
+static CvTsSimpleSeq* cvTsCreateSimpleSeq( int max_count, int elem_size )
+{
+ CvTsSimpleSeq* seq = (CvTsSimpleSeq*)cvAlloc( sizeof(*seq) + max_count * elem_size );
+ seq->elem_size = elem_size;
+ seq->max_count = max_count;
+ seq->count = 0;
+ seq->array = (schar*)(seq + 1);
+ return seq;
+}
+
+
+static void cvTsReleaseSimpleSeq( CvTsSimpleSeq** seq )
+{
+ cvFree( seq );
+}
+
+
+static schar* cvTsSimpleSeqElem( CvTsSimpleSeq* seq, int index )
+{
+ assert( 0 <= index && index < seq->count );
+ return seq->array + index * seq->elem_size;
+}
+
+
+static void cvTsClearSimpleSeq( CvTsSimpleSeq* seq )
+{
+ seq->count = 0;
+}
+
+
+static void cvTsSimpleSeqShiftAndCopy( CvTsSimpleSeq* seq, int from_idx, int to_idx, void* elem=0 )
+{
+ int elem_size = seq->elem_size;
+
+ if( from_idx == to_idx )
+ return;
+ assert( (from_idx > to_idx && !elem) || (from_idx < to_idx && elem) );
+
+ if( from_idx < seq->count )
+ {
+ memmove( seq->array + to_idx*elem_size, seq->array + from_idx*elem_size,
+ (seq->count - from_idx)*elem_size );
+ }
+ seq->count += to_idx - from_idx;
+ if( elem && to_idx > from_idx )
+ memcpy( seq->array + from_idx*elem_size, elem, (to_idx - from_idx)*elem_size );
+}
+
+static void cvTsSimpleSeqInvert( CvTsSimpleSeq* seq )
+{
+ int i, k, len = seq->count, elem_size = seq->elem_size;
+ schar *data = seq->array, t;
+
+ for( i = 0; i < len/2; i++ )
+ {
+ schar* a = data + i*elem_size;
+ schar* b = data + (len - i - 1)*elem_size;
+ for( k = 0; k < elem_size; k++ )
+ CV_SWAP( a[k], b[k], t );
+ }
+}
+
+/****************************************************************************************\
+ * simple cvset implementation *
+ \****************************************************************************************/
+
+typedef struct CvTsSimpleSet
+{
+ schar* array;
+ int count, max_count;
+ int elem_size;
+ int* free_stack;
+ int free_count;
+} CvTsSimpleSet;
+
+
+static void cvTsClearSimpleSet( CvTsSimpleSet* set_header )
+{
+ int i;
+ int elem_size = set_header->elem_size;
+
+ for( i = 0; i < set_header->max_count; i++ )
+ {
+ set_header->array[i*elem_size] = 0;
+ set_header->free_stack[i] = set_header->max_count - i - 1;
+ }
+ set_header->free_count = set_header->max_count;
+ set_header->count = 0;
+}
+
+
+static CvTsSimpleSet* cvTsCreateSimpleSet( int max_count, int elem_size )
+{
+ CvTsSimpleSet* set_header = (CvTsSimpleSet*)cvAlloc( sizeof(*set_header) + max_count *
+ (elem_size + 1 + sizeof(int)));
+ set_header->elem_size = elem_size + 1;
+ set_header->max_count = max_count;
+ set_header->free_stack = (int*)(set_header + 1);
+ set_header->array = (schar*)(set_header->free_stack + max_count);
+
+ cvTsClearSimpleSet( set_header );
+ return set_header;
+}
+
+
+static void cvTsReleaseSimpleSet( CvTsSimpleSet** set_header )
+{
+ cvFree( set_header );
+}
+
+
+static schar* cvTsSimpleSetFind( CvTsSimpleSet* set_header, int index )
+{
+ int idx = index * set_header->elem_size;
+ assert( 0 <= index && index < set_header->max_count );
+ return set_header->array[idx] ? set_header->array + idx + 1 : 0;
+}
+
+
+static int cvTsSimpleSetAdd( CvTsSimpleSet* set_header, void* elem )
+{
+ int idx, idx2;
+ assert( set_header->free_count > 0 );
+
+ idx = set_header->free_stack[--set_header->free_count];
+ idx2 = idx * set_header->elem_size;
+ assert( set_header->array[idx2] == 0 );
+ set_header->array[idx2] = 1;
+ if( set_header->elem_size > 1 )
+ memcpy( set_header->array + idx2 + 1, elem, set_header->elem_size - 1 );
+ set_header->count = MAX( set_header->count, idx + 1 );
+
+ return idx;
+}
+
+
+static void cvTsSimpleSetRemove( CvTsSimpleSet* set_header, int index )
+{
+ assert( set_header->free_count < set_header->max_count &&
+ 0 <= index && index < set_header->max_count );
+ assert( set_header->array[index * set_header->elem_size] == 1 );
+
+ set_header->free_stack[set_header->free_count++] = index;
+ set_header->array[index * set_header->elem_size] = 0;
+}
+
+
+/****************************************************************************************\
+ * simple graph implementation *
+ \****************************************************************************************/
+
+typedef struct CvTsSimpleGraph
+{
+ char* matrix;
+ int edge_size;
+ int oriented;
+ CvTsSimpleSet* vtx;
+} CvTsSimpleGraph;
+
+
+static void cvTsClearSimpleGraph( CvTsSimpleGraph* graph )
+{
+ int max_vtx_count = graph->vtx->max_count;
+ cvTsClearSimpleSet( graph->vtx );
+ memset( graph->matrix, 0, max_vtx_count * max_vtx_count * graph->edge_size );
+}
+
+
+static CvTsSimpleGraph* cvTsCreateSimpleGraph( int max_vtx_count, int vtx_size,
+ int edge_size, int oriented )
+{
+ CvTsSimpleGraph* graph;
+
+ assert( max_vtx_count > 1 && vtx_size >= 0 && edge_size >= 0 );
+ graph = (CvTsSimpleGraph*)cvAlloc( sizeof(*graph) +
+ max_vtx_count * max_vtx_count * (edge_size + 1));
+ graph->vtx = cvTsCreateSimpleSet( max_vtx_count, vtx_size );
+ graph->edge_size = edge_size + 1;
+ graph->matrix = (char*)(graph + 1);
+ graph->oriented = oriented;
+
+ cvTsClearSimpleGraph( graph );
+ return graph;
+}
+
+
+static void cvTsReleaseSimpleGraph( CvTsSimpleGraph** graph )
+{
+ if( *graph )
+ {
+ cvTsReleaseSimpleSet( &(graph[0]->vtx) );
+ cvFree( graph );
+ }
+}
+
+
+static int cvTsSimpleGraphAddVertex( CvTsSimpleGraph* graph, void* vertex )
+{
+ return cvTsSimpleSetAdd( graph->vtx, vertex );
+}
+
+
+static void cvTsSimpleGraphRemoveVertex( CvTsSimpleGraph* graph, int index )
+{
+ int i, max_vtx_count = graph->vtx->max_count;
+ int edge_size = graph->edge_size;
+ cvTsSimpleSetRemove( graph->vtx, index );
+
+ /* remove all the corresponding edges */
+ for( i = 0; i < max_vtx_count; i++ )
+ {
+ graph->matrix[(i*max_vtx_count + index)*edge_size] =
+ graph->matrix[(index*max_vtx_count + i)*edge_size] = 0;
+ }
+}
+
+
+static void cvTsSimpleGraphAddEdge( CvTsSimpleGraph* graph, int idx1, int idx2, void* edge )
+{
+ int i, t, n = graph->oriented ? 1 : 2;
+
+ assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
+ cvTsSimpleSetFind( graph->vtx, idx2 ));
+
+ for( i = 0; i < n; i++ )
+ {
+ int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
+ assert( graph->matrix[ofs] == 0 );
+ graph->matrix[ofs] = 1;
+ if( graph->edge_size > 1 )
+ memcpy( graph->matrix + ofs + 1, edge, graph->edge_size - 1 );
+
+ CV_SWAP( idx1, idx2, t );
+ }
+}
+
+
+static void cvTsSimpleGraphRemoveEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
+{
+ int i, t, n = graph->oriented ? 1 : 2;
+
+ assert( cvTsSimpleSetFind( graph->vtx, idx1 ) &&
+ cvTsSimpleSetFind( graph->vtx, idx2 ));
+
+ for( i = 0; i < n; i++ )
+ {
+ int ofs = (idx1*graph->vtx->max_count + idx2)*graph->edge_size;
+ assert( graph->matrix[ofs] == 1 );
+ graph->matrix[ofs] = 0;
+ CV_SWAP( idx1, idx2, t );
+ }
+}
+
+
+static schar* cvTsSimpleGraphFindVertex( CvTsSimpleGraph* graph, int index )
+{
+ return cvTsSimpleSetFind( graph->vtx, index );
+}
+
+
+static char* cvTsSimpleGraphFindEdge( CvTsSimpleGraph* graph, int idx1, int idx2 )
+{
+ if( cvTsSimpleGraphFindVertex( graph, idx1 ) &&
+ cvTsSimpleGraphFindVertex( graph, idx2 ))
+ {
+ char* edge = graph->matrix + (idx1 * graph->vtx->max_count + idx2)*graph->edge_size;
+ if( edge[0] ) return edge + 1;
+ }
+ return 0;
+}
+
+
+static int cvTsSimpleGraphVertexDegree( CvTsSimpleGraph* graph, int index )
+{
+ int i, count = 0;
+ int edge_size = graph->edge_size;
+ int max_vtx_count = graph->vtx->max_count;
+ assert( cvTsSimpleGraphFindVertex( graph, index ) != 0 );
+
+ for( i = 0; i < max_vtx_count; i++ )
+ {
+ count += graph->matrix[(i*max_vtx_count + index)*edge_size] +
+ graph->matrix[(index*max_vtx_count + i)*edge_size];
+ }
+
+ if( !graph->oriented )
+ {
+ assert( count % 2 == 0 );
+ count /= 2;
+ }
+ return count;
+}
+
+
+///////////////////////////////////// the tests //////////////////////////////////
+
+#define CV_TS_SEQ_CHECK_CONDITION( expr, err_msg ) \
+if( !(expr) ) \
+{ \
+set_error_context( #expr, err_msg, __FILE__, __LINE__ ); \
+ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );\
+throw -1; \
+}
+
+class Core_DynStructBaseTest : public cvtest::BaseTest
+{
+public:
+ Core_DynStructBaseTest();
+ virtual ~Core_DynStructBaseTest();
+ bool can_do_fast_forward();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void run_func(void);
+ void set_error_context( const char* condition,
+ const char* err_msg,
+ const char* file, int line );
+ int test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total );
+ void update_progressbar();
+
+ int struct_count, max_struct_size, iterations, generations;
+ int min_log_storage_block_size, max_log_storage_block_size;
+ int min_log_elem_size, max_log_elem_size;
+ int gen, struct_idx, iter;
+ int test_progress;
+ int64 start_time;
+ double cpu_freq;
+ vector<void*> cxcore_struct;
+ vector<void*> simple_struct;
+ Ptr<CvMemStorage> storage;
+};
+
+
+Core_DynStructBaseTest::Core_DynStructBaseTest()
+{
+ struct_count = 2;
+ max_struct_size = 2000;
+ min_log_storage_block_size = 7;
+ max_log_storage_block_size = 12;
+ min_log_elem_size = 0;
+ max_log_elem_size = 8;
+ generations = 10;
+ iterations = max_struct_size*2;
+ gen = struct_idx = iter = -1;
+ test_progress = -1;
+
+ storage = 0;
+}
+
+
+Core_DynStructBaseTest::~Core_DynStructBaseTest()
+{
+ clear();
+}
+
+
+void Core_DynStructBaseTest::run_func()
+{
+}
+
+bool Core_DynStructBaseTest::can_do_fast_forward()
+{
+ return false;
+}
+
+
+void Core_DynStructBaseTest::clear()
+{
+ cvtest::BaseTest::clear();
+}
+
+
+int Core_DynStructBaseTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ double sqrt_scale = sqrt(ts->get_test_case_count_scale());
+ if( code < 0 )
+ return code;
+
+ struct_count = cvReadInt( find_param( fs, "struct_count" ), struct_count );
+ max_struct_size = cvReadInt( find_param( fs, "max_struct_size" ), max_struct_size );
+ generations = cvReadInt( find_param( fs, "generations" ), generations );
+ iterations = cvReadInt( find_param( fs, "iterations" ), iterations );
+ generations = cvRound(generations*sqrt_scale);
+ iterations = cvRound(iterations*sqrt_scale);
+
+ min_log_storage_block_size = cvReadInt( find_param( fs, "min_log_storage_block_size" ),
+ min_log_storage_block_size );
+ max_log_storage_block_size = cvReadInt( find_param( fs, "max_log_storage_block_size" ),
+ max_log_storage_block_size );
+ min_log_elem_size = cvReadInt( find_param( fs, "min_log_elem_size" ), min_log_elem_size );
+ max_log_elem_size = cvReadInt( find_param( fs, "max_log_elem_size" ), max_log_elem_size );
+
+ struct_count = cvtest::clipInt( struct_count, 1, 100 );
+ max_struct_size = cvtest::clipInt( max_struct_size, 1, 1<<20 );
+ generations = cvtest::clipInt( generations, 1, 100 );
+ iterations = cvtest::clipInt( iterations, 100, 1<<20 );
+
+ min_log_storage_block_size = cvtest::clipInt( min_log_storage_block_size, 7, 20 );
+ max_log_storage_block_size = cvtest::clipInt( max_log_storage_block_size,
+ min_log_storage_block_size, 20 );
+
+ min_log_elem_size = cvtest::clipInt( min_log_elem_size, 0, 8 );
+ max_log_elem_size = cvtest::clipInt( max_log_elem_size, min_log_elem_size, 10 );
+
+ return 0;
+}
+
+
+void Core_DynStructBaseTest::update_progressbar()
+{
+ int64 t;
+
+ if( test_progress < 0 )
+ {
+ test_progress = 0;
+ cpu_freq = cv::getTickFrequency();
+ start_time = cv::getTickCount();
+ }
+
+ t = cv::getTickCount();
+ test_progress = update_progress( test_progress, 0, 0, (double)(t - start_time)/cpu_freq );
+}
+
+
+void Core_DynStructBaseTest::set_error_context( const char* condition,
+ const char* err_msg,
+ const char* filename, int lineno )
+{
+ ts->printf( cvtest::TS::LOG, "file %s, line %d: %s\n(\"%s\" failed).\n"
+ "generation = %d, struct_idx = %d, iter = %d\n",
+ filename, lineno, err_msg, condition, gen, struct_idx, iter );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+}
+
+
+int Core_DynStructBaseTest::test_seq_block_consistence( int _struct_idx, CvSeq* seq, int total )
+{
+ int sum = 0;
+ struct_idx = _struct_idx;
+
+ CV_TS_SEQ_CHECK_CONDITION( seq != 0, "Null sequence pointer" );
+
+ if( seq->first )
+ {
+ CvSeqBlock* block = seq->first;
+ CvSeqBlock* prev_block = block->prev;
+
+ int delta_idx = seq->first->start_index;
+
+ for( ;; )
+ {
+ CV_TS_SEQ_CHECK_CONDITION( sum == block->start_index - delta_idx &&
+ block->count > 0 && block->prev == prev_block &&
+ prev_block->next == block,
+ "sequence blocks are inconsistent" );
+ sum += block->count;
+ prev_block = block;
+ block = block->next;
+ if( block == seq->first ) break;
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( block->prev->count * seq->elem_size +
+ block->prev->data <= seq->block_max,
+ "block->data or block_max pointer are incorrect" );
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == sum && sum == total,
+ "total number of elements is incorrect" );
+
+ return 0;
+}
+
+
+/////////////////////////////////// sequence tests ////////////////////////////////////
+
+class Core_SeqBaseTest : public Core_DynStructBaseTest
+{
+public:
+ Core_SeqBaseTest();
+ void clear();
+ void run( int );
+
+protected:
+ int test_multi_create();
+ int test_get_seq_elem( int _struct_idx, int iters );
+ int test_get_seq_reading( int _struct_idx, int iters );
+ int test_seq_ops( int iters );
+};
+
+
+Core_SeqBaseTest::Core_SeqBaseTest()
+{
+}
+
+
+void Core_SeqBaseTest::clear()
+{
+ for( size_t i = 0; i < simple_struct.size(); i++ )
+ cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
+ Core_DynStructBaseTest::clear();
+}
+
+
+int Core_SeqBaseTest::test_multi_create()
+{
+ vector<CvSeqWriter> writer(struct_count);
+ vector<int> pos(struct_count);
+ vector<int> index(struct_count);
+ int cur_count, elem_size;
+ RNG& rng = ts->get_rng();
+
+ for( int i = 0; i < struct_count; i++ )
+ {
+ double t;
+ CvTsSimpleSeq* sseq;
+
+ pos[i] = -1;
+ index[i] = i;
+
+ t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
+ elem_size = cvRound( exp(t * CV_LOG2) );
+ elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) -
+ sizeof(CvSeqBlock) - sizeof(CvMemBlock)) );
+
+ cvTsReleaseSimpleSeq( (CvTsSimpleSeq**)&simple_struct[i] );
+ simple_struct[i] = sseq = cvTsCreateSimpleSeq( max_struct_size, elem_size );
+ cxcore_struct[i] = 0;
+ sseq->count = cvtest::randInt( rng ) % max_struct_size;
+ Mat m( 1, MAX(sseq->count,1)*elem_size, CV_8UC1, sseq->array );
+ cvtest::randUni( rng, m, Scalar::all(0), Scalar::all(256) );
+ }
+
+ for( cur_count = struct_count; cur_count > 0; cur_count-- )
+ {
+ for(;;)
+ {
+ int k = cvtest::randInt( rng ) % cur_count;
+ struct_idx = index[k];
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
+
+ if( pos[struct_idx] < 0 )
+ {
+ int hdr_size = (cvtest::randInt(rng) % 10)*4 + sizeof(CvSeq);
+ hdr_size = MIN( hdr_size, (int)(storage->block_size - sizeof(CvMemBlock)) );
+ elem_size = sseq->elem_size;
+
+ if( cvtest::randInt(rng) % 2 )
+ {
+ cvStartWriteSeq( 0, hdr_size, elem_size, storage, &writer[struct_idx] );
+ }
+ else
+ {
+ CvSeq* s;
+ s = cvCreateSeq( 0, hdr_size, elem_size, storage );
+ cvStartAppendToSeq( s, &writer[struct_idx] );
+ }
+
+ cvSetSeqBlockSize( writer[struct_idx].seq, cvtest::randInt( rng ) % 10000 );
+ pos[struct_idx] = 0;
+ }
+
+ update_progressbar();
+ if( pos[struct_idx] == sseq->count )
+ {
+ cxcore_struct[struct_idx] = cvEndWriteSeq( &writer[struct_idx] );
+ /* del index */
+ for( ; k < cur_count-1; k++ )
+ index[k] = index[k+1];
+ break;
+ }
+
+ {
+ schar* el = cvTsSimpleSeqElem( sseq, pos[struct_idx] );
+ CV_WRITE_SEQ_ELEM_VAR( el, writer[struct_idx] );
+ }
+ pos[struct_idx]++;
+ }
+ }
+
+ return 0;
+}
+
+
+int Core_SeqBaseTest::test_get_seq_elem( int _struct_idx, int iters )
+{
+ RNG& rng = ts->get_rng();
+
+ CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
+ struct_idx = _struct_idx;
+
+ assert( seq->total == sseq->count );
+
+ if( sseq->count == 0 )
+ return 0;
+
+ for( int i = 0; i < iters; i++ )
+ {
+ int idx = cvtest::randInt(rng) % (sseq->count*3) - sseq->count*3/2;
+ int idx0 = (unsigned)idx < (unsigned)(sseq->count) ? idx : idx < 0 ?
+ idx + sseq->count : idx - sseq->count;
+ int bad_range = (unsigned)idx0 >= (unsigned)(sseq->count);
+ schar* elem;
+ elem = cvGetSeqElem( seq, idx );
+
+ if( bad_range )
+ {
+ CV_TS_SEQ_CHECK_CONDITION( elem == 0,
+ "cvGetSeqElem doesn't "
+ "handle \"out of range\" properly" );
+ }
+ else
+ {
+ CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
+ !memcmp( elem, cvTsSimpleSeqElem(sseq, idx0), sseq->elem_size ),
+ "cvGetSeqElem returns wrong element" );
+
+ idx = cvSeqElemIdx(seq, elem );
+ CV_TS_SEQ_CHECK_CONDITION( idx >= 0 && idx == idx0,
+ "cvSeqElemIdx is incorrect" );
+ }
+ }
+
+ return 0;
+}
+
+
+int Core_SeqBaseTest::test_get_seq_reading( int _struct_idx, int iters )
+{
+ const int max_val = 3*5 + 2;
+ CvSeq* seq = (CvSeq*)cxcore_struct[_struct_idx];
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[_struct_idx];
+ int total = seq->total;
+ RNG& rng = ts->get_rng();
+ CvSeqReader reader;
+ vector<schar> _elem(sseq->elem_size);
+ schar* elem = &_elem[0];
+
+ assert( total == sseq->count );
+ this->struct_idx = _struct_idx;
+
+ int pos = cvtest::randInt(rng) % 2;
+ cvStartReadSeq( seq, &reader, pos );
+
+ if( total == 0 )
+ {
+ CV_TS_SEQ_CHECK_CONDITION( reader.ptr == 0, "Empty sequence reader pointer is not NULL" );
+ return 0;
+ }
+
+ pos = pos ? seq->total - 1 : 0;
+
+ CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos(&reader),
+ "initial reader position is wrong" );
+
+ for( iter = 0; iter < iters; iter++ )
+ {
+ int op = cvtest::randInt(rng) % max_val;
+
+ if( op >= max_val - 2 )
+ {
+ int new_pos, new_pos0;
+ int bad_range;
+ int is_relative = op == max_val - 1;
+
+ new_pos = cvtest::randInt(rng) % (total*2) - total;
+ new_pos0 = new_pos + (is_relative ? pos : 0 );
+
+ if( new_pos0 < 0 ) new_pos0 += total;
+ if( new_pos0 >= total ) new_pos0 -= total;
+
+ bad_range = (unsigned)new_pos0 >= (unsigned)total;
+ cvSetSeqReaderPos( &reader, new_pos, is_relative );
+
+ if( !bad_range )
+ {
+ CV_TS_SEQ_CHECK_CONDITION( new_pos0 == cvGetSeqReaderPos( &reader ),
+ "cvset reader position doesn't work" );
+ pos = new_pos0;
+ }
+ else
+ {
+ CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
+ "reader doesn't stay at the current position after wrong positioning" );
+ }
+ }
+ else
+ {
+ int direction = (op % 3) - 1;
+ memcpy( elem, reader.ptr, sseq->elem_size );
+
+ if( direction > 0 )
+ {
+ CV_NEXT_SEQ_ELEM( sseq->elem_size, reader );
+ }
+ else if( direction < 0 )
+ {
+ CV_PREV_SEQ_ELEM( sseq->elem_size, reader );
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( memcmp(elem, cvTsSimpleSeqElem(sseq, pos),
+ sseq->elem_size) == 0, "reading is incorrect" );
+ pos += direction;
+ if( pos < 0 ) pos += total;
+ if( pos >= total ) pos -= total;
+
+ CV_TS_SEQ_CHECK_CONDITION( pos == cvGetSeqReaderPos( &reader ),
+ "reader doesn't move correctly after reading" );
+ }
+ }
+
+ return 0;
+}
+
+
+int Core_SeqBaseTest::test_seq_ops( int iters )
+{
+ const int max_op = 14;
+ int max_elem_size = 0;
+ schar* elem2 = 0;
+ RNG& rng = ts->get_rng();
+
+ for( int i = 0; i < struct_count; i++ )
+ max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
+
+ vector<schar> elem_buf(max_struct_size*max_elem_size);
+ schar* elem = (schar*)&elem_buf[0];
+ Mat elem_mat;
+
+ for( iter = 0; iter < iters; iter++ )
+ {
+ struct_idx = cvtest::randInt(rng) % struct_count;
+ int op = cvtest::randInt(rng) % max_op;
+ CvSeq* seq = (CvSeq*)cxcore_struct[struct_idx];
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[struct_idx];
+ int elem_size = sseq->elem_size;
+ int whence = 0, pos = 0, count = 0;
+
+ switch( op )
+ {
+ case 0:
+ case 1:
+ case 2: // push/pushfront/insert
+ if( sseq->count == sseq->max_count )
+ break;
+
+ elem_mat = Mat(1, elem_size, CV_8U, elem);
+ cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
+
+ whence = op - 1;
+ if( whence < 0 )
+ {
+ pos = 0;
+ cvSeqPushFront( seq, elem );
+ }
+ else if( whence > 0 )
+ {
+ pos = sseq->count;
+ cvSeqPush( seq, elem );
+ }
+ else
+ {
+ pos = cvtest::randInt(rng) % (sseq->count + 1);
+ cvSeqInsert( seq, pos, elem );
+ }
+
+ cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + 1, elem );
+ elem2 = cvGetSeqElem( seq, pos );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "The inserted element could not be retrieved" );
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
+ memcmp(elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
+ "The inserted sequence element is wrong" );
+ break;
+
+ case 3:
+ case 4:
+ case 5: // pop/popfront/remove
+ if( sseq->count == 0 )
+ break;
+
+ whence = op - 4;
+ if( whence < 0 )
+ {
+ pos = 0;
+ cvSeqPopFront( seq, elem );
+ }
+ else if( whence > 0 )
+ {
+ pos = sseq->count-1;
+ cvSeqPop( seq, elem );
+ }
+ else
+ {
+ pos = cvtest::randInt(rng) % sseq->count;
+ cvSeqRemove( seq, pos );
+ }
+
+ if( whence != 0 )
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - 1 &&
+ memcmp( elem, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
+ "The popped sequence element isn't correct" );
+
+ cvTsSimpleSeqShiftAndCopy( sseq, pos + 1, pos );
+
+ if( sseq->count > 0 )
+ {
+ elem2 = cvGetSeqElem( seq, pos < sseq->count ? pos : -1 );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "GetSeqElem fails after removing the element" );
+
+ CV_TS_SEQ_CHECK_CONDITION( memcmp( elem2,
+ cvTsSimpleSeqElem(sseq, pos - (pos == sseq->count)), elem_size) == 0,
+ "The first shifted element is not correct after removing another element" );
+ }
+ else
+ {
+ CV_TS_SEQ_CHECK_CONDITION( seq->first == 0,
+ "The sequence doesn't become empty after the final remove" );
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 8: // push [front] multi/insert slice
+ if( sseq->count == sseq->max_count )
+ break;
+
+ count = cvtest::randInt( rng ) % (sseq->max_count - sseq->count + 1);
+ elem_mat = Mat(1, MAX(count,1) * elem_size, CV_8U, elem);
+ cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
+
+ whence = op - 7;
+ pos = whence < 0 ? 0 : whence > 0 ? sseq->count : cvtest::randInt(rng) % (sseq->count+1);
+ if( whence != 0 )
+ {
+ cvSeqPushMulti( seq, elem, count, whence < 0 );
+ }
+ else
+ {
+ CvSeq header;
+ CvSeqBlock block;
+ cvMakeSeqHeaderForArray( CV_SEQ_KIND_GENERIC, sizeof(CvSeq),
+ sseq->elem_size,
+ elem, count,
+ &header, &block );
+
+ cvSeqInsertSlice( seq, pos, &header );
+ }
+ cvTsSimpleSeqShiftAndCopy( sseq, pos, pos + count, elem );
+
+ if( sseq->count > 0 )
+ {
+ // choose the random element among the added
+ pos = count > 0 ? cvtest::randInt(rng) % count + pos : MAX(pos-1,0);
+ elem2 = cvGetSeqElem( seq, pos );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "multi push operation doesn't add elements" );
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count &&
+ memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
+ "One of the added elements is wrong" );
+ }
+ else
+ {
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
+ "Adding no elements to empty sequence fails" );
+ }
+ break;
+
+ case 9:
+ case 10:
+ case 11: // pop [front] multi
+ if( sseq->count == 0 )
+ break;
+
+ count = cvtest::randInt(rng) % (sseq->count+1);
+ whence = op - 10;
+ pos = whence < 0 ? 0 : whence > 0 ? sseq->count - count :
+ cvtest::randInt(rng) % (sseq->count - count + 1);
+
+ if( whence != 0 )
+ {
+ cvSeqPopMulti( seq, elem, count, whence < 0 );
+
+ if( count > 0 )
+ {
+ CV_TS_SEQ_CHECK_CONDITION( memcmp(elem,
+ cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
+ "The first (in the sequence order) removed element is wrong after popmulti" );
+ }
+ }
+ else
+ {
+ cvSeqRemoveSlice( seq, cvSlice(pos, pos + count) );
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == sseq->count - count,
+ "The popmulti left a wrong number of elements in the sequence" );
+
+ cvTsSimpleSeqShiftAndCopy( sseq, pos + count, pos, 0 );
+ if( sseq->count > 0 )
+ {
+ pos = whence < 0 ? 0 : MIN( pos, sseq->count - 1 );
+ elem2 = cvGetSeqElem( seq, pos );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 &&
+ memcmp( elem2, cvTsSimpleSeqElem(sseq,pos), elem_size) == 0,
+ "The last sequence element is wrong after POP" );
+ }
+ else
+ {
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
+ "The sequence doesn't become empty after final POP" );
+ }
+ break;
+ case 12: // seqslice
+ {
+ CvMemStoragePos storage_pos;
+ cvSaveMemStoragePos( storage, &storage_pos );
+
+ int copy_data = cvtest::randInt(rng) % 2;
+ count = cvtest::randInt(rng) % (seq->total + 1);
+ pos = cvtest::randInt(rng) % (seq->total - count + 1);
+ CvSeq* seq_slice = cvSeqSlice( seq, cvSlice(pos, pos + count), storage, copy_data );
+
+ CV_TS_SEQ_CHECK_CONDITION( seq_slice && seq_slice->total == count,
+ "cvSeqSlice returned incorrect slice" );
+
+ if( count > 0 )
+ {
+ int test_idx = cvtest::randInt(rng) % count;
+ elem2 = cvGetSeqElem( seq_slice, test_idx );
+ schar* elem3 = cvGetSeqElem( seq, pos + test_idx );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 &&
+ memcmp( elem2, cvTsSimpleSeqElem(sseq,pos + test_idx), elem_size) == 0,
+ "The extracted slice elements are not correct" );
+ CV_TS_SEQ_CHECK_CONDITION( (elem2 == elem3) ^ copy_data,
+ "copy_data flag is handled incorrectly" );
+ }
+
+ cvRestoreMemStoragePos( storage, &storage_pos );
+ }
+ break;
+ case 13: // clear
+ cvTsClearSimpleSeq( sseq );
+ cvClearSeq( seq );
+ CV_TS_SEQ_CHECK_CONDITION( seq->total == 0 && seq->first == 0,
+ "The sequence doesn't become empty after clear" );
+ break;
+ default:
+ assert(0);
+ return -1;
+ }
+
+ if( test_seq_block_consistence(struct_idx, seq, sseq->count) < 0 )
+ return -1;
+
+ if( test_get_seq_elem(struct_idx, 7) < 0 )
+ return -1;
+
+ update_progressbar();
+ }
+
+ return 0;
+}
+
+
+void Core_SeqBaseTest::run( int )
+{
+ try
+ {
+ RNG& rng = ts->get_rng();
+ int i;
+ double t;
+
+ clear();
+ test_progress = -1;
+
+ simple_struct.resize(struct_count, 0);
+ cxcore_struct.resize(struct_count, 0);
+
+ for( gen = 0; gen < generations; gen++ )
+ {
+ struct_idx = iter = -1;
+
+ if( !storage )
+ {
+ t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
+ + min_log_storage_block_size;
+ storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
+ }
+
+ iter = struct_idx = -1;
+ test_multi_create();
+
+ for( i = 0; i < struct_count; i++ )
+ {
+ if( test_seq_block_consistence(i, (CvSeq*)cxcore_struct[i],
+ ((CvTsSimpleSeq*)simple_struct[i])->count) < 0 )
+ return;
+
+ if( test_get_seq_elem( i, MAX(iterations/3,7) ) < 0 )
+ return;
+
+ if( test_get_seq_reading( i, MAX(iterations/3,7) ) < 0 )
+ return;
+ update_progressbar();
+ }
+
+ if( test_seq_ops( iterations ) < 0 )
+ return;
+
+ if( cvtest::randInt(rng) % 2 )
+ storage.release();
+ else
+ cvClearMemStorage( storage );
+ }
+ }
+ catch(int)
+ {
+ }
+}
+
+
+////////////////////////////// more sequence tests //////////////////////////////////////
+
+class Core_SeqSortInvTest : public Core_SeqBaseTest
+{
+public:
+ Core_SeqSortInvTest();
+ void run( int );
+
+protected:
+};
+
+
+Core_SeqSortInvTest::Core_SeqSortInvTest()
+{
+}
+
+
+static int icvCmpSeqElems( const void* a, const void* b, void* userdata )
+{
+ return memcmp( a, b, ((CvSeq*)userdata)->elem_size );
+}
+
+static int icvCmpSeqElems2_elem_size = 0;
+static int icvCmpSeqElems2( const void* a, const void* b )
+{
+ return memcmp( a, b, icvCmpSeqElems2_elem_size );
+}
+
+
+void Core_SeqSortInvTest::run( int )
+{
+ try
+ {
+ RNG& rng = ts->get_rng();
+ int i, k;
+ double t;
+ schar *elem0, *elem, *elem2;
+ vector<uchar> buffer;
+
+ clear();
+ test_progress = -1;
+
+ simple_struct.resize(struct_count, 0);
+ cxcore_struct.resize(struct_count, 0);
+
+ for( gen = 0; gen < generations; gen++ )
+ {
+ struct_idx = iter = -1;
+
+ if( storage.empty() )
+ {
+ t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size)
+ + min_log_storage_block_size;
+ storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
+ }
+
+ for( iter = 0; iter < iterations/10; iter++ )
+ {
+ int max_size = 0;
+ test_multi_create();
+
+ for( i = 0; i < struct_count; i++ )
+ {
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
+ max_size = MAX( max_size, sseq->count*sseq->elem_size );
+ }
+
+ buffer.resize(max_size);
+
+ for( i = 0; i < struct_count; i++ )
+ {
+ CvSeq* seq = (CvSeq*)cxcore_struct[i];
+ CvTsSimpleSeq* sseq = (CvTsSimpleSeq*)simple_struct[i];
+ CvSlice slice = CV_WHOLE_SEQ;
+
+ //printf("%d. %d. %d-th size = %d\n", gen, iter, i, sseq->count );
+
+ cvSeqInvert( seq );
+ cvTsSimpleSeqInvert( sseq );
+
+ if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
+ return;
+
+ if( sseq->count > 0 && cvtest::randInt(rng) % 2 == 0 )
+ {
+ slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
+ slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
+ slice.end_index += slice.start_index;
+ }
+
+ cvCvtSeqToArray( seq, &buffer[0], slice );
+
+ slice.end_index = MIN( slice.end_index, sseq->count );
+ CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
+ sseq->array + slice.start_index*sseq->elem_size,
+ (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
+ "cvSeqInvert returned wrong result" );
+
+ for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
+ {
+ int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
+ elem0 = cvTsSimpleSeqElem( sseq, idx0 );
+ elem = cvGetSeqElem( seq, idx0 );
+ elem2 = cvSeqSearch( seq, elem0, k % 2 ? icvCmpSeqElems : 0, 0, &idx, seq );
+
+ CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
+ memcmp( elem0, elem, seq->elem_size ) == 0,
+ "cvSeqInvert gives incorrect result" );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
+ memcmp( elem0, elem2, seq->elem_size ) == 0 &&
+ elem2 == cvGetSeqElem( seq, idx ),
+ "cvSeqSearch failed (linear search)" );
+ }
+
+ cvSeqSort( seq, icvCmpSeqElems, seq );
+
+ if( test_seq_block_consistence( i, seq, sseq->count ) < 0 )
+ return;
+
+ if( sseq->count > 0 )
+ {
+ // !!! This is not thread-safe !!!
+ icvCmpSeqElems2_elem_size = sseq->elem_size;
+ qsort( sseq->array, sseq->count, sseq->elem_size, icvCmpSeqElems2 );
+
+ if( cvtest::randInt(rng) % 2 == 0 )
+ {
+ slice.end_index = cvtest::randInt(rng) % sseq->count + 1;
+ slice.start_index = cvtest::randInt(rng) % (sseq->count - slice.end_index + 1);
+ slice.end_index += slice.start_index;
+ }
+ }
+
+ cvCvtSeqToArray( seq, &buffer[0], slice );
+ CV_TS_SEQ_CHECK_CONDITION( sseq->count == 0 || memcmp( &buffer[0],
+ sseq->array + slice.start_index*sseq->elem_size,
+ (slice.end_index - slice.start_index)*sseq->elem_size ) == 0,
+ "cvSeqSort returned wrong result" );
+
+ for( k = 0; k < (sseq->count > 0 ? 10 : 0); k++ )
+ {
+ int idx0 = cvtest::randInt(rng) % sseq->count, idx = 0;
+ elem0 = cvTsSimpleSeqElem( sseq, idx0 );
+ elem = cvGetSeqElem( seq, idx0 );
+ elem2 = cvSeqSearch( seq, elem0, icvCmpSeqElems, 1, &idx, seq );
+
+ CV_TS_SEQ_CHECK_CONDITION( elem != 0 &&
+ memcmp( elem0, elem, seq->elem_size ) == 0,
+ "cvSeqSort gives incorrect result" );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 &&
+ memcmp( elem0, elem2, seq->elem_size ) == 0 &&
+ elem2 == cvGetSeqElem( seq, idx ),
+ "cvSeqSearch failed (binary search)" );
+ }
+ }
+
+ cvClearMemStorage( storage );
+ }
+
+ storage.release();
+ }
+ }
+ catch (int)
+ {
+ }
+}
+
+
+/////////////////////////////////////// set tests ///////////////////////////////////////
+
+class Core_SetTest : public Core_DynStructBaseTest
+{
+public:
+ Core_SetTest();
+ void clear();
+ void run( int );
+
+protected:
+ //int test_seq_block_consistence( int struct_idx );
+ int test_set_ops( int iters );
+};
+
+
+Core_SetTest::Core_SetTest()
+{
+}
+
+
+void Core_SetTest::clear()
+{
+ for( size_t i = 0; i < simple_struct.size(); i++ )
+ cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
+ Core_DynStructBaseTest::clear();
+}
+
+
+int Core_SetTest::test_set_ops( int iters )
+{
+ const int max_op = 4;
+ int max_elem_size = 0;
+ int idx, idx0;
+ CvSetElem *elem = 0, *elem2 = 0, *elem3 = 0;
+ schar* elem_data = 0;
+ RNG& rng = ts->get_rng();
+ //int max_active_count = 0, mean_active_count = 0;
+
+ for( int i = 0; i < struct_count; i++ )
+ max_elem_size = MAX( max_elem_size, ((CvSeq*)cxcore_struct[i])->elem_size );
+
+ vector<schar> elem_buf(max_elem_size);
+ Mat elem_mat;
+
+ for( iter = 0; iter < iters; iter++ )
+ {
+ struct_idx = cvtest::randInt(rng) % struct_count;
+
+ CvSet* cvset = (CvSet*)cxcore_struct[struct_idx];
+ CvTsSimpleSet* sset = (CvTsSimpleSet*)simple_struct[struct_idx];
+ int pure_elem_size = sset->elem_size - 1;
+ int prev_total = cvset->total, prev_count = cvset->active_count;
+ int op = cvtest::randInt(rng) % (iter <= iters/10 ? 2 : max_op);
+ int by_ptr = op % 2 == 0;
+ CvSetElem* first_free = cvset->free_elems;
+ CvSetElem* next_free = first_free ? first_free->next_free : 0;
+ int pass_data = 0;
+
+ if( iter > iters/10 && cvtest::randInt(rng)%200 == 0 ) // clear set
+ {
+ int prev_count = cvset->total;
+ cvClearSet( cvset );
+ cvTsClearSimpleSet( sset );
+
+ CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == 0 && cvset->total == 0 &&
+ cvset->first == 0 && cvset->free_elems == 0 &&
+ (cvset->free_blocks != 0 || prev_count == 0),
+ "cvClearSet doesn't remove all the elements" );
+ continue;
+ }
+ else if( op == 0 || op == 1 ) // add element
+ {
+ if( sset->free_count == 0 )
+ continue;
+
+ elem_mat = Mat(1, cvset->elem_size, CV_8U, &elem_buf[0]);
+ cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
+ elem = (CvSetElem*)&elem_buf[0];
+
+ if( by_ptr )
+ {
+ elem2 = cvSetNew( cvset );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0, "cvSetNew returned NULL pointer" );
+ }
+ else
+ {
+ pass_data = cvtest::randInt(rng) % 2;
+ idx = cvSetAdd( cvset, pass_data ? elem : 0, &elem2 );
+ CV_TS_SEQ_CHECK_CONDITION( elem2 != 0 && elem2->flags == idx,
+ "cvSetAdd returned NULL pointer or a wrong index" );
+ }
+
+ elem_data = (schar*)elem + sizeof(int);
+
+ if( !pass_data )
+ memcpy( (schar*)elem2 + sizeof(int), elem_data, pure_elem_size );
+
+ idx = elem2->flags;
+ idx0 = cvTsSimpleSetAdd( sset, elem_data );
+ elem3 = cvGetSetElem( cvset, idx );
+
+ CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem3) &&
+ idx == idx0 && elem3 == elem2 && (!pass_data ||
+ memcmp( (char*)elem3 + sizeof(int), elem_data, pure_elem_size) == 0),
+ "The added element is not correct" );
+
+ CV_TS_SEQ_CHECK_CONDITION( (!first_free || elem3 == first_free) &&
+ (!next_free || cvset->free_elems == next_free) &&
+ cvset->active_count == prev_count + 1,
+ "The free node list is modified incorrectly" );
+ }
+ else if( op == 2 || op == 3 ) // remove element
+ {
+ idx = cvtest::randInt(rng) % sset->max_count;
+
+ if( sset->free_count == sset->max_count || idx >= sset->count )
+ continue;
+
+ elem_data = cvTsSimpleSetFind(sset, idx);
+ if( elem_data == 0 )
+ continue;
+
+ elem = cvGetSetElem( cvset, idx );
+ CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(elem) && elem->flags == idx &&
+ memcmp((char*)elem + sizeof(int), elem_data, pure_elem_size) == 0,
+ "cvGetSetElem returned wrong element" );
+
+ if( by_ptr )
+ {
+ cvSetRemoveByPtr( cvset, elem );
+ }
+ else
+ {
+ cvSetRemove( cvset, idx );
+ }
+
+ cvTsSimpleSetRemove( sset, idx );
+
+ CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(elem) && !cvGetSetElem(cvset, idx) &&
+ (elem->flags & CV_SET_ELEM_IDX_MASK) == idx,
+ "cvSetRemove[ByPtr] didn't release the element properly" );
+
+ CV_TS_SEQ_CHECK_CONDITION( elem->next_free == first_free &&
+ cvset->free_elems == elem &&
+ cvset->active_count == prev_count - 1,
+ "The free node list has not been updated properly" );
+ }
+
+ //max_active_count = MAX( max_active_count, cvset->active_count );
+ //mean_active_count += cvset->active_count;
+ CV_TS_SEQ_CHECK_CONDITION( cvset->active_count == sset->max_count - sset->free_count &&
+ cvset->total >= cvset->active_count &&
+ (cvset->total == 0 || cvset->total >= prev_total),
+ "The total number of cvset elements is not correct" );
+
+ // CvSet and simple set do not neccessary have the same "total" (active & free) number,
+ // so pass "set->total" to skip that check
+ test_seq_block_consistence( struct_idx, (CvSeq*)cvset, cvset->total );
+ update_progressbar();
+ }
+
+ return 0;
+}
+
+
+void Core_SetTest::run( int )
+{
+ try
+ {
+ RNG& rng = ts->get_rng();
+ double t;
+
+ clear();
+ test_progress = -1;
+
+ simple_struct.resize(struct_count, 0);
+ cxcore_struct.resize(struct_count, 0);
+
+ for( gen = 0; gen < generations; gen++ )
+ {
+ struct_idx = iter = -1;
+ t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
+ storage = cvCreateMemStorage( cvRound( exp(t * CV_LOG2) ) );
+
+ for( int i = 0; i < struct_count; i++ )
+ {
+ t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
+ int pure_elem_size = cvRound( exp(t * CV_LOG2) );
+ int elem_size = pure_elem_size + sizeof(int);
+ elem_size = (elem_size + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
+ elem_size = MAX( elem_size, (int)sizeof(CvSetElem) );
+ elem_size = MIN( elem_size, (int)(storage->block_size - sizeof(void*) - sizeof(CvMemBlock) - sizeof(CvSeqBlock)) );
+ pure_elem_size = MIN( pure_elem_size, elem_size-(int)sizeof(CvSetElem) );
+
+ cvTsReleaseSimpleSet( (CvTsSimpleSet**)&simple_struct[i] );
+ simple_struct[i] = cvTsCreateSimpleSet( max_struct_size, pure_elem_size );
+ cxcore_struct[i] = cvCreateSet( 0, sizeof(CvSet), elem_size, storage );
+ }
+
+ if( test_set_ops( iterations*100 ) < 0 )
+ return;
+
+ storage.release();
+ }
+ }
+ catch(int)
+ {
+ }
+}
+
+
+/////////////////////////////////////// graph tests //////////////////////////////////
+
+class Core_GraphTest : public Core_DynStructBaseTest
+{
+public:
+ Core_GraphTest();
+ void clear();
+ void run( int );
+
+protected:
+ //int test_seq_block_consistence( int struct_idx );
+ int test_graph_ops( int iters );
+};
+
+
+Core_GraphTest::Core_GraphTest()
+{
+}
+
+
+void Core_GraphTest::clear()
+{
+ for( size_t i = 0; i < simple_struct.size(); i++ )
+ cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
+ Core_DynStructBaseTest::clear();
+}
+
+
+int Core_GraphTest::test_graph_ops( int iters )
+{
+ const int max_op = 4;
+ int i, k;
+ int max_elem_size = 0;
+ int idx, idx0;
+ CvGraphVtx *vtx = 0, *vtx2 = 0, *vtx3 = 0;
+ CvGraphEdge* edge = 0, *edge2 = 0;
+ RNG& rng = ts->get_rng();
+ //int max_active_count = 0, mean_active_count = 0;
+
+ for( i = 0; i < struct_count; i++ )
+ {
+ CvGraph* graph = (CvGraph*)cxcore_struct[i];
+ max_elem_size = MAX( max_elem_size, graph->elem_size );
+ max_elem_size = MAX( max_elem_size, graph->edges->elem_size );
+ }
+
+ vector<schar> elem_buf(max_elem_size);
+ Mat elem_mat;
+
+ for( iter = 0; iter < iters; iter++ )
+ {
+ struct_idx = cvtest::randInt(rng) % struct_count;
+ CvGraph* graph = (CvGraph*)cxcore_struct[struct_idx];
+ CvTsSimpleGraph* sgraph = (CvTsSimpleGraph*)simple_struct[struct_idx];
+ CvSet* edges = graph->edges;
+ schar *vtx_data;
+ char *edge_data;
+ int pure_vtx_size = sgraph->vtx->elem_size - 1,
+ pure_edge_size = sgraph->edge_size - 1;
+ int prev_vtx_total = graph->total,
+ prev_edge_total = graph->edges->total,
+ prev_vtx_count = graph->active_count,
+ prev_edge_count = graph->edges->active_count;
+ int op = cvtest::randInt(rng) % max_op;
+ int pass_data = 0, vtx_degree0 = 0, vtx_degree = 0;
+ CvSetElem *first_free, *next_free;
+
+ if( cvtest::randInt(rng) % 200 == 0 ) // clear graph
+ {
+ int prev_vtx_count = graph->total, prev_edge_count = graph->edges->total;
+
+ cvClearGraph( graph );
+ cvTsClearSimpleGraph( sgraph );
+
+ CV_TS_SEQ_CHECK_CONDITION( graph->active_count == 0 && graph->total == 0 &&
+ graph->first == 0 && graph->free_elems == 0 &&
+ (graph->free_blocks != 0 || prev_vtx_count == 0),
+ "The graph is not empty after clearing" );
+
+ CV_TS_SEQ_CHECK_CONDITION( edges->active_count == 0 && edges->total == 0 &&
+ edges->first == 0 && edges->free_elems == 0 &&
+ (edges->free_blocks != 0 || prev_edge_count == 0),
+ "The graph is not empty after clearing" );
+ }
+ else if( op == 0 ) // add vertex
+ {
+ if( sgraph->vtx->free_count == 0 )
+ continue;
+
+ first_free = graph->free_elems;
+ next_free = first_free ? first_free->next_free : 0;
+
+ if( pure_vtx_size )
+ {
+ elem_mat = Mat(1, graph->elem_size, CV_8U, &elem_buf[0]);
+ cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
+ }
+
+ vtx = (CvGraphVtx*)&elem_buf[0];
+ idx0 = cvTsSimpleGraphAddVertex( sgraph, vtx + 1 );
+
+ pass_data = cvtest::randInt(rng) % 2;
+ idx = cvGraphAddVtx( graph, pass_data ? vtx : 0, &vtx2 );
+
+ if( !pass_data && pure_vtx_size > 0 )
+ memcpy( vtx2 + 1, vtx + 1, pure_vtx_size );
+
+ vtx3 = cvGetGraphVtx( graph, idx );
+
+ CV_TS_SEQ_CHECK_CONDITION( (CV_IS_SET_ELEM(vtx3) && vtx3->flags == idx &&
+ vtx3->first == 0) || (idx == idx0 && vtx3 == vtx2 &&
+ (!pass_data || pure_vtx_size == 0 ||
+ memcmp(vtx3 + 1, vtx + 1, pure_vtx_size) == 0)),
+ "The added element is not correct" );
+
+ CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)vtx3) &&
+ (!next_free || graph->free_elems == next_free) &&
+ graph->active_count == prev_vtx_count + 1,
+ "The free node list is modified incorrectly" );
+ }
+ else if( op == 1 ) // remove vertex
+ {
+ idx = cvtest::randInt(rng) % sgraph->vtx->max_count;
+ if( sgraph->vtx->free_count == sgraph->vtx->max_count || idx >= sgraph->vtx->count )
+ continue;
+
+ vtx_data = cvTsSimpleGraphFindVertex(sgraph, idx);
+ if( vtx_data == 0 )
+ continue;
+
+ vtx_degree0 = cvTsSimpleGraphVertexDegree( sgraph, idx );
+ first_free = graph->free_elems;
+
+ vtx = cvGetGraphVtx( graph, idx );
+ CV_TS_SEQ_CHECK_CONDITION( CV_IS_SET_ELEM(vtx) && vtx->flags == idx &&
+ (pure_vtx_size == 0 || memcmp( vtx + 1, vtx_data, pure_vtx_size) == 0),
+ "cvGetGraphVtx returned wrong element" );
+
+ if( cvtest::randInt(rng) % 2 )
+ {
+ vtx_degree = cvGraphVtxDegreeByPtr( graph, vtx );
+ cvGraphRemoveVtxByPtr( graph, vtx );
+ }
+ else
+ {
+ vtx_degree = cvGraphVtxDegree( graph, idx );
+ cvGraphRemoveVtx( graph, idx );
+ }
+
+ cvTsSimpleGraphRemoveVertex( sgraph, idx );
+
+ CV_TS_SEQ_CHECK_CONDITION( vtx_degree == vtx_degree0,
+ "Number of incident edges is different in two graph representations" );
+
+ CV_TS_SEQ_CHECK_CONDITION( !CV_IS_SET_ELEM(vtx) && !cvGetGraphVtx(graph, idx) &&
+ (vtx->flags & CV_SET_ELEM_IDX_MASK) == idx,
+ "cvGraphRemoveVtx[ByPtr] didn't release the vertex properly" );
+
+ CV_TS_SEQ_CHECK_CONDITION( graph->edges->active_count == prev_edge_count - vtx_degree,
+ "cvGraphRemoveVtx[ByPtr] didn't remove all the incident edges "
+ "(or removed some extra)" );
+
+ CV_TS_SEQ_CHECK_CONDITION( ((CvSetElem*)vtx)->next_free == first_free &&
+ graph->free_elems == (CvSetElem*)vtx &&
+ graph->active_count == prev_vtx_count - 1,
+ "The free node list has not been updated properly" );
+ }
+ else if( op == 2 ) // add edge
+ {
+ int v_idx[2] = {0,0}, res = 0;
+ int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
+
+ if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
+ continue;
+
+ for( i = 0, k = 0; i < 10; i++ )
+ {
+ int j = cvtest::randInt(rng) % sgraph->vtx->count;
+ vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
+ if( vtx_data )
+ {
+ v_idx[k] = j;
+ if( k == 0 )
+ k++;
+ else if( v_idx[0] != v_idx[1] &&
+ cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] ) == 0 )
+ {
+ k++;
+ break;
+ }
+ }
+ }
+
+ if( k < 2 )
+ continue;
+
+ first_free = graph->edges->free_elems;
+ next_free = first_free ? first_free->next_free : 0;
+
+ edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
+ CV_TS_SEQ_CHECK_CONDITION( edge == 0, "Extra edge appeared in the graph" );
+
+ if( pure_edge_size > 0 )
+ {
+ elem_mat = Mat(1, graph->edges->elem_size, CV_8U, &elem_buf[0]);
+ cvtest::randUni( rng, elem_mat, cvScalarAll(0), cvScalarAll(255) );
+ }
+ edge = (CvGraphEdge*)&elem_buf[0];
+
+ // assign some default weight that is easy to check for
+ // consistensy, 'cause an edge weight is not stored
+ // in the simple graph
+ edge->weight = (float)(v_idx[0] + v_idx[1]);
+ pass_data = cvtest::randInt(rng) % 2;
+
+ vtx = cvGetGraphVtx( graph, v_idx[0] );
+ vtx2 = cvGetGraphVtx( graph, v_idx[1] );
+ CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
+ vtx2->flags == v_idx[1], "Some of the vertices are missing" );
+
+ if( cvtest::randInt(rng) % 2 )
+ {
+ v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
+ v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
+ res = cvGraphAddEdgeByPtr(graph, vtx, vtx2, pass_data ? edge : 0, &edge2);
+ v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
+ v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
+ }
+ else
+ {
+ v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
+ v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
+ res = cvGraphAddEdge(graph, v_idx[0], v_idx[1], pass_data ? edge : 0, &edge2);
+ v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
+ v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
+ }
+
+ //edge3 = (CvGraphEdge*)cvGetSetElem( graph->edges, idx );
+ CV_TS_SEQ_CHECK_CONDITION( res == 1 && edge2 != 0 && CV_IS_SET_ELEM(edge2) &&
+ ((edge2->vtx[0] == vtx && edge2->vtx[1] == vtx2) ||
+ (!CV_IS_GRAPH_ORIENTED(graph) && edge2->vtx[0] == vtx2 && edge2->vtx[1] == vtx)) &&
+ (!pass_data || pure_edge_size == 0 || memcmp( edge2 + 1, edge + 1, pure_edge_size ) == 0),
+ "The edge has been added incorrectly" );
+
+ if( !pass_data )
+ {
+ if( pure_edge_size > 0 )
+ memcpy( edge2 + 1, edge + 1, pure_edge_size );
+ edge2->weight = edge->weight;
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] + 1 &&
+ v_degree[1] == v_prev_degree[1] + 1,
+ "The vertices lists have not been updated properly" );
+
+ cvTsSimpleGraphAddEdge( sgraph, v_idx[0], v_idx[1], edge + 1 );
+
+ CV_TS_SEQ_CHECK_CONDITION( (!first_free || first_free == (CvSetElem*)edge2) &&
+ (!next_free || graph->edges->free_elems == next_free) &&
+ graph->edges->active_count == prev_edge_count + 1,
+ "The free node list is modified incorrectly" );
+ }
+ else if( op == 3 ) // find & remove edge
+ {
+ int v_idx[2] = {0,0}, by_ptr;
+ int v_prev_degree[2] = {0,0}, v_degree[2] = {0,0};
+
+ if( sgraph->vtx->free_count >= sgraph->vtx->max_count-1 )
+ continue;
+
+ edge_data = 0;
+ for( i = 0, k = 0; i < 10; i++ )
+ {
+ int j = cvtest::randInt(rng) % sgraph->vtx->count;
+ vtx_data = cvTsSimpleGraphFindVertex( sgraph, j );
+ if( vtx_data )
+ {
+ v_idx[k] = j;
+ if( k == 0 )
+ k++;
+ else
+ {
+ edge_data = cvTsSimpleGraphFindEdge( sgraph, v_idx[0], v_idx[1] );
+ if( edge_data )
+ {
+ k++;
+ break;
+ }
+ }
+ }
+ }
+
+ if( k < 2 )
+ continue;
+
+ by_ptr = cvtest::randInt(rng) % 2;
+ first_free = graph->edges->free_elems;
+
+ vtx = cvGetGraphVtx( graph, v_idx[0] );
+ vtx2 = cvGetGraphVtx( graph, v_idx[1] );
+ CV_TS_SEQ_CHECK_CONDITION( vtx != 0 && vtx2 != 0 && vtx->flags == v_idx[0] &&
+ vtx2->flags == v_idx[1], "Some of the vertices are missing" );
+
+ if( by_ptr )
+ {
+ edge = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
+ v_prev_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
+ v_prev_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
+ }
+ else
+ {
+ edge = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
+ v_prev_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
+ v_prev_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
+ }
+
+ idx = edge->flags;
+
+ CV_TS_SEQ_CHECK_CONDITION( edge != 0 && edge->weight == v_idx[0] + v_idx[1] &&
+ ((edge->vtx[0] == vtx && edge->vtx[1] == vtx2) ||
+ (!CV_IS_GRAPH_ORIENTED(graph) && edge->vtx[1] == vtx && edge->vtx[0] == vtx2)) &&
+ (pure_edge_size == 0 || memcmp(edge + 1, edge_data, pure_edge_size) == 0),
+ "An edge is missing or incorrect" );
+
+ if( by_ptr )
+ {
+ cvGraphRemoveEdgeByPtr( graph, vtx, vtx2 );
+ edge2 = cvFindGraphEdgeByPtr( graph, vtx, vtx2 );
+ v_degree[0] = cvGraphVtxDegreeByPtr( graph, vtx );
+ v_degree[1] = cvGraphVtxDegreeByPtr( graph, vtx2 );
+ }
+ else
+ {
+ cvGraphRemoveEdge(graph, v_idx[0], v_idx[1] );
+ edge2 = cvFindGraphEdge( graph, v_idx[0], v_idx[1] );
+ v_degree[0] = cvGraphVtxDegree( graph, v_idx[0] );
+ v_degree[1] = cvGraphVtxDegree( graph, v_idx[1] );
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( !edge2 && !CV_IS_SET_ELEM(edge),
+ "The edge has not been removed from the edge set" );
+
+ CV_TS_SEQ_CHECK_CONDITION( v_degree[0] == v_prev_degree[0] - 1 &&
+ v_degree[1] == v_prev_degree[1] - 1,
+ "The vertices lists have not been updated properly" );
+
+ cvTsSimpleGraphRemoveEdge( sgraph, v_idx[0], v_idx[1] );
+
+ CV_TS_SEQ_CHECK_CONDITION( graph->edges->free_elems == (CvSetElem*)edge &&
+ graph->edges->free_elems->next_free == first_free &&
+ graph->edges->active_count == prev_edge_count - 1,
+ "The free edge list has not been modified properly" );
+ }
+
+ //max_active_count = MAX( max_active_count, graph->active_count );
+ //mean_active_count += graph->active_count;
+
+ CV_TS_SEQ_CHECK_CONDITION( graph->active_count == sgraph->vtx->max_count - sgraph->vtx->free_count &&
+ graph->total >= graph->active_count &&
+ (graph->total == 0 || graph->total >= prev_vtx_total),
+ "The total number of graph vertices is not correct" );
+
+ CV_TS_SEQ_CHECK_CONDITION( graph->edges->total >= graph->edges->active_count &&
+ (graph->edges->total == 0 || graph->edges->total >= prev_edge_total),
+ "The total number of graph vertices is not correct" );
+
+ // CvGraph and simple graph do not neccessary have the same "total" (active & free) number,
+ // so pass "graph->total" (or "graph->edges->total") to skip that check
+ test_seq_block_consistence( struct_idx, (CvSeq*)graph, graph->total );
+ test_seq_block_consistence( struct_idx, (CvSeq*)graph->edges, graph->edges->total );
+ update_progressbar();
+ }
+
+ return 0;
+}
+
+
+void Core_GraphTest::run( int )
+{
+ try
+ {
+ RNG& rng = ts->get_rng();
+ int i, k;
+ double t;
+
+ clear();
+ test_progress = -1;
+
+ simple_struct.resize(struct_count, 0);
+ cxcore_struct.resize(struct_count, 0);
+
+ for( gen = 0; gen < generations; gen++ )
+ {
+ struct_idx = iter = -1;
+ t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
+ int block_size = cvRound( exp(t * CV_LOG2) );
+ block_size = MAX(block_size, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
+
+ storage = cvCreateMemStorage(block_size);
+
+ for( i = 0; i < struct_count; i++ )
+ {
+ int pure_elem_size[2], elem_size[2];
+ int is_oriented = (gen + i) % 2;
+ for( k = 0; k < 2; k++ )
+ {
+ t = cvtest::randReal(rng)*(max_log_elem_size - min_log_elem_size) + min_log_elem_size;
+ int pe = cvRound( exp(t * CV_LOG2) ) - 1; // pure_elem_size==0 does also make sense
+ int delta = k == 0 ? sizeof(CvGraphVtx) : sizeof(CvGraphEdge);
+ int e = pe + delta;
+ e = (e + sizeof(size_t) - 1) & ~(sizeof(size_t)-1);
+ e = MIN( e, (int)(storage->block_size - sizeof(CvMemBlock) -
+ sizeof(CvSeqBlock) - sizeof(void*)) );
+ pe = MIN(pe, e - delta);
+ pure_elem_size[k] = pe;
+ elem_size[k] = e;
+ }
+
+ cvTsReleaseSimpleGraph( (CvTsSimpleGraph**)&simple_struct[i] );
+ simple_struct[i] = cvTsCreateSimpleGraph( max_struct_size/4, pure_elem_size[0],
+ pure_elem_size[1], is_oriented );
+ cxcore_struct[i] = cvCreateGraph( is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
+ sizeof(CvGraph), elem_size[0], elem_size[1],
+ storage );
+ }
+
+ if( test_graph_ops( iterations*10 ) < 0 )
+ return;
+
+ storage.release();
+ }
+ }
+ catch(int)
+ {
+ }
+}
+
+
+//////////// graph scan test //////////////
+
+class Core_GraphScanTest : public Core_DynStructBaseTest
+{
+public:
+ Core_GraphScanTest();
+ void run( int );
+
+protected:
+ //int test_seq_block_consistence( int struct_idx );
+ int create_random_graph( int );
+};
+
+
+Core_GraphScanTest::Core_GraphScanTest()
+{
+ iterations = 100;
+ struct_count = 1;
+}
+
+
+int Core_GraphScanTest::create_random_graph( int _struct_idx )
+{
+ RNG& rng = ts->get_rng();
+ int is_oriented = cvtest::randInt(rng) % 2;
+ int i, vtx_count = cvtest::randInt(rng) % max_struct_size;
+ int edge_count = cvtest::randInt(rng) % MAX(vtx_count*20, 1);
+ CvGraph* graph;
+
+ struct_idx = _struct_idx;
+ cxcore_struct[_struct_idx] = graph =
+ cvCreateGraph(is_oriented ? CV_ORIENTED_GRAPH : CV_GRAPH,
+ sizeof(CvGraph), sizeof(CvGraphVtx),
+ sizeof(CvGraphEdge), storage );
+
+ for( i = 0; i < vtx_count; i++ )
+ cvGraphAddVtx( graph );
+
+ assert( graph->active_count == vtx_count );
+
+ for( i = 0; i < edge_count; i++ )
+ {
+ int j = cvtest::randInt(rng) % vtx_count;
+ int k = cvtest::randInt(rng) % vtx_count;
+
+ if( j != k )
+ cvGraphAddEdge( graph, j, k );
+ }
+
+ assert( graph->active_count == vtx_count && graph->edges->active_count <= edge_count );
+
+ return 0;
+}
+
+
+void Core_GraphScanTest::run( int )
+{
+ CvGraphScanner* scanner = 0;
+ try
+ {
+ RNG& rng = ts->get_rng();
+ vector<uchar> vtx_mask, edge_mask;
+ double t;
+ int i;
+
+ clear();
+ test_progress = -1;
+
+ cxcore_struct.resize(struct_count, 0);
+
+ for( gen = 0; gen < generations; gen++ )
+ {
+ struct_idx = iter = -1;
+ t = cvtest::randReal(rng)*(max_log_storage_block_size - min_log_storage_block_size) + min_log_storage_block_size;
+ int storage_blocksize = cvRound( exp(t * CV_LOG2) );
+ storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraph) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
+ storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphEdge) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
+ storage_blocksize = MAX(storage_blocksize, (int)(sizeof(CvGraphVtx) + sizeof(CvMemBlock) + sizeof(CvSeqBlock)));
+ storage = cvCreateMemStorage(storage_blocksize);
+
+ if( gen == 0 )
+ {
+ // special regression test for one sample graph.
+ // !!! ATTENTION !!! The test relies on the particular order of the inserted edges
+ // (LIFO: the edge inserted last goes first in the list of incident edges).
+ // if it is changed, the test will have to be modified.
+
+ int vtx_count = -1, edge_count = 0, edges[][3] =
+ {
+ {0,4,'f'}, {0,1,'t'}, {1,4,'t'}, {1,2,'t'}, {2,3,'t'}, {4,3,'c'}, {3,1,'b'},
+ {5,7,'t'}, {7,5,'b'}, {5,6,'t'}, {6,0,'c'}, {7,6,'c'}, {6,4,'c'}, {-1,-1,0}
+ };
+
+ CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH, sizeof(CvGraph),
+ sizeof(CvGraphVtx), sizeof(CvGraphEdge), storage );
+
+ for( i = 0; edges[i][0] >= 0; i++ )
+ {
+ vtx_count = MAX( vtx_count, edges[i][0] );
+ vtx_count = MAX( vtx_count, edges[i][1] );
+ }
+ vtx_count++;
+
+ for( i = 0; i < vtx_count; i++ )
+ cvGraphAddVtx( graph );
+
+ for( i = 0; edges[i][0] >= 0; i++ )
+ {
+ CvGraphEdge* edge;
+ cvGraphAddEdge( graph, edges[i][0], edges[i][1], 0, &edge );
+ edge->weight = (float)edges[i][2];
+ }
+
+ edge_count = i;
+ scanner = cvCreateGraphScanner( graph, 0, CV_GRAPH_ALL_ITEMS );
+
+ for(;;)
+ {
+ int code, a = -1, b = -1;
+ const char* event = "";
+ code = cvNextGraphItem( scanner );
+
+ switch( code )
+ {
+ case CV_GRAPH_VERTEX:
+ event = "Vertex";
+ vtx_count--;
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ break;
+ case CV_GRAPH_TREE_EDGE:
+ event = "Tree Edge";
+ edge_count--;
+ CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'t',
+ "Invalid edge type" );
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ b = cvGraphVtxIdx( graph, scanner->dst );
+ break;
+ case CV_GRAPH_BACK_EDGE:
+ event = "Back Edge";
+ edge_count--;
+ CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'b',
+ "Invalid edge type" );
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ b = cvGraphVtxIdx( graph, scanner->dst );
+ break;
+ case CV_GRAPH_CROSS_EDGE:
+ event = "Cross Edge";
+ edge_count--;
+ CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'c',
+ "Invalid edge type" );
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ b = cvGraphVtxIdx( graph, scanner->dst );
+ break;
+ case CV_GRAPH_FORWARD_EDGE:
+ event = "Forward Edge";
+ edge_count--;
+ CV_TS_SEQ_CHECK_CONDITION( scanner->edge->weight == (float)'f',
+ "Invalid edge type" );
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ b = cvGraphVtxIdx( graph, scanner->dst );
+ break;
+ case CV_GRAPH_BACKTRACKING:
+ event = "Backtracking";
+ a = cvGraphVtxIdx( graph, scanner->vtx );
+ break;
+ case CV_GRAPH_NEW_TREE:
+ event = "New search tree";
+ break;
+ case CV_GRAPH_OVER:
+ event = "End of procedure";
+ break;
+ default:
+ CV_TS_SEQ_CHECK_CONDITION( 0, "Invalid code appeared during graph scan" );
+ }
+
+ ts->printf( cvtest::TS::LOG, "%s", event );
+ if( a >= 0 )
+ {
+ if( b >= 0 )
+ ts->printf( cvtest::TS::LOG, ": (%d,%d)", a, b );
+ else
+ ts->printf( cvtest::TS::LOG, ": %d", a );
+ }
+
+ ts->printf( cvtest::TS::LOG, "\n" );
+
+ if( code < 0 )
+ break;
+ }
+
+ CV_TS_SEQ_CHECK_CONDITION( vtx_count == 0 && edge_count == 0,
+ "Not every vertex/edge has been visited" );
+ update_progressbar();
+ }
+
+ // for a random graph the test just checks that every graph vertex and
+ // every edge is vitisted during the scan
+ for( iter = 0; iter < iterations; iter++ )
+ {
+ create_random_graph(0);
+ CvGraph* graph = (CvGraph*)cxcore_struct[0];
+
+ // iterate twice to check that scanner doesn't damage the graph
+ for( i = 0; i < 2; i++ )
+ {
+ CvGraphVtx* start_vtx = cvtest::randInt(rng) % 2 || graph->active_count == 0 ? 0 :
+ cvGetGraphVtx( graph, cvtest::randInt(rng) % graph->active_count );
+
+ scanner = cvCreateGraphScanner( graph, start_vtx, CV_GRAPH_ALL_ITEMS );
+
+ vtx_mask.resize(0);
+ vtx_mask.resize(graph->active_count, 0);
+ edge_mask.resize(0);
+ edge_mask.resize(graph->edges->active_count, 0);
+
+ for(;;)
+ {
+ int code = cvNextGraphItem( scanner );
+
+ if( code == CV_GRAPH_OVER )
+ break;
+ else if( code & CV_GRAPH_ANY_EDGE )
+ {
+ int edge_idx = scanner->edge->flags & CV_SET_ELEM_IDX_MASK;
+
+ CV_TS_SEQ_CHECK_CONDITION( edge_idx < graph->edges->active_count &&
+ edge_mask[edge_idx] == 0,
+ "The edge is not found or visited for the second time" );
+ edge_mask[edge_idx] = 1;
+ }
+ else if( code & CV_GRAPH_VERTEX )
+ {
+ int vtx_idx = scanner->vtx->flags & CV_SET_ELEM_IDX_MASK;
+
+ CV_TS_SEQ_CHECK_CONDITION( vtx_idx < graph->active_count &&
+ vtx_mask[vtx_idx] == 0,
+ "The vtx is not found or visited for the second time" );
+ vtx_mask[vtx_idx] = 1;
+ }
+ }
+
+ cvReleaseGraphScanner( &scanner );
+
+ CV_TS_SEQ_CHECK_CONDITION( cvtest::norm(Mat(vtx_mask),CV_L1) == graph->active_count &&
+ cvtest::norm(Mat(edge_mask),CV_L1) == graph->edges->active_count,
+ "Some vertices or edges have not been visited" );
+ update_progressbar();
+ }
+ cvClearMemStorage( storage );
+ }
+
+ storage.release();
+ }
+ }
+ catch(int)
+ {
+ }
+
+ cvReleaseGraphScanner( &scanner );
+}
+
+
+TEST(Core_DS_Seq, basic_operations) { Core_SeqBaseTest test; test.safe_run(); }
+TEST(Core_DS_Seq, sort_invert) { Core_SeqSortInvTest test; test.safe_run(); }
+TEST(Core_DS_Set, basic_operations) { Core_SetTest test; test.safe_run(); }
+TEST(Core_DS_Graph, basic_operations) { Core_GraphTest test; test.safe_run(); }
+TEST(Core_DS_Graph, scan) { Core_GraphScanTest test; test.safe_run(); }
+
+
--- /dev/null
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+namespace cvtest
+{
+
+static Mat initDFTWave( int n, bool inv )
+{
+ int i;
+ double angle = (inv ? 1 : -1)*CV_PI*2/n;
+ Complexd wi, w1;
+ Mat wave(1, n, CV_64FC2);
+ Complexd* w = wave.ptr<Complexd>();
+
+ w1.re = cos(angle);
+ w1.im = sin(angle);
+ w[0].re = wi.re = 1.;
+ w[0].im = wi.im = 0.;
+
+ for( i = 1; i < n; i++ )
+ {
+ double t = wi.re*w1.re - wi.im*w1.im;
+ wi.im = wi.re*w1.im + wi.im*w1.re;
+ wi.re = t;
+ w[i] = wi;
+ }
+
+ return wave;
+}
+
+
+static void DFT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat())
+{
+ _dst.create(_src.size(), _src.type());
+ int i, j, k, n = _dst.cols + _dst.rows - 1;
+ Mat wave = _wave;
+ double scale = (flags & DFT_SCALE) ? 1./n : 1.;
+ size_t esz = _src.elemSize();
+ size_t srcstep = esz, dststep = esz;
+ const uchar* src0 = _src.data;
+ uchar* dst0 = _dst.data;
+
+ CV_Assert( _src.cols + _src.rows - 1 == n );
+
+ if( wave.empty() )
+ wave = initDFTWave( n, (flags & DFT_INVERSE) != 0 );
+
+ const Complexd* w = wave.ptr<Complexd>();
+ if( !_src.isContinuous() )
+ srcstep = _src.step;
+ if( !_dst.isContinuous() )
+ dststep = _dst.step;
+
+ if( _src.type() == CV_32FC2 )
+ {
+ for( i = 0; i < n; i++ )
+ {
+ Complexf* dst = (Complexf*)(dst0 + i*dststep);
+ Complexd sum(0,0);
+ int delta = i;
+ k = 0;
+
+ for( j = 0; j < n; j++ )
+ {
+ const Complexf* src = (const Complexf*)(src0 + j*srcstep);
+ sum.re += src->re*w[k].re - src->im*w[k].im;
+ sum.im += src->re*w[k].im + src->im*w[k].re;
+ k += delta;
+ k -= (k >= n ? n : 0);
+ }
+
+ dst->re = (float)(sum.re*scale);
+ dst->im = (float)(sum.im*scale);
+ }
+ }
+ else if( _src.type() == CV_64FC2 )
+ {
+ for( i = 0; i < n; i++ )
+ {
+ Complexd* dst = (Complexd*)(dst0 + i*dststep);
+ Complexd sum(0,0);
+ int delta = i;
+ k = 0;
+
+ for( j = 0; j < n; j++ )
+ {
+ const Complexd* src = (const Complexd*)(src0 + j*srcstep);
+ sum.re += src->re*w[k].re - src->im*w[k].im;
+ sum.im += src->re*w[k].im + src->im*w[k].re;
+ k += delta;
+ k -= (k >= n ? n : 0);
+ }
+
+ dst->re = sum.re*scale;
+ dst->im = sum.im*scale;
+ }
+ }
+ else
+ CV_Error(CV_StsUnsupportedFormat, "");
+}
+
+
+static void DFT_2D( const Mat& src, Mat& dst, int flags )
+{
+ const int cn = 2;
+ int i;
+ dst.create(src.size(), src.type());
+ Mat tmp( src.cols, src.rows, src.type());
+ Mat wave = initDFTWave( dst.cols, (flags & DFT_INVERSE) != 0 );
+
+ // 1. row-wise transform
+ for( i = 0; i < dst.rows; i++ )
+ {
+ Mat srci = src.row(i).reshape(cn, src.cols), dsti = tmp.col(i);
+ DFT_1D(srci, dsti, flags, wave );
+ }
+
+ if( (flags & DFT_ROWS) == 0 )
+ {
+ if( dst.cols != dst.rows )
+ wave = initDFTWave( dst.rows, (flags & DFT_INVERSE) != 0 );
+
+ // 2. column-wise transform
+ for( i = 0; i < dst.cols; i++ )
+ {
+ Mat srci = tmp.row(i).reshape(cn, tmp.cols), dsti = dst.col(i);
+ DFT_1D(srci, dsti, flags, wave );
+ }
+ }
+ else
+ cvtest::transpose(tmp, dst);
+}
+
+
+static Mat initDCTWave( int n, bool inv )
+{
+ int i, k;
+ double angle = CV_PI*0.5/n;
+ Mat wave(n, n, CV_64F);
+
+ double scale = sqrt(1./n);
+ for( k = 0; k < n; k++ )
+ wave.at<double>(0, k) = scale;
+ scale *= sqrt(2.);
+ for( i = 1; i < n; i++ )
+ for( k = 0; k < n; k++ )
+ wave.at<double>(i, k) = scale*cos( angle*i*(2*k + 1) );
+
+ if( inv )
+ cv::transpose( wave, wave );
+
+ return wave;
+}
+
+
+static void DCT_1D( const Mat& _src, Mat& _dst, int flags, const Mat& _wave=Mat() )
+{
+ _dst.create( _src.size(), _src.type() );
+ int i, j, n = _dst.cols + _dst.rows - 1;
+ Mat wave = _wave;
+ int srcstep = 1, dststep = 1;
+ double* w;
+
+ CV_Assert( _src.cols + _src.rows - 1 == n);
+
+ if( wave.empty() )
+ wave = initDCTWave( n, (flags & DFT_INVERSE) != 0 );
+ w = wave.ptr<double>();
+
+ if( !_src.isContinuous() )
+ srcstep = _src.step/_src.elemSize();
+ if( !_dst.isContinuous() )
+ dststep = _dst.step/_dst.elemSize();
+
+ if( _src.type() == CV_32FC1 )
+ {
+ float *dst = _dst.ptr<float>();
+
+ for( i = 0; i < n; i++, dst += dststep )
+ {
+ const float* src = _src.ptr<float>();
+ double sum = 0;
+
+ for( j = 0; j < n; j++, src += srcstep )
+ sum += src[0]*w[j];
+ w += n;
+ dst[0] = (float)sum;
+ }
+ }
+ else if( _src.type() == CV_64FC1 )
+ {
+ double *dst = _dst.ptr<double>();
+
+ for( i = 0; i < n; i++, dst += dststep )
+ {
+ const double* src = _src.ptr<double>();
+ double sum = 0;
+
+ for( j = 0; j < n; j++, src += srcstep )
+ sum += src[0]*w[j];
+ w += n;
+ dst[0] = sum;
+ }
+ }
+ else
+ assert(0);
+}
+
+
+static void DCT_2D( const Mat& src, Mat& dst, int flags )
+{
+ const int cn = 1;
+ int i;
+ dst.create( src.size(), src.type() );
+ Mat tmp(dst.cols, dst.rows, dst.type() );
+ Mat wave = initDCTWave( dst.cols, (flags & DCT_INVERSE) != 0 );
+
+ // 1. row-wise transform
+ for( i = 0; i < dst.rows; i++ )
+ {
+ Mat srci = src.row(i).reshape(cn, src.cols);
+ Mat dsti = tmp.col(i);
+ DCT_1D(srci, dsti, flags, wave);
+ }
+
+ if( (flags & DCT_ROWS) == 0 )
+ {
+ if( dst.cols != dst.rows )
+ wave = initDCTWave( dst.rows, (flags & DCT_INVERSE) != 0 );
+
+ // 2. column-wise transform
+ for( i = 0; i < dst.cols; i++ )
+ {
+ Mat srci = tmp.row(i).reshape(cn, tmp.cols);
+ Mat dsti = dst.col(i);
+ DCT_1D( srci, dsti, flags, wave );
+ }
+ }
+ else
+ cvtest::transpose( tmp, dst );
+}
+
+
+static void convertFromCCS( const Mat& _src0, const Mat& _src1, Mat& _dst, int flags )
+{
+ if( _dst.rows > 1 && (_dst.cols > 1 || (flags & DFT_ROWS)) )
+ {
+ int i, count = _dst.rows, len = _dst.cols;
+ bool is2d = (flags & DFT_ROWS) == 0;
+ Mat src0row, src1row, dstrow;
+ for( i = 0; i < count; i++ )
+ {
+ int j = !is2d || i == 0 ? i : count - i;
+ src0row = _src0.row(i);
+ src1row = _src1.row(j);
+ dstrow = _dst.row(i);
+ convertFromCCS( src0row, src1row, dstrow, 0 );
+ }
+
+ if( is2d )
+ {
+ src0row = _src0.col(0);
+ dstrow = _dst.col(0);
+ convertFromCCS( src0row, src0row, dstrow, 0 );
+ if( (len & 1) == 0 )
+ {
+ src0row = _src0.col(_src0.cols - 1);
+ dstrow = _dst.col(len/2);
+ convertFromCCS( src0row, src0row, dstrow, 0 );
+ }
+ }
+ }
+ else
+ {
+ int i, n = _dst.cols + _dst.rows - 1, n2 = (n+1) >> 1;
+ int cn = _src0.channels();
+ int srcstep = cn, dststep = 1;
+
+ if( !_dst.isContinuous() )
+ dststep = _dst.step/_dst.elemSize();
+
+ if( !_src0.isContinuous() )
+ srcstep = _src0.step/_src0.elemSize1();
+
+ if( _dst.depth() == CV_32F )
+ {
+ Complexf* dst = _dst.ptr<Complexf>();
+ const float* src0 = _src0.ptr<float>();
+ const float* src1 = _src1.ptr<float>();
+ int delta0, delta1;
+
+ dst->re = src0[0];
+ dst->im = 0;
+
+ if( (n & 1) == 0 )
+ {
+ dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
+ dst[n2*dststep].im = 0;
+ }
+
+ delta0 = srcstep;
+ delta1 = delta0 + (cn == 1 ? srcstep : 1);
+ if( cn == 1 )
+ srcstep *= 2;
+
+ for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
+ {
+ float t0 = src0[delta0];
+ float t1 = src0[delta1];
+
+ dst[i*dststep].re = t0;
+ dst[i*dststep].im = t1;
+
+ t0 = src1[delta0];
+ t1 = -src1[delta1];
+
+ dst[(n-i)*dststep].re = t0;
+ dst[(n-i)*dststep].im = t1;
+ }
+ }
+ else
+ {
+ Complexd* dst = _dst.ptr<Complexd>();
+ const double* src0 = _src0.ptr<double>();
+ const double* src1 = _src1.ptr<double>();
+ int delta0, delta1;
+
+ dst->re = src0[0];
+ dst->im = 0;
+
+ if( (n & 1) == 0 )
+ {
+ dst[n2*dststep].re = src0[(cn == 1 ? n-1 : n2)*srcstep];
+ dst[n2*dststep].im = 0;
+ }
+
+ delta0 = srcstep;
+ delta1 = delta0 + (cn == 1 ? srcstep : 1);
+ if( cn == 1 )
+ srcstep *= 2;
+
+ for( i = 1; i < n2; i++, delta0 += srcstep, delta1 += srcstep )
+ {
+ double t0 = src0[delta0];
+ double t1 = src0[delta1];
+
+ dst[i*dststep].re = t0;
+ dst[i*dststep].im = t1;
+
+ t0 = src1[delta0];
+ t1 = -src1[delta1];
+
+ dst[(n-i)*dststep].re = t0;
+ dst[(n-i)*dststep].im = t1;
+ }
+ }
+ }
+}
+
+
+static void fixCCS( Mat& mat, int cols, int flags )
+{
+ int i, rows = mat.rows;
+ int rows2 = (flags & DFT_ROWS) ? rows : rows/2 + 1, cols2 = cols/2 + 1;
+
+ CV_Assert( cols2 == mat.cols );
+
+ if( mat.type() == CV_32FC2 )
+ {
+ for( i = 0; i < rows2; i++ )
+ {
+ Complexf* row = mat.ptr<Complexf>(i);
+ if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
+ {
+ row[0].im = 0;
+ if( cols % 2 == 0 )
+ row[cols2-1].im = 0;
+ }
+ else
+ {
+ Complexf* row2 = mat.ptr<Complexf>(rows-i);
+ row2[0].re = row[0].re;
+ row2[0].im = -row[0].im;
+
+ if( cols % 2 == 0 )
+ {
+ row2[cols2-1].re = row[cols2-1].re;
+ row2[cols2-1].im = -row[cols2-1].im;
+ }
+ }
+ }
+ }
+ else if( mat.type() == CV_64FC2 )
+ {
+ for( i = 0; i < rows2; i++ )
+ {
+ Complexd* row = mat.ptr<Complexd>(i);
+ if( (flags & DFT_ROWS) || i == 0 || (i == rows2 - 1 && rows % 2 == 0) )
+ {
+ row[0].im = 0;
+ if( cols % 2 == 0 )
+ row[cols2-1].im = 0;
+ }
+ else
+ {
+ Complexd* row2 = mat.ptr<Complexd>(rows-i);
+ row2[0].re = row[0].re;
+ row2[0].im = -row[0].im;
+
+ if( cols % 2 == 0 )
+ {
+ row2[cols2-1].re = row[cols2-1].re;
+ row2[cols2-1].im = -row[cols2-1].im;
+ }
+ }
+ }
+ }
+}
+
+
+static void mulComplex( const Mat& src1, const Mat& src2, Mat& dst, int flags )
+{
+ dst.create(src1.rows, src1.cols, src1.type());
+ int i, j, depth = src1.depth(), cols = src1.cols*2;
+
+ CV_Assert( src1.size == src2.size && src1.type() == src2.type() &&
+ (src1.type() == CV_32FC2 || src1.type() == CV_64FC2) );
+
+ for( i = 0; i < dst.rows; i++ )
+ {
+ if( depth == CV_32F )
+ {
+ const float* a = src1.ptr<float>(i);
+ const float* b = src2.ptr<float>(i);
+ float* c = dst.ptr<float>(i);
+
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = 0; j < cols; j += 2 )
+ {
+ double re = (double)a[j]*b[j] - (double)a[j+1]*b[j+1];
+ double im = (double)a[j+1]*b[j] + (double)a[j]*b[j+1];
+
+ c[j] = (float)re;
+ c[j+1] = (float)im;
+ }
+ else
+ for( j = 0; j < cols; j += 2 )
+ {
+ double re = (double)a[j]*b[j] + (double)a[j+1]*b[j+1];
+ double im = (double)a[j+1]*b[j] - (double)a[j]*b[j+1];
+
+ c[j] = (float)re;
+ c[j+1] = (float)im;
+ }
+ }
+ else
+ {
+ const double* a = src1.ptr<double>(i);
+ const double* b = src2.ptr<double>(i);
+ double* c = dst.ptr<double>(i);
+
+ if( !(flags & CV_DXT_MUL_CONJ) )
+ for( j = 0; j < cols; j += 2 )
+ {
+ double re = a[j]*b[j] - a[j+1]*b[j+1];
+ double im = a[j+1]*b[j] + a[j]*b[j+1];
+
+ c[j] = re;
+ c[j+1] = im;
+ }
+ else
+ for( j = 0; j < cols; j += 2 )
+ {
+ double re = a[j]*b[j] + a[j+1]*b[j+1];
+ double im = a[j+1]*b[j] - a[j]*b[j+1];
+
+ c[j] = re;
+ c[j+1] = im;
+ }
+ }
+ }
+}
+
+}
+
+
+class CxCore_DXTBaseTest : public cvtest::ArrayTest
+{
+public:
+ typedef cvtest::ArrayTest Base;
+ CxCore_DXTBaseTest( bool _allow_complex=false, bool _allow_odd=false,
+ bool _spectrum_mode=false );
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ int prepare_test_case( int test_case_idx );
+ double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
+ int flags; // transformation flags
+ bool allow_complex; // whether input/output may be complex or not:
+ // true for DFT and MulSpectrums, false for DCT
+ bool allow_odd; // whether input/output may be have odd (!=1) dimensions:
+ // true for DFT and MulSpectrums, false for DCT
+ bool spectrum_mode; // (2 complex/ccs inputs, 1 complex/ccs output):
+ // true for MulSpectrums, false for DFT and DCT
+ bool inplace; // inplace operation (set for each individual test case)
+ bool temp_dst; // use temporary destination (for real->ccs DFT and ccs MulSpectrums)
+};
+
+
+CxCore_DXTBaseTest::CxCore_DXTBaseTest( bool _allow_complex, bool _allow_odd, bool _spectrum_mode )
+: Base(), flags(0), allow_complex(_allow_complex), allow_odd(_allow_odd),
+spectrum_mode(_spectrum_mode), inplace(false), temp_dst(false)
+{
+ test_array[INPUT].push_back(NULL);
+ if( spectrum_mode )
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+
+ max_log_array_size = 9;
+ element_wise_relative_error = spectrum_mode;
+}
+
+
+void CxCore_DXTBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ int depth = cvtest::randInt(rng)%2 + CV_32F;
+ int cn = !allow_complex || !(bits & 256) ? 1 : 2;
+ Size size;
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ flags = bits & (CV_DXT_INVERSE | CV_DXT_SCALE | CV_DXT_ROWS | CV_DXT_MUL_CONJ);
+ if( spectrum_mode )
+ flags &= ~CV_DXT_INVERSE;
+ types[TEMP][0] = types[TEMP][1] = types[INPUT][0] =
+ types[OUTPUT][0] = CV_MAKETYPE(depth, cn);
+ size = sizes[INPUT][0];
+
+ temp_dst = false;
+
+ if( flags & CV_DXT_ROWS && (bits&1024) )
+ {
+ if( bits&16 )
+ size.width = 1;
+ else
+ size.height = 1;
+ flags &= ~CV_DXT_ROWS;
+ }
+
+ const int P2_MIN_SIZE = 32;
+ if( ((bits >> 10) & 1) == 0 )
+ {
+ size.width = (size.width / P2_MIN_SIZE)*P2_MIN_SIZE;
+ size.width = MAX(size.width, 1);
+ size.height = (size.height / P2_MIN_SIZE)*P2_MIN_SIZE;
+ size.height = MAX(size.height, 1);
+ }
+
+ if( !allow_odd )
+ {
+ if( size.width > 1 && (size.width&1) != 0 )
+ size.width = (size.width + 1) & -2;
+
+ if( size.height > 1 && (size.height&1) != 0 && !(flags & CV_DXT_ROWS) )
+ size.height = (size.height + 1) & -2;
+ }
+
+ sizes[INPUT][0] = sizes[OUTPUT][0] = size;
+ sizes[TEMP][0] = sizes[TEMP][1] = cvSize(0,0);
+
+ if( spectrum_mode )
+ {
+ if( cn == 1 )
+ {
+ types[OUTPUT][0] = depth + 8;
+ sizes[TEMP][0] = size;
+ }
+ sizes[INPUT][0] = sizes[INPUT][1] = size;
+ types[INPUT][1] = types[INPUT][0];
+ }
+ else if( /*(cn == 2 && (bits&32)) ||*/ (cn == 1 && allow_complex) )
+ {
+ types[TEMP][0] = depth + 8; // CV_??FC2
+ sizes[TEMP][0] = size;
+ size = cvSize(size.width/2+1, size.height);
+
+ if( flags & CV_DXT_INVERSE )
+ {
+ if( cn == 2 )
+ {
+ types[OUTPUT][0] = depth;
+ sizes[INPUT][0] = size;
+ }
+ types[TEMP][1] = types[TEMP][0];
+ sizes[TEMP][1] = sizes[TEMP][0];
+ }
+ else
+ {
+ if( allow_complex )
+ types[OUTPUT][0] = depth + 8;
+
+ if( cn == 2 )
+ {
+ types[INPUT][0] = depth;
+ types[TEMP][1] = types[TEMP][0];
+ sizes[TEMP][1] = size;
+ }
+ else
+ {
+ types[TEMP][1] = depth;
+ sizes[TEMP][1] = sizes[TEMP][0];
+ }
+ temp_dst = true;
+ }
+ }
+
+ inplace = false;
+ if( spectrum_mode ||
+ (!temp_dst && types[INPUT][0] == types[OUTPUT][0]) ||
+ (temp_dst && types[INPUT][0] == types[TEMP][1]) )
+ inplace = (bits & 64) != 0;
+
+ types[REF_OUTPUT][0] = types[OUTPUT][0];
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+}
+
+
+double CxCore_DXTBaseTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ return Base::get_success_error_level( test_case_idx, i, j );
+}
+
+
+int CxCore_DXTBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = Base::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ int in_type = test_mat[INPUT][0].type();
+ int out_type = test_mat[OUTPUT][0].type();
+
+ if( CV_MAT_CN(in_type) == 2 && CV_MAT_CN(out_type) == 1 )
+ cvtest::fixCCS( test_mat[INPUT][0], test_mat[OUTPUT][0].cols, flags );
+
+ if( inplace )
+ cvtest::copy( test_mat[INPUT][test_case_idx & (int)spectrum_mode],
+ temp_dst ? test_mat[TEMP][1] :
+ in_type == out_type ? test_mat[OUTPUT][0] :
+ test_mat[TEMP][0] );
+ }
+
+ return code;
+}
+
+
+////////////////////// FFT ////////////////////////
+class CxCore_DFTTest : public CxCore_DXTBaseTest
+{
+public:
+ CxCore_DFTTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+CxCore_DFTTest::CxCore_DFTTest() : CxCore_DXTBaseTest( true, true, false )
+{
+}
+
+
+void CxCore_DFTTest::run_func()
+{
+ Mat& dst = temp_dst ? test_mat[TEMP][1] : test_mat[OUTPUT][0];
+ const Mat& src = inplace ? dst : test_mat[INPUT][0];
+
+ if(!(flags & CV_DXT_INVERSE))
+ cv::dft( src, dst, flags );
+ else
+ cv::idft(src, dst, flags & ~CV_DXT_INVERSE);
+}
+
+
+void CxCore_DFTTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_OUTPUT][0];
+ Mat* tmp_src = &src;
+ Mat* tmp_dst = &dst;
+ int src_cn = src.channels();
+ int dst_cn = dst.channels();
+
+ if( src_cn != 2 || dst_cn != 2 )
+ {
+ tmp_src = &test_mat[TEMP][0];
+
+ if( !(flags & CV_DXT_INVERSE ) )
+ {
+ Mat& cvdft_dst = test_mat[TEMP][1];
+ cvtest::convertFromCCS( cvdft_dst, cvdft_dst,
+ test_mat[OUTPUT][0], flags );
+ *tmp_src = Scalar::all(0);
+ cvtest::insert( src, *tmp_src, 0 );
+ }
+ else
+ {
+ cvtest::convertFromCCS( src, src, *tmp_src, flags );
+ tmp_dst = &test_mat[TEMP][1];
+ }
+ }
+
+ if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
+ cvtest::DFT_1D( *tmp_src, *tmp_dst, flags );
+ else
+ cvtest::DFT_2D( *tmp_src, *tmp_dst, flags );
+
+ if( tmp_dst != &dst )
+ cvtest::extract( *tmp_dst, dst, 0 );
+}
+
+////////////////////// DCT ////////////////////////
+class CxCore_DCTTest : public CxCore_DXTBaseTest
+{
+public:
+ CxCore_DCTTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+CxCore_DCTTest::CxCore_DCTTest() : CxCore_DXTBaseTest( false, false, false )
+{
+}
+
+
+void CxCore_DCTTest::run_func()
+{
+ Mat& dst = test_mat[OUTPUT][0];
+ const Mat& src = inplace ? dst : test_mat[INPUT][0];
+
+ if(!(flags & CV_DXT_INVERSE))
+ cv::dct( src, dst, flags );
+ else
+ cv::idct( src, dst, flags & ~CV_DXT_INVERSE);
+}
+
+
+void CxCore_DCTTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_OUTPUT][0];
+
+ if( src.rows == 1 || (src.cols == 1 && !(flags & CV_DXT_ROWS)) )
+ cvtest::DCT_1D( src, dst, flags );
+ else
+ cvtest::DCT_2D( src, dst, flags );
+}
+
+
+////////////////////// MulSpectrums ////////////////////////
+class CxCore_MulSpectrumsTest : public CxCore_DXTBaseTest
+{
+public:
+ CxCore_MulSpectrumsTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+CxCore_MulSpectrumsTest::CxCore_MulSpectrumsTest() : CxCore_DXTBaseTest( true, true, true )
+{
+}
+
+
+void CxCore_MulSpectrumsTest::run_func()
+{
+ Mat& dst = !test_mat[TEMP].empty() && !test_mat[TEMP][0].empty() ?
+ test_mat[TEMP][0] : test_mat[OUTPUT][0];
+ const Mat* src1 = &test_mat[INPUT][0], *src2 = &test_mat[INPUT][1];
+
+ if( inplace )
+ {
+ if( ts->get_current_test_info()->test_case_idx & 1 )
+ src2 = &dst;
+ else
+ src1 = &dst;
+ }
+
+ cv::mulSpectrums( *src1, *src2, dst, flags, (flags & CV_DXT_MUL_CONJ) != 0 );
+}
+
+
+void CxCore_MulSpectrumsTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat* src1 = &test_mat[INPUT][0];
+ Mat* src2 = &test_mat[INPUT][1];
+ Mat& dst = test_mat[OUTPUT][0];
+ Mat& dst0 = test_mat[REF_OUTPUT][0];
+ int cn = src1->channels();
+
+ if( cn == 1 )
+ {
+ cvtest::convertFromCCS( *src1, *src1, dst, flags );
+ cvtest::convertFromCCS( *src2, *src2, dst0, flags );
+ src1 = &dst;
+ src2 = &dst0;
+ }
+
+ cvtest::mulComplex( *src1, *src2, dst0, flags );
+ if( cn == 1 )
+ {
+ Mat& temp = test_mat[TEMP][0];
+ cvtest::convertFromCCS( temp, temp, dst, flags );
+ }
+}
+
+TEST(Core_DCT, accuracy) { CxCore_DCTTest test; test.safe_run(); }
+TEST(Core_DFT, accuracy) { CxCore_DFTTest test; test.safe_run(); }
+TEST(Core_MulSpectrums, accuracy) { CxCore_MulSpectrumsTest test; test.safe_run(); }
+
--- /dev/null
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+static SparseMat cvTsGetRandomSparseMat(int dims, const int* sz, int type,
+ int nzcount, double a, double b, RNG& rng)
+{
+ SparseMat m(dims, sz, type);
+ int i, j;
+ CV_Assert(CV_MAT_CN(type) == 1);
+ for( i = 0; i < nzcount; i++ )
+ {
+ int idx[CV_MAX_DIM];
+ for( j = 0; j < dims; j++ )
+ idx[j] = cvtest::randInt(rng) % sz[j];
+ double val = cvtest::randReal(rng)*(b - a) + a;
+ uchar* ptr = m.ptr(idx, true, 0);
+ if( type == CV_8U )
+ *(uchar*)ptr = saturate_cast<uchar>(val);
+ else if( type == CV_8S )
+ *(schar*)ptr = saturate_cast<schar>(val);
+ else if( type == CV_16U )
+ *(ushort*)ptr = saturate_cast<ushort>(val);
+ else if( type == CV_16S )
+ *(short*)ptr = saturate_cast<short>(val);
+ else if( type == CV_32S )
+ *(int*)ptr = saturate_cast<int>(val);
+ else if( type == CV_32F )
+ *(float*)ptr = saturate_cast<float>(val);
+ else
+ *(double*)ptr = saturate_cast<double>(val);
+ }
+
+ return m;
+}
+
+static bool cvTsCheckSparse(const CvSparseMat* m1, const CvSparseMat* m2, double eps)
+{
+ CvSparseMatIterator it1;
+ CvSparseNode* node1;
+ int depth = CV_MAT_DEPTH(m1->type);
+
+ if( m1->heap->active_count != m2->heap->active_count ||
+ m1->dims != m2->dims || CV_MAT_TYPE(m1->type) != CV_MAT_TYPE(m2->type) )
+ return false;
+
+ for( node1 = cvInitSparseMatIterator( m1, &it1 );
+ node1 != 0; node1 = cvGetNextSparseNode( &it1 ))
+ {
+ uchar* v1 = (uchar*)CV_NODE_VAL(m1,node1);
+ uchar* v2 = cvPtrND( m2, CV_NODE_IDX(m1,node1), 0, 0, &node1->hashval );
+ if( !v2 )
+ return false;
+ if( depth == CV_8U || depth == CV_8S )
+ {
+ if( *v1 != *v2 )
+ return false;
+ }
+ else if( depth == CV_16U || depth == CV_16S )
+ {
+ if( *(ushort*)v1 != *(ushort*)v2 )
+ return false;
+ }
+ else if( depth == CV_32S )
+ {
+ if( *(int*)v1 != *(int*)v2 )
+ return false;
+ }
+ else if( depth == CV_32F )
+ {
+ if( fabs(*(float*)v1 - *(float*)v2) > eps*(fabs(*(float*)v2) + 1) )
+ return false;
+ }
+ else if( fabs(*(double*)v1 - *(double*)v2) > eps*(fabs(*(double*)v2) + 1) )
+ return false;
+ }
+
+ return true;
+}
+
+
+class Core_IOTest : public cvtest::BaseTest
+{
+public:
+ Core_IOTest() {};
+protected:
+ void run(int)
+ {
+ double ranges[][2] = {{0, 256}, {-128, 128}, {0, 65536}, {-32768, 32768},
+ {-1000000, 1000000}, {-10, 10}, {-10, 10}};
+ RNG& rng = ts->get_rng();
+ RNG rng0;
+ test_case_count = 2;
+ int progress = 0;
+ MemStorage storage(cvCreateMemStorage(0));
+
+ for( int idx = 0; idx < test_case_count; idx++ )
+ {
+ ts->update_context( this, idx, false );
+ progress = update_progress( progress, idx, test_case_count, 0 );
+
+ cvClearMemStorage(storage);
+
+ char buf[L_tmpnam+16];
+ char* filename = tmpnam(buf);
+ strcat(filename, idx % 2 ? ".yml" : ".xml");
+ if(filename[0] == '\\')
+ filename++;
+
+ FileStorage fs(filename, FileStorage::WRITE);
+
+ int test_int = (int)cvtest::randInt(rng);
+ double test_real = (cvtest::randInt(rng)%2?1:-1)*exp(cvtest::randReal(rng)*18-9);
+ string test_string = "vw wv23424rt\"&<>&'@#$@$%$%&%IJUKYILFD@#$@%$&*&() ";
+
+ int depth = cvtest::randInt(rng) % (CV_64F+1);
+ int cn = cvtest::randInt(rng) % 4 + 1;
+ Mat test_mat(cvtest::randInt(rng)%30+1, cvtest::randInt(rng)%30+1, CV_MAKETYPE(depth, cn));
+
+ rng0.fill(test_mat, CV_RAND_UNI, Scalar::all(ranges[depth][0]), Scalar::all(ranges[depth][1]));
+ if( depth >= CV_32F )
+ {
+ exp(test_mat, test_mat);
+ Mat test_mat_scale(test_mat.size(), test_mat.type());
+ rng0.fill(test_mat_scale, CV_RAND_UNI, Scalar::all(-1), Scalar::all(1));
+ multiply(test_mat, test_mat_scale, test_mat);
+ }
+
+ CvSeq* seq = cvCreateSeq(test_mat.type(), (int)sizeof(CvSeq),
+ (int)test_mat.elemSize(), storage);
+ cvSeqPushMulti(seq, test_mat.data, test_mat.cols*test_mat.rows);
+
+ CvGraph* graph = cvCreateGraph( CV_ORIENTED_GRAPH,
+ sizeof(CvGraph), sizeof(CvGraphVtx),
+ sizeof(CvGraphEdge), storage );
+ int edges[][2] = {{0,1},{1,2},{2,0},{0,3},{3,4},{4,1}};
+ int i, vcount = 5, ecount = 6;
+ for( i = 0; i < vcount; i++ )
+ cvGraphAddVtx(graph);
+ for( i = 0; i < ecount; i++ )
+ {
+ CvGraphEdge* edge;
+ cvGraphAddEdge(graph, edges[i][0], edges[i][1], 0, &edge);
+ edge->weight = (float)(i+1);
+ }
+
+ depth = cvtest::randInt(rng) % (CV_64F+1);
+ cn = cvtest::randInt(rng) % 4 + 1;
+ int sz[] = {cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1};
+ MatND test_mat_nd(3, sz, CV_MAKETYPE(depth, cn));
+
+ rng0.fill(test_mat_nd, CV_RAND_UNI, Scalar::all(ranges[depth][0]), Scalar::all(ranges[depth][1]));
+ if( depth >= CV_32F )
+ {
+ exp(test_mat_nd, test_mat_nd);
+ MatND test_mat_scale(test_mat_nd.dims, test_mat_nd.size, test_mat_nd.type());
+ rng0.fill(test_mat_scale, CV_RAND_UNI, Scalar::all(-1), Scalar::all(1));
+ multiply(test_mat_nd, test_mat_scale, test_mat_nd);
+ }
+
+ int ssz[] = {cvtest::randInt(rng)%10+1, cvtest::randInt(rng)%10+1,
+ cvtest::randInt(rng)%10+1,cvtest::randInt(rng)%10+1};
+ SparseMat test_sparse_mat = cvTsGetRandomSparseMat(4, ssz, cvtest::randInt(rng)%(CV_64F+1),
+ cvtest::randInt(rng) % 10000, 0, 100, rng);
+
+ fs << "test_int" << test_int << "test_real" << test_real << "test_string" << test_string;
+ fs << "test_mat" << test_mat;
+ fs << "test_mat_nd" << test_mat_nd;
+ fs << "test_sparse_mat" << test_sparse_mat;
+
+ fs << "test_list" << "[" << 0.0000000000001 << 2 << CV_PI << -3435345 << "2-502 2-029 3egegeg" <<
+ "{:" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]";
+ fs << "test_map" << "{" << "x" << 1 << "y" << 2 << "width" << 100 << "height" << 200 << "lbp" << "[:";
+
+ const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1};
+ fs.writeRaw("u", arr, (int)(sizeof(arr)/sizeof(arr[0])));
+
+ fs << "]" << "}";
+ cvWriteComment(*fs, "test comment", 0);
+
+ fs.writeObj("test_seq", seq);
+ fs.writeObj("test_graph",graph);
+ CvGraph* graph2 = (CvGraph*)cvClone(graph);
+
+ fs.release();
+
+ if(!fs.open(filename, FileStorage::READ))
+ {
+ ts->printf( cvtest::TS::LOG, "filename %s can not be read\n", filename );
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
+ return;
+ }
+
+ int real_int = (int)fs["test_int"];
+ double real_real = (double)fs["test_real"];
+ string real_string = (string)fs["test_string"];
+
+ if( real_int != test_int ||
+ fabs(real_real - test_real) > DBL_EPSILON*(fabs(test_real)+1) ||
+ real_string != test_string )
+ {
+ ts->printf( cvtest::TS::LOG, "the read scalars are not correct\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ CvMat* m = (CvMat*)fs["test_mat"].readObj();
+ CvMat _test_mat = test_mat;
+ double max_diff = 0;
+ CvMat stub1, _test_stub1;
+ cvReshape(m, &stub1, 1, 0);
+ cvReshape(&_test_mat, &_test_stub1, 1, 0);
+ vector<int> pt;
+
+ if( !m || !CV_IS_MAT(m) || m->rows != test_mat.rows || m->cols != test_mat.cols ||
+ cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "the read matrix is not correct: (%.20g vs %.20g) at (%d,%d)\n",
+ cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[0], pt[1]),
+ pt[0], pt[1] );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ if( m && CV_IS_MAT(m))
+ cvReleaseMat(&m);
+
+ CvMatND* m_nd = (CvMatND*)fs["test_mat_nd"].readObj();
+ CvMatND _test_mat_nd = test_mat_nd;
+
+ if( !m_nd || !CV_IS_MATND(m_nd) )
+ {
+ ts->printf( cvtest::TS::LOG, "the read nd-matrix is not correct\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ CvMat stub, _test_stub;
+ cvGetMat(m_nd, &stub, 0, 1);
+ cvGetMat(&_test_mat_nd, &_test_stub, 0, 1);
+ cvReshape(&stub, &stub1, 1, 0);
+ cvReshape(&_test_stub, &_test_stub1, 1, 0);
+
+ if( !CV_ARE_TYPES_EQ(&stub, &_test_stub) ||
+ !CV_ARE_SIZES_EQ(&stub, &_test_stub) ||
+ //cvNorm(&stub, &_test_stub, CV_L2) != 0 )
+ cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "readObj method: the read nd matrix is not correct: (%.20g vs %.20g) vs at (%d,%d)\n",
+ cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[0], pt[1]),
+ pt[0], pt[1] );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ MatND mat_nd2;
+ fs["test_mat_nd"] >> mat_nd2;
+ CvMatND m_nd2 = mat_nd2;
+ cvGetMat(&m_nd2, &stub, 0, 1);
+ cvReshape(&stub, &stub1, 1, 0);
+
+ if( !CV_ARE_TYPES_EQ(&stub, &_test_stub) ||
+ !CV_ARE_SIZES_EQ(&stub, &_test_stub) ||
+ //cvNorm(&stub, &_test_stub, CV_L2) != 0 )
+ cvtest::cmpEps( Mat(&stub1), Mat(&_test_stub1), &max_diff, 0, &pt, true) < 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "C++ method: the read nd matrix is not correct: (%.20g vs %.20g) vs at (%d,%d)\n",
+ cvGetReal2D(&stub1, pt[0], pt[1]), cvGetReal2D(&_test_stub1, pt[1], pt[0]),
+ pt[0], pt[1] );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ cvRelease((void**)&m_nd);
+
+ Ptr<CvSparseMat> m_s = (CvSparseMat*)fs["test_sparse_mat"].readObj();
+ Ptr<CvSparseMat> _test_sparse_ = (CvSparseMat*)test_sparse_mat;
+ Ptr<CvSparseMat> _test_sparse = (CvSparseMat*)cvClone(_test_sparse_);
+ SparseMat m_s2;
+ fs["test_sparse_mat"] >> m_s2;
+ Ptr<CvSparseMat> _m_s2 = (CvSparseMat*)m_s2;
+
+ if( !m_s || !CV_IS_SPARSE_MAT(m_s) ||
+ !cvTsCheckSparse(m_s, _test_sparse,0) ||
+ !cvTsCheckSparse(_m_s2, _test_sparse,0))
+ {
+ ts->printf( cvtest::TS::LOG, "the read sparse matrix is not correct\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ FileNode tl = fs["test_list"];
+ if( tl.type() != FileNode::SEQ || tl.size() != 6 ||
+ fabs((double)tl[0] - 0.0000000000001) >= DBL_EPSILON ||
+ (int)tl[1] != 2 ||
+ fabs((double)tl[2] - CV_PI) >= DBL_EPSILON ||
+ (int)tl[3] != -3435345 ||
+ (string)tl[4] != "2-502 2-029 3egegeg" ||
+ tl[5].type() != FileNode::MAP || tl[5].size() != 3 ||
+ (int)tl[5]["month"] != 12 ||
+ (int)tl[5]["day"] != 31 ||
+ (int)tl[5]["year"] != 1969 )
+ {
+ ts->printf( cvtest::TS::LOG, "the test list is incorrect\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ FileNode tm = fs["test_map"];
+ FileNode tm_lbp = tm["lbp"];
+
+ int real_x = (int)tm["x"];
+ int real_y = (int)tm["y"];
+ int real_width = (int)tm["width"];
+ int real_height = (int)tm["height"];
+
+
+ int real_lbp_val = 0;
+ FileNodeIterator it;
+ it = tm_lbp.begin();
+ real_lbp_val |= (int)*it << 0;
+ ++it;
+ real_lbp_val |= (int)*it << 1;
+ it++;
+ real_lbp_val |= (int)*it << 2;
+ it += 1;
+ real_lbp_val |= (int)*it << 3;
+ FileNodeIterator it2(it);
+ it2 += 4;
+ real_lbp_val |= (int)*it2 << 7;
+ --it2;
+ real_lbp_val |= (int)*it2 << 6;
+ it2--;
+ real_lbp_val |= (int)*it2 << 5;
+ it2 -= 1;
+ real_lbp_val |= (int)*it2 << 4;
+ it2 += -1;
+ CV_Assert( it == it2 );
+
+ if( tm.type() != FileNode::MAP || tm.size() != 5 ||
+ real_x != 1 ||
+ real_y != 2 ||
+ real_width != 100 ||
+ real_height != 200 ||
+ tm_lbp.type() != FileNode::SEQ ||
+ tm_lbp.size() != 8 ||
+ real_lbp_val != 0xb6 )
+ {
+ ts->printf( cvtest::TS::LOG, "the test map is incorrect\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ CvGraph* graph3 = (CvGraph*)fs["test_graph"].readObj();
+ if(graph2->active_count != vcount || graph3->active_count != vcount ||
+ graph2->edges->active_count != ecount || graph3->edges->active_count != ecount)
+ {
+ ts->printf( cvtest::TS::LOG, "the cloned or read graph have wrong number of vertices or edges\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ for( i = 0; i < ecount; i++ )
+ {
+ CvGraphEdge* edge2 = cvFindGraphEdge(graph2, edges[i][0], edges[i][1]);
+ CvGraphEdge* edge3 = cvFindGraphEdge(graph3, edges[i][0], edges[i][1]);
+ if( !edge2 || edge2->weight != (float)(i+1) ||
+ !edge3 || edge3->weight != (float)(i+1) )
+ {
+ ts->printf( cvtest::TS::LOG, "the cloned or read graph do not have the edge (%d, %d)\n", edges[i][0], edges[i][1] );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ }
+
+ fs.release();
+ remove(filename);
+ }
+ }
+};
+
+TEST(Core_InputOutput, write_read_consistency) { Core_IOTest test; test.safe_run(); }
#include "test_precomp.hpp"
-#include "opencv2/gtest/gtest_main.hpp"
+
+CV_TEST_MAIN("cv")
--- /dev/null
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+
+class Core_ReduceTest : public cvtest::BaseTest
+{
+public:
+ Core_ReduceTest() {};
+protected:
+ void run( int);
+ int checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim, double eps );
+ int checkCase( int srcType, int dstType, int dim, Size sz );
+ int checkDim( int dim, Size sz );
+ int checkSize( Size sz );
+};
+
+template<class Type>
+void testReduce( const Mat& src, Mat& sum, Mat& avg, Mat& max, Mat& min, int dim )
+{
+ assert( src.channels() == 1 );
+ if( dim == 0 ) // row
+ {
+ sum.create( 1, src.cols, CV_64FC1 );
+ max.create( 1, src.cols, CV_64FC1 );
+ min.create( 1, src.cols, CV_64FC1 );
+ }
+ else
+ {
+ sum.create( src.rows, 1, CV_64FC1 );
+ max.create( src.rows, 1, CV_64FC1 );
+ min.create( src.rows, 1, CV_64FC1 );
+ }
+ sum.setTo(Scalar(0));
+ max.setTo(Scalar(-DBL_MAX));
+ min.setTo(Scalar(DBL_MAX));
+
+ const Mat_<Type>& src_ = src;
+ Mat_<double>& sum_ = (Mat_<double>&)sum;
+ Mat_<double>& min_ = (Mat_<double>&)min;
+ Mat_<double>& max_ = (Mat_<double>&)max;
+
+ if( dim == 0 )
+ {
+ for( int ri = 0; ri < src.rows; ri++ )
+ {
+ for( int ci = 0; ci < src.cols; ci++ )
+ {
+ sum_(0, ci) += src_(ri, ci);
+ max_(0, ci) = std::max( max_(0, ci), (double)src_(ri, ci) );
+ min_(0, ci) = std::min( min_(0, ci), (double)src_(ri, ci) );
+ }
+ }
+ }
+ else
+ {
+ for( int ci = 0; ci < src.cols; ci++ )
+ {
+ for( int ri = 0; ri < src.rows; ri++ )
+ {
+ sum_(ri, 0) += src_(ri, ci);
+ max_(ri, 0) = std::max( max_(ri, 0), (double)src_(ri, ci) );
+ min_(ri, 0) = std::min( min_(ri, 0), (double)src_(ri, ci) );
+ }
+ }
+ }
+ sum.convertTo( avg, CV_64FC1 );
+ avg = avg * (1.0 / (dim==0 ? (double)src.rows : (double)src.cols));
+}
+
+void getMatTypeStr( int type, string& str)
+{
+ str = type == CV_8UC1 ? "CV_8UC1" :
+ type == CV_8SC1 ? "CV_8SC1" :
+ type == CV_16UC1 ? "CV_16UC1" :
+ type == CV_16SC1 ? "CV_16SC1" :
+ type == CV_32SC1 ? "CV_32SC1" :
+ type == CV_32FC1 ? "CV_32FC1" :
+ type == CV_64FC1 ? "CV_64FC1" : "unsupported matrix type";
+}
+
+int Core_ReduceTest::checkOp( const Mat& src, int dstType, int opType, const Mat& opRes, int dim, double eps )
+{
+ int srcType = src.type();
+ bool support = false;
+ if( opType == CV_REDUCE_SUM || opType == CV_REDUCE_AVG )
+ {
+ if( srcType == CV_8U && (dstType == CV_32S || dstType == CV_32F || dstType == CV_64F) )
+ support = true;
+ if( srcType == CV_16U && (dstType == CV_32F || dstType == CV_64F) )
+ support = true;
+ if( srcType == CV_16S && (dstType == CV_32F || dstType == CV_64F) )
+ support = true;
+ if( srcType == CV_32F && (dstType == CV_32F || dstType == CV_64F) )
+ support = true;
+ if( srcType == CV_64F && dstType == CV_64F)
+ support = true;
+ }
+ else if( opType == CV_REDUCE_MAX )
+ {
+ if( srcType == CV_8U && dstType == CV_8U )
+ support = true;
+ if( srcType == CV_32F && dstType == CV_32F )
+ support = true;
+ if( srcType == CV_64F && dstType == CV_64F )
+ support = true;
+ }
+ else if( opType == CV_REDUCE_MIN )
+ {
+ if( srcType == CV_8U && dstType == CV_8U)
+ support = true;
+ if( srcType == CV_32F && dstType == CV_32F)
+ support = true;
+ if( srcType == CV_64F && dstType == CV_64F)
+ support = true;
+ }
+ if( !support )
+ return cvtest::TS::OK;
+
+ assert( opRes.type() == CV_64FC1 );
+ Mat _dst, dst;
+ reduce( src, _dst, dim, opType, dstType );
+ _dst.convertTo( dst, CV_64FC1 );
+ if( norm( opRes, dst, NORM_INF ) > eps )
+ {
+ char msg[100];
+ const char* opTypeStr = opType == CV_REDUCE_SUM ? "CV_REDUCE_SUM" :
+ opType == CV_REDUCE_AVG ? "CV_REDUCE_AVG" :
+ opType == CV_REDUCE_MAX ? "CV_REDUCE_MAX" :
+ opType == CV_REDUCE_MIN ? "CV_REDUCE_MIN" : "unknown operation type";
+ string srcTypeStr, dstTypeStr;
+ getMatTypeStr( src.type(), srcTypeStr );
+ getMatTypeStr( dstType, dstTypeStr );
+ const char* dimStr = dim == 0 ? "ROWS" : "COLS";
+
+ sprintf( msg, "bad accuracy with srcType = %s, dstType = %s, opType = %s, dim = %s",
+ srcTypeStr.c_str(), dstTypeStr.c_str(), opTypeStr, dimStr );
+ ts->printf( cvtest::TS::LOG, msg );
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ return cvtest::TS::OK;
+}
+
+int Core_ReduceTest::checkCase( int srcType, int dstType, int dim, Size sz )
+{
+ int code = cvtest::TS::OK, tempCode;
+ Mat src, sum, avg, max, min;
+
+ src.create( sz, srcType );
+ randu( src, Scalar(0), Scalar(100) );
+
+ if( srcType == CV_8UC1 )
+ testReduce<uchar>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_8SC1 )
+ testReduce<char>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_16UC1 )
+ testReduce<unsigned short int>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_16SC1 )
+ testReduce<short int>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_32SC1 )
+ testReduce<int>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_32FC1 )
+ testReduce<float>( src, sum, avg, max, min, dim );
+ else if( srcType == CV_64FC1 )
+ testReduce<double>( src, sum, avg, max, min, dim );
+ else
+ assert( 0 );
+
+ // 1. sum
+ tempCode = checkOp( src, dstType, CV_REDUCE_SUM, sum, dim,
+ srcType == CV_32FC1 && dstType == CV_32FC1 ? 0.05 : FLT_EPSILON );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // 2. avg
+ tempCode = checkOp( src, dstType, CV_REDUCE_AVG, avg, dim,
+ dstType == CV_32SC1 ? 0.6 : 0.00007 );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // 3. max
+ tempCode = checkOp( src, dstType, CV_REDUCE_MAX, max, dim, FLT_EPSILON );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // 4. min
+ tempCode = checkOp( src, dstType, CV_REDUCE_MIN, min, dim, FLT_EPSILON );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ return code;
+}
+
+int Core_ReduceTest::checkDim( int dim, Size sz )
+{
+ int code = cvtest::TS::OK, tempCode;
+
+ // CV_8UC1
+ tempCode = checkCase( CV_8UC1, CV_8UC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_8UC1, CV_32SC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_8UC1, CV_32FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_8UC1, CV_64FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // CV_16UC1
+ tempCode = checkCase( CV_16UC1, CV_32FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_16UC1, CV_64FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // CV_16SC1
+ tempCode = checkCase( CV_16SC1, CV_32FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_16SC1, CV_64FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // CV_32FC1
+ tempCode = checkCase( CV_32FC1, CV_32FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkCase( CV_32FC1, CV_64FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ // CV_64FC1
+ tempCode = checkCase( CV_64FC1, CV_64FC1, dim, sz );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ return code;
+}
+
+int Core_ReduceTest::checkSize( Size sz )
+{
+ int code = cvtest::TS::OK, tempCode;
+
+ tempCode = checkDim( 0, sz ); // rows
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkDim( 1, sz ); // cols
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ return code;
+}
+
+void Core_ReduceTest::run( int )
+{
+ int code = cvtest::TS::OK, tempCode;
+
+ tempCode = checkSize( Size(1,1) );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkSize( Size(1,100) );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkSize( Size(100,1) );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ tempCode = checkSize( Size(1000,500) );
+ code = tempCode != cvtest::TS::OK ? tempCode : code;
+
+ ts->set_failed_test_info( code );
+}
+
+
+#define CHECK_C
+
+Size sz(200, 500);
+
+class Core_PCATest : public cvtest::BaseTest
+{
+public:
+ Core_PCATest() {}
+protected:
+ void run(int)
+ {
+ int code = cvtest::TS::OK;
+
+ double diffPrjEps, diffBackPrjEps,
+ prjEps, backPrjEps,
+ evalEps, evecEps;
+ int maxComponents = 100;
+ Mat rPoints(sz, CV_32FC1), rTestPoints(sz, CV_32FC1);
+ RNG& rng = ts->get_rng();
+
+ rng.fill( rPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
+ rng.fill( rTestPoints, RNG::UNIFORM, Scalar::all(0.0), Scalar::all(1.0) );
+
+ PCA rPCA( rPoints, Mat(), CV_PCA_DATA_AS_ROW, maxComponents ), cPCA;
+
+ // 1. check C++ PCA & ROW
+ Mat rPrjTestPoints = rPCA.project( rTestPoints );
+ Mat rBackPrjTestPoints = rPCA.backProject( rPrjTestPoints );
+
+ Mat avg(1, sz.width, CV_32FC1 );
+ reduce( rPoints, avg, 0, CV_REDUCE_AVG );
+ Mat Q = rPoints - repeat( avg, rPoints.rows, 1 ), Qt = Q.t(), eval, evec;
+ Q = Qt * Q;
+ Q = Q /(float)rPoints.rows;
+
+ eigen( Q, eval, evec );
+ /*SVD svd(Q);
+ evec = svd.vt;
+ eval = svd.w;*/
+
+ Mat subEval( maxComponents, 1, eval.type(), eval.data ),
+ subEvec( maxComponents, evec.cols, evec.type(), evec.data );
+
+ #ifdef CHECK_C
+ Mat prjTestPoints, backPrjTestPoints, cPoints = rPoints.t(), cTestPoints = rTestPoints.t();
+ CvMat _points, _testPoints, _avg, _eval, _evec, _prjTestPoints, _backPrjTestPoints;
+ #endif
+
+ // check eigen()
+ double eigenEps = 1e-6;
+ double err;
+ for(int i = 0; i < Q.rows; i++ )
+ {
+ Mat v = evec.row(i).t();
+ Mat Qv = Q * v;
+
+ Mat lv = eval.at<float>(i,0) * v;
+ err = norm( Qv, lv );
+ if( err > eigenEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of eigen(); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ }
+ // check pca eigenvalues
+ evalEps = 1e-6, evecEps = 1;
+ err = norm( rPCA.eigenvalues, subEval );
+ if( err > evalEps )
+ {
+ ts->printf( cvtest::TS::LOG, "pca.eigenvalues is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ // check pca eigenvectors
+ err = norm( rPCA.eigenvectors, subEvec, CV_RELATIVE_L2 );
+ if( err > evecEps )
+ {
+ ts->printf( cvtest::TS::LOG, "pca.eigenvectors is incorrect (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+
+ prjEps = 1.265, backPrjEps = 1.265;
+ for( int i = 0; i < rTestPoints.rows; i++ )
+ {
+ // check pca project
+ Mat subEvec_t = subEvec.t();
+ Mat prj = rTestPoints.row(i) - avg; prj *= subEvec_t;
+ err = norm(rPrjTestPoints.row(i), prj, CV_RELATIVE_L2);
+ if( err > prjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ // check pca backProject
+ Mat backPrj = rPrjTestPoints.row(i) * subEvec + avg;
+ err = norm( rBackPrjTestPoints.row(i), backPrj, CV_RELATIVE_L2 );
+ if( err > backPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ }
+
+ // 2. check C++ PCA & COL
+ cPCA( rPoints.t(), Mat(), CV_PCA_DATA_AS_COL, maxComponents );
+ diffPrjEps = 1, diffBackPrjEps = 1;
+ err = norm(cPCA.project(rTestPoints.t()), rPrjTestPoints.t(), CV_RELATIVE_L2 );
+ if( err > diffPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of project() (CV_PCA_DATA_AS_COL); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ err = norm(cPCA.backProject(rPrjTestPoints.t()), rBackPrjTestPoints.t(), CV_RELATIVE_L2 );
+ if( err > diffBackPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of backProject() (CV_PCA_DATA_AS_COL); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+
+ #ifdef CHECK_C
+ // 3. check C PCA & ROW
+ _points = rPoints;
+ _testPoints = rTestPoints;
+ _avg = avg;
+ _eval = eval;
+ _evec = evec;
+ prjTestPoints.create(rTestPoints.rows, maxComponents, rTestPoints.type() );
+ backPrjTestPoints.create(rPoints.size(), rPoints.type() );
+ _prjTestPoints = prjTestPoints;
+ _backPrjTestPoints = backPrjTestPoints;
+
+ cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_ROW );
+ cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
+ cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
+
+ err = norm(prjTestPoints, rPrjTestPoints, CV_RELATIVE_L2);
+ if( err > diffPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ err = norm(backPrjTestPoints, rBackPrjTestPoints, CV_RELATIVE_L2);
+ if( err > diffBackPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_ROW); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+
+ // 3. check C PCA & COL
+ _points = cPoints;
+ _testPoints = cTestPoints;
+ avg = avg.t(); _avg = avg;
+ eval = eval.t(); _eval = eval;
+ evec = evec.t(); _evec = evec;
+ prjTestPoints = prjTestPoints.t(); _prjTestPoints = prjTestPoints;
+ backPrjTestPoints = backPrjTestPoints.t(); _backPrjTestPoints = backPrjTestPoints;
+
+ cvCalcPCA( &_points, &_avg, &_eval, &_evec, CV_PCA_DATA_AS_COL );
+ cvProjectPCA( &_testPoints, &_avg, &_evec, &_prjTestPoints );
+ cvBackProjectPCA( &_prjTestPoints, &_avg, &_evec, &_backPrjTestPoints );
+
+ err = norm(prjTestPoints, rPrjTestPoints.t(), CV_RELATIVE_L2 );
+ if( err > diffPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of cvProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ err = norm(backPrjTestPoints, rBackPrjTestPoints.t(), CV_RELATIVE_L2);
+ if( err > diffBackPrjEps )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of cvBackProjectPCA() (CV_PCA_DATA_AS_COL); err = %f\n", err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto exit_func;
+ }
+ #endif
+
+ exit_func:
+
+ RNG& _rng = ts->get_rng();
+ _rng = rng;
+ ts->set_failed_test_info( code );
+ }
+};
+
+class Core_ArrayOpTest : public cvtest::BaseTest
+{
+public:
+ Core_ArrayOpTest();
+ ~Core_ArrayOpTest();
+protected:
+ void run(int);
+};
+
+
+Core_ArrayOpTest::Core_ArrayOpTest()
+{
+}
+Core_ArrayOpTest::~Core_ArrayOpTest() {}
+
+static string idx2string(const int* idx, int dims)
+{
+ char buf[256];
+ char* ptr = buf;
+ for( int k = 0; k < dims; k++ )
+ {
+ sprintf(ptr, "%4d ", idx[k]);
+ ptr += strlen(ptr);
+ }
+ ptr[-1] = '\0';
+ return string(buf);
+}
+
+static const int* string2idx(const string& s, int* idx, int dims)
+{
+ const char* ptr = s.c_str();
+ for( int k = 0; k < dims; k++ )
+ {
+ int n = 0;
+ sscanf(ptr, "%d%n", idx + k, &n);
+ ptr += n;
+ }
+ return idx;
+}
+
+static double getValue(SparseMat& M, const int* idx, RNG& rng)
+{
+ int d = M.dims();
+ size_t hv = 0, *phv = 0;
+ if( (unsigned)rng % 2 )
+ {
+ hv = d == 2 ? M.hash(idx[0], idx[1]) :
+ d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
+ phv = &hv;
+ }
+
+ const uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], false, phv) :
+ d == 3 ? M.ptr(idx[0], idx[1], idx[2], false, phv) :
+ M.ptr(idx, false, phv);
+ return !ptr ? 0 : M.type() == CV_32F ? *(float*)ptr : M.type() == CV_64F ? *(double*)ptr : 0;
+}
+
+static double getValue(const CvSparseMat* M, const int* idx)
+{
+ int type = 0;
+ const uchar* ptr = cvPtrND(M, idx, &type, 0);
+ return !ptr ? 0 : type == CV_32F ? *(float*)ptr : type == CV_64F ? *(double*)ptr : 0;
+}
+
+static void eraseValue(SparseMat& M, const int* idx, RNG& rng)
+{
+ int d = M.dims();
+ size_t hv = 0, *phv = 0;
+ if( (unsigned)rng % 2 )
+ {
+ hv = d == 2 ? M.hash(idx[0], idx[1]) :
+ d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
+ phv = &hv;
+ }
+
+ if( d == 2 )
+ M.erase(idx[0], idx[1], phv);
+ else if( d == 3 )
+ M.erase(idx[0], idx[1], idx[2], phv);
+ else
+ M.erase(idx, phv);
+}
+
+static void eraseValue(CvSparseMat* M, const int* idx)
+{
+ cvClearND(M, idx);
+}
+
+static void setValue(SparseMat& M, const int* idx, double value, RNG& rng)
+{
+ int d = M.dims();
+ size_t hv = 0, *phv = 0;
+ if( (unsigned)rng % 2 )
+ {
+ hv = d == 2 ? M.hash(idx[0], idx[1]) :
+ d == 3 ? M.hash(idx[0], idx[1], idx[2]) : M.hash(idx);
+ phv = &hv;
+ }
+
+ uchar* ptr = d == 2 ? M.ptr(idx[0], idx[1], true, phv) :
+ d == 3 ? M.ptr(idx[0], idx[1], idx[2], true, phv) :
+ M.ptr(idx, true, phv);
+ if( M.type() == CV_32F )
+ *(float*)ptr = (float)value;
+ else if( M.type() == CV_64F )
+ *(double*)ptr = value;
+ else
+ CV_Error(CV_StsUnsupportedFormat, "");
+}
+
+void Core_ArrayOpTest::run( int /* start_from */)
+{
+ int errcount = 0;
+
+ // dense matrix operations
+ {
+ int sz3[] = {5, 10, 15};
+ MatND A(3, sz3, CV_32F), B(3, sz3, CV_16SC4);
+ CvMatND matA = A, matB = B;
+ RNG rng;
+ rng.fill(A, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
+ rng.fill(B, CV_RAND_UNI, Scalar::all(-10), Scalar::all(10));
+
+ int idx0[] = {3,4,5}, idx1[] = {0, 9, 7};
+ float val0 = 130;
+ Scalar val1(-1000, 30, 3, 8);
+ cvSetRealND(&matA, idx0, val0);
+ cvSetReal3D(&matA, idx1[0], idx1[1], idx1[2], -val0);
+ cvSetND(&matB, idx0, val1);
+ cvSet3D(&matB, idx1[0], idx1[1], idx1[2], -val1);
+ Ptr<CvMatND> matC = cvCloneMatND(&matB);
+
+ if( A.at<float>(idx0[0], idx0[1], idx0[2]) != val0 ||
+ A.at<float>(idx1[0], idx1[1], idx1[2]) != -val0 ||
+ cvGetReal3D(&matA, idx0[0], idx0[1], idx0[2]) != val0 ||
+ cvGetRealND(&matA, idx1) != -val0 ||
+
+ Scalar(B.at<Vec4s>(idx0[0], idx0[1], idx0[2])) != val1 ||
+ Scalar(B.at<Vec4s>(idx1[0], idx1[1], idx1[2])) != -val1 ||
+ Scalar(cvGet3D(matC, idx0[0], idx0[1], idx0[2])) != val1 ||
+ Scalar(cvGetND(matC, idx1)) != -val1 )
+ {
+ ts->printf(cvtest::TS::LOG, "one of cvSetReal3D, cvSetRealND, cvSet3D, cvSetND "
+ "or the corresponding *Get* functions is not correct\n");
+ errcount++;
+ }
+ }
+
+ RNG rng;
+ const int MAX_DIM = 5, MAX_DIM_SZ = 10;
+ // sparse matrix operations
+ for( int si = 0; si < 10; si++ )
+ {
+ int depth = (unsigned)rng % 2 == 0 ? CV_32F : CV_64F;
+ int dims = ((unsigned)rng % MAX_DIM) + 1;
+ int i, k, size[MAX_DIM]={0}, idx[MAX_DIM]={0};
+ vector<string> all_idxs;
+ vector<double> all_vals;
+ vector<double> all_vals2;
+ string sidx, min_sidx, max_sidx;
+ double min_val=0, max_val=0;
+
+ int p = 1;
+ for( k = 0; k < dims; k++ )
+ {
+ size[k] = ((unsigned)rng % MAX_DIM_SZ) + 1;
+ p *= size[k];
+ }
+ SparseMat M( dims, size, depth );
+ map<string, double> M0;
+
+ int nz0 = (unsigned)rng % max(p/5,10);
+ nz0 = min(max(nz0, 1), p);
+ all_vals.resize(nz0);
+ all_vals2.resize(nz0);
+ Mat_<double> _all_vals(all_vals), _all_vals2(all_vals2);
+ rng.fill(_all_vals, CV_RAND_UNI, Scalar(-1000), Scalar(1000));
+ if( depth == CV_32F )
+ {
+ Mat _all_vals_f;
+ _all_vals.convertTo(_all_vals_f, CV_32F);
+ _all_vals_f.convertTo(_all_vals, CV_64F);
+ }
+ _all_vals.convertTo(_all_vals2, _all_vals2.type(), 2);
+ if( depth == CV_32F )
+ {
+ Mat _all_vals2_f;
+ _all_vals2.convertTo(_all_vals2_f, CV_32F);
+ _all_vals2_f.convertTo(_all_vals2, CV_64F);
+ }
+
+ minMaxLoc(_all_vals, &min_val, &max_val);
+ double _norm0 = norm(_all_vals, CV_C);
+ double _norm1 = norm(_all_vals, CV_L1);
+ double _norm2 = norm(_all_vals, CV_L2);
+
+ for( i = 0; i < nz0; i++ )
+ {
+ for(;;)
+ {
+ for( k = 0; k < dims; k++ )
+ idx[k] = (unsigned)rng % size[k];
+ sidx = idx2string(idx, dims);
+ if( M0.count(sidx) == 0 )
+ break;
+ }
+ all_idxs.push_back(sidx);
+ M0[sidx] = all_vals[i];
+ if( all_vals[i] == min_val )
+ min_sidx = sidx;
+ if( all_vals[i] == max_val )
+ max_sidx = sidx;
+ setValue(M, idx, all_vals[i], rng);
+ double v = getValue(M, idx, rng);
+ if( v != all_vals[i] )
+ {
+ ts->printf(cvtest::TS::LOG, "%d. immediately after SparseMat[%s]=%.20g the current value is %.20g\n",
+ i, sidx.c_str(), all_vals[i], v);
+ errcount++;
+ break;
+ }
+ }
+
+ Ptr<CvSparseMat> M2 = (CvSparseMat*)M;
+ MatND Md;
+ M.copyTo(Md);
+ SparseMat M3; SparseMat(Md).convertTo(M3, Md.type(), 2);
+
+ int nz1 = (int)M.nzcount(), nz2 = (int)M3.nzcount();
+ double norm0 = norm(M, CV_C);
+ double norm1 = norm(M, CV_L1);
+ double norm2 = norm(M, CV_L2);
+ double eps = depth == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000;
+
+ if( nz1 != nz0 || nz2 != nz0)
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "%d: The number of non-zero elements before/after converting to/from dense matrix is not correct: %d/%d (while it should be %d)\n",
+ si, nz1, nz2, nz0 );
+ break;
+ }
+
+ if( fabs(norm0 - _norm0) > fabs(_norm0)*eps ||
+ fabs(norm1 - _norm1) > fabs(_norm1)*eps ||
+ fabs(norm2 - _norm2) > fabs(_norm2)*eps )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "%d: The norms are different: %.20g/%.20g/%.20g vs %.20g/%.20g/%.20g\n",
+ si, norm0, norm1, norm2, _norm0, _norm1, _norm2 );
+ break;
+ }
+
+ int n = (unsigned)rng % max(p/5,10);
+ n = min(max(n, 1), p) + nz0;
+
+ for( i = 0; i < n; i++ )
+ {
+ double val1, val2, val3, val0;
+ if(i < nz0)
+ {
+ sidx = all_idxs[i];
+ string2idx(sidx, idx, dims);
+ val0 = all_vals[i];
+ }
+ else
+ {
+ for( k = 0; k < dims; k++ )
+ idx[k] = (unsigned)rng % size[k];
+ sidx = idx2string(idx, dims);
+ val0 = M0[sidx];
+ }
+ val1 = getValue(M, idx, rng);
+ val2 = getValue(M2, idx);
+ val3 = getValue(M3, idx, rng);
+
+ if( val1 != val0 || val2 != val0 || fabs(val3 - val0*2) > fabs(val0*2)*FLT_EPSILON )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "SparseMat M[%s] = %g/%g/%g (while it should be %g)\n", sidx.c_str(), val1, val2, val3, val0 );
+ break;
+ }
+ }
+
+ for( i = 0; i < n; i++ )
+ {
+ double val1, val2;
+ if(i < nz0)
+ {
+ sidx = all_idxs[i];
+ string2idx(sidx, idx, dims);
+ }
+ else
+ {
+ for( k = 0; k < dims; k++ )
+ idx[k] = (unsigned)rng % size[k];
+ sidx = idx2string(idx, dims);
+ }
+ eraseValue(M, idx, rng);
+ eraseValue(M2, idx);
+ val1 = getValue(M, idx, rng);
+ val2 = getValue(M2, idx);
+ if( val1 != 0 || val2 != 0 )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "SparseMat: after deleting M[%s], it is =%g/%g (while it should be 0)\n", sidx.c_str(), val1, val2 );
+ break;
+ }
+ }
+
+ int nz = (int)M.nzcount();
+ if( nz != 0 )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "The number of non-zero elements after removing all the elements = %d (while it should be 0)\n", nz );
+ break;
+ }
+
+ int idx1[MAX_DIM], idx2[MAX_DIM];
+ double val1 = 0, val2 = 0;
+ M3 = SparseMat(Md);
+ minMaxLoc(M3, &val1, &val2, idx1, idx2);
+ string s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
+ if( val1 != min_val || val2 != max_val || s1 != min_sidx || s2 != max_sidx )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "%d. Sparse: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t"
+ "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
+ min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
+ break;
+ }
+
+ minMaxLoc(Md, &val1, &val2, idx1, idx2);
+ s1 = idx2string(idx1, dims), s2 = idx2string(idx2, dims);
+ if( (min_val < 0 && (val1 != min_val || s1 != min_sidx)) ||
+ (max_val > 0 && (val2 != max_val || s2 != max_sidx)) )
+ {
+ errcount++;
+ ts->printf(cvtest::TS::LOG, "%d. Dense: The value and positions of minimum/maximum elements are different from the reference values and positions:\n\t"
+ "(%g, %g, %s, %s) vs (%g, %g, %s, %s)\n", si, val1, val2, s1.c_str(), s2.c_str(),
+ min_val, max_val, min_sidx.c_str(), max_sidx.c_str());
+ break;
+ }
+ }
+
+ ts->set_failed_test_info(errcount == 0 ? cvtest::TS::OK : cvtest::TS::FAIL_INVALID_OUTPUT);
+}
+
+TEST(Core_PCA, accuracy) { Core_PCATest test; test.safe_run(); }
+TEST(Core_Reduce, accuracy) { Core_ReduceTest test; test.safe_run(); }
+TEST(Core_Array, basic_operations) { Core_ArrayOpTest test; test.safe_run(); }
--- /dev/null
+//////////////////////////////////////////////////////////////////////////////////////////
+/////////////////// tests for matrix operations and math functions ///////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#include "test_precomp.hpp"
+#include <float.h>
+#include <math.h>
+
+using namespace cv;
+using namespace std;
+
+/// !!! NOTE !!! These tests happily avoid overflow cases & out-of-range arguments
+/// so that output arrays contain neigher Inf's nor Nan's.
+/// Handling such cases would require special modification of check function
+/// (validate_test_results) => TBD.
+/// Also, need some logarithmic-scale generation of input data. Right now it is done (in some tests)
+/// by generating min/max boundaries for random data in logarimithic scale, but
+/// within the same test case all the input array elements are of the same order.
+
+class Core_MathTest : public cvtest::ArrayTest
+{
+public:
+ typedef cvtest::ArrayTest Base;
+ Core_MathTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes,
+ vector<vector<int> >& types);
+ double get_success_error_level( int /*test_case_idx*/, int i, int j );
+ bool test_nd;
+};
+
+
+Core_MathTest::Core_MathTest()
+{
+ optional_mask = false;
+
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+
+ test_nd = false;
+}
+
+
+double Core_MathTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ return test_mat[i][j].depth() == CV_32F ? FLT_EPSILON*128 : DBL_EPSILON*1024;
+}
+
+
+void Core_MathTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types)
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng)%2 + CV_32F;
+ int cn = cvtest::randInt(rng) % 4 + 1, type = CV_MAKETYPE(depth, cn);
+ size_t i, j;
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ for( i = 0; i < test_array.size(); i++ )
+ {
+ size_t count = test_array[i].size();
+ for( j = 0; j < count; j++ )
+ types[i][j] = type;
+ }
+ test_nd = cvtest::randInt(rng)%3 == 0;
+}
+
+
+////////// pow /////////////
+
+class Core_PowTest : public Core_MathTest
+{
+public:
+ typedef Core_MathTest Base;
+ Core_PowTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ double power;
+};
+
+
+Core_PowTest::Core_PowTest()
+{
+ power = 0;
+}
+
+
+void Core_PowTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % (CV_64F+1);
+ int cn = cvtest::randInt(rng) % 4 + 1;
+ size_t i, j;
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth += depth == CV_8S;
+
+ if( depth < CV_32F || cvtest::randInt(rng)%8 == 0 )
+ // integer power
+ power = (int)(cvtest::randInt(rng)%21 - 10);
+ else
+ {
+ i = cvtest::randInt(rng)%17;
+ power = i == 16 ? 1./3 : i == 15 ? 0.5 : i == 14 ? -0.5 : cvtest::randReal(rng)*10 - 5;
+ }
+
+ for( i = 0; i < test_array.size(); i++ )
+ {
+ size_t count = test_array[i].size();
+ int type = CV_MAKETYPE(depth, cn);
+ for( j = 0; j < count; j++ )
+ types[i][j] = type;
+ }
+ test_nd = cvtest::randInt(rng)%3 == 0;
+}
+
+
+double Core_PowTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ if( depth < CV_32F )
+ return power == cvRound(power) && power >= 0 ? 0 : 1;
+ else
+ return Base::get_success_error_level( test_case_idx, i, j );
+}
+
+
+void Core_PowTest::get_minmax_bounds( int /*i*/, int /*j*/, int type, Scalar& low, Scalar& high )
+{
+ double l, u = cvtest::randInt(ts->get_rng())%1000 + 1;
+ if( power > 0 )
+ {
+ double mval = cvtest::getMaxVal(type);
+ double u1 = pow(mval,1./power)*2;
+ u = MIN(u,u1);
+ }
+
+ l = power == cvRound(power) ? -u : FLT_EPSILON;
+ low = Scalar::all(l);
+ high = Scalar::all(u);
+}
+
+
+void Core_PowTest::run_func()
+{
+ if(!test_nd)
+ {
+ if( fabs(power-1./3) <= DBL_EPSILON && test_mat[INPUT][0].depth() == CV_32F )
+ {
+ Mat a = test_mat[INPUT][0], b = test_mat[OUTPUT][0];
+
+ a = a.reshape(1);
+ b = b.reshape(1);
+ for( int i = 0; i < a.rows; i++ )
+ {
+ b.at<float>(i,0) = (float)fabs(cvCbrt(a.at<float>(i,0)));
+ for( int j = 1; j < a.cols; j++ )
+ b.at<float>(i,j) = (float)fabs(cv::cubeRoot(a.at<float>(i,j)));
+ }
+ }
+ else
+ cvPow( test_array[INPUT][0], test_array[OUTPUT][0], power );
+ }
+ else
+ {
+ Mat& a = test_mat[INPUT][0];
+ Mat& b = test_mat[OUTPUT][0];
+ if(power == 0.5)
+ cv::sqrt(a, b);
+ else
+ cv::pow(a, power, b);
+ }
+}
+
+
+inline static int ipow( int a, int power )
+{
+ int b = 1;
+ while( power > 0 )
+ {
+ if( power&1 )
+ b *= a, power--;
+ else
+ a *= a, power >>= 1;
+ }
+ return b;
+}
+
+
+inline static double ipow( double a, int power )
+{
+ double b = 1.;
+ while( power > 0 )
+ {
+ if( power&1 )
+ b *= a, power--;
+ else
+ a *= a, power >>= 1;
+ }
+ return b;
+}
+
+
+void Core_PowTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& a = test_mat[INPUT][0];
+ Mat& b = test_mat[REF_OUTPUT][0];
+
+ int depth = a.depth();
+ int ncols = a.cols*a.channels();
+ int ipower = cvRound(power), apower = abs(ipower);
+ int i, j;
+
+ for( i = 0; i < a.rows; i++ )
+ {
+ const uchar* a_data = a.ptr(i);
+ uchar* b_data = b.ptr(i);
+
+ switch( depth )
+ {
+ case CV_8U:
+ if( ipower < 0 )
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((uchar*)a_data)[j];
+ ((uchar*)b_data)[j] = (uchar)(val <= 1 ? val :
+ val == 2 && ipower == -1 ? 1 : 0);
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((uchar*)a_data)[j];
+ val = ipow( val, ipower );
+ ((uchar*)b_data)[j] = saturate_cast<uchar>(val);
+ }
+ break;
+ case CV_8S:
+ if( ipower < 0 )
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((char*)a_data)[j];
+ ((char*)b_data)[j] = (char)((val&~1)==0 ? val :
+ val ==-1 ? 1-2*(ipower&1) :
+ val == 2 && ipower == -1 ? 1 : 0);
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((char*)a_data)[j];
+ val = ipow( val, ipower );
+ ((char*)b_data)[j] = saturate_cast<schar>(val);
+ }
+ break;
+ case CV_16U:
+ if( ipower < 0 )
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((ushort*)a_data)[j];
+ ((ushort*)b_data)[j] = (ushort)((val&~1)==0 ? val :
+ val ==-1 ? 1-2*(ipower&1) :
+ val == 2 && ipower == -1 ? 1 : 0);
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((ushort*)a_data)[j];
+ val = ipow( val, ipower );
+ ((ushort*)b_data)[j] = saturate_cast<ushort>(val);
+ }
+ break;
+ case CV_16S:
+ if( ipower < 0 )
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((short*)a_data)[j];
+ ((short*)b_data)[j] = (short)((val&~1)==0 ? val :
+ val ==-1 ? 1-2*(ipower&1) :
+ val == 2 && ipower == -1 ? 1 : 0);
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((short*)a_data)[j];
+ val = ipow( val, ipower );
+ ((short*)b_data)[j] = saturate_cast<short>(val);
+ }
+ break;
+ case CV_32S:
+ if( ipower < 0 )
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((int*)a_data)[j];
+ ((int*)b_data)[j] = (val&~1)==0 ? val :
+ val ==-1 ? 1-2*(ipower&1) :
+ val == 2 && ipower == -1 ? 1 : 0;
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ int val = ((int*)a_data)[j];
+ val = ipow( val, ipower );
+ ((int*)b_data)[j] = val;
+ }
+ break;
+ case CV_32F:
+ if( power != ipower )
+ for( j = 0; j < ncols; j++ )
+ {
+ double val = ((float*)a_data)[j];
+ val = pow( fabs(val), power );
+ ((float*)b_data)[j] = (float)val;
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ double val = ((float*)a_data)[j];
+ if( ipower < 0 )
+ val = 1./val;
+ val = ipow( val, apower );
+ ((float*)b_data)[j] = (float)val;
+ }
+ break;
+ case CV_64F:
+ if( power != ipower )
+ for( j = 0; j < ncols; j++ )
+ {
+ double val = ((double*)a_data)[j];
+ val = pow( fabs(val), power );
+ ((double*)b_data)[j] = (double)val;
+ }
+ else
+ for( j = 0; j < ncols; j++ )
+ {
+ double val = ((double*)a_data)[j];
+ if( ipower < 0 )
+ val = 1./val;
+ val = ipow( val, apower );
+ ((double*)b_data)[j] = (double)val;
+ }
+ break;
+ }
+ }
+}
+
+
+
+///////////////////////////////////////// matrix tests ////////////////////////////////////////////
+
+class Core_MatrixTest : public cvtest::ArrayTest
+{
+public:
+ typedef cvtest::ArrayTest Base;
+ Core_MatrixTest( int in_count, int out_count,
+ bool allow_int, bool scalar_output, int max_cn );
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ bool allow_int;
+ bool scalar_output;
+ int max_cn;
+};
+
+
+Core_MatrixTest::Core_MatrixTest( int in_count, int out_count,
+ bool _allow_int, bool _scalar_output, int _max_cn )
+: allow_int(_allow_int), scalar_output(_scalar_output), max_cn(_max_cn)
+{
+ int i;
+ for( i = 0; i < in_count; i++ )
+ test_array[INPUT].push_back(NULL);
+
+ for( i = 0; i < out_count; i++ )
+ {
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ }
+
+ element_wise_relative_error = false;
+}
+
+
+void Core_MatrixTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % (allow_int ? CV_64F+1 : 2);
+ int cn = cvtest::randInt(rng) % max_cn + 1;
+ size_t i, j;
+
+ if( allow_int )
+ depth += depth == CV_8S;
+ else
+ depth += CV_32F;
+
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ for( i = 0; i < test_array.size(); i++ )
+ {
+ size_t count = test_array[i].size();
+ int flag = (i == OUTPUT || i == REF_OUTPUT) && scalar_output;
+ int type = !flag ? CV_MAKETYPE(depth, cn) : CV_64FC1;
+
+ for( j = 0; j < count; j++ )
+ {
+ types[i][j] = type;
+ if( flag )
+ sizes[i][j] = Size( 4, 1 );
+ }
+ }
+}
+
+
+double Core_MatrixTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ int input_depth = test_mat[INPUT][0].depth();
+ double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 5e-5 : 5e-10;
+ double output_precision = Base::get_success_error_level( test_case_idx, i, j );
+ return MAX(input_precision, output_precision);
+}
+
+
+///////////////// Trace /////////////////////
+
+class Core_TraceTest : public Core_MatrixTest
+{
+public:
+ Core_TraceTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_TraceTest::Core_TraceTest() : Core_MatrixTest( 1, 1, true, true, 4 )
+{
+}
+
+
+void Core_TraceTest::run_func()
+{
+ test_mat[OUTPUT][0].at<Scalar>(0,0) = cvTrace(test_array[INPUT][0]);
+}
+
+
+void Core_TraceTest::prepare_to_validation( int )
+{
+ Mat& mat = test_mat[INPUT][0];
+ int count = MIN( mat.rows, mat.cols );
+ Mat diag(count, 1, mat.type(), mat.data, mat.step + mat.elemSize());
+ Scalar r = cvtest::mean(diag);
+ r *= (double)count;
+
+ test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = r;
+}
+
+
+///////// dotproduct //////////
+
+class Core_DotProductTest : public Core_MatrixTest
+{
+public:
+ Core_DotProductTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_DotProductTest::Core_DotProductTest() : Core_MatrixTest( 2, 1, true, true, 4 )
+{
+}
+
+
+void Core_DotProductTest::run_func()
+{
+ test_mat[OUTPUT][0].at<Scalar>(0,0) = Scalar(cvDotProduct( test_array[INPUT][0], test_array[INPUT][1] ));
+}
+
+
+void Core_DotProductTest::prepare_to_validation( int )
+{
+ test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = Scalar(cvtest::crossCorr( test_mat[INPUT][0], test_mat[INPUT][1] ));
+}
+
+
+///////// crossproduct //////////
+
+class Core_CrossProductTest : public Core_MatrixTest
+{
+public:
+ Core_CrossProductTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_CrossProductTest::Core_CrossProductTest() : Core_MatrixTest( 2, 1, false, false, 1 )
+{
+}
+
+
+void Core_CrossProductTest::get_test_array_types_and_sizes( int,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2 + CV_32F;
+ int cn = cvtest::randInt(rng) & 1 ? 3 : 1, type = CV_MAKETYPE(depth, cn);
+ CvSize sz;
+
+ types[INPUT][0] = types[INPUT][1] = types[OUTPUT][0] = types[REF_OUTPUT][0] = type;
+
+ if( cn == 3 )
+ sz = Size(1,1);
+ else if( cvtest::randInt(rng) & 1 )
+ sz = Size(3,1);
+ else
+ sz = Size(1,3);
+
+ sizes[INPUT][0] = sizes[INPUT][1] = sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
+}
+
+
+void Core_CrossProductTest::run_func()
+{
+ cvCrossProduct( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0] );
+}
+
+
+void Core_CrossProductTest::prepare_to_validation( int )
+{
+ CvScalar a = {{0,0,0,0}}, b = {{0,0,0,0}}, c = {{0,0,0,0}};
+
+ if( test_mat[INPUT][0].rows > 1 )
+ {
+ a.val[0] = cvGetReal2D( test_array[INPUT][0], 0, 0 );
+ a.val[1] = cvGetReal2D( test_array[INPUT][0], 1, 0 );
+ a.val[2] = cvGetReal2D( test_array[INPUT][0], 2, 0 );
+
+ b.val[0] = cvGetReal2D( test_array[INPUT][1], 0, 0 );
+ b.val[1] = cvGetReal2D( test_array[INPUT][1], 1, 0 );
+ b.val[2] = cvGetReal2D( test_array[INPUT][1], 2, 0 );
+ }
+ else if( test_mat[INPUT][0].cols > 1 )
+ {
+ a.val[0] = cvGetReal1D( test_array[INPUT][0], 0 );
+ a.val[1] = cvGetReal1D( test_array[INPUT][0], 1 );
+ a.val[2] = cvGetReal1D( test_array[INPUT][0], 2 );
+
+ b.val[0] = cvGetReal1D( test_array[INPUT][1], 0 );
+ b.val[1] = cvGetReal1D( test_array[INPUT][1], 1 );
+ b.val[2] = cvGetReal1D( test_array[INPUT][1], 2 );
+ }
+ else
+ {
+ a = cvGet1D( test_array[INPUT][0], 0 );
+ b = cvGet1D( test_array[INPUT][1], 0 );
+ }
+
+ c.val[2] = a.val[0]*b.val[1] - a.val[1]*b.val[0];
+ c.val[1] = -a.val[0]*b.val[2] + a.val[2]*b.val[0];
+ c.val[0] = a.val[1]*b.val[2] - a.val[2]*b.val[1];
+
+ if( test_mat[REF_OUTPUT][0].rows > 1 )
+ {
+ cvSetReal2D( test_array[REF_OUTPUT][0], 0, 0, c.val[0] );
+ cvSetReal2D( test_array[REF_OUTPUT][0], 1, 0, c.val[1] );
+ cvSetReal2D( test_array[REF_OUTPUT][0], 2, 0, c.val[2] );
+ }
+ else if( test_mat[REF_OUTPUT][0].cols > 1 )
+ {
+ cvSetReal1D( test_array[REF_OUTPUT][0], 0, c.val[0] );
+ cvSetReal1D( test_array[REF_OUTPUT][0], 1, c.val[1] );
+ cvSetReal1D( test_array[REF_OUTPUT][0], 2, c.val[2] );
+ }
+ else
+ {
+ cvSet1D( test_array[REF_OUTPUT][0], 0, c );
+ }
+}
+
+
+///////////////// gemm /////////////////////
+
+class Core_GEMMTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_GEMMTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int tabc_flag;
+ double alpha, beta;
+};
+
+Core_GEMMTest::Core_GEMMTest() : Core_MatrixTest( 5, 1, false, false, 2 )
+{
+ test_case_count = 100;
+ max_log_array_size = 10;
+ alpha = beta = 0;
+}
+
+
+void Core_GEMMTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ Size sizeA;
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ sizeA = sizes[INPUT][0];
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ sizes[INPUT][0] = sizeA;
+ sizes[INPUT][2] = sizes[INPUT][3] = Size(1,1);
+ types[INPUT][2] = types[INPUT][3] &= ~CV_MAT_CN_MASK;
+
+ tabc_flag = cvtest::randInt(rng) & 7;
+
+ switch( tabc_flag & (CV_GEMM_A_T|CV_GEMM_B_T) )
+ {
+ case 0:
+ sizes[INPUT][1].height = sizes[INPUT][0].width;
+ sizes[OUTPUT][0].height = sizes[INPUT][0].height;
+ sizes[OUTPUT][0].width = sizes[INPUT][1].width;
+ break;
+ case CV_GEMM_B_T:
+ sizes[INPUT][1].width = sizes[INPUT][0].width;
+ sizes[OUTPUT][0].height = sizes[INPUT][0].height;
+ sizes[OUTPUT][0].width = sizes[INPUT][1].height;
+ break;
+ case CV_GEMM_A_T:
+ sizes[INPUT][1].height = sizes[INPUT][0].height;
+ sizes[OUTPUT][0].height = sizes[INPUT][0].width;
+ sizes[OUTPUT][0].width = sizes[INPUT][1].width;
+ break;
+ case CV_GEMM_A_T | CV_GEMM_B_T:
+ sizes[INPUT][1].width = sizes[INPUT][0].height;
+ sizes[OUTPUT][0].height = sizes[INPUT][0].width;
+ sizes[OUTPUT][0].width = sizes[INPUT][1].height;
+ break;
+ }
+
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+
+ if( cvtest::randInt(rng) & 1 )
+ sizes[INPUT][4] = Size(0,0);
+ else if( !(tabc_flag & CV_GEMM_C_T) )
+ sizes[INPUT][4] = sizes[OUTPUT][0];
+ else
+ {
+ sizes[INPUT][4].width = sizes[OUTPUT][0].height;
+ sizes[INPUT][4].height = sizes[OUTPUT][0].width;
+ }
+}
+
+
+int Core_GEMMTest::prepare_test_case( int test_case_idx )
+{
+ int code = Base::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ alpha = cvGetReal2D( test_array[INPUT][2], 0, 0 );
+ beta = cvGetReal2D( test_array[INPUT][3], 0, 0 );
+ }
+ return code;
+}
+
+
+void Core_GEMMTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = Scalar::all(-10.);
+ high = Scalar::all(10.);
+}
+
+
+void Core_GEMMTest::run_func()
+{
+ cvGEMM( test_array[INPUT][0], test_array[INPUT][1], alpha,
+ test_array[INPUT][4], beta, test_array[OUTPUT][0], tabc_flag );
+}
+
+
+void Core_GEMMTest::prepare_to_validation( int )
+{
+ cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][1], alpha,
+ test_array[INPUT][4] ? test_mat[INPUT][4] : Mat(),
+ beta, test_mat[REF_OUTPUT][0], tabc_flag );
+}
+
+
+///////////////// multransposed /////////////////////
+
+class Core_MulTransposedTest : public Core_MatrixTest
+{
+public:
+ Core_MulTransposedTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int order;
+};
+
+
+Core_MulTransposedTest::Core_MulTransposedTest() : Core_MatrixTest( 2, 1, false, false, 1 )
+{
+ test_case_count = 100;
+ order = 0;
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_MulTransposedTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ int src_type = cvtest::randInt(rng) % 5;
+ int dst_type = cvtest::randInt(rng) % 2;
+
+ src_type = src_type == 0 ? CV_8U : src_type == 1 ? CV_16U : src_type == 2 ? CV_16S :
+ src_type == 3 ? CV_32F : CV_64F;
+ dst_type = dst_type == 0 ? CV_32F : CV_64F;
+ dst_type = MAX( dst_type, src_type );
+
+ Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( bits & 1 )
+ sizes[INPUT][1] = Size(0,0);
+ else
+ {
+ sizes[INPUT][1] = sizes[INPUT][0];
+ if( bits & 2 )
+ sizes[INPUT][1].height = 1;
+ if( bits & 4 )
+ sizes[INPUT][1].width = 1;
+ }
+
+ sizes[TEMP][0] = sizes[INPUT][0];
+ types[INPUT][0] = src_type;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][1] = types[TEMP][0] = dst_type;
+
+ order = (bits & 8) != 0;
+ sizes[OUTPUT][0].width = sizes[OUTPUT][0].height = order == 0 ?
+ sizes[INPUT][0].height : sizes[INPUT][0].width;
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+}
+
+
+void Core_MulTransposedTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-10.);
+ high = cvScalarAll(10.);
+}
+
+
+void Core_MulTransposedTest::run_func()
+{
+ cvMulTransposed( test_array[INPUT][0], test_array[OUTPUT][0],
+ order, test_array[INPUT][1] );
+}
+
+
+void Core_MulTransposedTest::prepare_to_validation( int )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat delta = test_mat[INPUT][1];
+ Mat& temp = test_mat[TEMP][0];
+ if( !delta.empty() )
+ {
+ if( delta.rows < src.rows || delta.cols < src.cols )
+ {
+ cv::repeat( delta, src.rows/delta.rows, src.cols/delta.cols, temp);
+ delta = temp;
+ }
+ cvtest::add( src, 1, delta, -1, Scalar::all(0), temp, temp.type());
+ }
+ else
+ src.convertTo(temp, temp.type());
+
+ cvtest::gemm( temp, temp, 1., Mat(), 0, test_mat[REF_OUTPUT][0], order == 0 ? GEMM_2_T : GEMM_1_T );
+}
+
+
+///////////////// Transform /////////////////////
+
+class Core_TransformTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_TransformTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+
+ double scale;
+ bool diagMtx;
+};
+
+
+Core_TransformTest::Core_TransformTest() : Core_MatrixTest( 3, 1, true, false, 4 )
+{
+}
+
+
+void Core_TransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ int depth, dst_cn, mat_cols, mattype;
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ mat_cols = CV_MAT_CN(types[INPUT][0]);
+ depth = CV_MAT_DEPTH(types[INPUT][0]);
+ dst_cn = cvtest::randInt(rng) % 4 + 1;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, dst_cn);
+
+ mattype = depth < CV_32S ? CV_32F : depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
+ types[INPUT][1] = mattype;
+ types[INPUT][2] = CV_MAKETYPE(mattype, dst_cn);
+
+ scale = 1./((cvtest::randInt(rng)%4)*50+1);
+
+ if( bits & 2 )
+ {
+ sizes[INPUT][2] = Size(0,0);
+ mat_cols += (bits & 4) != 0;
+ }
+ else if( bits & 4 )
+ sizes[INPUT][2] = Size(1,1);
+ else
+ {
+ if( bits & 8 )
+ sizes[INPUT][2] = Size(dst_cn,1);
+ else
+ sizes[INPUT][2] = Size(1,dst_cn);
+ types[INPUT][2] &= ~CV_MAT_CN_MASK;
+ }
+ diagMtx = (bits & 16) != 0;
+
+ sizes[INPUT][1] = Size(mat_cols,dst_cn);
+}
+
+
+int Core_TransformTest::prepare_test_case( int test_case_idx )
+{
+ int code = Base::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ Mat& m = test_mat[INPUT][1];
+ cvtest::add(m, scale, m, 0, Scalar::all(0), m, m.type() );
+ if(diagMtx)
+ {
+ Mat mask = Mat::eye(m.rows, m.cols, CV_8U)*255;
+ mask = ~mask;
+ m.setTo(Scalar::all(0), mask);
+ }
+ }
+ return code;
+}
+
+
+double Core_TransformTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 1 : depth <= CV_32S ? 9 : Base::get_success_error_level( test_case_idx, i, j );
+}
+
+void Core_TransformTest::run_func()
+{
+ CvMat _m = test_mat[INPUT][1], _shift = test_mat[INPUT][2];
+ cvTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m, _shift.data.ptr ? &_shift : 0);
+}
+
+
+void Core_TransformTest::prepare_to_validation( int )
+{
+ Mat transmat = test_mat[INPUT][1];
+ Mat shift = test_mat[INPUT][2];
+
+ cvtest::transform( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], transmat, shift );
+}
+
+
+///////////////// PerspectiveTransform /////////////////////
+
+class Core_PerspectiveTransformTest : public Core_MatrixTest
+{
+public:
+ Core_PerspectiveTransformTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_PerspectiveTransformTest::Core_PerspectiveTransformTest() : Core_MatrixTest( 2, 1, false, false, 2 )
+{
+}
+
+
+void Core_PerspectiveTransformTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ int depth, cn, mattype;
+ Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ cn = CV_MAT_CN(types[INPUT][0]) + 1;
+ depth = CV_MAT_DEPTH(types[INPUT][0]);
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+
+ mattype = depth == CV_64F ? CV_64F : bits & 1 ? CV_32F : CV_64F;
+ types[INPUT][1] = mattype;
+ sizes[INPUT][1] = Size(cn + 1, cn + 1);
+}
+
+
+double Core_PerspectiveTransformTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_32F ? 1e-4 : depth == CV_64F ? 1e-8 :
+ Core_MatrixTest::get_success_error_level(test_case_idx, i, j);
+}
+
+
+void Core_PerspectiveTransformTest::run_func()
+{
+ CvMat _m = test_mat[INPUT][1];
+ cvPerspectiveTransform( test_array[INPUT][0], test_array[OUTPUT][0], &_m );
+}
+
+
+static void cvTsPerspectiveTransform( const CvArr* _src, CvArr* _dst, const CvMat* transmat )
+{
+ int i, j, cols;
+ int cn, depth, mat_depth;
+ CvMat astub, bstub, *a, *b;
+ double mat[16];
+
+ a = cvGetMat( _src, &astub, 0, 0 );
+ b = cvGetMat( _dst, &bstub, 0, 0 );
+
+ cn = CV_MAT_CN(a->type);
+ depth = CV_MAT_DEPTH(a->type);
+ mat_depth = CV_MAT_DEPTH(transmat->type);
+ cols = transmat->cols;
+
+ // prepare cn x (cn + 1) transform matrix
+ if( mat_depth == CV_32F )
+ {
+ for( i = 0; i < transmat->rows; i++ )
+ for( j = 0; j < cols; j++ )
+ mat[i*cols + j] = ((float*)(transmat->data.ptr + transmat->step*i))[j];
+ }
+ else
+ {
+ assert( mat_depth == CV_64F );
+ for( i = 0; i < transmat->rows; i++ )
+ for( j = 0; j < cols; j++ )
+ mat[i*cols + j] = ((double*)(transmat->data.ptr + transmat->step*i))[j];
+ }
+
+ // transform data
+ cols = a->cols * cn;
+ vector<double> buf(cols);
+
+ for( i = 0; i < a->rows; i++ )
+ {
+ uchar* src = a->data.ptr + i*a->step;
+ uchar* dst = b->data.ptr + i*b->step;
+
+ switch( depth )
+ {
+ case CV_32F:
+ for( j = 0; j < cols; j++ )
+ buf[j] = ((float*)src)[j];
+ break;
+ case CV_64F:
+ for( j = 0; j < cols; j++ )
+ buf[j] = ((double*)src)[j];
+ break;
+ default:
+ assert(0);
+ }
+
+ switch( cn )
+ {
+ case 2:
+ for( j = 0; j < cols; j += 2 )
+ {
+ double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + mat[2];
+ double t1 = buf[j]*mat[3] + buf[j+1]*mat[4] + mat[5];
+ double w = buf[j]*mat[6] + buf[j+1]*mat[7] + mat[8];
+ w = w ? 1./w : 0;
+ buf[j] = t0*w;
+ buf[j+1] = t1*w;
+ }
+ break;
+ case 3:
+ for( j = 0; j < cols; j += 3 )
+ {
+ double t0 = buf[j]*mat[0] + buf[j+1]*mat[1] + buf[j+2]*mat[2] + mat[3];
+ double t1 = buf[j]*mat[4] + buf[j+1]*mat[5] + buf[j+2]*mat[6] + mat[7];
+ double t2 = buf[j]*mat[8] + buf[j+1]*mat[9] + buf[j+2]*mat[10] + mat[11];
+ double w = buf[j]*mat[12] + buf[j+1]*mat[13] + buf[j+2]*mat[14] + mat[15];
+ w = w ? 1./w : 0;
+ buf[j] = t0*w;
+ buf[j+1] = t1*w;
+ buf[j+2] = t2*w;
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ switch( depth )
+ {
+ case CV_32F:
+ for( j = 0; j < cols; j++ )
+ ((float*)dst)[j] = (float)buf[j];
+ break;
+ case CV_64F:
+ for( j = 0; j < cols; j++ )
+ ((double*)dst)[j] = buf[j];
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+void Core_PerspectiveTransformTest::prepare_to_validation( int )
+{
+ CvMat transmat = test_mat[INPUT][1];
+ cvTsPerspectiveTransform( test_array[INPUT][0], test_array[REF_OUTPUT][0], &transmat );
+}
+
+///////////////// Mahalanobis /////////////////////
+
+class Core_MahalanobisTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_MahalanobisTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_MahalanobisTest::Core_MahalanobisTest() : Core_MatrixTest( 3, 1, false, true, 1 )
+{
+ test_case_count = 100;
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_MahalanobisTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( cvtest::randInt(rng) & 1 )
+ sizes[INPUT][0].width = sizes[INPUT][1].width = 1;
+ else
+ sizes[INPUT][0].height = sizes[INPUT][1].height = 1;
+
+ sizes[TEMP][0] = sizes[TEMP][1] = sizes[INPUT][0];
+ sizes[INPUT][2].width = sizes[INPUT][2].height = sizes[INPUT][0].width + sizes[INPUT][0].height - 1;
+ sizes[TEMP][2] = sizes[INPUT][2];
+ types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
+}
+
+int Core_MahalanobisTest::prepare_test_case( int test_case_idx )
+{
+ int code = Base::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ // make sure that the inverted "covariation" matrix is symmetrix and positively defined.
+ cvtest::gemm( test_mat[INPUT][2], test_mat[INPUT][2], 1., Mat(), 0., test_mat[TEMP][2], GEMM_2_T );
+ cvtest::copy( test_mat[TEMP][2], test_mat[INPUT][2] );
+ }
+
+ return code;
+}
+
+
+void Core_MahalanobisTest::run_func()
+{
+ test_mat[OUTPUT][0].at<Scalar>(0,0) =
+ cvRealScalar(cvMahalanobis(test_array[INPUT][0], test_array[INPUT][1], test_array[INPUT][2]));
+}
+
+void Core_MahalanobisTest::prepare_to_validation( int )
+{
+ cvtest::add( test_mat[INPUT][0], 1., test_mat[INPUT][1], -1.,
+ Scalar::all(0), test_mat[TEMP][0], test_mat[TEMP][0].type() );
+ if( test_mat[INPUT][0].rows == 1 )
+ cvtest::gemm( test_mat[TEMP][0], test_mat[INPUT][2], 1.,
+ Mat(), 0., test_mat[TEMP][1], 0 );
+ else
+ cvtest::gemm( test_mat[INPUT][2], test_mat[TEMP][0], 1.,
+ Mat(), 0., test_mat[TEMP][1], 0 );
+
+ test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(sqrt(cvtest::crossCorr(test_mat[TEMP][0], test_mat[TEMP][1])));
+}
+
+
+///////////////// covarmatrix /////////////////////
+
+class Core_CovarMatrixTest : public Core_MatrixTest
+{
+public:
+ Core_CovarMatrixTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ vector<void*> temp_hdrs;
+ vector<uchar> hdr_data;
+ int flags, t_flag, len, count;
+ bool are_images;
+};
+
+
+Core_CovarMatrixTest::Core_CovarMatrixTest() : Core_MatrixTest( 1, 1, true, false, 1 ),
+flags(0), t_flag(0), are_images(false)
+{
+ test_case_count = 100;
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_CovarMatrixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ int i, single_matrix;
+ Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ flags = bits & (CV_COVAR_NORMAL | CV_COVAR_USE_AVG | CV_COVAR_SCALE | CV_COVAR_ROWS );
+ single_matrix = flags & CV_COVAR_ROWS;
+ t_flag = (bits & 256) != 0;
+
+ const int min_count = 2;
+
+ if( !t_flag )
+ {
+ len = sizes[INPUT][0].width;
+ count = sizes[INPUT][0].height;
+ count = MAX(count, min_count);
+ sizes[INPUT][0] = Size(len, count);
+ }
+ else
+ {
+ len = sizes[INPUT][0].height;
+ count = sizes[INPUT][0].width;
+ count = MAX(count, min_count);
+ sizes[INPUT][0] = Size(count, len);
+ }
+
+ if( single_matrix && t_flag )
+ flags = (flags & ~CV_COVAR_ROWS) | CV_COVAR_COLS;
+
+ if( CV_MAT_DEPTH(types[INPUT][0]) == CV_32S )
+ types[INPUT][0] = (types[INPUT][0] & ~CV_MAT_DEPTH_MASK) | CV_32F;
+
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = flags & CV_COVAR_NORMAL ? Size(len,len) : Size(count,count);
+ sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = !t_flag ? Size(len,1) : Size(1,len);
+ sizes[TEMP][0] = sizes[INPUT][0];
+
+ types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] =
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = types[TEMP][0] =
+ CV_MAT_DEPTH(types[INPUT][0]) == CV_64F || (bits & 512) ? CV_64F : CV_32F;
+
+ are_images = (bits & 1024) != 0;
+ for( i = 0; i < (single_matrix ? 1 : count); i++ )
+ temp_hdrs.push_back(NULL);
+}
+
+
+int Core_CovarMatrixTest::prepare_test_case( int test_case_idx )
+{
+ int code = Core_MatrixTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ int i;
+ int single_matrix = flags & (CV_COVAR_ROWS|CV_COVAR_COLS);
+ int hdr_size = are_images ? sizeof(IplImage) : sizeof(CvMat);
+
+ hdr_data.resize(count*hdr_size);
+ uchar* _hdr_data = &hdr_data[0];
+ if( single_matrix )
+ {
+ if( !are_images )
+ *((CvMat*)_hdr_data) = test_mat[INPUT][0];
+ else
+ *((IplImage*)_hdr_data) = test_mat[INPUT][0];
+ temp_hdrs[0] = _hdr_data;
+ }
+ else
+ for( i = 0; i < count; i++ )
+ {
+ Mat part;
+ void* ptr = _hdr_data + i*hdr_size;
+
+ if( !t_flag )
+ part = test_mat[INPUT][0].row(i);
+ else
+ part = test_mat[INPUT][0].col(i);
+
+ if( !are_images )
+ *((CvMat*)ptr) = part;
+ else
+ *((IplImage*)ptr) = part;
+
+ temp_hdrs[i] = ptr;
+ }
+ }
+
+ return code;
+}
+
+
+void Core_CovarMatrixTest::run_func()
+{
+ cvCalcCovarMatrix( (const void**)&temp_hdrs[0], count,
+ test_array[OUTPUT][0], test_array[INPUT_OUTPUT][0], flags );
+}
+
+
+void Core_CovarMatrixTest::prepare_to_validation( int )
+{
+ Mat& avg = test_mat[REF_INPUT_OUTPUT][0];
+ double scale = 1.;
+
+ if( !(flags & CV_COVAR_USE_AVG) )
+ {
+ Mat hdrs0 = cvarrToMat(temp_hdrs[0]);
+
+ int i;
+ avg = Scalar::all(0);
+
+ for( i = 0; i < count; i++ )
+ {
+ Mat vec;
+ if( flags & CV_COVAR_ROWS )
+ vec = hdrs0.row(i);
+ else if( flags & CV_COVAR_COLS )
+ vec = hdrs0.col(i);
+ else
+ vec = cvarrToMat(temp_hdrs[i]);
+
+ cvtest::add(avg, 1, vec, 1, Scalar::all(0), avg, avg.type());
+ }
+
+ cvtest::add(avg, 1./count, avg, 0., Scalar::all(0), avg, avg.type());
+ }
+
+ if( flags & CV_COVAR_SCALE )
+ {
+ scale = 1./count;
+ }
+
+ Mat& temp0 = test_mat[TEMP][0];
+ cv::repeat( avg, temp0.rows/avg.rows, temp0.cols/avg.cols, temp0 );
+ cvtest::add( test_mat[INPUT][0], 1, temp0, -1, Scalar::all(0), temp0, temp0.type());
+
+ cvtest::gemm( temp0, temp0, scale, Mat(), 0., test_mat[REF_OUTPUT][0],
+ t_flag ^ ((flags & CV_COVAR_NORMAL) != 0) ? CV_GEMM_A_T : CV_GEMM_B_T );
+ temp_hdrs.clear();
+}
+
+
+static void cvTsFloodWithZeros( Mat& mat, RNG& rng )
+{
+ int k, total = mat.rows*mat.cols, type = mat.type();
+ int zero_total = cvtest::randInt(rng) % total;
+ CV_Assert( type == CV_32FC1 || type == CV_64FC1 );
+
+ for( k = 0; k < zero_total; k++ )
+ {
+ int i = cvtest::randInt(rng) % mat.rows;
+ int j = cvtest::randInt(rng) % mat.cols;
+
+ if( type == CV_32FC1 )
+ mat.at<float>(i,j) = 0.f;
+ else
+ mat.at<double>(i,j) = 0.;
+ }
+}
+
+
+///////////////// determinant /////////////////////
+
+class Core_DetTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_DetTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+Core_DetTest::Core_DetTest() : Core_MatrixTest( 1, 1, false, true, 1 )
+{
+ test_case_count = 100;
+ max_log_array_size = 7;
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_DetTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ sizes[INPUT][0].width = sizes[INPUT][0].height = sizes[INPUT][0].height;
+ sizes[TEMP][0] = sizes[INPUT][0];
+ types[TEMP][0] = CV_64FC1;
+}
+
+
+void Core_DetTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-2.);
+ high = cvScalarAll(2.);
+}
+
+
+double Core_DetTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-2 : 1e-5;
+}
+
+
+int Core_DetTest::prepare_test_case( int test_case_idx )
+{
+ int code = Core_MatrixTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
+
+ return code;
+}
+
+
+void Core_DetTest::run_func()
+{
+ test_mat[OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvDet(test_array[INPUT][0]));
+}
+
+
+// LU method that chooses the optimal in a column pivot element
+static double cvTsLU( CvMat* a, CvMat* b=NULL, CvMat* x=NULL, int* rank=0 )
+{
+ int i, j, k, N = a->rows, N1 = a->cols, Nm = MIN(N, N1), step = a->step/sizeof(double);
+ int M = b ? b->cols : 0, b_step = b ? b->step/sizeof(double) : 0;
+ int x_step = x ? x->step/sizeof(double) : 0;
+ double *a0 = a->data.db, *b0 = b ? b->data.db : 0;
+ double *x0 = x ? x->data.db : 0;
+ double t, det = 1.;
+ assert( CV_MAT_TYPE(a->type) == CV_64FC1 &&
+ (!b || CV_ARE_TYPES_EQ(a,b)) && (!x || CV_ARE_TYPES_EQ(a,x)));
+
+ for( i = 0; i < Nm; i++ )
+ {
+ double max_val = fabs(a0[i*step + i]);
+ double *a1, *a2, *b1 = 0, *b2 = 0;
+ k = i;
+
+ for( j = i+1; j < N; j++ )
+ {
+ t = fabs(a0[j*step + i]);
+ if( max_val < t )
+ {
+ max_val = t;
+ k = j;
+ }
+ }
+
+ if( k != i )
+ {
+ for( j = i; j < N1; j++ )
+ CV_SWAP( a0[i*step + j], a0[k*step + j], t );
+
+ for( j = 0; j < M; j++ )
+ CV_SWAP( b0[i*b_step + j], b0[k*b_step + j], t );
+ det = -det;
+ }
+
+ if( max_val == 0 )
+ {
+ if( rank )
+ *rank = i;
+ return 0.;
+ }
+
+ a1 = a0 + i*step;
+ a2 = a1 + step;
+ b1 = b0 + i*b_step;
+ b2 = b1 + b_step;
+
+ for( j = i+1; j < N; j++, a2 += step, b2 += b_step )
+ {
+ t = a2[i]/a1[i];
+ for( k = i+1; k < N1; k++ )
+ a2[k] -= t*a1[k];
+
+ for( k = 0; k < M; k++ )
+ b2[k] -= t*b1[k];
+ }
+
+ det *= a1[i];
+ }
+
+ if( x )
+ {
+ assert( b );
+
+ for( i = N-1; i >= 0; i-- )
+ {
+ double* a1 = a0 + i*step;
+ double* b1 = b0 + i*b_step;
+ for( j = 0; j < M; j++ )
+ {
+ t = b1[j];
+ for( k = i+1; k < N1; k++ )
+ t -= a1[k]*x0[k*x_step + j];
+ x0[i*x_step + j] = t/a1[i];
+ }
+ }
+ }
+
+ if( rank )
+ *rank = i;
+ return det;
+}
+
+
+void Core_DetTest::prepare_to_validation( int )
+{
+ test_mat[INPUT][0].convertTo(test_mat[TEMP][0], test_mat[TEMP][0].type());
+ CvMat temp0 = test_mat[TEMP][0];
+ test_mat[REF_OUTPUT][0].at<Scalar>(0,0) = cvRealScalar(cvTsLU(&temp0, 0, 0));
+}
+
+
+///////////////// invert /////////////////////
+
+class Core_InvertTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_InvertTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int method, rank;
+ double result;
+};
+
+
+Core_InvertTest::Core_InvertTest()
+: Core_MatrixTest( 1, 1, false, false, 1 ), method(0), rank(0), result(0.)
+{
+ test_case_count = 100;
+ max_log_array_size = 7;
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_InvertTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
+
+ if( (bits & 3) == 0 )
+ {
+ method = CV_SVD;
+ if( bits & 4 )
+ {
+ sizes[INPUT][0] = Size(min_size, min_size);
+ if( bits & 16 )
+ method = CV_CHOLESKY;
+ }
+ }
+ else
+ {
+ method = CV_LU;
+ sizes[INPUT][0] = Size(min_size, min_size);
+ }
+
+ sizes[TEMP][0].width = sizes[INPUT][0].height;
+ sizes[TEMP][0].height = sizes[INPUT][0].width;
+ sizes[TEMP][1] = sizes[INPUT][0];
+ types[TEMP][0] = types[INPUT][0];
+ types[TEMP][1] = CV_64FC1;
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(min_size, min_size);
+}
+
+
+double Core_InvertTest::get_success_error_level( int /*test_case_idx*/, int, int )
+{
+ return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 1e-2 : 1e-6;
+}
+
+int Core_InvertTest::prepare_test_case( int test_case_idx )
+{
+ int code = Core_MatrixTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ cvTsFloodWithZeros( test_mat[INPUT][0], ts->get_rng() );
+
+ if( method == CV_CHOLESKY )
+ {
+ cvtest::gemm( test_mat[INPUT][0], test_mat[INPUT][0], 1.,
+ Mat(), 0., test_mat[TEMP][0], CV_GEMM_B_T );
+ cvtest::copy( test_mat[TEMP][0], test_mat[INPUT][0] );
+ }
+ }
+
+ return code;
+}
+
+
+
+void Core_InvertTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-1.);
+ high = cvScalarAll(1.);
+}
+
+
+void Core_InvertTest::run_func()
+{
+ result = cvInvert(test_array[INPUT][0], test_array[TEMP][0], method);
+}
+
+
+static double cvTsSVDet( CvMat* mat, double* ratio )
+{
+ int type = CV_MAT_TYPE(mat->type);
+ int i, nm = MIN( mat->rows, mat->cols );
+ CvMat* w = cvCreateMat( nm, 1, type );
+ double det = 1.;
+
+ cvSVD( mat, w, 0, 0, 0 );
+
+ if( type == CV_32FC1 )
+ {
+ for( i = 0; i < nm; i++ )
+ det *= w->data.fl[i];
+ *ratio = w->data.fl[nm-1] < FLT_EPSILON ? FLT_MAX : w->data.fl[nm-1]/w->data.fl[0];
+ }
+ else
+ {
+ for( i = 0; i < nm; i++ )
+ det *= w->data.db[i];
+ *ratio = w->data.db[nm-1] < FLT_EPSILON ? DBL_MAX : w->data.db[nm-1]/w->data.db[0];
+ }
+
+ cvReleaseMat( &w );
+ return det;
+}
+
+void Core_InvertTest::prepare_to_validation( int )
+{
+ Mat& input = test_mat[INPUT][0];
+ Mat& temp0 = test_mat[TEMP][0];
+ Mat& temp1 = test_mat[TEMP][1];
+ Mat& dst0 = test_mat[REF_OUTPUT][0];
+ Mat& dst = test_mat[OUTPUT][0];
+ CvMat _input = input;
+ double ratio = 0, det = cvTsSVDet( &_input, &ratio );
+ double threshold = (input.depth() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
+
+ cvtest::convert( input, temp1, temp1.type() );
+
+ if( det < threshold ||
+ ((method == CV_LU || method == CV_CHOLESKY) && (result == 0 || ratio < threshold)) ||
+ ((method == CV_SVD || method == CV_SVD_SYM) && result < threshold) )
+ {
+ dst = Scalar::all(0);
+ dst0 = Scalar::all(0);
+ return;
+ }
+
+ if( input.rows >= input.cols )
+ cvtest::gemm( temp0, input, 1., Mat(), 0., dst, 0 );
+ else
+ cvtest::gemm( input, temp0, 1., Mat(), 0., dst, 0 );
+
+ cv::setIdentity( dst0, Scalar::all(1) );
+}
+
+
+///////////////// solve /////////////////////
+
+class Core_SolveTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_SolveTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int method, rank;
+ double result;
+};
+
+
+Core_SolveTest::Core_SolveTest() : Core_MatrixTest( 2, 1, false, false, 1 ), method(0), rank(0), result(0.)
+{
+ test_case_count = 100;
+ max_log_array_size = 7;
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_SolveTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize in_sz = sizes[INPUT][0];
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ sizes[INPUT][0] = in_sz;
+ int min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
+
+ if( (bits & 3) == 0 )
+ {
+ method = CV_SVD;
+ if( bits & 4 )
+ {
+ sizes[INPUT][0] = Size(min_size, min_size);
+ /*if( bits & 8 )
+ method = CV_SVD_SYM;*/
+ }
+ }
+ else
+ {
+ method = CV_LU;
+ sizes[INPUT][0] = Size(min_size, min_size);
+ }
+
+ sizes[INPUT][1].height = sizes[INPUT][0].height;
+ sizes[TEMP][0].width = sizes[INPUT][1].width;
+ sizes[TEMP][0].height = sizes[INPUT][0].width;
+ sizes[TEMP][1] = sizes[INPUT][0];
+ types[TEMP][0] = types[INPUT][0];
+ types[TEMP][1] = CV_64FC1;
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size(sizes[INPUT][1].width, min_size);
+}
+
+
+int Core_SolveTest::prepare_test_case( int test_case_idx )
+{
+ int code = Core_MatrixTest::prepare_test_case( test_case_idx );
+
+ /*if( method == CV_SVD_SYM )
+ {
+ cvTsGEMM( test_array[INPUT][0], test_array[INPUT][0], 1.,
+ 0, 0., test_array[TEMP][0], CV_GEMM_B_T );
+ cvTsCopy( test_array[TEMP][0], test_array[INPUT][0] );
+ }*/
+
+ return code;
+}
+
+
+void Core_SolveTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-1.);
+ high = cvScalarAll(1.);
+}
+
+
+double Core_SolveTest::get_success_error_level( int /*test_case_idx*/, int, int )
+{
+ return CV_MAT_DEPTH(cvGetElemType(test_array[OUTPUT][0])) == CV_32F ? 5e-2 : 1e-8;
+}
+
+
+void Core_SolveTest::run_func()
+{
+ result = cvSolve(test_array[INPUT][0], test_array[INPUT][1], test_array[TEMP][0], method);
+}
+
+void Core_SolveTest::prepare_to_validation( int )
+{
+ //int rank = test_mat[REF_OUTPUT][0].rows;
+ Mat& input = test_mat[INPUT][0];
+ Mat& dst = test_mat[OUTPUT][0];
+ Mat& dst0 = test_mat[REF_OUTPUT][0];
+
+ if( method == CV_LU )
+ {
+ if( result == 0 )
+ {
+ Mat& temp1 = test_mat[TEMP][1];
+ cvtest::convert(input, temp1, temp1.type());
+ dst = Scalar::all(0);
+ CvMat _temp1 = temp1;
+ double det = cvTsLU( &_temp1, 0, 0 );
+ dst0 = Scalar::all(det != 0);
+ return;
+ }
+
+ double threshold = (input.type() == CV_32F ? FLT_EPSILON : DBL_EPSILON)*1000;
+ CvMat _input = input;
+ double ratio = 0, det = cvTsSVDet( &_input, &ratio );
+ if( det < threshold || ratio < threshold )
+ {
+ dst = Scalar::all(0);
+ dst0 = Scalar::all(0);
+ return;
+ }
+ }
+
+ Mat* pdst = input.rows <= input.cols ? &test_mat[OUTPUT][0] : &test_mat[INPUT][1];
+
+ cvtest::gemm( input, test_mat[TEMP][0], 1., test_mat[INPUT][1], -1., *pdst, 0 );
+ if( pdst != &dst )
+ cvtest::gemm( input, *pdst, 1., Mat(), 0., dst, CV_GEMM_A_T );
+ dst0 = Scalar::all(0);
+}
+
+
+///////////////// SVD /////////////////////
+
+class Core_SVDTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_SVDTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int flags;
+ bool have_u, have_v, symmetric, compact, vector_w;
+};
+
+
+Core_SVDTest::Core_SVDTest() :
+Core_MatrixTest( 1, 4, false, false, 1 ),
+flags(0), have_u(false), have_v(false), symmetric(false), compact(false), vector_w(false)
+{
+ test_case_count = 100;
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_SVDTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ Core_MatrixTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int min_size, i, m, n;
+
+ min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
+
+ flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
+ have_u = (bits & 8) != 0;
+ have_v = (bits & 16) != 0;
+ symmetric = (bits & 32) != 0;
+ compact = (bits & 64) != 0;
+ vector_w = (bits & 128) != 0;
+
+ if( symmetric )
+ sizes[INPUT][0] = Size(min_size, min_size);
+
+ m = sizes[INPUT][0].height;
+ n = sizes[INPUT][0].width;
+
+ if( compact )
+ sizes[TEMP][0] = Size(min_size, min_size);
+ else
+ sizes[TEMP][0] = sizes[INPUT][0];
+ sizes[TEMP][3] = Size(0,0);
+
+ if( vector_w )
+ {
+ sizes[TEMP][3] = sizes[TEMP][0];
+ if( bits & 256 )
+ sizes[TEMP][0] = Size(1, min_size);
+ else
+ sizes[TEMP][0] = Size(min_size, 1);
+ }
+
+ if( have_u )
+ {
+ sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
+
+ if( flags & CV_SVD_U_T )
+ CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
+ }
+ else
+ sizes[TEMP][1] = Size(0,0);
+
+ if( have_v )
+ {
+ sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
+
+ if( !(flags & CV_SVD_V_T) )
+ CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
+ }
+ else
+ sizes[TEMP][2] = Size(0,0);
+
+ types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[TEMP][3] = types[INPUT][0];
+ types[OUTPUT][0] = types[OUTPUT][1] = types[OUTPUT][2] = types[INPUT][0];
+ types[OUTPUT][3] = CV_8UC1;
+ sizes[OUTPUT][0] = !have_u || !have_v ? Size(0,0) : sizes[INPUT][0];
+ sizes[OUTPUT][1] = !have_u ? Size(0,0) : compact ? Size(min_size,min_size) : Size(m,m);
+ sizes[OUTPUT][2] = !have_v ? Size(0,0) : compact ? Size(min_size,min_size) : Size(n,n);
+ sizes[OUTPUT][3] = Size(min_size,1);
+
+ for( i = 0; i < 4; i++ )
+ {
+ sizes[REF_OUTPUT][i] = sizes[OUTPUT][i];
+ types[REF_OUTPUT][i] = types[OUTPUT][i];
+ }
+}
+
+
+int Core_SVDTest::prepare_test_case( int test_case_idx )
+{
+ int code = Core_MatrixTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ Mat& input = test_mat[INPUT][0];
+ cvTsFloodWithZeros( input, ts->get_rng() );
+
+ if( symmetric && (have_u || have_v) )
+ {
+ Mat& temp = test_mat[TEMP][have_u ? 1 : 2];
+ cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
+ cvtest::copy( temp, input );
+ }
+
+ if( (flags & CV_SVD_MODIFY_A) && test_array[OUTPUT][0] )
+ cvtest::copy( input, test_mat[OUTPUT][0] );
+ }
+
+ return code;
+}
+
+
+void Core_SVDTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-2.);
+ high = cvScalarAll(2.);
+}
+
+double Core_SVDTest::get_success_error_level( int test_case_idx, int i, int j )
+{
+ int input_depth = CV_MAT_DEPTH(cvGetElemType( test_array[INPUT][0] ));
+ double input_precision = input_depth < CV_32F ? 0 : input_depth == CV_32F ? 5e-5 : 5e-11;
+ double output_precision = Base::get_success_error_level( test_case_idx, i, j );
+ return MAX(input_precision, output_precision);
+}
+
+void Core_SVDTest::run_func()
+{
+ CvArr* src = test_array[!(flags & CV_SVD_MODIFY_A) ? INPUT : OUTPUT][0];
+ if( !src )
+ src = test_array[INPUT][0];
+ cvSVD( src, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
+}
+
+
+void Core_SVDTest::prepare_to_validation( int )
+{
+ Mat& input = test_mat[INPUT][0];
+ int depth = input.depth();
+ int m = input.rows, n = input.cols, min_size = MIN(m, n);
+ Mat *src, *dst, *w;
+ double prev = 0, threshold = depth == CV_32F ? FLT_EPSILON : DBL_EPSILON;
+ int i, step;
+
+ if( have_u )
+ {
+ src = &test_mat[TEMP][1];
+ dst = &test_mat[OUTPUT][1];
+ cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
+ cv::setIdentity( test_mat[REF_OUTPUT][1], Scalar::all(1.) );
+ }
+
+ if( have_v )
+ {
+ src = &test_mat[TEMP][2];
+ dst = &test_mat[OUTPUT][2];
+ cvtest::gemm( *src, *src, 1., Mat(), 0., *dst, src->rows == dst->rows ? CV_GEMM_B_T : CV_GEMM_A_T );
+ cv::setIdentity( test_mat[REF_OUTPUT][2], Scalar::all(1.) );
+ }
+
+ w = &test_mat[TEMP][0];
+ step = w->rows == 1 ? 1 : w->step1();
+ for( i = 0; i < min_size; i++ )
+ {
+ double normval = 0, aii;
+ if( w->rows > 1 && w->cols > 1 )
+ {
+ normval = cvtest::norm( w->row(i), NORM_L1 );
+ aii = depth == CV_32F ? w->at<float>(i,i) : w->at<double>(i,i);
+ }
+ else
+ {
+ normval = aii = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
+ }
+
+ normval = fabs(normval - aii);
+ test_mat[OUTPUT][3].at<uchar>(i) = aii >= 0 && normval < threshold && (i == 0 || aii <= prev);
+ prev = aii;
+ }
+
+ test_mat[REF_OUTPUT][3] = Scalar::all(1);
+
+ if( have_u && have_v )
+ {
+ if( vector_w )
+ {
+ test_mat[TEMP][3] = Scalar::all(0);
+ for( i = 0; i < min_size; i++ )
+ {
+ double val = depth == CV_32F ? w->at<float>(i) : w->at<double>(i);
+ cvSetReal2D( test_array[TEMP][3], i, i, val );
+ }
+ w = &test_mat[TEMP][3];
+ }
+
+ if( m >= n )
+ {
+ cvtest::gemm( test_mat[TEMP][1], *w, 1., Mat(), 0., test_mat[REF_OUTPUT][0],
+ flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
+ cvtest::gemm( test_mat[REF_OUTPUT][0], test_mat[TEMP][2], 1., Mat(), 0.,
+ test_mat[OUTPUT][0], flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
+ }
+ else
+ {
+ cvtest::gemm( *w, test_mat[TEMP][2], 1., Mat(), 0., test_mat[REF_OUTPUT][0],
+ flags & CV_SVD_V_T ? 0 : CV_GEMM_B_T );
+ cvtest::gemm( test_mat[TEMP][1], test_mat[REF_OUTPUT][0], 1., Mat(), 0.,
+ test_mat[OUTPUT][0], flags & CV_SVD_U_T ? CV_GEMM_A_T : 0 );
+ }
+
+ cvtest::copy( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
+ }
+}
+
+
+
+///////////////// SVBkSb /////////////////////
+
+class Core_SVBkSbTest : public Core_MatrixTest
+{
+public:
+ typedef Core_MatrixTest Base;
+ Core_SVBkSbTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+ int flags;
+ bool have_b, symmetric, compact, vector_w;
+};
+
+
+Core_SVBkSbTest::Core_SVBkSbTest() : Core_MatrixTest( 2, 1, false, false, 1 ),
+flags(0), have_b(false), symmetric(false), compact(false), vector_w(false)
+{
+ test_case_count = 100;
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+ test_array[TEMP].push_back(NULL);
+}
+
+
+void Core_SVBkSbTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int bits = cvtest::randInt(rng);
+ Base::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int min_size, i, m, n;
+ CvSize b_size;
+
+ min_size = MIN( sizes[INPUT][0].width, sizes[INPUT][0].height );
+
+ flags = bits & (CV_SVD_MODIFY_A+CV_SVD_U_T+CV_SVD_V_T);
+ have_b = (bits & 16) != 0;
+ symmetric = (bits & 32) != 0;
+ compact = (bits & 64) != 0;
+ vector_w = (bits & 128) != 0;
+
+ if( symmetric )
+ sizes[INPUT][0] = Size(min_size, min_size);
+
+ m = sizes[INPUT][0].height;
+ n = sizes[INPUT][0].width;
+
+ sizes[INPUT][1] = Size(0,0);
+ b_size = Size(m,m);
+ if( have_b )
+ {
+ sizes[INPUT][1].height = sizes[INPUT][0].height;
+ sizes[INPUT][1].width = cvtest::randInt(rng) % 100 + 1;
+ b_size = sizes[INPUT][1];
+ }
+
+ if( compact )
+ sizes[TEMP][0] = Size(min_size, min_size);
+ else
+ sizes[TEMP][0] = sizes[INPUT][0];
+
+ if( vector_w )
+ {
+ if( bits & 256 )
+ sizes[TEMP][0] = Size(1, min_size);
+ else
+ sizes[TEMP][0] = Size(min_size, 1);
+ }
+
+ sizes[TEMP][1] = compact ? Size(min_size, m) : Size(m, m);
+
+ if( flags & CV_SVD_U_T )
+ CV_SWAP( sizes[TEMP][1].width, sizes[TEMP][1].height, i );
+
+ sizes[TEMP][2] = compact ? Size(n, min_size) : Size(n, n);
+
+ if( !(flags & CV_SVD_V_T) )
+ CV_SWAP( sizes[TEMP][2].width, sizes[TEMP][2].height, i );
+
+ types[TEMP][0] = types[TEMP][1] = types[TEMP][2] = types[INPUT][0];
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0];
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = Size( b_size.width, n );
+}
+
+
+int Core_SVBkSbTest::prepare_test_case( int test_case_idx )
+{
+ int code = Base::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ Mat& input = test_mat[INPUT][0];
+ cvTsFloodWithZeros( input, ts->get_rng() );
+
+ if( symmetric )
+ {
+ Mat& temp = test_mat[TEMP][1];
+ cvtest::gemm( input, input, 1., Mat(), 0., temp, CV_GEMM_B_T );
+ cvtest::copy( temp, input );
+ }
+
+ CvMat _input = input;
+ cvSVD( &_input, test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2], flags );
+ }
+
+ return code;
+}
+
+
+void Core_SVBkSbTest::get_minmax_bounds( int /*i*/, int /*j*/, int /*type*/, Scalar& low, Scalar& high )
+{
+ low = cvScalarAll(-2.);
+ high = cvScalarAll(2.);
+}
+
+
+double Core_SVBkSbTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return CV_MAT_DEPTH(cvGetElemType(test_array[INPUT][0])) == CV_32F ? 1e-3 : 1e-7;
+}
+
+
+void Core_SVBkSbTest::run_func()
+{
+ cvSVBkSb( test_array[TEMP][0], test_array[TEMP][1], test_array[TEMP][2],
+ test_array[INPUT][1], test_array[OUTPUT][0], flags );
+}
+
+
+void Core_SVBkSbTest::prepare_to_validation( int )
+{
+ Mat& input = test_mat[INPUT][0];
+ int i, m = input.rows, n = input.cols, min_size = MIN(m, n);
+ bool is_float = input.type() == CV_32F;
+ Size w_size = compact ? Size(min_size,min_size) : Size(m,n);
+ Mat& w = test_mat[TEMP][0];
+ Mat wdb( w_size.height, w_size.width, CV_64FC1 );
+ CvMat _w = w, _wdb = wdb;
+ // use exactly the same threshold as in icvSVD... ,
+ // so the changes in the library and here should be synchronized.
+ double threshold = cv::sum(w)[0]*2*(is_float ? FLT_EPSILON : DBL_EPSILON);
+
+ wdb = Scalar::all(0);
+ for( i = 0; i < min_size; i++ )
+ {
+ double wii = vector_w ? cvGetReal1D(&_w,i) : cvGetReal2D(&_w,i,i);
+ cvSetReal2D( &_wdb, i, i, wii > threshold ? 1./wii : 0. );
+ }
+
+ Mat u = test_mat[TEMP][1];
+ Mat v = test_mat[TEMP][2];
+ Mat b = test_mat[INPUT][1];
+
+ if( is_float )
+ {
+ test_mat[TEMP][1].convertTo(u, CV_64F);
+ test_mat[TEMP][2].convertTo(v, CV_64F);
+ if( !b.empty() )
+ test_mat[INPUT][1].convertTo(b, CV_64F);
+ }
+
+ Mat t0, t1;
+
+ if( !b.empty() )
+ cvtest::gemm( u, b, 1., Mat(), 0., t0, !(flags & CV_SVD_U_T) ? CV_GEMM_A_T : 0 );
+ else if( flags & CV_SVD_U_T )
+ cvtest::copy( u, t0 );
+ else
+ cvtest::transpose( u, t0 );
+
+ cvtest::gemm( wdb, t0, 1, Mat(), 0, t1, 0 );
+
+ cvtest::gemm( v, t1, 1, Mat(), 0, t0, flags & CV_SVD_V_T ? CV_GEMM_A_T : 0 );
+ Mat& dst0 = test_mat[REF_OUTPUT][0];
+ t0.convertTo(dst0, dst0.type() );
+}
+
+
+typedef std::complex<double> complex_type;
+
+struct pred_complex
+{
+ bool operator() (const complex_type& lhs, const complex_type& rhs) const
+ {
+ return fabs(lhs.real() - rhs.real()) > fabs(rhs.real())*FLT_EPSILON ? lhs.real() < rhs.real() : lhs.imag() < rhs.imag();
+ }
+};
+
+struct pred_double
+{
+ bool operator() (const double& lhs, const double& rhs) const
+ {
+ return lhs < rhs;
+ }
+};
+
+class Core_SolvePolyTest : public cvtest::BaseTest
+{
+public:
+ Core_SolvePolyTest();
+ ~Core_SolvePolyTest();
+protected:
+ virtual void run( int start_from );
+};
+
+Core_SolvePolyTest::Core_SolvePolyTest() {}
+
+Core_SolvePolyTest::~Core_SolvePolyTest() {}
+
+void Core_SolvePolyTest::run( int )
+{
+ RNG& rng = ts->get_rng();
+ int fig = 100;
+ double range = 50;
+ double err_eps = 1e-4;
+
+ for (int idx = 0, max_idx = 1000, progress = 0; idx < max_idx; ++idx)
+ {
+ progress = update_progress(progress, idx-1, max_idx, 0);
+ int n = cvtest::randInt(rng) % 13 + 1;
+ std::vector<complex_type> r(n), ar(n), c(n + 1, 0);
+ std::vector<double> a(n + 1), u(n * 2), ar1(n), ar2(n);
+
+ int rr_odds = 3; // odds that we get a real root
+ for (int j = 0; j < n;)
+ {
+ if (cvtest::randInt(rng) % rr_odds == 0 || j == n - 1)
+ r[j++] = cvtest::randReal(rng) * range;
+ else
+ {
+ r[j] = complex_type(cvtest::randReal(rng) * range,
+ cvtest::randReal(rng) * range + 1);
+ r[j + 1] = std::conj(r[j]);
+ j += 2;
+ }
+ }
+
+ for (int j = 0, k = 1 << n, jj, kk; j < k; ++j)
+ {
+ int p = 0;
+ complex_type v(1);
+ for (jj = 0, kk = 1; jj < n && !(j & kk); ++jj, ++p, kk <<= 1)
+ ;
+ for (; jj < n; ++jj, kk <<= 1)
+ {
+ if (j & kk)
+ v *= -r[jj];
+ else
+ ++p;
+ }
+ c[p] += v;
+ }
+
+ bool pass = false;
+ double div = 0, s = 0;
+ int cubic_case = idx & 1;
+ for (int maxiter = 100; !pass && maxiter < 10000; maxiter *= 2, cubic_case = (cubic_case + 1) % 2)
+ {
+ for (int j = 0; j < n + 1; ++j)
+ a[j] = c[j].real();
+
+ CvMat amat, umat;
+ cvInitMatHeader(&amat, n + 1, 1, CV_64FC1, &a[0]);
+ cvInitMatHeader(&umat, n, 1, CV_64FC2, &u[0]);
+ cvSolvePoly(&amat, &umat, maxiter, fig);
+
+ for (int j = 0; j < n; ++j)
+ ar[j] = complex_type(u[j * 2], u[j * 2 + 1]);
+
+ std::sort(r.begin(), r.end(), pred_complex());
+ std::sort(ar.begin(), ar.end(), pred_complex());
+
+ pass = true;
+ if( n == 3 )
+ {
+ ar2.resize(n);
+ cv::Mat _umat2(3, 1, CV_64F, &ar2[0]), umat2 = _umat2;
+ cvFlip(&amat, &amat, 0);
+ int nr2;
+ if( cubic_case == 0 )
+ nr2 = cv::solveCubic(cv::Mat(&amat),umat2);
+ else
+ nr2 = cv::solveCubic(cv::Mat_<float>(cv::Mat(&amat)), umat2);
+ cvFlip(&amat, &amat, 0);
+ if(nr2 > 0)
+ std::sort(ar2.begin(), ar2.begin()+nr2, pred_double());
+ ar2.resize(nr2);
+
+ int nr1 = 0;
+ for(int j = 0; j < n; j++)
+ if( fabs(r[j].imag()) < DBL_EPSILON )
+ ar1[nr1++] = r[j].real();
+
+ pass = pass && nr1 == nr2;
+ if( nr2 > 0 )
+ {
+ div = s = 0;
+ for(int j = 0; j < nr1; j++)
+ {
+ s += fabs(ar1[j]);
+ div += fabs(ar1[j] - ar2[j]);
+ }
+ div /= s;
+ pass = pass && div < err_eps;
+ }
+ }
+
+ div = s = 0;
+ for (int j = 0; j < n; ++j)
+ {
+ s += fabs(r[j].real()) + fabs(r[j].imag());
+ div += sqrt(pow(r[j].real() - ar[j].real(), 2) + pow(r[j].imag() - ar[j].imag(), 2));
+ }
+ div /= s;
+ pass = pass && div < err_eps;
+ }
+
+ if (!pass)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
+ ts->printf( cvtest::TS::LOG, "too big diff = %g\n", div );
+
+ for (size_t j=0;j<ar2.size();++j)
+ ts->printf( cvtest::TS::LOG, "ar2[%d]=%g\n", j, ar2[j]);
+ ts->printf(cvtest::TS::LOG, "\n");
+
+ for (size_t j=0;j<r.size();++j)
+ ts->printf( cvtest::TS::LOG, "r[%d]=(%g, %g)\n", j, r[j].real(), r[j].imag());
+ ts->printf( cvtest::TS::LOG, "\n" );
+ for (size_t j=0;j<ar.size();++j)
+ ts->printf( cvtest::TS::LOG, "ar[%d]=(%g, %g)\n", j, ar[j].real(), ar[j].imag());
+ break;
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST(Core_CovarMatrix, accuracy) { Core_CovarMatrixTest test; test.safe_run(); }
+TEST(Core_CrossProduct, accuracy) { Core_CrossProductTest test; test.safe_run(); }
+TEST(Core_Determinant, accuracy) { Core_DetTest test; test.safe_run(); }
+TEST(Core_DotProduct, accuracy) { Core_DotProductTest test; test.safe_run(); }
+TEST(Core_GEMM, accuracy) { Core_GEMMTest test; test.safe_run(); }
+TEST(Core_Invert, accuracy) { Core_InvertTest test; test.safe_run(); }
+TEST(Core_Mahalanobis, accuracy) { Core_MahalanobisTest test; test.safe_run(); }
+TEST(Core_MulTransposed, accuracy) { Core_MulTransposedTest test; test.safe_run(); }
+TEST(Core_Transform, accuracy) { Core_TransformTest test; test.safe_run(); }
+TEST(Core_PerspectiveTransform, accuracy) { Core_PerspectiveTransformTest test; test.safe_run(); }
+TEST(Core_Pow, accuracy) { Core_PowTest test; test.safe_run(); }
+TEST(Core_SolveLinearSystem, accuracy) { Core_SolveTest test; test.safe_run(); }
+TEST(Core_SVD, accuracy) { Core_SVDTest test; test.safe_run(); }
+TEST(Core_SVBkSb, accuracy) { Core_SVBkSbTest test; test.safe_run(); }
+TEST(Core_Trace, accuracy) { Core_TraceTest test; test.safe_run(); }
+TEST(Core_SolvePoly, accuracy) { Core_SolvePolyTest test; test.safe_run(); }
+
+// TODO: eigenvv, invsqrt, cbrt, fastarctan, (round, floor, ceil(?)),
+
+/* End of file. */
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+using namespace cv;
+using namespace std;
+
+
+class CV_OperationsTest : public cvtest::BaseTest
+{
+public:
+ CV_OperationsTest();
+ ~CV_OperationsTest();
+protected:
+ void run(int);
+
+ struct test_excep
+ {
+ test_excep(const string& _s=string("")) : s(_s) {};
+ string s;
+ };
+
+ bool SomeMatFunctions();
+ bool TestMat();
+ bool TestTemplateMat();
+ bool TestMatND();
+ bool TestSparseMat();
+ bool operations1();
+
+ void checkDiff(const Mat& m1, const Mat& m2, const string& s) { if (norm(m1, m2, NORM_INF) != 0) throw test_excep(s); }
+ void checkDiffF(const Mat& m1, const Mat& m2, const string& s) { if (norm(m1, m2, NORM_INF) > 1e-5) throw test_excep(s); }
+
+};
+
+CV_OperationsTest::CV_OperationsTest()
+{
+}
+
+CV_OperationsTest::~CV_OperationsTest() {}
+
+#define STR(a) STR2(a)
+#define STR2(a) #a
+
+#define CHECK_DIFF(a, b) checkDiff(a, b, "(" #a ") != (" #b ") at l." STR(__LINE__))
+#define CHECK_DIFF_FLT(a, b) checkDiffF(a, b, "(" #a ") !=(eps) (" #b ") at l." STR(__LINE__))
+
+#if defined _MSC_VER && _MSC_VER < 1400
+#define MSVC_OLD 1
+#else
+#define MSVC_OLD 0
+#endif
+
+bool CV_OperationsTest::TestMat()
+{
+ try
+ {
+ Mat one_3x1(3, 1, CV_32F, Scalar(1.0));
+ Mat shi_3x1(3, 1, CV_32F, Scalar(1.2));
+ Mat shi_2x1(2, 1, CV_32F, Scalar(-1));
+ Scalar shift = Scalar::all(15);
+
+ float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f };
+ Mat rot_2x3(2, 3, CV_32F, data);
+
+ Mat res = one_3x1 + shi_3x1 + shi_3x1 + shi_3x1;
+ res = Mat(Mat(2 * rot_2x3) * res - shi_2x1) + shift;
+
+ Mat tmp, res2;
+ add(one_3x1, shi_3x1, tmp);
+ add(tmp, shi_3x1, tmp);
+ add(tmp, shi_3x1, tmp);
+ gemm(rot_2x3, tmp, 2, shi_2x1, -1, res2, 0);
+ add(res2, Mat(2, 1, CV_32F, shift), res2);
+
+ CHECK_DIFF(res, res2);
+
+ Mat mat4x4(4, 4, CV_32F);
+ randu(mat4x4, Scalar(0), Scalar(10));
+
+ Mat roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2)));
+ Mat roi2 = mat4x4(Range(1, 3), Range(1, 3));
+
+ CHECK_DIFF(roi1, roi2);
+ CHECK_DIFF(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size())));
+
+ Mat intMat10(3, 3, CV_32S, Scalar(10));
+ Mat intMat11(3, 3, CV_32S, Scalar(11));
+ Mat resMat(3, 3, CV_8U, Scalar(255));
+
+ CHECK_DIFF(resMat, intMat10 == intMat10);
+ CHECK_DIFF(resMat, intMat10 < intMat11);
+ CHECK_DIFF(resMat, intMat11 > intMat10);
+ CHECK_DIFF(resMat, intMat10 <= intMat11);
+ CHECK_DIFF(resMat, intMat11 >= intMat10);
+ CHECK_DIFF(resMat, intMat11 != intMat10);
+
+ CHECK_DIFF(resMat, intMat10 == 10.0);
+ CHECK_DIFF(resMat, 10.0 == intMat10);
+ CHECK_DIFF(resMat, intMat10 < 11.0);
+ CHECK_DIFF(resMat, 11.0 > intMat10);
+ CHECK_DIFF(resMat, 10.0 < intMat11);
+ CHECK_DIFF(resMat, 11.0 >= intMat10);
+ CHECK_DIFF(resMat, 10.0 <= intMat11);
+ CHECK_DIFF(resMat, 10.0 != intMat11);
+ CHECK_DIFF(resMat, intMat11 != 10.0);
+
+ Mat eye = Mat::eye(3, 3, CV_16S);
+ Mat maskMat4(3, 3, CV_16S, Scalar(4));
+ Mat maskMat1(3, 3, CV_16S, Scalar(1));
+ Mat maskMat5(3, 3, CV_16S, Scalar(5));
+ Mat maskMat0(3, 3, CV_16S, Scalar(0));
+
+ CHECK_DIFF(maskMat0, maskMat4 & maskMat1);
+ CHECK_DIFF(maskMat0, Scalar(1) & maskMat4);
+ CHECK_DIFF(maskMat0, maskMat4 & Scalar(1));
+
+ Mat m;
+ m = maskMat4.clone(); m &= maskMat1; CHECK_DIFF(maskMat0, m);
+ m = maskMat4.clone(); m &= maskMat1 | maskMat1; CHECK_DIFF(maskMat0, m);
+ m = maskMat4.clone(); m &= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat0, m);
+
+ m = maskMat4.clone(); m &= Scalar(1); CHECK_DIFF(maskMat0, m);
+ m = maskMat4.clone(); m |= maskMat1; CHECK_DIFF(maskMat5, m);
+ m = maskMat5.clone(); m ^= maskMat1; CHECK_DIFF(maskMat4, m);
+ m = maskMat4.clone(); m |= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat5, m);
+ m = maskMat5.clone(); m ^= (2* maskMat1 - maskMat1); CHECK_DIFF(maskMat4, m);
+
+ m = maskMat4.clone(); m |= Scalar(1); CHECK_DIFF(maskMat5, m);
+ m = maskMat5.clone(); m ^= Scalar(1); CHECK_DIFF(maskMat4, m);
+
+
+
+ CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & (maskMat1 | maskMat1));
+ CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & maskMat1);
+ CHECK_DIFF(maskMat0, maskMat4 & (maskMat1 | maskMat1));
+ CHECK_DIFF(maskMat0, (maskMat1 | maskMat1) & Scalar(4));
+ CHECK_DIFF(maskMat0, Scalar(4) & (maskMat1 | maskMat1));
+
+ CHECK_DIFF(maskMat0, maskMat5 ^ (maskMat4 | maskMat1));
+ CHECK_DIFF(maskMat0, (maskMat4 | maskMat1) ^ maskMat5);
+ CHECK_DIFF(maskMat0, (maskMat4 + maskMat1) ^ (maskMat4 + maskMat1));
+ CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 | Scalar(1)));
+ CHECK_DIFF(maskMat1, Scalar(5) ^ maskMat4);
+ CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 + maskMat1));
+ CHECK_DIFF(maskMat5, Scalar(5) | (maskMat4 + maskMat1));
+ CHECK_DIFF(maskMat0, (maskMat4 + maskMat1) ^ Scalar(5));
+
+ CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ maskMat1));
+ CHECK_DIFF(maskMat5, (maskMat4 ^ maskMat1) | maskMat5);
+ CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ Scalar(1)));
+ CHECK_DIFF(maskMat5, (maskMat4 | maskMat4) | Scalar(1));
+ CHECK_DIFF(maskMat5, Scalar(1) | (maskMat4 | maskMat4));
+ CHECK_DIFF(maskMat5, Scalar(1) | maskMat4);
+ CHECK_DIFF(maskMat5, (maskMat5 | maskMat5) | (maskMat4 ^ maskMat1));
+
+ CHECK_DIFF(maskMat1, min(maskMat1, maskMat5));
+ CHECK_DIFF(maskMat1, min(Mat(maskMat1 | maskMat1), maskMat5 | maskMat5));
+ CHECK_DIFF(maskMat5, max(maskMat1, maskMat5));
+ CHECK_DIFF(maskMat5, max(Mat(maskMat1 | maskMat1), maskMat5 | maskMat5));
+
+ CHECK_DIFF(maskMat1, min(maskMat1, maskMat5 | maskMat5));
+ CHECK_DIFF(maskMat1, min(maskMat1 | maskMat1, maskMat5));
+ CHECK_DIFF(maskMat5, max(maskMat1 | maskMat1, maskMat5));
+ CHECK_DIFF(maskMat5, max(maskMat1, maskMat5 | maskMat5));
+
+ CHECK_DIFF(~maskMat1, maskMat1 ^ -1);
+ CHECK_DIFF(~(maskMat1 | maskMat1), maskMat1 ^ -1);
+
+ CHECK_DIFF(maskMat1, maskMat4/4.0);
+
+ /////////////////////////////
+
+ CHECK_DIFF(1.0 - (maskMat5 | maskMat5), -maskMat4);
+ CHECK_DIFF((maskMat4 | maskMat4) * 1.0 + 1.0, maskMat5);
+ CHECK_DIFF(1.0 + (maskMat4 | maskMat4) * 1.0, maskMat5);
+ CHECK_DIFF((maskMat5 | maskMat5) * 1.0 - 1.0, maskMat4);
+ CHECK_DIFF(5.0 - (maskMat4 | maskMat4) * 1.0, maskMat1);
+ CHECK_DIFF((maskMat4 | maskMat4) * 1.0 + 0.5 + 0.5, maskMat5);
+ CHECK_DIFF(0.5 + ((maskMat4 | maskMat4) * 1.0 + 0.5), maskMat5);
+ CHECK_DIFF(((maskMat4 | maskMat4) * 1.0 + 2.0) - 1.0, maskMat5);
+ CHECK_DIFF(5.0 - ((maskMat1 | maskMat1) * 1.0 + 3.0), maskMat1);
+ CHECK_DIFF( ( (maskMat1 | maskMat1) * 2.0 + 2.0) * 1.25, maskMat5);
+ CHECK_DIFF( 1.25 * ( (maskMat1 | maskMat1) * 2.0 + 2.0), maskMat5);
+ CHECK_DIFF( -( (maskMat1 | maskMat1) * (-2.0) + 1.0), maskMat1);
+ CHECK_DIFF( maskMat1 * 1.0 + maskMat4 * 0.5 + 2.0, maskMat5);
+ CHECK_DIFF( 1.0 + (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat5);
+ CHECK_DIFF( (maskMat1 * 1.0 + maskMat4 * 0.5 + 2.0) - 1.0, maskMat4);
+ CHECK_DIFF(5.0 - (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat1);
+ CHECK_DIFF((maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0)*1.25, maskMat5);
+ CHECK_DIFF(1.25 * (maskMat1 * 1.0 + maskMat4 * 0.5 + 1.0), maskMat5);
+ CHECK_DIFF(-(maskMat1 * 2.0 + maskMat4 * (-1) + 1.0), maskMat1);
+ CHECK_DIFF((maskMat1 * 1.0 + maskMat4), maskMat5);
+ CHECK_DIFF((maskMat4 + maskMat1 * 1.0), maskMat5);
+ CHECK_DIFF((maskMat1 * 3.0 + 1.0) + maskMat1, maskMat5);
+ CHECK_DIFF(maskMat1 + (maskMat1 * 3.0 + 1.0), maskMat5);
+ CHECK_DIFF(maskMat1*4.0 + (maskMat1 | maskMat1), maskMat5);
+ CHECK_DIFF((maskMat1 | maskMat1) + maskMat1*4.0, maskMat5);
+ CHECK_DIFF((maskMat1*3.0 + 1.0) + (maskMat1 | maskMat1), maskMat5);
+ CHECK_DIFF((maskMat1 | maskMat1) + (maskMat1*3.0 + 1.0), maskMat5);
+ CHECK_DIFF(maskMat1*4.0 + maskMat4*2.0, maskMat1 * 12);
+ CHECK_DIFF((maskMat1*3.0 + 1.0) + maskMat4*2.0, maskMat1 * 12);
+ CHECK_DIFF(maskMat4*2.0 + (maskMat1*3.0 + 1.0), maskMat1 * 12);
+ CHECK_DIFF((maskMat1*3.0 + 1.0) + (maskMat1*2.0 + 2.0), maskMat1 * 8);
+
+ CHECK_DIFF(maskMat5*1.0 - maskMat4, maskMat1);
+ CHECK_DIFF(maskMat5 - maskMat1 * 4.0, maskMat1);
+ CHECK_DIFF((maskMat4 * 1.0 + 4.0)- maskMat4, maskMat4);
+ CHECK_DIFF(maskMat5 - (maskMat1 * 2.0 + 2.0), maskMat1);
+ CHECK_DIFF(maskMat5*1.0 - (maskMat4 | maskMat4), maskMat1);
+ CHECK_DIFF((maskMat5 | maskMat5) - maskMat1 * 4.0, maskMat1);
+ CHECK_DIFF((maskMat4 * 1.0 + 4.0)- (maskMat4 | maskMat4), maskMat4);
+ CHECK_DIFF((maskMat5 | maskMat5) - (maskMat1 * 2.0 + 2.0), maskMat1);
+ CHECK_DIFF(maskMat1*5.0 - maskMat4 * 1.0, maskMat1);
+ CHECK_DIFF((maskMat1*5.0 + 3.0)- maskMat4 * 1.0, maskMat4);
+ CHECK_DIFF(maskMat4 * 2.0 - (maskMat1*4.0 + 3.0), maskMat1);
+ CHECK_DIFF((maskMat1 * 2.0 + 3.0) - (maskMat1*3.0 + 1.0), maskMat1);
+
+ CHECK_DIFF((maskMat5 - maskMat4)* 4.0, maskMat4);
+ CHECK_DIFF(4.0 * (maskMat5 - maskMat4), maskMat4);
+
+ CHECK_DIFF(-((maskMat4 | maskMat4) - (maskMat5 | maskMat5)), maskMat1);
+
+ CHECK_DIFF(4.0 * (maskMat1 | maskMat1), maskMat4);
+ CHECK_DIFF((maskMat4 | maskMat4)/4.0, maskMat1);
+
+#if !MSVC_OLD
+ CHECK_DIFF(2.0 * (maskMat1 * 2.0) , maskMat4);
+#endif
+ CHECK_DIFF((maskMat4 / 2.0) / 2.0 , maskMat1);
+ CHECK_DIFF(-(maskMat4 - maskMat5) , maskMat1);
+ CHECK_DIFF(-((maskMat4 - maskMat5) * 1.0), maskMat1);
+
+
+ /////////////////////////////
+ CHECK_DIFF(maskMat4 / maskMat4, maskMat1);
+
+ ///// Element-wise multiplication
+
+ CHECK_DIFF(maskMat4.mul(maskMat4, 0.25), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat1 * 4, 0.25), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat4) * 0.25, maskMat4);
+ CHECK_DIFF(0.25 * maskMat4.mul(maskMat4), maskMat4);
+
+ ////// Element-wise division
+
+ CHECK_DIFF(maskMat4 / maskMat4, maskMat1);
+ CHECK_DIFF((maskMat4 & maskMat4) / (maskMat1 * 4), maskMat1);
+
+ CHECK_DIFF((maskMat4 & maskMat4) / maskMat4, maskMat1);
+ CHECK_DIFF(maskMat4 / (maskMat4 & maskMat4), maskMat1);
+ CHECK_DIFF((maskMat1 * 4) / maskMat4, maskMat1);
+
+ CHECK_DIFF(maskMat4 / (maskMat1 * 4), maskMat1);
+ CHECK_DIFF((maskMat4 * 0.5 )/ (maskMat1 * 2), maskMat1);
+
+ CHECK_DIFF(maskMat4 / maskMat4.mul(maskMat1), maskMat1);
+ CHECK_DIFF((maskMat4 & maskMat4) / maskMat4.mul(maskMat1), maskMat1);
+
+ CHECK_DIFF(4.0 / maskMat4, maskMat1);
+ CHECK_DIFF(4.0 / (maskMat4 | maskMat4), maskMat1);
+ CHECK_DIFF(4.0 / (maskMat1 * 4.0), maskMat1);
+ CHECK_DIFF(4.0 / (maskMat4 / maskMat1), maskMat1);
+
+ m = maskMat4.clone(); m/=4.0; CHECK_DIFF(m, maskMat1);
+ m = maskMat4.clone(); m/=maskMat4; CHECK_DIFF(m, maskMat1);
+ m = maskMat4.clone(); m/=(maskMat1 * 4.0); CHECK_DIFF(m, maskMat1);
+ m = maskMat4.clone(); m/=(maskMat4 / maskMat1); CHECK_DIFF(m, maskMat1);
+
+ /////////////////////////////
+ float matrix_data[] = { 3, 1, -4, -5, 1, 0, 0, 1.1f, 1.5f};
+ Mat mt(3, 3, CV_32F, matrix_data);
+ Mat mi = mt.inv();
+ Mat d1 = Mat::eye(3, 3, CV_32F);
+ Mat d2 = d1 * 2;
+ MatExpr mt_tr = mt.t();
+ MatExpr mi_tr = mi.t();
+ Mat mi2 = mi * 2;
+
+
+ CHECK_DIFF_FLT( mi2 * mt, d2 );
+ CHECK_DIFF_FLT( mi * mt, d1 );
+ CHECK_DIFF_FLT( mt_tr * mi_tr, d1 );
+
+ m = mi.clone(); m*=mt; CHECK_DIFF_FLT(m, d1);
+ m = mi.clone(); m*= (2 * mt - mt) ; CHECK_DIFF_FLT(m, d1);
+
+ m = maskMat4.clone(); m+=(maskMat1 * 1.0); CHECK_DIFF(m, maskMat5);
+ m = maskMat5.clone(); m-=(maskMat1 * 4.0); CHECK_DIFF(m, maskMat1);
+
+ m = maskMat1.clone(); m+=(maskMat1 * 3.0 + 1.0); CHECK_DIFF(m, maskMat5);
+ m = maskMat5.clone(); m-=(maskMat1 * 3.0 + 1.0); CHECK_DIFF(m, maskMat1);
+#if !MSVC_OLD
+ m = mi.clone(); m+=(3.0 * mi * mt + d1); CHECK_DIFF_FLT(m, mi + d1 * 4);
+ m = mi.clone(); m-=(3.0 * mi * mt + d1); CHECK_DIFF_FLT(m, mi - d1 * 4);
+ m = mi.clone(); m*=(mt * 1.0); CHECK_DIFF_FLT(m, d1);
+ m = mi.clone(); m*=(mt * 1.0 + Mat::eye(m.size(), m.type())); CHECK_DIFF_FLT(m, d1 + mi);
+ m = mi.clone(); m*=mt_tr.t(); CHECK_DIFF_FLT(m, d1);
+
+ CHECK_DIFF_FLT( (mi * 2) * mt, d2);
+ CHECK_DIFF_FLT( mi * (2 * mt), d2);
+ CHECK_DIFF_FLT( mt.t() * mi_tr, d1 );
+ CHECK_DIFF_FLT( mt_tr * mi.t(), d1 );
+ CHECK_DIFF_FLT( (mi * 0.4) * (mt * 5), d2);
+
+ CHECK_DIFF_FLT( mt.t() * (mi_tr * 2), d2 );
+ CHECK_DIFF_FLT( (mt_tr * 2) * mi.t(), d2 );
+
+ CHECK_DIFF_FLT(mt.t() * mi.t(), d1);
+ CHECK_DIFF_FLT( (mi * mt) * 2.0, d2);
+ CHECK_DIFF_FLT( 2.0 * (mi * mt), d2);
+ CHECK_DIFF_FLT( -(mi * mt), -d1);
+
+ CHECK_DIFF_FLT( (mi * mt) / 2.0, d1 / 2);
+
+ Mat mt_mul_2_plus_1;
+ gemm(mt, d1, 2, Mat::ones(3, 3, CV_32F), 1, mt_mul_2_plus_1);
+
+ CHECK_DIFF( (mt * 2.0 + 1.0) * mi, mt_mul_2_plus_1 * mi); // (A*alpha + beta)*B
+ CHECK_DIFF( mi * (mt * 2.0 + 1.0), mi * mt_mul_2_plus_1); // A*(B*alpha + beta)
+ CHECK_DIFF( (mt * 2.0 + 1.0) * (mi * 2), mt_mul_2_plus_1 * mi2); // (A*alpha + beta)*(B*gamma)
+ CHECK_DIFF( (mi *2)* (mt * 2.0 + 1.0), mi2 * mt_mul_2_plus_1); // (A*gamma)*(B*alpha + beta)
+ CHECK_DIFF_FLT( (mt * 2.0 + 1.0) * mi.t(), mt_mul_2_plus_1 * mi_tr); // (A*alpha + beta)*B^t
+ CHECK_DIFF_FLT( mi.t() * (mt * 2.0 + 1.0), mi_tr * mt_mul_2_plus_1); // A^t*(B*alpha + beta)
+
+ CHECK_DIFF_FLT( (mi * mt + d2)*5, d1 * 3 * 5);
+ CHECK_DIFF_FLT( mi * mt + d2, d1 * 3);
+ CHECK_DIFF_FLT( -(mi * mt) + d2, d1);
+ CHECK_DIFF_FLT( (mi * mt) + d1, d2);
+ CHECK_DIFF_FLT( d1 + (mi * mt), d2);
+ CHECK_DIFF_FLT( (mi * mt) - d2, -d1);
+ CHECK_DIFF_FLT( d2 - (mi * mt), d1);
+
+ CHECK_DIFF_FLT( (mi * mt) + d2 * 0.5, d2);
+ CHECK_DIFF_FLT( d2 * 0.5 + (mi * mt), d2);
+ CHECK_DIFF_FLT( (mi * mt) - d1 * 2, -d1);
+ CHECK_DIFF_FLT( d1 * 2 - (mi * mt), d1);
+
+ CHECK_DIFF_FLT( (mi * mt) + mi.t(), mi_tr + d1);
+ CHECK_DIFF_FLT( mi.t() + (mi * mt), mi_tr + d1);
+ CHECK_DIFF_FLT( (mi * mt) - mi.t(), d1 - mi_tr);
+ CHECK_DIFF_FLT( mi.t() - (mi * mt), mi_tr - d1);
+
+ CHECK_DIFF_FLT( 2.0 *(mi * mt + d2), d1 * 6);
+ CHECK_DIFF_FLT( -(mi * mt + d2), d1 * -3);
+
+ CHECK_DIFF_FLT(mt.inv() * mt, d1);
+
+ CHECK_DIFF_FLT(mt.inv() * (2*mt - mt), d1);
+#endif
+ }
+ catch (const test_excep& e)
+ {
+ ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str());
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+bool CV_OperationsTest::SomeMatFunctions()
+{
+ try
+ {
+ Mat rgba( 10, 10, CV_8UC4, Scalar(1,2,3,4) );
+ Mat bgr( rgba.rows, rgba.cols, CV_8UC3 );
+ Mat alpha( rgba.rows, rgba.cols, CV_8UC1 );
+ Mat out[] = { bgr, alpha };
+ // rgba[0] -> bgr[2], rgba[1] -> bgr[1],
+ // rgba[2] -> bgr[0], rgba[3] -> alpha[0]
+ int from_to[] = { 0,2, 1,1, 2,0, 3,3 };
+ mixChannels( &rgba, 1, out, 2, from_to, 4 );
+
+ Mat bgr_exp( rgba.size(), CV_8UC3, Scalar(3,2,1));
+ Mat alpha_exp( rgba.size(), CV_8UC1, Scalar(4));
+
+ CHECK_DIFF(bgr_exp, bgr);
+ CHECK_DIFF(alpha_exp, alpha);
+ }
+ catch (const test_excep& e)
+ {
+ ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str());
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+
+}
+
+
+bool CV_OperationsTest::TestTemplateMat()
+{
+ try
+ {
+ Mat_<float> one_3x1(3, 1, 1.0f);
+ Mat_<float> shi_3x1(3, 1, 1.2f);
+ Mat_<float> shi_2x1(2, 1, -2);
+ Scalar shift = Scalar::all(15);
+
+ float data[] = { sqrt(2.f)/2, -sqrt(2.f)/2, 1.f, sqrt(2.f)/2, sqrt(2.f)/2, 10.f };
+ Mat_<float> rot_2x3(2, 3, data);
+
+ Mat_<float> res = Mat(Mat(2 * rot_2x3) * Mat(one_3x1 + shi_3x1 + shi_3x1 + shi_3x1) - shi_2x1) + shift;
+ Mat_<float> resS = rot_2x3 * one_3x1;
+
+ Mat_<float> tmp, res2, resS2;
+ add(one_3x1, shi_3x1, tmp);
+ add(tmp, shi_3x1, tmp);
+ add(tmp, shi_3x1, tmp);
+ gemm(rot_2x3, tmp, 2, shi_2x1, -1, res2, 0);
+ add(res2, Mat(2, 1, CV_32F, shift), res2);
+
+ gemm(rot_2x3, one_3x1, 1, shi_2x1, 0, resS2, 0);
+ CHECK_DIFF(res, res2);
+ CHECK_DIFF(resS, resS2);
+
+
+ Mat_<float> mat4x4(4, 4);
+ randu(mat4x4, Scalar(0), Scalar(10));
+
+ Mat_<float> roi1 = mat4x4(Rect(Point(1, 1), Size(2, 2)));
+ Mat_<float> roi2 = mat4x4(Range(1, 3), Range(1, 3));
+
+ CHECK_DIFF(roi1, roi2);
+ CHECK_DIFF(mat4x4, mat4x4(Rect(Point(0,0), mat4x4.size())));
+
+ Mat_<int> intMat10(3, 3, 10);
+ Mat_<int> intMat11(3, 3, 11);
+ Mat_<uchar> resMat(3, 3, 255);
+
+ CHECK_DIFF(resMat, intMat10 == intMat10);
+ CHECK_DIFF(resMat, intMat10 < intMat11);
+ CHECK_DIFF(resMat, intMat11 > intMat10);
+ CHECK_DIFF(resMat, intMat10 <= intMat11);
+ CHECK_DIFF(resMat, intMat11 >= intMat10);
+
+ CHECK_DIFF(resMat, intMat10 == 10.0);
+ CHECK_DIFF(resMat, intMat10 < 11.0);
+ CHECK_DIFF(resMat, intMat11 > 10.0);
+ CHECK_DIFF(resMat, intMat10 <= 11.0);
+ CHECK_DIFF(resMat, intMat11 >= 10.0);
+
+ Mat_<uchar> maskMat4(3, 3, 4);
+ Mat_<uchar> maskMat1(3, 3, 1);
+ Mat_<uchar> maskMat5(3, 3, 5);
+ Mat_<uchar> maskMat0(3, 3, (uchar)0);
+
+ CHECK_DIFF(maskMat0, maskMat4 & maskMat1);
+ CHECK_DIFF(maskMat0, Scalar(1) & maskMat4);
+ CHECK_DIFF(maskMat0, maskMat4 & Scalar(1));
+
+ Mat_<uchar> m;
+ m = maskMat4.clone(); m&=maskMat1; CHECK_DIFF(maskMat0, m);
+ m = maskMat4.clone(); m&=Scalar(1); CHECK_DIFF(maskMat0, m);
+
+ m = maskMat4.clone(); m|=maskMat1; CHECK_DIFF(maskMat5, m);
+ m = maskMat4.clone(); m^=maskMat1; CHECK_DIFF(maskMat5, m);
+
+ CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & (maskMat1 | maskMat1));
+ CHECK_DIFF(maskMat0, (maskMat4 | maskMat4) & maskMat1);
+ CHECK_DIFF(maskMat0, maskMat4 & (maskMat1 | maskMat1));
+
+ CHECK_DIFF(maskMat0, maskMat5 ^ (maskMat4 | maskMat1));
+ CHECK_DIFF(maskMat0, Scalar(5) ^ (maskMat4 | Scalar(1)));
+
+ CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ maskMat1));
+ CHECK_DIFF(maskMat5, maskMat5 | (maskMat4 ^ Scalar(1)));
+
+ CHECK_DIFF(~maskMat1, maskMat1 ^ 0xFF);
+ CHECK_DIFF(~(maskMat1 | maskMat1), maskMat1 ^ 0xFF);
+
+ CHECK_DIFF(maskMat1 + maskMat4, maskMat5);
+ CHECK_DIFF(maskMat1 + Scalar(4), maskMat5);
+ CHECK_DIFF(Scalar(4) + maskMat1, maskMat5);
+ CHECK_DIFF(Scalar(4) + (maskMat1 & maskMat1), maskMat5);
+
+ CHECK_DIFF(maskMat1 + 4.0, maskMat5);
+ CHECK_DIFF((maskMat1 & 0xFF) + 4.0, maskMat5);
+ CHECK_DIFF(4.0 + maskMat1, maskMat5);
+
+ m = maskMat4.clone(); m+=Scalar(1); CHECK_DIFF(m, maskMat5);
+ m = maskMat4.clone(); m+=maskMat1; CHECK_DIFF(m, maskMat5);
+ m = maskMat4.clone(); m+=(maskMat1 | maskMat1); CHECK_DIFF(m, maskMat5);
+
+ CHECK_DIFF(maskMat5 - maskMat1, maskMat4);
+ CHECK_DIFF(maskMat5 - Scalar(1), maskMat4);
+ CHECK_DIFF((maskMat5 | maskMat5) - Scalar(1), maskMat4);
+ CHECK_DIFF(maskMat5 - 1, maskMat4);
+ CHECK_DIFF((maskMat5 | maskMat5) - 1, maskMat4);
+ CHECK_DIFF((maskMat5 | maskMat5) - (maskMat1 | maskMat1), maskMat4);
+
+ CHECK_DIFF(maskMat1, min(maskMat1, maskMat5));
+ CHECK_DIFF(maskMat5, max(maskMat1, maskMat5));
+
+ m = maskMat5.clone(); m-=Scalar(1); CHECK_DIFF(m, maskMat4);
+ m = maskMat5.clone(); m-=maskMat1; CHECK_DIFF(m, maskMat4);
+ m = maskMat5.clone(); m-=(maskMat1 | maskMat1); CHECK_DIFF(m, maskMat4);
+
+ m = maskMat4.clone(); m |= Scalar(1); CHECK_DIFF(maskMat5, m);
+ m = maskMat5.clone(); m ^= Scalar(1); CHECK_DIFF(maskMat4, m);
+
+ CHECK_DIFF(maskMat1, maskMat4/4.0);
+
+ Mat_<float> negf(3, 3, -3.0);
+ Mat_<float> posf = -negf;
+ Mat_<float> posf2 = posf * 2;
+ Mat_<int> negi(3, 3, -3);
+
+ CHECK_DIFF(abs(negf), -negf);
+ CHECK_DIFF(abs(posf - posf2), -negf);
+ CHECK_DIFF(abs(negi), -(negi & negi));
+
+ CHECK_DIFF(5.0 - maskMat4, maskMat1);
+
+
+ CHECK_DIFF(maskMat4.mul(maskMat4, 0.25), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat1 * 4, 0.25), maskMat4);
+ CHECK_DIFF(maskMat4.mul(maskMat4 / 4), maskMat4);
+
+
+ ////// Element-wise division
+
+ CHECK_DIFF(maskMat4 / maskMat4, maskMat1);
+ CHECK_DIFF(4.0 / maskMat4, maskMat1);
+ m = maskMat4.clone(); m/=4.0; CHECK_DIFF(m, maskMat1);
+
+ ////////////////////////////////
+
+ typedef Mat_<int> TestMat_t;
+
+ const TestMat_t cnegi = negi.clone();
+
+ TestMat_t::iterator beg = negi.begin();
+ TestMat_t::iterator end = negi.end();
+
+ TestMat_t::const_iterator cbeg = cnegi.begin();
+ TestMat_t::const_iterator cend = cnegi.end();
+
+ int sum = 0;
+ for(; beg!=end; ++beg)
+ sum+=*beg;
+
+ for(; cbeg!=cend; ++cbeg)
+ sum-=*cbeg;
+
+ if (sum != 0) throw test_excep();
+
+ CHECK_DIFF(negi.col(1), negi.col(2));
+ CHECK_DIFF(negi.row(1), negi.row(2));
+ CHECK_DIFF(negi.col(1), negi.diag());
+
+ if (Mat_<Point2f>(1, 1).elemSize1() != sizeof(float)) throw test_excep();
+ if (Mat_<Point2f>(1, 1).elemSize() != 2 * sizeof(float)) throw test_excep();
+ if (Mat_<Point2f>(1, 1).depth() != CV_32F) throw test_excep();
+ if (Mat_<float>(1, 1).depth() != CV_32F) throw test_excep();
+ if (Mat_<int>(1, 1).depth() != CV_32S) throw test_excep();
+ if (Mat_<double>(1, 1).depth() != CV_64F) throw test_excep();
+ if (Mat_<Point3d>(1, 1).depth() != CV_64F) throw test_excep();
+ if (Mat_<signed char>(1, 1).depth() != CV_8S) throw test_excep();
+ if (Mat_<unsigned short>(1, 1).depth() != CV_16U) throw test_excep();
+ if (Mat_<unsigned short>(1, 1).channels() != 1) throw test_excep();
+ if (Mat_<Point2f>(1, 1).channels() != 2) throw test_excep();
+ if (Mat_<Point3f>(1, 1).channels() != 3) throw test_excep();
+ if (Mat_<Point3d>(1, 1).channels() != 3) throw test_excep();
+
+ Mat_<uchar> eye = Mat_<uchar>::zeros(2, 2); CHECK_DIFF(Mat_<uchar>::zeros(Size(2, 2)), eye);
+ eye.at<uchar>(Point(0,0)) = 1; eye.at<uchar>(1, 1) = 1;
+
+ CHECK_DIFF(Mat_<uchar>::eye(2, 2), eye);
+ CHECK_DIFF(eye, Mat_<uchar>::eye(Size(2,2)));
+
+ Mat_<uchar> ones(2, 2, (uchar)1);
+ CHECK_DIFF(ones, Mat_<uchar>::ones(Size(2,2)));
+ CHECK_DIFF(Mat_<uchar>::ones(2, 2), ones);
+
+ Mat_<Point2f> pntMat(2, 2, Point2f(1, 0));
+ if(pntMat.stepT() != 2) throw test_excep();
+
+ uchar uchar_data[] = {1, 0, 0, 1};
+
+ Mat_<uchar> matFromData(1, 4, uchar_data);
+ const Mat_<uchar> mat2 = matFromData.clone();
+ CHECK_DIFF(matFromData, eye.reshape(1));
+ if (matFromData(Point(0,0)) != uchar_data[0])throw test_excep();
+ if (mat2(Point(0,0)) != uchar_data[0]) throw test_excep();
+
+ if (matFromData(0,0) != uchar_data[0])throw test_excep();
+ if (mat2(0,0) != uchar_data[0]) throw test_excep();
+
+ Mat_<uchar> rect(eye, Rect(0, 0, 1, 1));
+ if (rect.cols != 1 || rect.rows != 1 || rect(0,0) != uchar_data[0]) throw test_excep();
+
+ //cv::Mat_<_Tp>::adjustROI(int,int,int,int)
+ //cv::Mat_<_Tp>::cross(const Mat_&) const
+ //cv::Mat_<_Tp>::Mat_(const vector<_Tp>&,bool)
+ //cv::Mat_<_Tp>::Mat_(int,int,_Tp*,size_t)
+ //cv::Mat_<_Tp>::Mat_(int,int,const _Tp&)
+ //cv::Mat_<_Tp>::Mat_(Size,const _Tp&)
+ //cv::Mat_<_Tp>::mul(const Mat_<_Tp>&,double) const
+ //cv::Mat_<_Tp>::mul(const MatExpr_<MatExpr_Op2_<Mat_<_Tp>,double,Mat_<_Tp>,MatOp_DivRS_<Mat> >,Mat_<_Tp> >&,double) const
+ //cv::Mat_<_Tp>::mul(const MatExpr_<MatExpr_Op2_<Mat_<_Tp>,double,Mat_<_Tp>,MatOp_Scale_<Mat> >,Mat_<_Tp> >&,double) const
+ //cv::Mat_<_Tp>::operator Mat_<T2>() const
+ //cv::Mat_<_Tp>::operator MatExpr_<Mat_<_Tp>,Mat_<_Tp> >() const
+ //cv::Mat_<_Tp>::operator()(const Range&,const Range&) const
+ //cv::Mat_<_Tp>::operator()(const Rect&) const
+
+ //cv::Mat_<_Tp>::operator=(const MatExpr_Base&)
+ //cv::Mat_<_Tp>::operator[](int) const
+
+
+ ///////////////////////////////
+
+ float matrix_data[] = { 3, 1, -4, -5, 1, 0, 0, 1.1f, 1.5f};
+ Mat_<float> mt(3, 3, matrix_data);
+ Mat_<float> mi = mt.inv();
+ Mat_<float> d1 = Mat_<float>::eye(3, 3);
+ Mat_<float> d2 = d1 * 2;
+ Mat_<float> mt_tr = mt.t();
+ Mat_<float> mi_tr = mi.t();
+ Mat_<float> mi2 = mi * 2;
+
+ CHECK_DIFF_FLT( mi2 * mt, d2 );
+ CHECK_DIFF_FLT( mi * mt, d1 );
+ CHECK_DIFF_FLT( mt_tr * mi_tr, d1 );
+
+ Mat_<float> mf;
+ mf = mi.clone(); mf*=mt; CHECK_DIFF_FLT(mf, d1);
+
+ ////// typedefs //////
+
+ if (Mat1b(1, 1).elemSize() != sizeof(uchar)) throw test_excep();
+ if (Mat2b(1, 1).elemSize() != 2 * sizeof(uchar)) throw test_excep();
+ if (Mat3b(1, 1).elemSize() != 3 * sizeof(uchar)) throw test_excep();
+ if (Mat1f(1, 1).elemSize() != sizeof(float)) throw test_excep();
+ if (Mat2f(1, 1).elemSize() != 2 * sizeof(float)) throw test_excep();
+ if (Mat3f(1, 1).elemSize() != 3 * sizeof(float)) throw test_excep();
+ if (Mat1f(1, 1).depth() != CV_32F) throw test_excep();
+ if (Mat3f(1, 1).depth() != CV_32F) throw test_excep();
+ if (Mat3f(1, 1).type() != CV_32FC3) throw test_excep();
+ if (Mat1i(1, 1).depth() != CV_32S) throw test_excep();
+ if (Mat1d(1, 1).depth() != CV_64F) throw test_excep();
+ if (Mat1b(1, 1).depth() != CV_8U) throw test_excep();
+ if (Mat3b(1, 1).type() != CV_8UC3) throw test_excep();
+ if (Mat1w(1, 1).depth() != CV_16U) throw test_excep();
+ if (Mat1s(1, 1).depth() != CV_16S) throw test_excep();
+ if (Mat1f(1, 1).channels() != 1) throw test_excep();
+ if (Mat1b(1, 1).channels() != 1) throw test_excep();
+ if (Mat1i(1, 1).channels() != 1) throw test_excep();
+ if (Mat1w(1, 1).channels() != 1) throw test_excep();
+ if (Mat1s(1, 1).channels() != 1) throw test_excep();
+ if (Mat2f(1, 1).channels() != 2) throw test_excep();
+ if (Mat2b(1, 1).channels() != 2) throw test_excep();
+ if (Mat2i(1, 1).channels() != 2) throw test_excep();
+ if (Mat2w(1, 1).channels() != 2) throw test_excep();
+ if (Mat2s(1, 1).channels() != 2) throw test_excep();
+ if (Mat3f(1, 1).channels() != 3) throw test_excep();
+ if (Mat3b(1, 1).channels() != 3) throw test_excep();
+ if (Mat3i(1, 1).channels() != 3) throw test_excep();
+ if (Mat3w(1, 1).channels() != 3) throw test_excep();
+ if (Mat3s(1, 1).channels() != 3) throw test_excep();
+
+ }
+ catch (const test_excep& e)
+ {
+ ts->printf(cvtest::TS::LOG, "%s\n", e.s.c_str());
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+bool CV_OperationsTest::TestMatND()
+{
+ int sizes[] = { 3, 3, 3};
+ cv::MatND nd(3, sizes, CV_32F);
+
+ return true;
+}
+
+bool CV_OperationsTest::TestSparseMat()
+{
+ try
+ {
+ int sizes[] = { 10, 10, 10};
+ int dims = sizeof(sizes)/sizeof(sizes[0]);
+ SparseMat mat(dims, sizes, CV_32FC2);
+
+ if (mat.dims() != dims) throw test_excep();
+ if (mat.channels() != 2) throw test_excep();
+ if (mat.depth() != CV_32F) throw test_excep();
+
+ SparseMat mat2 = mat.clone();
+ }
+ catch (const test_excep&)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+bool CV_OperationsTest::operations1()
+{
+ try
+ {
+ Point3d p1(1, 1, 1), p2(2, 2, 2), p4(4, 4, 4);
+ p1*=2;
+ if (!(p1 == p2)) throw test_excep();
+ if (!(p2 * 2 == p4)) throw test_excep();
+ if (!(p2 * 2.f == p4)) throw test_excep();
+ if (!(p2 * 2.f == p4)) throw test_excep();
+
+ Point2d pi1(1, 1), pi2(2, 2), pi4(4, 4);
+ pi1*=2;
+ if (!(pi1 == pi2)) throw test_excep();
+ if (!(pi2 * 2 == pi4)) throw test_excep();
+ if (!(pi2 * 2.f == pi4)) throw test_excep();
+ if (!(pi2 * 2.f == pi4)) throw test_excep();
+
+ Vec2d v12(1, 1), v22(2, 2);
+ v12*=2.0;
+ if (!(v12 == v22)) throw test_excep();
+
+ Vec3d v13(1, 1, 1), v23(2, 2, 2);
+ v13*=2.0;
+ if (!(v13 == v23)) throw test_excep();
+
+ Vec4d v14(1, 1, 1, 1), v24(2, 2, 2, 2);
+ v14*=2.0;
+ if (!(v14 == v24)) throw test_excep();
+
+ Size sz(10, 20);
+ if (sz.area() != 200) throw test_excep();
+ if (sz.width != 10 || sz.height != 20) throw test_excep();
+ if (((CvSize)sz).width != 10 || ((CvSize)sz).height != 20) throw test_excep();
+
+ Vec<double, 5> v5d(1, 1, 1, 1, 1);
+ Vec<double, 6> v6d(1, 1, 1, 1, 1, 1);
+ Vec<double, 7> v7d(1, 1, 1, 1, 1, 1, 1);
+ Vec<double, 8> v8d(1, 1, 1, 1, 1, 1, 1, 1);
+ Vec<double, 9> v9d(1, 1, 1, 1, 1, 1, 1, 1, 1);
+ Vec<double,10> v10d(1, 1, 1, 1, 1, 1, 1, 1, 1, 1);
+
+ Vec<double,10> v10dzero;
+ for (int ii = 0; ii < 10; ++ii) {
+ if (!v10dzero[ii] == 0.0)
+ throw test_excep();
+ }
+ }
+ catch(const test_excep&)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+void CV_OperationsTest::run( int /* start_from */)
+{
+ if (!TestMat())
+ return;
+
+ if (!SomeMatFunctions())
+ return;
+
+ if (!TestTemplateMat())
+ return;
+
+ /* if (!TestMatND())
+ return;*/
+
+ if (!TestSparseMat())
+ return;
+
+ if (!operations1())
+ return;
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Core_Array, expressions) { CV_OperationsTest test; test.safe_run(); }
-#include "opencv2/gtest/gtestcv.hpp"
-#include "opencv2/core/core.hpp"
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/core/core_c.h"
+#include <iostream>
+
+#endif
--- /dev/null
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class Core_RandTest : public cvtest::BaseTest
+{
+public:
+ Core_RandTest();
+protected:
+ void run(int);
+ bool check_pdf(const Mat& hist, double scale, int dist_type,
+ double& refval, double& realval);
+};
+
+
+Core_RandTest::Core_RandTest()
+{
+}
+
+static double chi2_p95(int n)
+{
+ static float chi2_tab95[] = {
+ 3.841f, 5.991f, 7.815f, 9.488f, 11.07f, 12.59f, 14.07f, 15.51f,
+ 16.92f, 18.31f, 19.68f, 21.03f, 21.03f, 22.36f, 23.69f, 25.00f,
+ 26.30f, 27.59f, 28.87f, 30.14f, 31.41f, 32.67f, 33.92f, 35.17f,
+ 36.42f, 37.65f, 38.89f, 40.11f, 41.34f, 42.56f, 43.77f };
+ static const double xp = 1.64;
+ CV_Assert(n >= 1);
+
+ if( n <= 30 )
+ return chi2_tab95[n-1];
+ return n + sqrt((double)2*n)*xp + 0.6666666666666*(xp*xp - 1);
+}
+
+bool Core_RandTest::check_pdf(const Mat& hist, double scale,
+ int dist_type, double& refval, double& realval)
+{
+ Mat hist0(hist.size(), CV_32F);
+ const int* H = (const int*)hist.data;
+ float* H0 = ((float*)hist0.data);
+ int i, hsz = hist.cols;
+
+ double sum = 0;
+ for( i = 0; i < hsz; i++ )
+ sum += H[i];
+ CV_Assert( fabs(1./sum - scale) < FLT_EPSILON );
+
+ if( dist_type == CV_RAND_UNI )
+ {
+ float scale0 = (float)(1./hsz);
+ for( i = 0; i < hsz; i++ )
+ H0[i] = scale0;
+ }
+ else
+ {
+ double sum = 0, r = (hsz-1.)/2;
+ double alpha = 2*sqrt(2.)/r, beta = -alpha*r;
+ for( i = 0; i < hsz; i++ )
+ {
+ double x = i*alpha + beta;
+ H0[i] = (float)exp(-x*x);
+ sum += H0[i];
+ }
+ sum = 1./sum;
+ for( i = 0; i < hsz; i++ )
+ H0[i] = (float)(H0[i]*sum);
+ }
+
+ double chi2 = 0;
+ for( i = 0; i < hsz; i++ )
+ {
+ double a = H0[i];
+ double b = H[i]*scale;
+ if( a > DBL_EPSILON )
+ chi2 += (a - b)*(a - b)/(a + b);
+ }
+ realval = chi2;
+
+ double chi2_pval = chi2_p95(hsz - 1 - (dist_type == CV_RAND_NORMAL ? 2 : 0));
+ refval = chi2_pval*0.01;
+ return realval <= refval;
+}
+
+void Core_RandTest::run( int )
+{
+ static int _ranges[][2] =
+ {{ 0, 256 }, { -128, 128 }, { 0, 65536 }, { -32768, 32768 },
+ { -1000000, 1000000 }, { -1000, 1000 }, { -1000, 1000 }};
+
+ const int MAX_SDIM = 10;
+ const int N = 2000000;
+ const int maxSlice = 1000;
+ const int MAX_HIST_SIZE = 1000;
+ int progress = 0;
+
+ RNG& rng = ts->get_rng();
+ RNG tested_rng = theRNG();
+ test_case_count = 200;
+
+ for( int idx = 0; idx < test_case_count; idx++ )
+ {
+ progress = update_progress( progress, idx, test_case_count, 0 );
+ ts->update_context( this, idx, false );
+
+ int depth = cvtest::randInt(rng) % (CV_64F+1);
+ int c, cn = (cvtest::randInt(rng) % 4) + 1;
+ int type = CV_MAKETYPE(depth, cn);
+ int dist_type = cvtest::randInt(rng) % (CV_RAND_NORMAL+1);
+ int i, k, SZ = N/cn;
+ Scalar A, B;
+
+ bool do_sphere_test = dist_type == CV_RAND_UNI;
+ Mat arr[2], hist[4];
+ int W[] = {0,0,0,0};
+
+ arr[0].create(1, SZ, type);
+ arr[1].create(1, SZ, type);
+ bool fast_algo = dist_type == CV_RAND_UNI && depth < CV_32F;
+
+ for( c = 0; c < cn; c++ )
+ {
+ int a, b, hsz;
+ if( dist_type == CV_RAND_UNI )
+ {
+ a = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
+ _ranges[depth][0])) + _ranges[depth][0];
+ do
+ {
+ b = (int)(cvtest::randInt(rng) % (_ranges[depth][1] -
+ _ranges[depth][0])) + _ranges[depth][0];
+ }
+ while( abs(a-b) <= 1 );
+ if( a > b )
+ std::swap(a, b);
+
+ unsigned r = (unsigned)(b - a);
+ fast_algo = fast_algo && r <= 256 && (r & (r-1)) == 0;
+ hsz = min((unsigned)(b - a), (unsigned)MAX_HIST_SIZE);
+ do_sphere_test = do_sphere_test && b - a >= 100;
+ }
+ else
+ {
+ int vrange = _ranges[depth][1] - _ranges[depth][0];
+ int meanrange = vrange/16;
+ int mindiv = MAX(vrange/20, 5);
+ int maxdiv = MIN(vrange/8, 10000);
+
+ a = cvtest::randInt(rng) % meanrange - meanrange/2 +
+ (_ranges[depth][0] + _ranges[depth][1])/2;
+ b = cvtest::randInt(rng) % (maxdiv - mindiv) + mindiv;
+ hsz = min((unsigned)b*9, (unsigned)MAX_HIST_SIZE);
+ }
+ A[c] = a;
+ B[c] = b;
+ hist[c].create(1, hsz, CV_32S);
+ }
+
+ cv::RNG saved_rng = tested_rng;
+ int maxk = fast_algo ? 0 : 1;
+ for( k = 0; k <= maxk; k++ )
+ {
+ tested_rng = saved_rng;
+ int sz = 0, dsz = 0, slice;
+ for( slice = 0; slice < maxSlice; slice++, sz += dsz )
+ {
+ dsz = slice+1 < maxSlice ? cvtest::randInt(rng) % (SZ - sz + 1) : SZ - sz;
+ Mat aslice = arr[k].colRange(sz, sz + dsz);
+ tested_rng.fill(aslice, dist_type, A, B);
+ }
+ }
+
+ if( maxk >= 1 && norm(arr[0], arr[1], NORM_INF) != 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "RNG output depends on the array lengths (some generated numbers get lost?)" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ for( c = 0; c < cn; c++ )
+ {
+ const uchar* data = arr[0].data;
+ int* H = hist[c].ptr<int>();
+ int HSZ = hist[c].cols;
+ double minVal = dist_type == CV_RAND_UNI ? A[c] : A[c] - B[c]*4;
+ double maxVal = dist_type == CV_RAND_UNI ? B[c] : A[c] + B[c]*4;
+ double scale = HSZ/(maxVal - minVal);
+ double delta = -minVal*scale;
+
+ hist[c] = Scalar::all(0);
+
+ for( i = c; i < SZ*cn; i += cn )
+ {
+ double val = depth == CV_8U ? ((const uchar*)data)[i] :
+ depth == CV_8S ? ((const schar*)data)[i] :
+ depth == CV_16U ? ((const ushort*)data)[i] :
+ depth == CV_16S ? ((const short*)data)[i] :
+ depth == CV_32S ? ((const int*)data)[i] :
+ depth == CV_32F ? ((const float*)data)[i] :
+ ((const double*)data)[i];
+ int ival = cvFloor(val*scale + delta);
+ if( (unsigned)ival < (unsigned)HSZ )
+ {
+ H[ival]++;
+ W[c]++;
+ }
+ else if( dist_type == CV_RAND_UNI )
+ {
+ if( (minVal <= val && val < maxVal) || (depth >= CV_32F && val == maxVal) )
+ {
+ H[ival < 0 ? 0 : HSZ-1]++;
+ W[c]++;
+ }
+ else
+ {
+ putchar('^');
+ }
+ }
+ }
+
+ if( dist_type == CV_RAND_UNI && W[c] != SZ )
+ {
+ ts->printf( cvtest::TS::LOG, "Uniform RNG gave values out of the range [%g,%g) on channel %d/%d\n",
+ A[c], B[c], c, cn);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ if( dist_type == CV_RAND_NORMAL && W[c] < SZ*.90)
+ {
+ ts->printf( cvtest::TS::LOG, "Normal RNG gave too many values out of the range (%g+4*%g,%g+4*%g) on channel %d/%d\n",
+ A[c], B[c], A[c], B[c], c, cn);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ double refval = 0, realval = 0;
+
+ if( !check_pdf(hist[c], 1./W[c], dist_type, refval, realval) )
+ {
+ ts->printf( cvtest::TS::LOG, "RNG failed Chi-square test "
+ "(got %g vs probable maximum %g) on channel %d/%d\n",
+ realval, refval, c, cn);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ }
+
+ // Monte-Carlo test. Compute volume of SDIM-dimensional sphere
+ // inscribed in [-1,1]^SDIM cube.
+ if( do_sphere_test )
+ {
+ int SDIM = cvtest::randInt(rng) % (MAX_SDIM-1) + 2;
+ int N0 = (SZ*cn/SDIM), N = 0;
+ double r2 = 0;
+ const uchar* data = arr[0].data;
+ double scale[4], delta[4];
+ for( c = 0; c < cn; c++ )
+ {
+ scale[c] = 2./(B[c] - A[c]);
+ delta[c] = -A[c]*scale[c] - 1;
+ }
+
+ for( i = k = c = 0; i <= SZ*cn - SDIM; i++, k++, c++ )
+ {
+ double val = depth == CV_8U ? ((const uchar*)data)[i] :
+ depth == CV_8S ? ((const schar*)data)[i] :
+ depth == CV_16U ? ((const ushort*)data)[i] :
+ depth == CV_16S ? ((const short*)data)[i] :
+ depth == CV_32S ? ((const int*)data)[i] :
+ depth == CV_32F ? ((const float*)data)[i] : ((const double*)data)[i];
+ c &= c < cn ? -1 : 0;
+ val = val*scale[c] + delta[c];
+ r2 += val*val;
+ if( k == SDIM-1 )
+ {
+ N += r2 <= 1;
+ r2 = 0;
+ k = -1;
+ }
+ }
+
+ double V = ((double)N/N0)*(1 << SDIM);
+
+ // the theoretically computed volume
+ int sdim = SDIM % 2;
+ double V0 = sdim + 1;
+ for( sdim += 2; sdim <= SDIM; sdim += 2 )
+ V0 *= 2*CV_PI/sdim;
+
+ if( fabs(V - V0) > 0.3*fabs(V0) )
+ {
+ ts->printf( cvtest::TS::LOG, "RNG failed %d-dim sphere volume test (got %g instead of %g)\n",
+ SDIM, V, V0);
+ ts->printf( cvtest::TS::LOG, "depth = %d, N0 = %d\n", depth, N0);
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+ }
+ }
+}
+
+TEST(Core_Rand, quality) { Core_RandTest test; test.safe_run(); }
+
+
--- /dev/null
+#include "test_precomp.hpp"
+
+#if 0
+using namespace cv;
+
+class BruteForceMatcherTest : public cvtest::BaseTest
+{
+public:
+ BruteForceMatcherTest();
+protected:
+ void run( int );
+};
+
+struct CV_EXPORTS L2Fake : public L2<float>
+{
+};
+
+BruteForceMatcherTest::BruteForceMatcherTest() : cvtest::BaseTest( "BruteForceMatcher", "BruteForceMatcher::matchImpl")
+{
+ support_testing_modes = cvtest::TS::TIMING_MODE;
+}
+
+void BruteForceMatcherTest::run( int )
+{
+ const int dimensions = 64;
+ const int descriptorsNumber = 5000;
+
+ Mat train = Mat( descriptorsNumber, dimensions, CV_32FC1);
+ Mat query = Mat( descriptorsNumber, dimensions, CV_32FC1);
+
+ Mat permutation( 1, descriptorsNumber, CV_32SC1 );
+ for( int i=0;i<descriptorsNumber;i++ )
+ permutation.at<int>( 0, i ) = i;
+
+ //RNG rng = RNG( cvGetTickCount() );
+ RNG rng = RNG( *ts->get_rng() );
+ randShuffle( permutation, 1, &rng );
+
+ float boundary = 500.f;
+ for( int row=0;row<descriptorsNumber;row++ )
+ {
+ for( int col=0;col<dimensions;col++ )
+ {
+ int bit = rng( 2 );
+ train.at<float>( permutation.at<int>( 0, row ), col ) = bit*boundary + rng.uniform( 0.f, boundary );
+ query.at<float>( row, col ) = bit*boundary + rng.uniform( 0.f, boundary );
+ }
+ }
+
+ vector<DMatch> specMatches, genericMatches;
+ BruteForceMatcher<L2<float> > specMatcher;
+ BruteForceMatcher<L2Fake > genericMatcher;
+
+ int64 time0 = cvGetTickCount();
+ specMatcher.match( query, train, specMatches );
+ int64 time1 = cvGetTickCount();
+ genericMatcher.match( query, train, genericMatches );
+ int64 time2 = cvGetTickCount();
+
+ float specMatcherTime = float(time1 - time0)/(float)cvGetTickFrequency();
+ ts->printf( cvtest::TS::LOG, "Matching by matrix multiplication time s: %f, us per pair: %f\n",
+ specMatcherTime*1e-6, specMatcherTime/( descriptorsNumber*descriptorsNumber ) );
+
+ float genericMatcherTime = float(time2 - time1)/(float)cvGetTickFrequency();
+ ts->printf( cvtest::TS::LOG, "Matching without matrix multiplication time s: %f, us per pair: %f\n",
+ genericMatcherTime*1e-6, genericMatcherTime/( descriptorsNumber*descriptorsNumber ) );
+
+ if( (int)specMatches.size() != descriptorsNumber || (int)genericMatches.size() != descriptorsNumber )
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ for( int i=0;i<descriptorsNumber;i++ )
+ {
+ float epsilon = 0.01f;
+ bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon &&
+ specMatches[i].queryIdx == genericMatches[i].queryIdx &&
+ specMatches[i].trainIdx == genericMatches[i].trainIdx;
+ if( !isEquiv || specMatches[i].trainIdx != permutation.at<int>( 0, i ) )
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ break;
+ }
+ }
+
+
+ //Test mask
+ Mat mask( query.rows, train.rows, CV_8UC1 );
+ rng.fill( mask, RNG::UNIFORM, 0, 2 );
+
+
+ time0 = cvGetTickCount();
+ specMatcher.match( query, train, specMatches, mask );
+ time1 = cvGetTickCount();
+ genericMatcher.match( query, train, genericMatches, mask );
+ time2 = cvGetTickCount();
+
+ specMatcherTime = float(time1 - time0)/(float)cvGetTickFrequency();
+ ts->printf( cvtest::TS::LOG, "Matching by matrix multiplication time with mask s: %f, us per pair: %f\n",
+ specMatcherTime*1e-6, specMatcherTime/( descriptorsNumber*descriptorsNumber ) );
+
+ genericMatcherTime = float(time2 - time1)/(float)cvGetTickFrequency();
+ ts->printf( cvtest::TS::LOG, "Matching without matrix multiplication time with mask s: %f, us per pair: %f\n",
+ genericMatcherTime*1e-6, genericMatcherTime/( descriptorsNumber*descriptorsNumber ) );
+
+ if( specMatches.size() != genericMatches.size() )
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+
+ for( size_t i=0;i<specMatches.size();i++ )
+ {
+ //float epsilon = 1e-2;
+ float epsilon = 10000000;
+ bool isEquiv = fabs( specMatches[i].distance - genericMatches[i].distance ) < epsilon &&
+ specMatches[i].queryIdx == genericMatches[i].queryIdx &&
+ specMatches[i].trainIdx == genericMatches[i].trainIdx;
+ if( !isEquiv )
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ break;
+ }
+ }
+}
+
+BruteForceMatcherTest taBruteForceMatcherTest;
+#endif
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <limits>
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace cv;
+
+/****************************************************************************************\
+* Functions to evaluate affine covariant detectors and descriptors. *
+\****************************************************************************************/
+
+static inline Point2f applyHomography( const Mat_<double>& H, const Point2f& pt )
+{
+ double z = H(2,0)*pt.x + H(2,1)*pt.y + H(2,2);
+ if( z )
+ {
+ double w = 1./z;
+ return Point2f( (float)((H(0,0)*pt.x + H(0,1)*pt.y + H(0,2))*w),
+ (float)((H(1,0)*pt.x + H(1,1)*pt.y + H(1,2))*w) );
+ }
+ return Point2f( numeric_limits<float>::max(), numeric_limits<float>::max() );
+}
+
+static inline void linearizeHomographyAt( const Mat_<double>& H, const Point2f& pt, Mat_<double>& A )
+{
+ A.create(2,2);
+ double p1 = H(0,0)*pt.x + H(0,1)*pt.y + H(0,2),
+ p2 = H(1,0)*pt.x + H(1,1)*pt.y + H(1,2),
+ p3 = H(2,0)*pt.x + H(2,1)*pt.y + H(2,2),
+ p3_2 = p3*p3;
+ if( p3 )
+ {
+ A(0,0) = H(0,0)/p3 - p1*H(2,0)/p3_2; // fxdx
+ A(0,1) = H(0,1)/p3 - p1*H(2,1)/p3_2; // fxdy
+
+ A(1,0) = H(1,0)/p3 - p2*H(2,0)/p3_2; // fydx
+ A(1,1) = H(1,1)/p3 - p2*H(2,1)/p3_2; // fydx
+ }
+ else
+ A.setTo(Scalar::all(numeric_limits<double>::max()));
+}
+
+static void calcKeyPointProjections( const vector<KeyPoint>& src, const Mat_<double>& H, vector<KeyPoint>& dst )
+{
+ if( !src.empty() )
+ {
+ assert( !H.empty() && H.cols == 3 && H.rows == 3);
+ dst.resize(src.size());
+ vector<KeyPoint>::const_iterator srcIt = src.begin();
+ vector<KeyPoint>::iterator dstIt = dst.begin();
+ for( ; srcIt != src.end(); ++srcIt, ++dstIt )
+ {
+ Point2f dstPt = applyHomography(H, srcIt->pt);
+
+ float srcSize2 = srcIt->size * srcIt->size;
+ Mat_<double> M(2, 2);
+ M(0,0) = M(1,1) = 1./srcSize2;
+ M(1,0) = M(0,1) = 0;
+ Mat_<double> invM; invert(M, invM);
+ Mat_<double> Aff; linearizeHomographyAt(H, srcIt->pt, Aff);
+ Mat_<double> dstM; invert(Aff*invM*Aff.t(), dstM);
+ Mat_<double> eval; eigen( dstM, eval );
+ assert( eval(0,0) && eval(1,0) );
+ float dstSize = (float)pow(1./(eval(0,0)*eval(1,0)), 0.25);
+
+ // TODO: check angle projection
+ float srcAngleRad = (float)(srcIt->angle*CV_PI/180);
+ Point2f vec1(cos(srcAngleRad), sin(srcAngleRad)), vec2;
+ vec2.x = (float)(Aff(0,0)*vec1.x + Aff(0,1)*vec1.y);
+ vec2.y = (float)(Aff(1,0)*vec1.x + Aff(0,1)*vec1.y);
+ float dstAngleGrad = fastAtan2(vec2.y, vec2.x);
+
+ *dstIt = KeyPoint( dstPt, dstSize, dstAngleGrad, srcIt->response, srcIt->octave, srcIt->class_id );
+ }
+ }
+}
+
+static void filterKeyPointsByImageSize( vector<KeyPoint>& keypoints, const Size& imgSize )
+{
+ if( !keypoints.empty() )
+ {
+ vector<KeyPoint> filtered;
+ filtered.reserve(keypoints.size());
+ Rect r(0, 0, imgSize.width, imgSize.height);
+ vector<KeyPoint>::const_iterator it = keypoints.begin();
+ for( int i = 0; it != keypoints.end(); ++it, i++ )
+ if( r.contains(it->pt) )
+ filtered.push_back(*it);
+ keypoints.assign(filtered.begin(), filtered.end());
+ }
+}
+
+/****************************************************************************************\
+* Detectors evaluation *
+\****************************************************************************************/
+const int DATASETS_COUNT = 8;
+const int TEST_CASE_COUNT = 5;
+
+const string IMAGE_DATASETS_DIR = "detectors_descriptors_evaluation/images_datasets/";
+const string DETECTORS_DIR = "detectors_descriptors_evaluation/detectors/";
+const string DESCRIPTORS_DIR = "detectors_descriptors_evaluation/descriptors/";
+const string KEYPOINTS_DIR = "detectors_descriptors_evaluation/keypoints_datasets/";
+
+const string PARAMS_POSTFIX = "_params.xml";
+const string RES_POSTFIX = "_res.xml";
+
+const string REPEAT = "repeatability";
+const string CORRESP_COUNT = "correspondence_count";
+
+string DATASET_NAMES[DATASETS_COUNT] = { "bark", "bikes", "boat", "graf", "leuven", "trees", "ubc", "wall"};
+
+string DEFAULT_PARAMS = "default";
+
+string IS_ACTIVE_PARAMS = "isActiveParams";
+string IS_SAVE_KEYPOINTS = "isSaveKeypoints";
+
+
+class BaseQualityTest : public cvtest::BaseTest
+{
+public:
+ BaseQualityTest( const char* _algName ) : algName(_algName)
+ {
+ //TODO: change this
+ isWriteGraphicsData = true;
+ }
+
+protected:
+ virtual string getRunParamsFilename() const = 0;
+ virtual string getResultsFilename() const = 0;
+ virtual string getPlotPath() const = 0;
+
+ virtual void validQualityClear( int datasetIdx ) = 0;
+ virtual void calcQualityClear( int datasetIdx ) = 0;
+ virtual void validQualityCreate( int datasetIdx ) = 0;
+ virtual bool isValidQualityEmpty( int datasetIdx ) const = 0;
+ virtual bool isCalcQualityEmpty( int datasetIdx ) const = 0;
+
+ void readAllDatasetsRunParams();
+ virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ) = 0;
+ void writeAllDatasetsRunParams() const;
+ virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const = 0;
+ void setDefaultAllDatasetsRunParams();
+ virtual void setDefaultDatasetRunParams( int datasetIdx ) = 0;
+ virtual void readDefaultRunParams( FileNode& /*fn*/ ) {}
+ virtual void writeDefaultRunParams( FileStorage& /*fs*/ ) const {}
+
+ virtual void readResults();
+ virtual void readResults( FileNode& fn, int datasetIdx, int caseIdx ) = 0;
+ void writeResults() const;
+ virtual void writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const = 0;
+
+ bool readDataset( const string& datasetName, vector<Mat>& Hs, vector<Mat>& imgs );
+
+ virtual void readAlgorithm( ) {};
+ virtual void processRunParamsFile () {};
+ virtual void runDatasetTest( const vector<Mat>& /*imgs*/, const vector<Mat>& /*Hs*/, int /*di*/, int& /*progress*/ ) {}
+ void run( int );
+
+ virtual void processResults( int datasetIdx );
+ virtual int processResults( int datasetIdx, int caseIdx ) = 0;
+ virtual void processResults();
+ virtual void writePlotData( int /*datasetIdx*/ ) const {}
+ virtual void writeAveragePlotData() const {};
+
+ string algName;
+ bool isWriteParams, isWriteResults, isWriteGraphicsData;
+};
+
+void BaseQualityTest::readAllDatasetsRunParams()
+{
+ string filename = getRunParamsFilename();
+ FileStorage fs( filename, FileStorage::READ );
+ if( !fs.isOpened() )
+ {
+ isWriteParams = true;
+ setDefaultAllDatasetsRunParams();
+ ts->printf(cvtest::TS::LOG, "all runParams are default\n");
+ }
+ else
+ {
+ isWriteParams = false;
+ FileNode topfn = fs.getFirstTopLevelNode();
+
+ FileNode fn = topfn[DEFAULT_PARAMS];
+ readDefaultRunParams(fn);
+
+ for( int i = 0; i < DATASETS_COUNT; i++ )
+ {
+ FileNode fn = topfn[DATASET_NAMES[i]];
+ if( fn.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "%d-runParams is default\n", i);
+ setDefaultDatasetRunParams(i);
+ }
+ else
+ readDatasetRunParams(fn, i);
+ }
+ }
+}
+
+void BaseQualityTest::writeAllDatasetsRunParams() const
+{
+ string filename = getRunParamsFilename();
+ FileStorage fs( filename, FileStorage::WRITE );
+ if( fs.isOpened() )
+ {
+ fs << "run_params" << "{"; // top file node
+ fs << DEFAULT_PARAMS << "{";
+ writeDefaultRunParams(fs);
+ fs << "}";
+ for( int i = 0; i < DATASETS_COUNT; i++ )
+ {
+ fs << DATASET_NAMES[i] << "{";
+ writeDatasetRunParams(fs, i);
+ fs << "}";
+ }
+ fs << "}";
+ }
+ else
+ ts->printf(cvtest::TS::LOG, "file %s for writing run params can not be opened\n", filename.c_str() );
+}
+
+void BaseQualityTest::setDefaultAllDatasetsRunParams()
+{
+ for( int i = 0; i < DATASETS_COUNT; i++ )
+ setDefaultDatasetRunParams(i);
+}
+
+bool BaseQualityTest::readDataset( const string& datasetName, vector<Mat>& Hs, vector<Mat>& imgs )
+{
+ Hs.resize( TEST_CASE_COUNT );
+ imgs.resize( TEST_CASE_COUNT+1 );
+ string dirname = string(ts->get_data_path()) + IMAGE_DATASETS_DIR + datasetName + "/";
+
+ for( int i = 0; i < (int)Hs.size(); i++ )
+ {
+ stringstream filename; filename << "H1to" << i+2 << "p.xml";
+ FileStorage fs( dirname + filename.str(), FileStorage::READ );
+ if( !fs.isOpened() )
+ return false;
+ fs.getFirstTopLevelNode() >> Hs[i];
+ }
+
+ for( int i = 0; i < (int)imgs.size(); i++ )
+ {
+ stringstream filename; filename << "img" << i+1 << ".png";
+ imgs[i] = imread( dirname + filename.str(), 0 );
+ if( imgs[i].empty() )
+ return false;
+ }
+ return true;
+}
+
+void BaseQualityTest::readResults()
+{
+ string filename = getResultsFilename();
+ FileStorage fs( filename, FileStorage::READ );
+ if( fs.isOpened() )
+ {
+ isWriteResults = false;
+ FileNode topfn = fs.getFirstTopLevelNode();
+ for( int di = 0; di < DATASETS_COUNT; di++ )
+ {
+ FileNode datafn = topfn[DATASET_NAMES[di]];
+ if( datafn.empty() )
+ {
+ validQualityClear(di);
+ ts->printf( cvtest::TS::LOG, "results for %s dataset were not read\n",
+ DATASET_NAMES[di].c_str() );
+ }
+ else
+ {
+ validQualityCreate(di);
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ stringstream ss; ss << "case" << ci;
+ FileNode casefn = datafn[ss.str()];
+ CV_Assert( !casefn.empty() );
+ readResults( casefn , di, ci );
+ }
+ }
+ }
+ }
+ else
+ isWriteResults = true;
+}
+
+void BaseQualityTest::writeResults() const
+{
+ string filename = getResultsFilename();;
+ FileStorage fs( filename, FileStorage::WRITE );
+ if( fs.isOpened() )
+ {
+ fs << "results" << "{";
+ for( int di = 0; di < DATASETS_COUNT; di++ )
+ {
+ if( isCalcQualityEmpty(di) )
+ {
+ ts->printf(cvtest::TS::LOG, "results on %s dataset were not write because of empty\n",
+ DATASET_NAMES[di].c_str());
+ }
+ else
+ {
+ fs << DATASET_NAMES[di] << "{";
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ stringstream ss; ss << "case" << ci;
+ fs << ss.str() << "{";
+ writeResults( fs, di, ci );
+ fs << "}"; //ss.str()
+ }
+ fs << "}"; //DATASET_NAMES[di]
+ }
+ }
+ fs << "}"; //results
+ }
+ else
+ ts->printf(cvtest::TS::LOG, "results were not written because file %s can not be opened\n", filename.c_str() );
+}
+
+void BaseQualityTest::processResults( int datasetIdx )
+{
+ if( isWriteGraphicsData )
+ writePlotData( datasetIdx );
+}
+
+void BaseQualityTest::processResults()
+{
+ if( isWriteParams )
+ writeAllDatasetsRunParams();
+
+ if( isWriteGraphicsData )
+ writeAveragePlotData();
+
+ int res = cvtest::TS::OK;
+ if( isWriteResults )
+ writeResults();
+ else
+ {
+ for( int di = 0; di < DATASETS_COUNT; di++ )
+ {
+ if( isValidQualityEmpty(di) || isCalcQualityEmpty(di) )
+ continue;
+
+ ts->printf(cvtest::TS::LOG, "\nDataset: %s\n", DATASET_NAMES[di].c_str() );
+
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ ts->printf(cvtest::TS::LOG, "case%d\n", ci);
+ int currRes = processResults( di, ci );
+ res = currRes == cvtest::TS::OK ? res : currRes;
+ }
+ }
+ }
+
+ if( res != cvtest::TS::OK )
+ ts->printf(cvtest::TS::LOG, "BAD ACCURACY\n");
+ ts->set_failed_test_info( res );
+}
+
+void BaseQualityTest::run ( int )
+{
+ readAlgorithm ();
+ processRunParamsFile ();
+ readResults();
+
+ int notReadDatasets = 0;
+ int progress = 0;
+
+ FileStorage runParamsFS( getRunParamsFilename(), FileStorage::READ );
+ isWriteParams = (! runParamsFS.isOpened());
+ FileNode topfn = runParamsFS.getFirstTopLevelNode();
+ FileNode defaultParams = topfn[DEFAULT_PARAMS];
+ readDefaultRunParams (defaultParams);
+
+ for(int di = 0; di < DATASETS_COUNT; di++ )
+ {
+ vector<Mat> imgs, Hs;
+ if( !readDataset( DATASET_NAMES[di], Hs, imgs ) )
+ {
+ calcQualityClear (di);
+ ts->printf( cvtest::TS::LOG, "images or homography matrices of dataset named %s can not be read\n",
+ DATASET_NAMES[di].c_str());
+ notReadDatasets++;
+ continue;
+ }
+
+ FileNode fn = topfn[DATASET_NAMES[di]];
+ readDatasetRunParams(fn, di);
+
+ runDatasetTest (imgs, Hs, di, progress);
+ processResults( di );
+ }
+ if( notReadDatasets == DATASETS_COUNT )
+ {
+ ts->printf(cvtest::TS::LOG, "All datasets were not be read\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ }
+ else
+ processResults();
+ runParamsFS.release();
+}
+
+
+
+class DetectorQualityTest : public BaseQualityTest
+{
+public:
+ DetectorQualityTest( const char* _detectorName ) :
+ BaseQualityTest( _detectorName )
+ {
+ validQuality.resize(DATASETS_COUNT);
+ calcQuality.resize(DATASETS_COUNT);
+ isSaveKeypoints.resize(DATASETS_COUNT);
+ isActiveParams.resize(DATASETS_COUNT);
+
+ isSaveKeypointsDefault = false;
+ isActiveParamsDefault = false;
+ }
+
+protected:
+ using BaseQualityTest::readResults;
+ using BaseQualityTest::writeResults;
+ using BaseQualityTest::processResults;
+
+ virtual string getRunParamsFilename() const;
+ virtual string getResultsFilename() const;
+ virtual string getPlotPath() const;
+
+ virtual void validQualityClear( int datasetIdx );
+ virtual void calcQualityClear( int datasetIdx );
+ virtual void validQualityCreate( int datasetIdx );
+ virtual bool isValidQualityEmpty( int datasetIdx ) const;
+ virtual bool isCalcQualityEmpty( int datasetIdx ) const;
+
+ virtual void readResults( FileNode& fn, int datasetIdx, int caseIdx );
+ virtual void writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const;
+
+ virtual void readDatasetRunParams( FileNode& fn, int datasetIdx );
+ virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
+ virtual void setDefaultDatasetRunParams( int datasetIdx );
+ virtual void readDefaultRunParams( FileNode &fn );
+ virtual void writeDefaultRunParams( FileStorage &fs ) const;
+
+ virtual void writePlotData( int di ) const;
+ virtual void writeAveragePlotData() const;
+
+ void openToWriteKeypointsFile( FileStorage& fs, int datasetIdx );
+
+ virtual void readAlgorithm( );
+ virtual void processRunParamsFile () {};
+ virtual void runDatasetTest( const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress );
+ virtual int processResults( int datasetIdx, int caseIdx );
+
+ Ptr<FeatureDetector> specificDetector;
+ Ptr<FeatureDetector> defaultDetector;
+
+ struct Quality
+ {
+ float repeatability;
+ int correspondenceCount;
+ };
+ vector<vector<Quality> > validQuality;
+ vector<vector<Quality> > calcQuality;
+
+ vector<bool> isSaveKeypoints;
+ vector<bool> isActiveParams;
+
+ bool isSaveKeypointsDefault;
+ bool isActiveParamsDefault;
+};
+
+string DetectorQualityTest::getRunParamsFilename() const
+{
+ return string(ts->get_data_path()) + DETECTORS_DIR + algName + PARAMS_POSTFIX;
+}
+
+string DetectorQualityTest::getResultsFilename() const
+{
+ return string(ts->get_data_path()) + DETECTORS_DIR + algName + RES_POSTFIX;
+}
+
+string DetectorQualityTest::getPlotPath() const
+{
+ return string(ts->get_data_path()) + DETECTORS_DIR + "plots/";
+}
+
+void DetectorQualityTest::validQualityClear( int datasetIdx )
+{
+ validQuality[datasetIdx].clear();
+}
+
+void DetectorQualityTest::calcQualityClear( int datasetIdx )
+{
+ calcQuality[datasetIdx].clear();
+}
+
+void DetectorQualityTest::validQualityCreate( int datasetIdx )
+{
+ validQuality[datasetIdx].resize(TEST_CASE_COUNT);
+}
+
+bool DetectorQualityTest::isValidQualityEmpty( int datasetIdx ) const
+{
+ return validQuality[datasetIdx].empty();
+}
+
+bool DetectorQualityTest::isCalcQualityEmpty( int datasetIdx ) const
+{
+ return calcQuality[datasetIdx].empty();
+}
+
+void DetectorQualityTest::readResults( FileNode& fn, int datasetIdx, int caseIdx )
+{
+ validQuality[datasetIdx][caseIdx].repeatability = fn[REPEAT];
+ validQuality[datasetIdx][caseIdx].correspondenceCount = fn[CORRESP_COUNT];
+}
+
+void DetectorQualityTest::writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const
+{
+ fs << REPEAT << calcQuality[datasetIdx][caseIdx].repeatability;
+ fs << CORRESP_COUNT << calcQuality[datasetIdx][caseIdx].correspondenceCount;
+}
+
+void DetectorQualityTest::readDefaultRunParams (FileNode &fn)
+{
+ if (! fn.empty() )
+ {
+ isSaveKeypointsDefault = (int)fn[IS_SAVE_KEYPOINTS] != 0;
+ defaultDetector->read (fn);
+ }
+}
+
+void DetectorQualityTest::writeDefaultRunParams (FileStorage &fs) const
+{
+ fs << IS_SAVE_KEYPOINTS << isSaveKeypointsDefault;
+ defaultDetector->write (fs);
+}
+
+void DetectorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx )
+{
+ isActiveParams[datasetIdx] = (int)fn[IS_ACTIVE_PARAMS] != 0;
+ if (isActiveParams[datasetIdx])
+ {
+ isSaveKeypoints[datasetIdx] = (int)fn[IS_SAVE_KEYPOINTS] != 0;
+ specificDetector->read (fn);
+ }
+ else
+ {
+ setDefaultDatasetRunParams(datasetIdx);
+ }
+}
+
+void DetectorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
+{
+ fs << IS_ACTIVE_PARAMS << isActiveParams[datasetIdx];
+ fs << IS_SAVE_KEYPOINTS << isSaveKeypoints[datasetIdx];
+ defaultDetector->write (fs);
+}
+
+void DetectorQualityTest::setDefaultDatasetRunParams( int datasetIdx )
+{
+ isSaveKeypoints[datasetIdx] = isSaveKeypointsDefault;
+ isActiveParams[datasetIdx] = isActiveParamsDefault;
+}
+
+void DetectorQualityTest::writePlotData(int di ) const
+{
+ int imgXVals[] = { 2, 3, 4, 5, 6 }; // if scale, blur or light changes
+ int viewpointXVals[] = { 20, 30, 40, 50, 60 }; // if viewpoint changes
+ int jpegXVals[] = { 60, 80, 90, 95, 98 }; // if jpeg compression
+
+ int* xVals = 0;
+ if( !DATASET_NAMES[di].compare("ubc") )
+ {
+ xVals = jpegXVals;
+ }
+ else if( !DATASET_NAMES[di].compare("graf") || !DATASET_NAMES[di].compare("wall") )
+ {
+ xVals = viewpointXVals;
+ }
+ else
+ xVals = imgXVals;
+
+ stringstream rFilename, cFilename;
+ rFilename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << "_repeatability.csv";
+ cFilename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << "_correspondenceCount.csv";
+ ofstream rfile(rFilename.str().c_str()), cfile(cFilename.str().c_str());
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ rfile << xVals[ci] << ", " << calcQuality[di][ci].repeatability << endl;
+ cfile << xVals[ci] << ", " << calcQuality[di][ci].correspondenceCount << endl;
+ }
+}
+
+void DetectorQualityTest::writeAveragePlotData() const
+{
+ stringstream rFilename, cFilename;
+ rFilename << getPlotPath() << algName << "_average_repeatability.csv";
+ cFilename << getPlotPath() << algName << "_average_correspondenceCount.csv";
+ ofstream rfile(rFilename.str().c_str()), cfile(cFilename.str().c_str());
+ float avRep = 0, avCorCount = 0;
+ for( int di = 0; di < DATASETS_COUNT; di++ )
+ {
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ avRep += calcQuality[di][ci].repeatability;
+ avCorCount += calcQuality[di][ci].correspondenceCount;
+ }
+ }
+ avRep /= DATASETS_COUNT*TEST_CASE_COUNT;
+ avCorCount /= DATASETS_COUNT*TEST_CASE_COUNT;
+ rfile << algName << ", " << avRep << endl;
+ cfile << algName << ", " << cvRound(avCorCount) << endl;
+}
+
+void DetectorQualityTest::openToWriteKeypointsFile( FileStorage& fs, int datasetIdx )
+{
+ string filename = string(ts->get_data_path()) + KEYPOINTS_DIR + algName + "_"+
+ DATASET_NAMES[datasetIdx] + ".xml.gz" ;
+
+ fs.open(filename, FileStorage::WRITE);
+ if( !fs.isOpened() )
+ ts->printf( cvtest::TS::LOG, "keypoints can not be written in file %s because this file can not be opened\n",
+ filename.c_str());
+}
+
+inline void writeKeypoints( FileStorage& fs, const vector<KeyPoint>& keypoints, int imgIdx )
+{
+ if( fs.isOpened() )
+ {
+ stringstream imgName; imgName << "img" << imgIdx;
+ write( fs, imgName.str(), keypoints );
+ }
+}
+
+inline void readKeypoints( FileStorage& fs, vector<KeyPoint>& keypoints, int imgIdx )
+{
+ assert( fs.isOpened() );
+ stringstream imgName; imgName << "img" << imgIdx;
+ read( fs[imgName.str()], keypoints);
+}
+
+void DetectorQualityTest::readAlgorithm ()
+{
+ defaultDetector = FeatureDetector::create( algName );
+ specificDetector = FeatureDetector::create( algName );
+ if( defaultDetector == 0 )
+ {
+ ts->printf(cvtest::TS::LOG, "Algorithm can not be read\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_GENERIC);
+ }
+}
+
+void DetectorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress)
+{
+ Ptr<FeatureDetector> detector = isActiveParams[di] ? specificDetector : defaultDetector;
+ FileStorage keypontsFS;
+ if( isSaveKeypoints[di] )
+ openToWriteKeypointsFile( keypontsFS, di );
+
+ calcQuality[di].resize(TEST_CASE_COUNT);
+
+ vector<KeyPoint> keypoints1;
+ detector->detect( imgs[0], keypoints1 );
+ writeKeypoints( keypontsFS, keypoints1, 0);
+ int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 );
+ vector<KeyPoint> keypoints2;
+ float rep;
+ evaluateFeatureDetector( imgs[0], imgs[ci+1], Hs[ci], &keypoints1, &keypoints2,
+ rep, calcQuality[di][ci].correspondenceCount,
+ detector );
+ calcQuality[di][ci].repeatability = rep == -1 ? rep : 100.f*rep;
+ writeKeypoints( keypontsFS, keypoints2, ci+1);
+ }
+}
+
+void testLog( cvtest::TS* ts, bool isBadAccuracy )
+{
+ if( isBadAccuracy )
+ ts->printf(cvtest::TS::LOG, " bad accuracy\n");
+ else
+ ts->printf(cvtest::TS::LOG, "\n");
+}
+
+int DetectorQualityTest::processResults( int datasetIdx, int caseIdx )
+{
+ int res = cvtest::TS::OK;
+ bool isBadAccuracy;
+
+ Quality valid = validQuality[datasetIdx][caseIdx], calc = calcQuality[datasetIdx][caseIdx];
+
+ const int countEps = 1 + cvRound( 0.005f*(float)valid.correspondenceCount );
+ const float rltvEps = 0.5f;
+
+ ts->printf(cvtest::TS::LOG, "%s: calc=%f, valid=%f", REPEAT.c_str(), calc.repeatability, valid.repeatability );
+ isBadAccuracy = (valid.repeatability - calc.repeatability) > rltvEps;
+ testLog( ts, isBadAccuracy );
+ res = isBadAccuracy ? cvtest::TS::FAIL_BAD_ACCURACY : res;
+
+ ts->printf(cvtest::TS::LOG, "%s: calc=%d, valid=%d", CORRESP_COUNT.c_str(), calc.correspondenceCount, valid.correspondenceCount );
+ isBadAccuracy = (valid.correspondenceCount - calc.correspondenceCount) > countEps;
+ testLog( ts, isBadAccuracy );
+ res = isBadAccuracy ? cvtest::TS::FAIL_BAD_ACCURACY : res;
+ return res;
+}
+
+/****************************************************************************************\
+* Descriptors evaluation *
+\****************************************************************************************/
+
+const string RECALL = "recall";
+const string PRECISION = "precision";
+
+const string KEYPOINTS_FILENAME = "keypointsFilename";
+const string PROJECT_KEYPOINTS_FROM_1IMAGE = "projectKeypointsFrom1Image";
+const string MATCH_FILTER = "matchFilter";
+const string RUN_PARAMS_IS_IDENTICAL = "runParamsIsIdentical";
+
+const string ONE_WAY_TRAIN_DIR = "detectors_descriptors_evaluation/one_way_train_images/";
+const string ONE_WAY_IMAGES_LIST = "one_way_train_images.txt";
+
+class DescriptorQualityTest : public BaseQualityTest
+{
+public:
+ enum{ NO_MATCH_FILTER = 0 };
+ DescriptorQualityTest( const char* _descriptorName, const char* _matcherName = 0 ) :
+ BaseQualityTest( _descriptorName )
+ {
+ validQuality.resize(DATASETS_COUNT);
+ calcQuality.resize(DATASETS_COUNT);
+ calcDatasetQuality.resize(DATASETS_COUNT);
+ commRunParams.resize(DATASETS_COUNT);
+
+ commRunParamsDefault.projectKeypointsFrom1Image = true;
+ commRunParamsDefault.matchFilter = NO_MATCH_FILTER;
+ commRunParamsDefault.isActiveParams = false;
+
+ if( _matcherName )
+ matcherName = _matcherName;
+ }
+
+protected:
+ using BaseQualityTest::readResults;
+ using BaseQualityTest::writeResults;
+ using BaseQualityTest::processResults;
+
+ virtual string getRunParamsFilename() const;
+ virtual string getResultsFilename() const;
+ virtual string getPlotPath() const;
+
+ virtual void validQualityClear( int datasetIdx );
+ virtual void calcQualityClear( int datasetIdx );
+ virtual void validQualityCreate( int datasetIdx );
+ virtual bool isValidQualityEmpty( int datasetIdx ) const;
+ virtual bool isCalcQualityEmpty( int datasetIdx ) const;
+
+ virtual void readResults( FileNode& fn, int datasetIdx, int caseIdx );
+ virtual void writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const;
+
+ virtual void readDatasetRunParams( FileNode& fn, int datasetIdx ); //
+ virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
+ virtual void setDefaultDatasetRunParams( int datasetIdx );
+ virtual void readDefaultRunParams( FileNode &fn );
+ virtual void writeDefaultRunParams( FileStorage &fs ) const;
+
+ virtual void readAlgorithm( );
+ virtual void processRunParamsFile () {};
+ virtual void runDatasetTest( const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress );
+
+ virtual int processResults( int datasetIdx, int caseIdx );
+
+ virtual void writePlotData( int di ) const;
+ void calculatePlotData( vector<vector<DMatch> > &allMatches, vector<vector<uchar> > &allCorrectMatchesMask, int di );
+
+ struct Quality
+ {
+ float recall;
+ float precision;
+ };
+ vector<vector<Quality> > validQuality;
+ vector<vector<Quality> > calcQuality;
+ vector<vector<Quality> > calcDatasetQuality;
+
+ struct CommonRunParams
+ {
+ string keypontsFilename;
+ bool projectKeypointsFrom1Image;
+ int matchFilter; // not used now
+ bool isActiveParams;
+ };
+ vector<CommonRunParams> commRunParams;
+
+ Ptr<GenericDescriptorMatch> specificDescMatcher;
+ Ptr<GenericDescriptorMatch> defaultDescMatcher;
+
+ CommonRunParams commRunParamsDefault;
+ string matcherName;
+};
+
+string DescriptorQualityTest::getRunParamsFilename() const
+{
+ return string(ts->get_data_path()) + DESCRIPTORS_DIR + algName + PARAMS_POSTFIX;
+}
+
+string DescriptorQualityTest::getResultsFilename() const
+{
+ return string(ts->get_data_path()) + DESCRIPTORS_DIR + algName + RES_POSTFIX;
+}
+
+string DescriptorQualityTest::getPlotPath() const
+{
+ return string(ts->get_data_path()) + DESCRIPTORS_DIR + "plots/";
+}
+
+void DescriptorQualityTest::validQualityClear( int datasetIdx )
+{
+ validQuality[datasetIdx].clear();
+}
+
+void DescriptorQualityTest::calcQualityClear( int datasetIdx )
+{
+ calcQuality[datasetIdx].clear();
+}
+
+void DescriptorQualityTest::validQualityCreate( int datasetIdx )
+{
+ validQuality[datasetIdx].resize(TEST_CASE_COUNT);
+}
+
+bool DescriptorQualityTest::isValidQualityEmpty( int datasetIdx ) const
+{
+ return validQuality[datasetIdx].empty();
+}
+
+bool DescriptorQualityTest::isCalcQualityEmpty( int datasetIdx ) const
+{
+ return calcQuality[datasetIdx].empty();
+}
+
+void DescriptorQualityTest::readResults( FileNode& fn, int datasetIdx, int caseIdx )
+{
+ validQuality[datasetIdx][caseIdx].recall = fn[RECALL];
+ validQuality[datasetIdx][caseIdx].precision = fn[PRECISION];
+}
+
+void DescriptorQualityTest::writeResults( FileStorage& fs, int datasetIdx, int caseIdx ) const
+{
+ fs << RECALL << calcQuality[datasetIdx][caseIdx].recall;
+ fs << PRECISION << calcQuality[datasetIdx][caseIdx].precision;
+}
+
+void DescriptorQualityTest::readDefaultRunParams (FileNode &fn)
+{
+ if (! fn.empty() )
+ {
+ commRunParamsDefault.projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
+ commRunParamsDefault.matchFilter = (int)fn[MATCH_FILTER];
+ defaultDescMatcher->read (fn);
+ }
+}
+
+void DescriptorQualityTest::writeDefaultRunParams (FileStorage &fs) const
+{
+ fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParamsDefault.projectKeypointsFrom1Image;
+ fs << MATCH_FILTER << commRunParamsDefault.matchFilter;
+ defaultDescMatcher->write (fs);
+}
+
+void DescriptorQualityTest::readDatasetRunParams( FileNode& fn, int datasetIdx )
+{
+ commRunParams[datasetIdx].isActiveParams = (int)fn[IS_ACTIVE_PARAMS] != 0;
+ if (commRunParams[datasetIdx].isActiveParams)
+ {
+ commRunParams[datasetIdx].keypontsFilename = (string)fn[KEYPOINTS_FILENAME];
+ commRunParams[datasetIdx].projectKeypointsFrom1Image = (int)fn[PROJECT_KEYPOINTS_FROM_1IMAGE] != 0;
+ commRunParams[datasetIdx].matchFilter = (int)fn[MATCH_FILTER];
+ specificDescMatcher->read (fn);
+ }
+ else
+ {
+ setDefaultDatasetRunParams(datasetIdx);
+ }
+}
+
+void DescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
+{
+ fs << IS_ACTIVE_PARAMS << commRunParams[datasetIdx].isActiveParams;
+ fs << KEYPOINTS_FILENAME << commRunParams[datasetIdx].keypontsFilename;
+ fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParams[datasetIdx].projectKeypointsFrom1Image;
+ fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
+
+ defaultDescMatcher->write (fs);
+}
+
+void DescriptorQualityTest::setDefaultDatasetRunParams( int datasetIdx )
+{
+ commRunParams[datasetIdx] = commRunParamsDefault;
+ commRunParams[datasetIdx].keypontsFilename = "SURF_" + DATASET_NAMES[datasetIdx] + ".xml.gz";
+}
+
+void DescriptorQualityTest::writePlotData( int di ) const
+{
+ stringstream filename;
+ filename << getPlotPath() << algName << "_" << DATASET_NAMES[di] << ".csv";
+ FILE *file = fopen (filename.str().c_str(), "w");
+ size_t size = calcDatasetQuality[di].size();
+ for (size_t i=0;i<size;i++)
+ {
+ fprintf( file, "%f, %f\n", 1 - calcDatasetQuality[di][i].precision, calcDatasetQuality[di][i].recall);
+ }
+ fclose( file );
+}
+
+void DescriptorQualityTest::readAlgorithm( )
+{
+ defaultDescMatcher = GenericDescriptorMatcher::create( algName );
+ specificDescMatcher = GenericDescriptorMatcher::create( algName );
+
+ if( defaultDescMatcher == 0 )
+ {
+ Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create( algName );
+ Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create( matcherName );
+ defaultDescMatcher = new VectorDescriptorMatch( extractor, matcher );
+ specificDescMatcher = new VectorDescriptorMatch( extractor, matcher );
+
+ if( extractor == 0 || matcher == 0 )
+ {
+ ts->printf(cvtest::TS::LOG, "Algorithm can not be read\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_GENERIC);
+ }
+ }
+}
+
+void DescriptorQualityTest::calculatePlotData( vector<vector<DMatch> > &allMatches, vector<vector<uchar> > &allCorrectMatchesMask, int di )
+{
+ vector<Point2f> recallPrecisionCurve;
+ computeRecallPrecisionCurve( allMatches, allCorrectMatchesMask, recallPrecisionCurve );
+
+ calcDatasetQuality[di].clear();
+ const float resultPrecision = 0.5;
+ bool isResultCalculated = false;
+ const double eps = 1e-2;
+
+ Quality initQuality;
+ initQuality.recall = 0;
+ initQuality.precision = 0;
+ calcDatasetQuality[di].push_back( initQuality );
+
+ for( size_t i=0;i<recallPrecisionCurve.size();i++ )
+ {
+ Quality quality;
+ quality.recall = recallPrecisionCurve[i].y;
+ quality.precision = 1 - recallPrecisionCurve[i].x;
+ Quality back = calcDatasetQuality[di].back();
+
+ if( fabs( quality.recall - back.recall ) < eps && fabs( quality.precision - back.precision ) < eps )
+ continue;
+
+ calcDatasetQuality[di].push_back( quality );
+
+ if( !isResultCalculated && quality.precision < resultPrecision )
+ {
+ for(int ci=0;ci<TEST_CASE_COUNT;ci++)
+ {
+ calcQuality[di][ci].recall = quality.recall;
+ calcQuality[di][ci].precision = quality.precision;
+ }
+ isResultCalculated = true;
+ }
+ }
+}
+
+void DescriptorQualityTest::runDatasetTest (const vector<Mat> &imgs, const vector<Mat> &Hs, int di, int &progress)
+{
+ FileStorage keypontsFS( string(ts->get_data_path()) + KEYPOINTS_DIR + commRunParams[di].keypontsFilename,
+ FileStorage::READ );
+ if( !keypontsFS.isOpened())
+ {
+ calcQuality[di].clear();
+ ts->printf( cvtest::TS::LOG, "keypoints from file %s can not be read\n", commRunParams[di].keypontsFilename.c_str() );
+ return;
+ }
+
+ Ptr<GenericDescriptorMatcher> descMatch = commRunParams[di].isActiveParams ? specificDescMatcher : defaultDescMatcher;
+ calcQuality[di].resize(TEST_CASE_COUNT);
+
+ vector<KeyPoint> keypoints1;
+ readKeypoints( keypontsFS, keypoints1, 0);
+
+ int progressCount = DATASETS_COUNT*TEST_CASE_COUNT;
+
+ vector<vector<DMatch> > allMatches1to2;
+ vector<vector<uchar> > allCorrectMatchesMask;
+ for( int ci = 0; ci < TEST_CASE_COUNT; ci++ )
+ {
+ progress = update_progress( progress, di*TEST_CASE_COUNT + ci, progressCount, 0 );
+
+ vector<KeyPoint> keypoints2;
+ if( commRunParams[di].projectKeypointsFrom1Image )
+ {
+ // TODO need to test function calcKeyPointProjections
+ calcKeyPointProjections( keypoints1, Hs[ci], keypoints2 );
+ filterKeyPointsByImageSize( keypoints2, imgs[ci+1].size() );
+ }
+ else
+ readKeypoints( keypontsFS, keypoints2, ci+1 );
+ // TODO if( commRunParams[di].matchFilter )
+
+ vector<vector<DMatch> > matches1to2;
+ vector<vector<uchar> > correctMatchesMask;
+ vector<Point2f> recallPrecisionCurve; // not used because we need recallPrecisionCurve for
+ // all images in dataset
+ evaluateGenericDescriptorMatcher( imgs[0], imgs[ci+1], Hs[ci], keypoints1, keypoints2,
+ &matches1to2, &correctMatchesMask, recallPrecisionCurve,
+ descMatch );
+ allMatches1to2.insert( allMatches1to2.end(), matches1to2.begin(), matches1to2.end() );
+ allCorrectMatchesMask.insert( allCorrectMatchesMask.end(), correctMatchesMask.begin(), correctMatchesMask.end() );
+ }
+
+ calculatePlotData( allMatches1to2, allCorrectMatchesMask, di );
+}
+
+int DescriptorQualityTest::processResults( int datasetIdx, int caseIdx )
+{
+ const float rltvEps = 0.001f;
+
+ int res = cvtest::TS::OK;
+ bool isBadAccuracy;
+
+ Quality valid = validQuality[datasetIdx][caseIdx], calc = calcQuality[datasetIdx][caseIdx];
+
+ ts->printf(cvtest::TS::LOG, "%s: calc=%f, valid=%f", RECALL.c_str(), calc.recall, valid.recall );
+ isBadAccuracy = (valid.recall - calc.recall) > rltvEps;
+ testLog( ts, isBadAccuracy );
+ res = isBadAccuracy ? cvtest::TS::FAIL_BAD_ACCURACY : res;
+
+ ts->printf(cvtest::TS::LOG, "%s: calc=%f, valid=%f", PRECISION.c_str(), calc.precision, valid.precision );
+ isBadAccuracy = (valid.precision - calc.precision) > rltvEps;
+ testLog( ts, isBadAccuracy );
+ res = isBadAccuracy ? cvtest::TS::FAIL_BAD_ACCURACY : res;
+
+ return res;
+}
+
+//--------------------------------- Calonder descriptor test --------------------------------------------
+class CalonderDescriptorQualityTest : public DescriptorQualityTest
+{
+public:
+ CalonderDescriptorQualityTest() :
+ DescriptorQualityTest( "Calonder", "quality-descriptor-calonder") {}
+ virtual void readAlgorithm( )
+ {
+ string classifierFile = string(ts->get_data_path()) + "/features2d/calonder_classifier.rtc";
+ defaultDescMatcher = new VectorDescriptorMatch( new CalonderDescriptorExtractor<float>( classifierFile ),
+ new BruteForceMatcher<L2<float> > );
+ specificDescMatcher = defaultDescMatcher;
+ }
+};
+
+//--------------------------------- One Way descriptor test --------------------------------------------
+class OneWayDescriptorQualityTest : public DescriptorQualityTest
+{
+public:
+ OneWayDescriptorQualityTest() :
+ DescriptorQualityTest("ONEWAY", "quality-descriptor-one-way")
+ {
+ }
+protected:
+ virtual void processRunParamsFile ();
+ virtual void writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const;
+};
+
+void OneWayDescriptorQualityTest::processRunParamsFile ()
+{
+ string filename = getRunParamsFilename();
+ FileStorage fs = FileStorage (filename, FileStorage::READ);
+ FileNode fn = fs.getFirstTopLevelNode();
+ fn = fn[DEFAULT_PARAMS];
+
+ string pcaFilename = string(ts->get_data_path()) + (string)fn["pcaFilename"];
+ string trainPath = string(ts->get_data_path()) + (string)fn["trainPath"];
+ string trainImagesList = (string)fn["trainImagesList"];
+ int patch_width = fn["patchWidth"];
+ int patch_height = fn["patchHeight"];
+ Size patchSize = cvSize (patch_width, patch_height);
+ int poseCount = fn["poseCount"];
+
+ if (trainImagesList.length () == 0 )
+ return;
+
+ fs.release ();
+
+ readAllDatasetsRunParams();
+
+ OneWayDescriptorBase *base = new OneWayDescriptorBase(patchSize, poseCount, pcaFilename,
+ trainPath, trainImagesList);
+
+ OneWayDescriptorMatch *match = new OneWayDescriptorMatch ();
+ match->initialize( OneWayDescriptorMatch::Params (), base );
+ defaultDescMatcher = match;
+ writeAllDatasetsRunParams();
+}
+
+void OneWayDescriptorQualityTest::writeDatasetRunParams( FileStorage& fs, int datasetIdx ) const
+{
+ fs << IS_ACTIVE_PARAMS << commRunParams[datasetIdx].isActiveParams;
+ fs << KEYPOINTS_FILENAME << commRunParams[datasetIdx].keypontsFilename;
+ fs << PROJECT_KEYPOINTS_FROM_1IMAGE << commRunParams[datasetIdx].projectKeypointsFrom1Image;
+ fs << MATCH_FILTER << commRunParams[datasetIdx].matchFilter;
+}
+
+// Detectors
+//DetectorQualityTest fastDetectorQuality = DetectorQualityTest( "FAST", "quality-detector-fast" );
+//DetectorQualityTest gfttDetectorQuality = DetectorQualityTest( "GFTT", "quality-detector-gftt" );
+//DetectorQualityTest harrisDetectorQuality = DetectorQualityTest( "HARRIS", "quality-detector-harris" );
+//DetectorQualityTest mserDetectorQuality = DetectorQualityTest( "MSER", "quality-detector-mser" );
+//DetectorQualityTest starDetectorQuality = DetectorQualityTest( "STAR", "quality-detector-star" );
+//DetectorQualityTest siftDetectorQuality = DetectorQualityTest( "SIFT", "quality-detector-sift" );
+//DetectorQualityTest surfDetectorQuality = DetectorQualityTest( "SURF", "quality-detector-surf" );
+
+// Descriptors
+//DescriptorQualityTest siftDescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift", "BruteForce" );
+//DescriptorQualityTest surfDescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf", "BruteForce" );
+//DescriptorQualityTest fernDescriptorQualityTest( "FERN", "quality-descriptor-fern");
+//CalonderDescriptorQualityTest calonderDescriptorQualityTest;
+
+
+
+// Don't run it because of bug in OneWayDescriptorBase many to many matching. TODO: fix this bug.
+//OneWayDescriptorQualityTest oneWayDescriptorQuality;
+
+// Don't run them (will validate and save results as "quality-descriptor-sift" and "quality-descriptor-surf" test data).
+// TODO: differ result filenames.
+//DescriptorQualityTest siftL1DescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-sift-L1", "BruteForce-L1" );
+//DescriptorQualityTest surfL1DescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-surf-L1", "BruteForce-L1" );
+//DescriptorQualityTest oppSiftL1DescriptorQuality = DescriptorQualityTest( "SIFT", "quality-descriptor-opponent-sift-L1", "BruteForce-L1" );
+//DescriptorQualityTest oppSurfL1DescriptorQuality = DescriptorQualityTest( "SURF", "quality-descriptor-opponent-surf-L1", "BruteForce-L1" );
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <numeric>
+#include <algorithm>
+#include <iterator>
+
+using namespace cv;
+using namespace std;
+
+class CV_DetectorsTest : public cvtest::BaseTest
+{
+public:
+ CV_DetectorsTest();
+ ~CV_DetectorsTest();
+protected:
+ void run(int);
+ template <class T> bool testDetector(const Mat& img, const T& detector, vector<KeyPoint>& expected);
+
+ void LoadExpected(const string& file, vector<KeyPoint>& out);
+};
+
+CV_DetectorsTest::CV_DetectorsTest()
+{
+}
+CV_DetectorsTest::~CV_DetectorsTest() {}
+
+void getRotation(const Mat& img, Mat& aff, Mat& out)
+{
+ Point center(img.cols/2, img.rows/2);
+ aff = getRotationMatrix2D(center, 30, 1);
+ warpAffine( img, out, aff, img.size());
+}
+
+void getZoom(const Mat& img, Mat& aff, Mat& out)
+{
+ const double mult = 1.2;
+
+ aff.create(2, 3, CV_64F);
+ double *data = aff.ptr<double>();
+ data[0] = mult; data[1] = 0; data[2] = 0;
+ data[3] = 0; data[4] = mult; data[5] = 0;
+
+ warpAffine( img, out, aff, img.size());
+}
+
+void getBlur(const Mat& img, Mat& aff, Mat& out)
+{
+ aff.create(2, 3, CV_64F);
+ double *data = aff.ptr<double>();
+ data[0] = 1; data[1] = 0; data[2] = 0;
+ data[3] = 0; data[4] = 1; data[5] = 0;
+
+ GaussianBlur(img, out, Size(5, 5), 2);
+}
+
+void getBrightness(const Mat& img, Mat& aff, Mat& out)
+{
+ aff.create(2, 3, CV_64F);
+ double *data = aff.ptr<double>();
+ data[0] = 1; data[1] = 0; data[2] = 0;
+ data[3] = 0; data[4] = 1; data[5] = 0;
+
+ add(img, Mat(img.size(), img.type(), Scalar(15)), out);
+}
+
+void showOrig(const Mat& img, const vector<KeyPoint>& orig_pts)
+{
+
+ Mat img_color;
+ cvtColor(img, img_color, CV_GRAY2BGR);
+
+ for(size_t i = 0; i < orig_pts.size(); ++i)
+ circle(img_color, orig_pts[i].pt, (int)orig_pts[i].size/2, CV_RGB(0, 255, 0));
+
+ namedWindow("O"); imshow("O", img_color);
+}
+
+void show(const string& name, const Mat& new_img, const vector<KeyPoint>& new_pts, const vector<KeyPoint>& transf_pts)
+{
+
+ Mat new_img_color;
+ cvtColor(new_img, new_img_color, CV_GRAY2BGR);
+
+ for(size_t i = 0; i < transf_pts.size(); ++i)
+ circle(new_img_color, transf_pts[i].pt, (int)transf_pts[i].size/2, CV_RGB(255, 0, 0));
+
+ for(size_t i = 0; i < new_pts.size(); ++i)
+ circle(new_img_color, new_pts[i].pt, (int)new_pts[i].size/2, CV_RGB(0, 0, 255));
+
+ namedWindow(name + "_T"); imshow(name + "_T", new_img_color);
+}
+
+struct WrapPoint
+{
+ const double* R;
+ WrapPoint(const Mat& rmat) : R(rmat.ptr<double>()) { };
+
+ KeyPoint operator()(const KeyPoint& kp) const
+ {
+ KeyPoint res = kp;
+ res.pt.x = static_cast<float>(kp.pt.x * R[0] + kp.pt.y * R[1] + R[2]);
+ res.pt.y = static_cast<float>(kp.pt.x * R[3] + kp.pt.y * R[4] + R[5]);
+ return res;
+ }
+};
+
+struct sortByR { bool operator()(const KeyPoint& kp1, const KeyPoint& kp2) { return norm(kp1.pt) < norm(kp2.pt); } };
+
+template <class T> bool CV_DetectorsTest::testDetector(const Mat& img, const T& detector, vector<KeyPoint>& exp)
+{
+ vector<KeyPoint> orig_kpts;
+ detector(img, orig_kpts);
+
+ typedef void (*TransfFunc )(const Mat&, Mat&, Mat& FransfFunc);
+ const TransfFunc transfFunc[] = { getRotation, getZoom, getBlur, getBrightness };
+ //const string names[] = { "Rotation", "Zoom", "Blur", "Brightness" };
+ const size_t case_num = sizeof(transfFunc)/sizeof(transfFunc[0]);
+
+ vector<Mat> affs(case_num);
+ vector<Mat> new_imgs(case_num);
+
+ vector< vector<KeyPoint> > new_kpts(case_num);
+ vector< vector<KeyPoint> > transf_kpts(case_num);
+
+ //showOrig(img, orig_kpts);
+ for(size_t i = 0; i < case_num; ++i)
+ {
+ transfFunc[i](img, affs[i], new_imgs[i]);
+ detector(new_imgs[i], new_kpts[i]);
+ transform(orig_kpts.begin(), orig_kpts.end(), back_inserter(transf_kpts[i]), WrapPoint(affs[i]));
+ //show(names[i], new_imgs[i], new_kpts[i], transf_kpts[i]);
+ }
+
+ const float thres = 3;
+ const float nthres = 3;
+
+ vector<KeyPoint> result;
+ for(size_t i = 0; i < orig_kpts.size(); ++i)
+ {
+ const KeyPoint& okp = orig_kpts[i];
+ int foundCounter = 0;
+ for(size_t j = 0; j < case_num; ++j)
+ {
+ const KeyPoint& tkp = transf_kpts[j][i];
+
+ size_t k = 0;
+
+ for(; k < new_kpts[j].size(); ++k)
+ if (norm(new_kpts[j][k].pt - tkp.pt) < nthres && fabs(new_kpts[j][k].size - tkp.size) < thres)
+ break;
+
+ if (k != new_kpts[j].size())
+ ++foundCounter;
+
+ }
+ if (foundCounter == (int)case_num)
+ result.push_back(okp);
+ }
+
+ sort(result.begin(), result.end(), sortByR());
+ sort(exp.begin(), exp.end(), sortByR());
+
+ if (result.size() != exp.size())
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_TEST_DATA);
+ return false;
+ }
+
+ int foundCounter1 = 0;
+ for(size_t i = 0; i < exp.size(); ++i)
+ {
+ const KeyPoint& e = exp[i];
+ size_t j = 0;
+ for(; j < result.size(); ++j)
+ {
+ const KeyPoint& r = result[i];
+ if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)
+ break;
+ }
+ if (j != result.size())
+ ++foundCounter1;
+ }
+
+ int foundCounter2 = 0;
+ for(size_t i = 0; i < result.size(); ++i)
+ {
+ const KeyPoint& r = result[i];
+ size_t j = 0;
+ for(; j < exp.size(); ++j)
+ {
+ const KeyPoint& e = exp[i];
+ if (norm(r.pt-e.pt) < nthres && fabs(r.size - e.size) < thres)
+ break;
+ }
+ if (j != exp.size())
+ ++foundCounter2;
+ }
+ //showOrig(img, result); waitKey();
+
+ const float errorRate = 0.9f;
+ if (float(foundCounter1)/exp.size() < errorRate || float(foundCounter2)/result.size() < errorRate)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+struct SurfNoMaskWrap
+{
+ const SURF& detector;
+ SurfNoMaskWrap(const SURF& surf) : detector(surf) {}
+ SurfNoMaskWrap& operator=(const SurfNoMaskWrap&);
+ void operator()(const Mat& img, vector<KeyPoint>& kpts) const { detector(img, Mat(), kpts); }
+};
+
+void CV_DetectorsTest::LoadExpected(const string& file, vector<KeyPoint>& out)
+{
+ Mat mat_exp;
+ FileStorage fs(file, FileStorage::READ);
+ if (fs.isOpened())
+ {
+ read( fs["ResultVectorData"], mat_exp, Mat() );
+ out.resize(mat_exp.cols / sizeof(KeyPoint));
+ copy(mat_exp.ptr<KeyPoint>(), mat_exp.ptr<KeyPoint>() + out.size(), out.begin());
+ }
+ else
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA);
+ out.clear();
+ }
+}
+
+void CV_DetectorsTest::run( int /*start_from*/ )
+{
+ Mat img = imread(string(ts->get_data_path()) + "shared/graffiti.png", 0);
+
+ if (img.empty())
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ Mat to_test(img.size() * 2, img.type(), Scalar(0));
+ Mat roi = to_test(Rect(img.rows/2, img.cols/2, img.cols, img.rows));
+ img.copyTo(roi);
+ GaussianBlur(to_test, to_test, Size(3, 3), 1.5);
+
+ vector<KeyPoint> exp;
+ LoadExpected(string(ts->get_data_path()) + "detectors/surf.xml", exp);
+ if (exp.empty())
+ return;
+
+ if (!testDetector(to_test, SurfNoMaskWrap(SURF(1536+512+512, 2)), exp))
+ return;
+
+ LoadExpected(string(ts->get_data_path()) + "detectors/star.xml", exp);
+ if (exp.empty())
+ return;
+
+ if (!testDetector(to_test, StarDetector(45, 30, 10, 8, 5), exp))
+ return;
+
+ ts->set_failed_test_info( cvtest::TS::OK);
+}
+
+
+TEST(Features2d_Detectors, regression) { CV_DetectorsTest test; test.safe_run(); }
+
+
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+
+class CV_FastTest : public cvtest::BaseTest
+{
+public:
+ CV_FastTest();
+ ~CV_FastTest();
+protected:
+ void run(int);
+};
+
+CV_FastTest::CV_FastTest() {}
+CV_FastTest::~CV_FastTest() {}
+
+void CV_FastTest::run( int )
+{
+ Mat image1 = imread(string(ts->get_data_path()) + "inpaint/orig.jpg");
+ Mat image2 = imread(string(ts->get_data_path()) + "cameracalibration/chess9.jpg");
+ string xml = string(ts->get_data_path()) + "fast/result.xml";
+
+ if (image1.empty() || image2.empty())
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ Mat gray1, gray2;
+ cvtColor(image1, gray1, CV_BGR2GRAY);
+ cvtColor(image2, gray2, CV_BGR2GRAY);
+
+ vector<KeyPoint> keypoints1;
+ vector<KeyPoint> keypoints2;
+ FAST(gray1, keypoints1, 30);
+ FAST(gray2, keypoints2, 30);
+
+ for(size_t i = 0; i < keypoints1.size(); ++i)
+ {
+ const KeyPoint& kp = keypoints1[i];
+ cv::circle(image1, kp.pt, cvRound(kp.size/2), CV_RGB(255, 0, 0));
+ }
+
+ for(size_t i = 0; i < keypoints2.size(); ++i)
+ {
+ const KeyPoint& kp = keypoints2[i];
+ cv::circle(image2, kp.pt, cvRound(kp.size/2), CV_RGB(255, 0, 0));
+ }
+
+ Mat kps1(1, (int)(keypoints1.size() * sizeof(KeyPoint)), CV_8U, &keypoints1[0]);
+ Mat kps2(1, (int)(keypoints2.size() * sizeof(KeyPoint)), CV_8U, &keypoints2[0]);
+
+ FileStorage fs(xml, FileStorage::READ);
+ if (!fs.isOpened())
+ {
+ fs.open(xml, FileStorage::WRITE);
+ fs << "exp_kps1" << kps1;
+ fs << "exp_kps2" << kps2;
+ fs.release();
+ }
+
+ if (!fs.isOpened())
+ fs.open(xml, FileStorage::READ);
+
+ Mat exp_kps1, exp_kps2;
+ read( fs["exp_kps1"], exp_kps1, Mat() );
+ read( fs["exp_kps2"], exp_kps2, Mat() );
+ fs.release();
+
+ if ( 0 != norm(exp_kps1, kps1, NORM_L2) || 0 != norm(exp_kps2, kps2, NORM_L2))
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return;
+ }
+
+ /* cv::namedWindow("Img1"); cv::imshow("Img1", image1);
+ cv::namedWindow("Img2"); cv::imshow("Img2", image2);
+ cv::waitKey(0);*/
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Features2d_FAST, regression) { CV_FastTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "test_precomp.hpp"
+#include "opencv2/highgui/highgui.hpp"
+
+using namespace std;
+using namespace cv;
+
+const string FEATURES2D_DIR = "features2d";
+const string DETECTOR_DIR = FEATURES2D_DIR + "/feature_detectors";
+const string DESCRIPTOR_DIR = FEATURES2D_DIR + "/descriptor_extractors";
+const string IMAGE_FILENAME = "tsukuba.png";
+
+/****************************************************************************************\
+* Regression tests for feature detectors comparing keypoints. *
+\****************************************************************************************/
+
+class CV_FeatureDetectorTest : public cvtest::BaseTest
+{
+public:
+ CV_FeatureDetectorTest( const Ptr<FeatureDetector>& _fdetector ) :
+ fdetector(_fdetector) {}
+
+protected:
+ bool isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 );
+ void compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints );
+
+ void emptyDataTest();
+ void regressionTest(); // TODO test of detect() with mask
+
+ virtual void run( int );
+
+ Ptr<FeatureDetector> fdetector;
+};
+
+void CV_FeatureDetectorTest::emptyDataTest()
+{
+ // One image.
+ Mat image;
+ vector<KeyPoint> keypoints;
+ try
+ {
+ fdetector->detect( image, keypoints );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "detect() on empty image must not generate exception (1).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ if( !keypoints.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "detect() on empty image must return empty keypoints vector (1).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ // Several images.
+ vector<Mat> images;
+ vector<vector<KeyPoint> > keypointCollection;
+ try
+ {
+ fdetector->detect( images, keypointCollection );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "detect() on empty image vector must not generate exception (2).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+}
+
+bool CV_FeatureDetectorTest::isSimilarKeypoints( const KeyPoint& p1, const KeyPoint& p2 )
+{
+ const float maxPtDif = 1.f;
+ const float maxSizeDif = 1.f;
+ const float maxAngleDif = 2.f;
+ const float maxResponseDif = 0.1f;
+
+ float dist = (float)norm( p1.pt - p2.pt );
+ return (dist < maxPtDif &&
+ fabs(p1.size - p2.size) < maxSizeDif &&
+ abs(p1.angle - p2.angle) < maxAngleDif &&
+ abs(p1.response - p2.response) < maxResponseDif &&
+ p1.octave == p2.octave &&
+ p1.class_id == p2.class_id );
+}
+
+void CV_FeatureDetectorTest::compareKeypointSets( const vector<KeyPoint>& validKeypoints, const vector<KeyPoint>& calcKeypoints )
+{
+ const float maxCountRatioDif = 0.01f;
+
+ // Compare counts of validation and calculated keypoints.
+ float countRatio = (float)validKeypoints.size() / (float)calcKeypoints.size();
+ if( countRatio < 1 - maxCountRatioDif || countRatio > 1.f + maxCountRatioDif )
+ {
+ ts->printf( cvtest::TS::LOG, "Bad keypoints count ratio (validCount = %d, calcCount = %d).\n",
+ validKeypoints.size(), calcKeypoints.size() );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ int progress = 0, progressCount = validKeypoints.size() * calcKeypoints.size();
+ int badPointCount = 0, commonPointCount = max(validKeypoints.size(), calcKeypoints.size());
+ for( size_t v = 0; v < validKeypoints.size(); v++ )
+ {
+ int nearestIdx = -1;
+ float minDist = std::numeric_limits<float>::max();
+
+ for( size_t c = 0; c < calcKeypoints.size(); c++ )
+ {
+ progress = update_progress( progress, v*calcKeypoints.size() + c, progressCount, 0 );
+ float curDist = (float)norm( calcKeypoints[c].pt - validKeypoints[v].pt );
+ if( curDist < minDist )
+ {
+ minDist = curDist;
+ nearestIdx = c;
+ }
+ }
+
+ assert( minDist >= 0 );
+ if( !isSimilarKeypoints( validKeypoints[v], calcKeypoints[nearestIdx] ) )
+ badPointCount++;
+ }
+ ts->printf( cvtest::TS::LOG, "badPointCount = %d; validPointCount = %d; calcPointCount = %d\n",
+ badPointCount, validKeypoints.size(), calcKeypoints.size() );
+ if( badPointCount > 0.9 * commonPointCount )
+ {
+ ts->printf( cvtest::TS::LOG, " - Bad accuracy!\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+ ts->printf( cvtest::TS::LOG, " - OK\n" );
+}
+
+void CV_FeatureDetectorTest::regressionTest()
+{
+ assert( !fdetector.empty() );
+ string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME;
+ string resFilename = string(ts->get_data_path()) + DETECTOR_DIR + "/" + string(name) + ".xml.gz";
+
+ // Read the test image.
+ Mat image = imread( imgFilename );
+ if( image.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ FileStorage fs( resFilename, FileStorage::READ );
+
+ // Compute keypoints.
+ vector<KeyPoint> calcKeypoints;
+ fdetector->detect( image, calcKeypoints );
+
+ if( fs.isOpened() ) // Compare computed and valid keypoints.
+ {
+ // TODO compare saved feature detector params with current ones
+
+ // Read validation keypoints set.
+ vector<KeyPoint> validKeypoints;
+ read( fs["keypoints"], validKeypoints );
+ if( validKeypoints.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "Keypoints can not be read.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ compareKeypointSets( validKeypoints, calcKeypoints );
+ }
+ else // Write detector parameters and computed keypoints as validation data.
+ {
+ fs.open( resFilename, FileStorage::WRITE );
+ if( !fs.isOpened() )
+ {
+ ts->printf( cvtest::TS::LOG, "File %s can not be opened to write.\n", resFilename.c_str() );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+ else
+ {
+ fs << "detector_params" << "{";
+ fdetector->write( fs );
+ fs << "}";
+
+ write( fs, "keypoints", calcKeypoints );
+ }
+ }
+}
+
+void CV_FeatureDetectorTest::run( int /*start_from*/ )
+{
+ if( fdetector.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "Feature detector is empty.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ emptyDataTest();
+ regressionTest();
+
+ ts->set_failed_test_info( cvtest::TS::OK );
+}
+
+/****************************************************************************************\
+* Regression tests for descriptor extractors. *
+\****************************************************************************************/
+static void writeMatInBin( const Mat& mat, const string& filename )
+{
+ FILE* f = fopen( filename.c_str(), "wb");
+ if( f )
+ {
+ int type = mat.type();
+ fwrite( (void*)&mat.rows, sizeof(int), 1, f );
+ fwrite( (void*)&mat.cols, sizeof(int), 1, f );
+ fwrite( (void*)&type, sizeof(int), 1, f );
+ int dataSize = mat.step * mat.rows * mat.channels();
+ fwrite( (void*)&dataSize, sizeof(int), 1, f );
+ fwrite( (void*)mat.data, 1, dataSize, f );
+ fclose(f);
+ }
+}
+
+static Mat readMatFromBin( const string& filename )
+{
+ FILE* f = fopen( filename.c_str(), "rb" );
+ if( f )
+ {
+ int rows, cols, type, dataSize;
+ fread( (void*)&rows, sizeof(int), 1, f );
+ fread( (void*)&cols, sizeof(int), 1, f );
+ fread( (void*)&type, sizeof(int), 1, f );
+ fread( (void*)&dataSize, sizeof(int), 1, f );
+
+ uchar* data = (uchar*)cvAlloc(dataSize);
+ fread( (void*)data, 1, dataSize, f );
+ fclose(f);
+
+ return Mat( rows, cols, type, data );
+ }
+ return Mat();
+}
+
+template<class Distance>
+class CV_DescriptorExtractorTest : public cvtest::BaseTest
+{
+public:
+ typedef typename Distance::ValueType ValueType;
+ typedef typename Distance::ResultType DistanceType;
+
+ CV_DescriptorExtractorTest( DistanceType _maxDist, const Ptr<DescriptorExtractor>& _dextractor, float _prevTime,
+ Distance d = Distance() ):
+ maxDist(_maxDist), prevTime(_prevTime), dextractor(_dextractor), distance(d) {}
+protected:
+ virtual void createDescriptorExtractor() {}
+
+ void compareDescriptors( const Mat& validDescriptors, const Mat& calcDescriptors )
+ {
+ if( validDescriptors.size != calcDescriptors.size || validDescriptors.type() != calcDescriptors.type() )
+ {
+ ts->printf(cvtest::TS::LOG, "Valid and computed descriptors matrices must have the same size and type.\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ CV_Assert( DataType<ValueType>::type == validDescriptors.type() );
+
+ int dimension = validDescriptors.cols;
+ DistanceType curMaxDist = std::numeric_limits<DistanceType>::min();
+ for( int y = 0; y < validDescriptors.rows; y++ )
+ {
+ DistanceType dist = distance( validDescriptors.ptr<ValueType>(y), calcDescriptors.ptr<ValueType>(y), dimension );
+ if( dist > curMaxDist )
+ curMaxDist = dist;
+ }
+
+ stringstream ss;
+ ss << "Max distance between valid and computed descriptors " << curMaxDist;
+ if( curMaxDist < maxDist )
+ ss << "." << endl;
+ else
+ {
+ ss << ">" << maxDist << " - bad accuracy!"<< endl;
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ }
+ ts->printf(cvtest::TS::LOG, ss.str().c_str() );
+ }
+
+ void emptyDataTest()
+ {
+ assert( !dextractor.empty() );
+
+ // One image.
+ Mat image;
+ vector<KeyPoint> keypoints;
+ Mat descriptors;
+
+ try
+ {
+ dextractor->compute( image, keypoints, descriptors );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "compute() on empty image and empty keypoints must not generate exception (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ }
+
+ image.create( 50, 50, CV_8UC3 );
+ try
+ {
+ dextractor->compute( image, keypoints, descriptors );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "compute() on nonempty image and empty keypoints must not generate exception (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ }
+
+ // Several images.
+ vector<Mat> images;
+ vector<vector<KeyPoint> > keypointsCollection;
+ vector<Mat> descriptorsCollection;
+ try
+ {
+ dextractor->compute( images, keypointsCollection, descriptorsCollection );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "compute() on empty images and empty keypoints collection must not generate exception (2).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ }
+ }
+
+ void regressionTest()
+ {
+ assert( !dextractor.empty() );
+
+ // Read the test image.
+ string imgFilename = string(ts->get_data_path()) + FEATURES2D_DIR + "/" + IMAGE_FILENAME;
+
+ Mat img = imread( imgFilename );
+ if( img.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "Image %s can not be read.\n", imgFilename.c_str() );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ vector<KeyPoint> keypoints;
+ FileStorage fs( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::READ );
+ if( fs.isOpened() )
+ {
+ read( fs.getFirstTopLevelNode(), keypoints );
+
+ Mat calcDescriptors;
+ double t = (double)getTickCount();
+ dextractor->compute( img, keypoints, calcDescriptors );
+ t = getTickCount() - t;
+ ts->printf(cvtest::TS::LOG, "\nAverage time of computiting one descriptor = %g ms (previous time = %g ms).\n", t/((double)cvGetTickFrequency()*1000.)/calcDescriptors.rows, prevTime );
+
+ if( calcDescriptors.rows != (int)keypoints.size() )
+ {
+ ts->printf( cvtest::TS::LOG, "Count of computed descriptors and keypoints count must be equal.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ if( calcDescriptors.cols != dextractor->descriptorSize() || calcDescriptors.type() != dextractor->descriptorType() )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect descriptor size or descriptor type.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return;
+ }
+
+ // TODO read and write descriptor extractor parameters and check them
+ Mat validDescriptors = readDescriptors();
+ if( !validDescriptors.empty() )
+ compareDescriptors( validDescriptors, calcDescriptors );
+ else
+ {
+ if( !writeDescriptors( calcDescriptors ) )
+ {
+ ts->printf( cvtest::TS::LOG, "Descriptors can not be written.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+ }
+ }
+ else
+ {
+ ts->printf( cvtest::TS::LOG, "Compute and write keypoints.\n" );
+ fs.open( string(ts->get_data_path()) + FEATURES2D_DIR + "/keypoints.xml.gz", FileStorage::WRITE );
+ if( fs.isOpened() )
+ {
+ SurfFeatureDetector fd;
+ fd.detect(img, keypoints);
+ write( fs, "keypoints", keypoints );
+ }
+ else
+ {
+ ts->printf(cvtest::TS::LOG, "File for writting keypoints can not be opened.\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+ }
+ }
+
+ void run(int)
+ {
+ createDescriptorExtractor();
+ if( dextractor.empty() )
+ {
+ ts->printf(cvtest::TS::LOG, "Descriptor extractor is empty.\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ emptyDataTest();
+ regressionTest();
+
+ ts->set_failed_test_info( cvtest::TS::OK );
+ }
+
+ virtual Mat readDescriptors()
+ {
+ Mat res = readMatFromBin( string(ts->get_data_path()) + DESCRIPTOR_DIR + "/" + string(name) );
+ return res;
+ }
+
+ virtual bool writeDescriptors( Mat& descs )
+ {
+ writeMatInBin( descs, string(ts->get_data_path()) + DESCRIPTOR_DIR + "/" + string(name) );
+ return true;
+ }
+
+ const DistanceType maxDist;
+ const float prevTime;
+
+ Ptr<DescriptorExtractor> dextractor;
+ Distance distance;
+
+private:
+ CV_DescriptorExtractorTest& operator=(const CV_DescriptorExtractorTest&) { return *this; }
+};
+
+template<typename T, typename Distance>
+class CV_CalonderDescriptorExtractorTest : public CV_DescriptorExtractorTest<Distance>
+{
+public:
+ CV_CalonderDescriptorExtractorTest( const char* testName, float _normDif, float _prevTime ) :
+ CV_DescriptorExtractorTest<Distance>( testName, _normDif, Ptr<DescriptorExtractor>(), _prevTime )
+ {}
+
+protected:
+ virtual void createDescriptorExtractor()
+ {
+ CV_DescriptorExtractorTest<Distance>::dextractor =
+ new CalonderDescriptorExtractor<T>( string(CV_DescriptorExtractorTest<Distance>::ts->get_data_path()) +
+ FEATURES2D_DIR + "/calonder_classifier.rtc");
+ }
+};
+
+/****************************************************************************************\
+* Algorithmic tests for descriptor matchers *
+\****************************************************************************************/
+class CV_DescriptorMatcherTest : public cvtest::BaseTest
+{
+public:
+ CV_DescriptorMatcherTest( const Ptr<DescriptorMatcher>& _dmatcher, float _badPart ) :
+ badPart(_badPart), dmatcher(_dmatcher)
+ {}
+protected:
+ static const int dim = 500;
+ static const int queryDescCount = 300; // must be even number because we split train data in some cases in two
+ static const int countFactor = 4; // do not change it
+ const float badPart;
+
+ virtual void run( int );
+ void generateData( Mat& query, Mat& train );
+
+ void emptyDataTest();
+ void matchTest( const Mat& query, const Mat& train );
+ void knnMatchTest( const Mat& query, const Mat& train );
+ void radiusMatchTest( const Mat& query, const Mat& train );
+
+ Ptr<DescriptorMatcher> dmatcher;
+private:
+ CV_DescriptorMatcherTest& operator=(const CV_DescriptorMatcherTest&) { return *this; }
+};
+
+void CV_DescriptorMatcherTest::emptyDataTest()
+{
+ assert( !dmatcher.empty() );
+ Mat queryDescriptors, trainDescriptors, mask;
+ vector<Mat> trainDescriptorCollection, masks;
+ vector<DMatch> matches;
+ vector<vector<DMatch> > vmatches;
+
+ try
+ {
+ dmatcher->match( queryDescriptors, trainDescriptors, matches, mask );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (1).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->knnMatch( queryDescriptors, trainDescriptors, vmatches, 2, mask );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (1).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->radiusMatch( queryDescriptors, trainDescriptors, vmatches, 10.f, mask );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (1).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->add( trainDescriptorCollection );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "add() on empty descriptors must not generate exception.\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->match( queryDescriptors, matches, masks );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "match() on empty descriptors must not generate exception (2).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->knnMatch( queryDescriptors, vmatches, 2, masks );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "knnMatch() on empty descriptors must not generate exception (2).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ try
+ {
+ dmatcher->radiusMatch( queryDescriptors, vmatches, 10.f, masks );
+ }
+ catch(...)
+ {
+ ts->printf( cvtest::TS::LOG, "radiusMatch() on empty descriptors must not generate exception (2).\n" );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+}
+
+void CV_DescriptorMatcherTest::generateData( Mat& query, Mat& train )
+{
+ RNG& rng = theRNG();
+
+ // Generate query descriptors randomly.
+ // Descriptor vector elements are integer values.
+ Mat buf( queryDescCount, dim, CV_32SC1 );
+ rng.fill( buf, RNG::UNIFORM, Scalar::all(0), Scalar(3) );
+ buf.convertTo( query, CV_32FC1 );
+
+ // Generate train decriptors as follows:
+ // copy each query descriptor to train set countFactor times
+ // and perturb some one element of the copied descriptors in
+ // in ascending order. General boundaries of the perturbation
+ // are (0.f, 1.f).
+ train.create( query.rows*countFactor, query.cols, CV_32FC1 );
+ float step = 1.f / countFactor;
+ for( int qIdx = 0; qIdx < query.rows; qIdx++ )
+ {
+ Mat queryDescriptor = query.row(qIdx);
+ for( int c = 0; c < countFactor; c++ )
+ {
+ int tIdx = qIdx * countFactor + c;
+ Mat trainDescriptor = train.row(tIdx);
+ queryDescriptor.copyTo( trainDescriptor );
+ int elem = rng(dim);
+ float diff = rng.uniform( step*c, step*(c+1) );
+ trainDescriptor.at<float>(0, elem) += diff;
+ }
+ }
+}
+
+void CV_DescriptorMatcherTest::matchTest( const Mat& query, const Mat& train )
+{
+ dmatcher->clear();
+
+ // test const version of match()
+ {
+ vector<DMatch> matches;
+ dmatcher->match( query, train, matches );
+
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test match() function (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ else
+ {
+ int badCount = 0;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ DMatch match = matches[i];
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
+ badCount++;
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (1).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ }
+ }
+
+ // test version of match() with add()
+ {
+ vector<DMatch> matches;
+ // make add() twice to test such case
+ dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
+ dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
+ // prepare masks (make first nearest match illegal)
+ vector<Mat> masks(2);
+ for(int mi = 0; mi < 2; mi++ )
+ {
+ masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
+ for( int di = 0; di < queryDescCount/2; di++ )
+ masks[mi].col(di*countFactor).setTo(Scalar::all(0));
+ }
+
+ dmatcher->match( query, matches, masks );
+
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test match() function (2).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ else
+ {
+ int badCount = 0;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ DMatch match = matches[i];
+ int shift = dmatcher->isMaskSupported() ? 1 : 0;
+ {
+ if( i < queryDescCount/2 )
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + shift) || (match.imgIdx != 0) )
+ badCount++;
+ }
+ else
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + shift) || (match.imgIdx != 1) )
+ badCount++;
+ }
+ }
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test match() function (2).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ }
+ }
+ }
+}
+
+void CV_DescriptorMatcherTest::knnMatchTest( const Mat& query, const Mat& train )
+{
+ dmatcher->clear();
+
+ // test const version of knnMatch()
+ {
+ const int knn = 3;
+
+ vector<vector<DMatch> > matches;
+ dmatcher->knnMatch( query, train, matches, knn );
+
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ else
+ {
+ int badCount = 0;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ if( (int)matches[i].size() != knn )
+ badCount++;
+ else
+ {
+ int localBadCount = 0;
+ for( int k = 0; k < knn; k++ )
+ {
+ DMatch match = matches[i][k];
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor+k) || (match.imgIdx != 0) )
+ localBadCount++;
+ }
+ badCount += localBadCount > 0 ? 1 : 0;
+ }
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (1).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ }
+ }
+
+ // test version of knnMatch() with add()
+ {
+ const int knn = 2;
+ vector<vector<DMatch> > matches;
+ // make add() twice to test such case
+ dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
+ dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
+ // prepare masks (make first nearest match illegal)
+ vector<Mat> masks(2);
+ for(int mi = 0; mi < 2; mi++ )
+ {
+ masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
+ for( int di = 0; di < queryDescCount/2; di++ )
+ masks[mi].col(di*countFactor).setTo(Scalar::all(0));
+ }
+
+ dmatcher->knnMatch( query, matches, knn, masks );
+
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test knnMatch() function (2).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ else
+ {
+ int badCount = 0;
+ int shift = dmatcher->isMaskSupported() ? 1 : 0;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ if( (int)matches[i].size() != knn )
+ badCount++;
+ else
+ {
+ int localBadCount = 0;
+ for( int k = 0; k < knn; k++ )
+ {
+ DMatch match = matches[i][k];
+ {
+ if( i < queryDescCount/2 )
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
+ (match.imgIdx != 0) )
+ localBadCount++;
+ }
+ else
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
+ (match.imgIdx != 1) )
+ localBadCount++;
+ }
+ }
+ }
+ badCount += localBadCount > 0 ? 1 : 0;
+ }
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test knnMatch() function (2).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ }
+ }
+ }
+}
+
+void CV_DescriptorMatcherTest::radiusMatchTest( const Mat& query, const Mat& train )
+{
+ dmatcher->clear();
+ // test const version of match()
+ {
+ const float radius = 1.f/countFactor;
+ vector<vector<DMatch> > matches;
+ dmatcher->radiusMatch( query, train, matches, radius );
+
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ else
+ {
+ int badCount = 0;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ if( (int)matches[i].size() != 1 )
+ badCount++;
+ else
+ {
+ DMatch match = matches[i][0];
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor) || (match.imgIdx != 0) )
+ badCount++;
+ }
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (1).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+ }
+ }
+
+ // test version of match() with add()
+ {
+ int n = 3;
+ const float radius = 1.f/countFactor * n;
+ vector<vector<DMatch> > matches;
+ // make add() twice to test such case
+ dmatcher->add( vector<Mat>(1,train.rowRange(0, train.rows/2)) );
+ dmatcher->add( vector<Mat>(1,train.rowRange(train.rows/2, train.rows)) );
+ // prepare masks (make first nearest match illegal)
+ vector<Mat> masks(2);
+ for(int mi = 0; mi < 2; mi++ )
+ {
+ masks[mi] = Mat(query.rows, train.rows/2, CV_8UC1, Scalar::all(1));
+ for( int di = 0; di < queryDescCount/2; di++ )
+ masks[mi].col(di*countFactor).setTo(Scalar::all(0));
+ }
+
+ dmatcher->radiusMatch( query, matches, radius, masks );
+
+ int curRes = cvtest::TS::OK;
+ if( (int)matches.size() != queryDescCount )
+ {
+ ts->printf(cvtest::TS::LOG, "Incorrect matches count while test radiusMatch() function (1).\n");
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ }
+
+ int badCount = 0;
+ int shift = dmatcher->isMaskSupported() ? 1 : 0;
+ int needMatchCount = dmatcher->isMaskSupported() ? n-1 : n;
+ for( size_t i = 0; i < matches.size(); i++ )
+ {
+ if( (int)matches[i].size() != needMatchCount )
+ badCount++;
+ else
+ {
+ int localBadCount = 0;
+ for( int k = 0; k < needMatchCount; k++ )
+ {
+ DMatch match = matches[i][k];
+ {
+ if( i < queryDescCount/2 )
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != (int)i*countFactor + k + shift) ||
+ (match.imgIdx != 0) )
+ localBadCount++;
+ }
+ else
+ {
+ if( (match.queryIdx != (int)i) || (match.trainIdx != ((int)i-queryDescCount/2)*countFactor + k + shift) ||
+ (match.imgIdx != 1) )
+ localBadCount++;
+ }
+ }
+ }
+ badCount += localBadCount > 0 ? 1 : 0;
+ }
+ }
+ if( (float)badCount > (float)queryDescCount*badPart )
+ {
+ curRes = cvtest::TS::FAIL_INVALID_OUTPUT;
+ ts->printf( cvtest::TS::LOG, "%f - too large bad matches part while test radiusMatch() function (2).\n",
+ (float)badCount/(float)queryDescCount );
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ }
+ }
+}
+
+void CV_DescriptorMatcherTest::run( int )
+{
+ Mat query, train;
+ generateData( query, train );
+
+ matchTest( query, train );
+
+ knnMatchTest( query, train );
+
+ radiusMatchTest( query, train );
+}
+
+/****************************************************************************************\
+* Tests registrations *
+\****************************************************************************************/
+
+/*
+ * Detectors
+ * "detector-fast, detector-gftt, detector-harris, detector-mser, detector-sift, detector-star, detector-surf, detector-grid-fast, detector-pyramid-fast"
+ */
+
+/*CV_FeatureDetectorTest fastTest( "detector-fast", FeatureDetector::create("FAST") );
+CV_FeatureDetectorTest gfttTest( "detector-gftt", FeatureDetector::create("GFTT") );
+CV_FeatureDetectorTest harrisTest( "detector-harris", FeatureDetector::create("HARRIS") );
+CV_FeatureDetectorTest mserTest( "detector-mser", FeatureDetector::create("MSER") );
+CV_FeatureDetectorTest siftTest( "detector-sift", FeatureDetector::create("SIFT") );
+CV_FeatureDetectorTest starTest( "detector-star", FeatureDetector::create("STAR") );
+CV_FeatureDetectorTest surfTest( "detector-surf", FeatureDetector::create("SURF") );
+CV_FeatureDetectorTest gridFastfTest( "detector-grid-fast", FeatureDetector::create("GridFAST") );
+CV_FeatureDetectorTest pyramidFastTest( "detector-pyramid-fast", FeatureDetector::create("PyramidFAST") );*/
+
+/*
+ * Descriptors
+ * "descriptor-sift, descriptor-surf, descriptor-calonder-uchar, descriptor-calonder-float, descriptor-brief, descriptor-opponent-sift, descriptor-opponent-surf"
+ */
+TEST( Features2d_Descriptor_SIFT, regression )
+{
+ CV_DescriptorExtractorTest<L2<float> > test( 0.03f, DescriptorExtractor::create("SIFT"), 8.06652f );
+ test.safe_run();
+}
+
+TEST( Features2d_Descriptor_SURF, regression )
+{
+ CV_DescriptorExtractorTest<L2<float> > test( 0.035f, DescriptorExtractor::create("SURF"), 0.147372f );
+ test.safe_run();
+}
+
+TEST( Features2d_Descriptor_BRIEF, regression )
+{
+ CV_DescriptorExtractorTest<Hamming> test( 1, DescriptorExtractor::create("BRIEF"), 0.00527548f );
+ test.safe_run();
+}
+
+TEST( Features2d_Descriptor_OpponentSIFT, regression )
+{
+ CV_DescriptorExtractorTest<L2<float> > test( 0.18f, DescriptorExtractor::create("OpponentSIFT"), 8.06652f );
+ test.safe_run();
+}
+
+TEST( Features2d_Descriptor_OpponentSURF, regression )
+{
+ CV_DescriptorExtractorTest<L2<float> > test( 0.18f, DescriptorExtractor::create("OpponentSURF"), 0.147372f );
+ test.safe_run();
+}
+
+#if CV_SSE2
+TEST( Features2d_Descriptor_Calonder_uchar, regression )
+{
+ CV_CalonderDescriptorExtractorTest<uchar, L2<uchar> > test(
+ std::numeric_limits<float>::epsilon() + 1,
+ 0.0132175f );
+ test.safe_run();
+}
+
+TEST( Features2d_Descriptor_Calonder_float, regression )
+{
+ CV_CalonderDescriptorExtractorTest<float, L2<float> > test(
+ std::numeric_limits<float>::epsilon(),
+ 0.0221308f );
+ test.safe_run();
+}
+#endif // CV_SSE2
+
+/*
+ * Matchers
+ * "descriptor-matcher-brute-force, descriptor-matcher-flann-based"
+ */
+TEST( Features2d_DescriptorMatcher_BruteForce_L2, accuracy )
+{
+ CV_DescriptorMatcherTest test( new BruteForceMatcher<L2<float> >, 0.01f );
+ test.safe_run();
+}
+
+TEST( Features2d_DescriptorMatcher_FLANN, accuracy )
+{
+ CV_DescriptorMatcherTest test( new FlannBasedMatcher, 0.04f );
+ test.safe_run();
+}
+
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <vector>
+#include <string>
+using namespace std;
+using namespace cv;
+
+class CV_MserTest : public cvtest::BaseTest
+{
+public:
+ CV_MserTest();
+protected:
+ void run(int);
+ int LoadBoxes(const char* path, vector<CvBox2D>& boxes);
+ int SaveBoxes(const char* path, const vector<CvBox2D>& boxes);
+ int CompareBoxes(const vector<CvBox2D>& boxes1,const vector<CvBox2D>& boxes2, float max_rel_diff = 0.01f);
+};
+
+CV_MserTest::CV_MserTest()
+{
+}
+
+int CV_MserTest::LoadBoxes(const char* path, vector<CvBox2D>& boxes)
+{
+ boxes.clear();
+ FILE* f = fopen(path,"r");
+
+ if (f==NULL)
+ {
+ return 0;
+ }
+
+ while (!feof(f))
+ {
+ CvBox2D box;
+ fscanf(f,"%f,%f,%f,%f,%f\n",&box.angle,&box.center.x,&box.center.y,&box.size.width,&box.size.height);
+ boxes.push_back(box);
+ }
+ fclose(f);
+ return 1;
+}
+
+int CV_MserTest::SaveBoxes(const char* path, const vector<CvBox2D>& boxes)
+{
+ FILE* f = fopen(path,"w");
+ if (f==NULL)
+ {
+ return 0;
+ }
+ for (int i=0;i<(int)boxes.size();i++)
+ {
+ fprintf(f,"%f,%f,%f,%f,%f\n",boxes[i].angle,boxes[i].center.x,boxes[i].center.y,boxes[i].size.width,boxes[i].size.height);
+ }
+ fclose(f);
+ return 1;
+}
+
+int CV_MserTest::CompareBoxes(const vector<CvBox2D>& boxes1,const vector<CvBox2D>& boxes2, float max_rel_diff)
+{
+ if (boxes1.size() != boxes2.size())
+ return 0;
+
+ for (int i=0; i<(int)boxes1.size();i++)
+ {
+ float rel_diff;
+ if (!((boxes1[i].angle == 0.0f) && (abs(boxes2[i].angle) < max_rel_diff)))
+ {
+ rel_diff = abs(boxes1[i].angle-boxes2[i].angle)/abs(boxes1[i].angle);
+ if (rel_diff > max_rel_diff)
+ return i;
+ }
+
+ if (!((boxes1[i].center.x == 0.0f) && (abs(boxes2[i].center.x) < max_rel_diff)))
+ {
+ rel_diff = abs(boxes1[i].center.x-boxes2[i].center.x)/abs(boxes1[i].center.x);
+ if (rel_diff > max_rel_diff)
+ return i;
+ }
+
+ if (!((boxes1[i].center.y == 0.0f) && (abs(boxes2[i].center.y) < max_rel_diff)))
+ {
+ rel_diff = abs(boxes1[i].center.y-boxes2[i].center.y)/abs(boxes1[i].center.y);
+ if (rel_diff > max_rel_diff)
+ return i;
+ }
+ if (!((boxes1[i].size.width == 0.0f) && (abs(boxes2[i].size.width) < max_rel_diff)))
+ {
+ rel_diff = abs(boxes1[i].size.width-boxes2[i].size.width)/abs(boxes1[i].size.width);
+ if (rel_diff > max_rel_diff)
+ return i;
+ }
+
+ if (!((boxes1[i].size.height == 0.0f) && (abs(boxes2[i].size.height) < max_rel_diff)))
+ {
+ rel_diff = abs(boxes1[i].size.height-boxes2[i].size.height)/abs(boxes1[i].size.height);
+ if (rel_diff > max_rel_diff)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void CV_MserTest::run(int)
+{
+ string image_path = string(ts->get_data_path()) + "mser/puzzle.png";
+
+ IplImage* img = cvLoadImage( image_path.c_str());
+ if (!img)
+ {
+ ts->printf( cvtest::TS::LOG, "Unable to open image mser/puzzle.png\n");
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
+ return;
+ }
+
+ CvSeq* contours;
+ CvMemStorage* storage= cvCreateMemStorage();
+ IplImage* hsv = cvCreateImage( cvGetSize( img ), IPL_DEPTH_8U, 3 );
+ cvCvtColor( img, hsv, CV_BGR2YCrCb );
+ CvMSERParams params = cvMSERParams();//cvMSERParams( 5, 60, cvRound(.2*img->width*img->height), .25, .2 );
+ cvExtractMSER( hsv, NULL, &contours, storage, params );
+
+ vector<CvBox2D> boxes;
+ vector<CvBox2D> boxes_orig;
+ for ( int i = 0; i < contours->total; i++ )
+ {
+ CvContour* r = *(CvContour**)cvGetSeqElem( contours, i );
+ CvBox2D box = cvFitEllipse2( r );
+ box.angle=(float)CV_PI/2-box.angle;
+ boxes.push_back(box);
+ }
+
+ string boxes_path = string(ts->get_data_path()) + "mser/boxes.txt";
+
+ if (!LoadBoxes(boxes_path.c_str(),boxes_orig))
+ {
+ SaveBoxes(boxes_path.c_str(),boxes);
+ ts->printf( cvtest::TS::LOG, "Unable to open data file mser/boxes.txt\n");
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
+ return;
+ }
+
+ const float dissimularity = 0.01f;
+ int n_box = CompareBoxes(boxes_orig,boxes,dissimularity);
+ if (n_box < 0)
+ {
+ ts->set_failed_test_info(cvtest::TS::OK);
+ }
+ else
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ ts->printf( cvtest::TS::LOG, "Incorrect correspondence in %d box\n",n_box);
+ }
+
+ cvReleaseMemStorage(&storage);
+ cvReleaseImage(&hsv);
+ cvReleaseImage(&img);
+}
+
+TEST(Features2d_MSER, regression) { CV_MserTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <algorithm>
+#include <vector>
+#include <iostream>
+
+using namespace cv;
+using namespace cv::flann;
+
+//--------------------------------------------------------------------------------
+class NearestNeighborTest : public cvtest::BaseTest
+{
+public:
+ NearestNeighborTest() {}
+protected:
+ static const int minValue = 0;
+ static const int maxValue = 1;
+ static const int dims = 30;
+ static const int featuresCount = 2000;
+ static const int K = 1; // * should also test 2nd nn etc.?
+
+
+ virtual void run( int start_from );
+ virtual void createModel( const Mat& data ) = 0;
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) = 0;
+ virtual int checkGetPoins( const Mat& data );
+ virtual int checkFindBoxed();
+ virtual int checkFind( const Mat& data );
+ virtual void releaseModel() = 0;
+};
+
+int NearestNeighborTest::checkGetPoins( const Mat& )
+{
+ return cvtest::TS::OK;
+}
+
+int NearestNeighborTest::checkFindBoxed()
+{
+ return cvtest::TS::OK;
+}
+
+int NearestNeighborTest::checkFind( const Mat& data )
+{
+ int code = cvtest::TS::OK;
+ int pointsCount = 1000;
+ float noise = 0.2f;
+
+ RNG rng;
+ Mat points( pointsCount, dims, CV_32FC1 );
+ Mat results( pointsCount, K, CV_32SC1 );
+
+ std::vector<int> fmap( pointsCount );
+ for( int pi = 0; pi < pointsCount; pi++ )
+ {
+ int fi = rng.next() % featuresCount;
+ fmap[pi] = fi;
+ for( int d = 0; d < dims; d++ )
+ points.at<float>(pi, d) = data.at<float>(fi, d) + rng.uniform(0.0f, 1.0f) * noise;
+ }
+
+ code = findNeighbors( points, results );
+
+ if( code == cvtest::TS::OK )
+ {
+ int correctMatches = 0;
+ for( int pi = 0; pi < pointsCount; pi++ )
+ {
+ if( fmap[pi] == results.at<int>(pi, 0) )
+ correctMatches++;
+ }
+
+ double correctPerc = correctMatches / (double)pointsCount;
+ if (correctPerc < .75)
+ {
+ ts->printf( cvtest::TS::LOG, "correct_perc = %d\n", correctPerc );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ }
+
+ return code;
+}
+
+void NearestNeighborTest::run( int /*start_from*/ ) {
+ int code = cvtest::TS::OK, tempCode;
+ Mat desc( featuresCount, dims, CV_32FC1 );
+ randu( desc, Scalar(minValue), Scalar(maxValue) );
+
+ createModel( desc );
+
+ tempCode = checkGetPoins( desc );
+ if( tempCode != cvtest::TS::OK )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of GetPoints \n" );
+ code = tempCode;
+ }
+
+ tempCode = checkFindBoxed();
+ if( tempCode != cvtest::TS::OK )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of FindBoxed \n" );
+ code = tempCode;
+ }
+
+ tempCode = checkFind( desc );
+ if( tempCode != cvtest::TS::OK )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy of Find \n" );
+ code = tempCode;
+ }
+
+ releaseModel();
+
+ ts->set_failed_test_info( code );
+}
+
+//--------------------------------------------------------------------------------
+class CV_LSHTest : public NearestNeighborTest
+{
+public:
+ CV_LSHTest() {}
+protected:
+ virtual void createModel( const Mat& data );
+ virtual int findNeighbors( Mat& points, Mat& neighbors );
+ virtual void releaseModel();
+ struct CvLSH* lsh;
+ CvMat desc;
+};
+
+void CV_LSHTest::createModel( const Mat& data )
+{
+ desc = data;
+ lsh = cvCreateMemoryLSH( data.cols, data.rows, 70, 20, CV_32FC1 );
+ cvLSHAdd( lsh, &desc );
+}
+
+int CV_LSHTest::findNeighbors( Mat& points, Mat& neighbors )
+{
+ const int emax = 20;
+ Mat dist( points.rows, neighbors.cols, CV_64FC1);
+ CvMat _dist = dist, _points = points, _neighbors = neighbors;
+ cvLSHQuery( lsh, &_points, &_neighbors, &_dist, neighbors.cols, emax );
+ return cvtest::TS::OK;
+}
+
+void CV_LSHTest::releaseModel()
+{
+ cvReleaseLSH( &lsh );
+}
+
+//--------------------------------------------------------------------------------
+class CV_FeatureTreeTest_C : public NearestNeighborTest
+{
+public:
+ CV_FeatureTreeTest_C() {}
+protected:
+ virtual int findNeighbors( Mat& points, Mat& neighbors );
+ virtual void releaseModel();
+ CvFeatureTree* tr;
+ CvMat desc;
+};
+
+int CV_FeatureTreeTest_C::findNeighbors( Mat& points, Mat& neighbors )
+{
+ const int emax = 20;
+ Mat dist( points.rows, neighbors.cols, CV_64FC1);
+ CvMat _dist = dist, _points = points, _neighbors = neighbors;
+ cvFindFeatures( tr, &_points, &_neighbors, &_dist, neighbors.cols, emax );
+ return cvtest::TS::OK;
+}
+
+void CV_FeatureTreeTest_C::releaseModel()
+{
+ cvReleaseFeatureTree( tr );
+}
+
+//--------------------------------------
+class CV_SpillTreeTest_C : public CV_FeatureTreeTest_C
+{
+public:
+ CV_SpillTreeTest_C() {}
+protected:
+ virtual void createModel( const Mat& data );
+};
+
+void CV_SpillTreeTest_C::createModel( const Mat& data )
+{
+ desc = data;
+ tr = cvCreateSpillTree( &desc );
+}
+
+//--------------------------------------
+class CV_KDTreeTest_C : public CV_FeatureTreeTest_C
+{
+public:
+ CV_KDTreeTest_C() {}
+protected:
+ virtual void createModel( const Mat& data );
+ virtual int checkFindBoxed();
+};
+
+void CV_KDTreeTest_C::createModel( const Mat& data )
+{
+ desc = data;
+ tr = cvCreateKDTree( &desc );
+}
+
+int CV_KDTreeTest_C::checkFindBoxed()
+{
+ Mat min(1, dims, CV_32FC1 ), max(1, dims, CV_32FC1 ), indices( 1, 1, CV_32SC1 );
+ float l = minValue, r = maxValue;
+ min.setTo(Scalar(l)), max.setTo(Scalar(r));
+ CvMat _min = min, _max = max, _indices = indices;
+ // TODO check indices
+ if( cvFindFeaturesBoxed( tr, &_min, &_max, &_indices ) != featuresCount )
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ return cvtest::TS::OK;
+}
+
+//--------------------------------------------------------------------------------
+class CV_KDTreeTest_CPP : public NearestNeighborTest
+{
+public:
+ CV_KDTreeTest_CPP() {}
+protected:
+ virtual void createModel( const Mat& data );
+ virtual int checkGetPoins( const Mat& data );
+ virtual int findNeighbors( Mat& points, Mat& neighbors );
+ virtual int checkFindBoxed();
+ virtual void releaseModel();
+ KDTree* tr;
+};
+
+
+void CV_KDTreeTest_CPP::createModel( const Mat& data )
+{
+ tr = new KDTree( data, false );
+}
+
+int CV_KDTreeTest_CPP::checkGetPoins( const Mat& data )
+{
+ Mat res1( data.size(), data.type() ),
+ res2( data.size(), data.type() ),
+ res3( data.size(), data.type() );
+ Mat idxs( 1, data.rows, CV_32SC1 );
+ for( int pi = 0; pi < data.rows; pi++ )
+ {
+ idxs.at<int>(0, pi) = pi;
+ // 1st way
+ const float* point = tr->getPoint(pi);
+ for( int di = 0; di < data.cols; di++ )
+ res1.at<float>(pi, di) = point[di];
+ }
+ // 2nd way
+ tr->getPoints( idxs.ptr<int>(0), data.rows, res2 );
+
+ // 3d way
+ tr->getPoints( idxs, res3 );
+
+ if( norm( res1, data, NORM_L1) != 0 ||
+ norm( res2, data, NORM_L1) != 0 ||
+ norm( res3, data, NORM_L1) != 0)
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ return cvtest::TS::OK;
+}
+
+int CV_KDTreeTest_CPP::checkFindBoxed()
+{
+ vector<float> min( dims, minValue), max(dims, maxValue);
+ vector<int> indices;
+ tr->findOrthoRange( &min[0], &max[0], &indices );
+ // TODO check indices
+ if( (int)indices.size() != featuresCount)
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ return cvtest::TS::OK;
+}
+
+int CV_KDTreeTest_CPP::findNeighbors( Mat& points, Mat& neighbors )
+{
+ const int emax = 20;
+ Mat neighbors2( neighbors.size(), CV_32SC1 );
+ int j;
+ vector<float> min(points.cols, minValue);
+ vector<float> max(points.cols, maxValue);
+ for( int pi = 0; pi < points.rows; pi++ )
+ {
+ // 1st way
+ tr->findNearest( points.ptr<float>(pi), neighbors.cols, emax, neighbors.ptr<int>(pi) );
+
+ // 2nd way
+ vector<int> neighborsIdx2( neighbors2.cols, 0 );
+ tr->findNearest( points.ptr<float>(pi), neighbors2.cols, emax, &neighborsIdx2 );
+ vector<int>::const_iterator it2 = neighborsIdx2.begin();
+ for( j = 0; it2 != neighborsIdx2.end(); ++it2, j++ )
+ neighbors2.at<int>(pi,j) = *it2;
+ }
+
+ // compare results
+ if( norm( neighbors, neighbors2, NORM_L1 ) != 0 )
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+
+ return cvtest::TS::OK;
+}
+
+void CV_KDTreeTest_CPP::releaseModel()
+{
+ delete tr;
+}
+
+//--------------------------------------------------------------------------------
+class CV_FlannTest : public NearestNeighborTest
+{
+public:
+ CV_FlannTest() {}
+protected:
+ void createIndex( const Mat& data, const IndexParams& params );
+ int knnSearch( Mat& points, Mat& neighbors );
+ int radiusSearch( Mat& points, Mat& neighbors );
+ virtual void releaseModel();
+ Index* index;
+};
+
+void CV_FlannTest::createIndex( const Mat& data, const IndexParams& params )
+{
+ index = new Index( data, params );
+}
+
+int CV_FlannTest::knnSearch( Mat& points, Mat& neighbors )
+{
+ Mat dist( points.rows, neighbors.cols, CV_32FC1);
+ int knn = 1, j;
+
+ // 1st way
+ index->knnSearch( points, neighbors, dist, knn, SearchParams() );
+
+ // 2nd way
+ Mat neighbors1( neighbors.size(), CV_32SC1 );
+ for( int i = 0; i < points.rows; i++ )
+ {
+ float* fltPtr = points.ptr<float>(i);
+ vector<float> query( fltPtr, fltPtr + points.cols );
+ vector<int> indices( neighbors1.cols, 0 );
+ vector<float> dists( dist.cols, 0 );
+ index->knnSearch( query, indices, dists, knn, SearchParams() );
+ vector<int>::const_iterator it = indices.begin();
+ for( j = 0; it != indices.end(); ++it, j++ )
+ neighbors1.at<int>(i,j) = *it;
+ }
+
+ // compare results
+ if( norm( neighbors, neighbors1, NORM_L1 ) != 0 )
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+
+ return cvtest::TS::OK;
+}
+
+int CV_FlannTest::radiusSearch( Mat& points, Mat& neighbors )
+{
+ Mat dist( 1, neighbors.cols, CV_32FC1);
+ Mat neighbors1( neighbors.size(), CV_32SC1 );
+ float radius = 10.0f;
+ int j;
+
+ // radiusSearch can only search one feature at a time for range search
+ for( int i = 0; i < points.rows; i++ )
+ {
+ // 1st way
+ Mat p( 1, points.cols, CV_32FC1, points.ptr<float>(i) ),
+ n( 1, neighbors.cols, CV_32SC1, neighbors.ptr<int>(i) );
+ index->radiusSearch( p, n, dist, radius, SearchParams() );
+
+ // 2nd way
+ float* fltPtr = points.ptr<float>(i);
+ vector<float> query( fltPtr, fltPtr + points.cols );
+ vector<int> indices( neighbors1.cols, 0 );
+ vector<float> dists( dist.cols, 0 );
+ index->radiusSearch( query, indices, dists, radius, SearchParams() );
+ vector<int>::const_iterator it = indices.begin();
+ for( j = 0; it != indices.end(); ++it, j++ )
+ neighbors1.at<int>(i,j) = *it;
+ }
+ // compare results
+ if( norm( neighbors, neighbors1, NORM_L1 ) != 0 )
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+
+ return cvtest::TS::OK;
+}
+
+void CV_FlannTest::releaseModel()
+{
+ delete index;
+}
+
+//---------------------------------------
+class CV_FlannLinearIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannLinearIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data ) { createIndex( data, LinearIndexParams() ); }
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
+};
+
+//---------------------------------------
+class CV_FlannKMeansIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannKMeansIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data ) { createIndex( data, KMeansIndexParams() ); }
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }
+};
+
+//---------------------------------------
+class CV_FlannKDTreeIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannKDTreeIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data ) { createIndex( data, KDTreeIndexParams() ); }
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return radiusSearch( points, neighbors ); }
+};
+
+//----------------------------------------
+class CV_FlannCompositeIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannCompositeIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data ) { createIndex( data, CompositeIndexParams() ); }
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
+};
+
+//----------------------------------------
+class CV_FlannAutotunedIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannAutotunedIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data ) { createIndex( data, AutotunedIndexParams() ); }
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
+};
+//----------------------------------------
+class CV_FlannSavedIndexTest : public CV_FlannTest
+{
+public:
+ CV_FlannSavedIndexTest() {}
+protected:
+ virtual void createModel( const Mat& data );
+ virtual int findNeighbors( Mat& points, Mat& neighbors ) { return knnSearch( points, neighbors ); }
+};
+
+void CV_FlannSavedIndexTest::createModel(const cv::Mat &data)
+{
+ switch ( cvtest::randInt(ts->get_rng()) % 2 )
+ {
+ //case 0: createIndex( data, LinearIndexParams() ); break; // nothing to save for linear search
+ case 0: createIndex( data, KMeansIndexParams() ); break;
+ case 1: createIndex( data, KDTreeIndexParams() ); break;
+ //case 2: createIndex( data, CompositeIndexParams() ); break; // nothing to save for linear search
+ //case 2: createIndex( data, AutotunedIndexParams() ); break; // possible linear index !
+ default: assert(0);
+ }
+ char filename[50];
+ tmpnam( filename );
+ if(filename[0] == '\\') filename[0] = '_';
+ index->save( filename );
+
+ createIndex( data, SavedIndexParams(filename));
+ remove( filename );
+}
+
+TEST(Features2d_LSH, regression) { CV_LSHTest test; test.safe_run(); }
+TEST(Features2d_SpillTree, regression) { CV_SpillTreeTest_C test; test.safe_run(); }
+TEST(Features2d_KDTree_C, regression) { CV_KDTreeTest_C test; test.safe_run(); }
+TEST(Features2d_KDTree_CPP, regression) { CV_KDTreeTest_CPP test; test.safe_run(); }
+TEST(Features2d_FLANN_Linear, regression) { CV_FlannLinearIndexTest test; test.safe_run(); }
+TEST(Features2d_FLANN_KMeans, regression) { CV_FlannKMeansIndexTest test; test.safe_run(); }
+TEST(Features2d_FLANN_KDTree, regression) { CV_FlannKDTreeIndexTest test; test.safe_run(); }
+TEST(Features2d_FLANN_Composite, regression) { CV_FlannCompositeIndexTest test; test.safe_run(); }
+TEST(Features2d_FLANN_Auto, regression) { CV_FlannAutotunedIndexTest test; test.safe_run(); }
+TEST(Features2d_FLANN_Saved, regression) { CV_FlannSavedIndexTest test; test.safe_run(); }
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/features2d/features2d.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <iostream>
+
+#endif
+++ /dev/null
-if(BUILD_SHARED_LIBS)
-add_definitions(-DGTEST_CREATE_SHARED_LIBRARY=1)
-endif()
-define_opencv_module(gtest opencv_core)
+++ /dev/null
-The new OpenCV test engine is based
-on the Google C++ Testing Framework (GTest).
-Below is the original GTest README.
------------------------------------
-
-Google C++ Testing Framework
-============================
-
-http://code.google.com/p/googletest/
-
-Overview
---------
-
-Google's framework for writing C++ tests on a variety of platforms
-(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
-xUnit architecture. Supports automatic test discovery, a rich set of
-assertions, user-defined assertions, death tests, fatal and non-fatal
-failures, various options for running the tests, and XML test report
-generation.
-
-Please see the project page above for more information as well as the
-mailing list for questions, discussions, and development. There is
-also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
-join us!
-
-Requirements for End Users
---------------------------
-
-Google Test is designed to have fairly minimal requirements to build
-and use with your projects, but there are some. Currently, we support
-Linux, Windows, Mac OS X, and Cygwin. We will also make our best
-effort to support other platforms (e.g. Solaris, AIX, and z/OS).
-However, since core members of the Google Test project have no access
-to these platforms, Google Test may have outstanding issues there. If
-you notice any problems on your platform, please notify
-googletestframework@googlegroups.com. Patches for fixing them are
-even more welcome!
-
-### Linux Requirements ###
-
-These are the base requirements to build and use Google Test from a source
-package (as described below):
- * GNU-compatible Make or gmake
- * POSIX-standard shell
- * POSIX(-2) Regular Expressions (regex.h)
- * A C++98-standard-compliant compiler
-
-### Windows Requirements ###
-
- * Microsoft Visual C++ 7.1 or newer
-
-### Cygwin Requirements ###
-
- * Cygwin 1.5.25-14 or newer
-
-### Mac OS X Requirements ###
-
- * Mac OS X 10.4 Tiger or newer
- * Developer Tools Installed
-
-Also, you'll need CMake 2.6.4 or higher if you want to build the
-samples using the provided CMake script, regardless of the platform.
-
-Requirements for Contributors
------------------------------
-
-We welcome patches. If you plan to contribute a patch, you need to
-build Google Test and its own tests from an SVN checkout (described
-below), which has further requirements:
-
- * Python version 2.3 or newer (for running some of the tests and
- re-generating certain source files from templates)
- * CMake 2.6.4 or newer
-
-Getting the Source
-------------------
-
-There are two primary ways of getting Google Test's source code: you
-can download a stable source release in your preferred archive format,
-or directly check out the source from our Subversion (SVN) repositary.
-The SVN checkout requires a few extra steps and some extra software
-packages on your system, but lets you track the latest development and
-make patches much more easily, so we highly encourage it.
-
-### Source Package ###
-
-Google Test is released in versioned source packages which can be
-downloaded from the download page [1]. Several different archive
-formats are provided, but the only difference is the tools used to
-manipulate them, and the size of the resulting file. Download
-whichever you are most comfortable with.
-
- [1] http://code.google.com/p/googletest/downloads/list
-
-Once the package is downloaded, expand it using whichever tools you
-prefer for that type. This will result in a new directory with the
-name "gtest-X.Y.Z" which contains all of the source code. Here are
-some examples on Linux:
-
- tar -xvzf gtest-X.Y.Z.tar.gz
- tar -xvjf gtest-X.Y.Z.tar.bz2
- unzip gtest-X.Y.Z.zip
-
-### SVN Checkout ###
-
-To check out the main branch (also known as the "trunk") of Google
-Test, run the following Subversion command:
-
- svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
-
-Setting up the Build
---------------------
-
-To build Google Test and your tests that use it, you need to tell your
-build system where to find its headers and source files. The exact
-way to do it depends on which build system you use, and is usually
-straightforward.
-
-### Generic Build Instructions ###
-
-Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
-create a library build target (or a project as called by Visual Studio
-and Xcode) to compile
-
- ${GTEST_DIR}/src/gtest-all.cc
-
-with
-
- ${GTEST_DIR}/include and ${GTEST_DIR}
-
-in the header search path. Assuming a Linux-like system and gcc,
-something like the following will do:
-
- g++ -I${GTEST_DIR}/include -I${GTEST_DIR} -c ${GTEST_DIR}/src/gtest-all.cc
- ar -rv libgtest.a gtest-all.o
-
-Next, you should compile your test source file with
-${GTEST_DIR}/include in the header search path, and link it with gtest
-and any other necessary libraries:
-
- g++ -I${GTEST_DIR}/include path/to/your_test.cc libgtest.a -o your_test
-
-As an example, the make/ directory contains a Makefile that you can
-use to build Google Test on systems where GNU make is available
-(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
-Test's own tests. Instead, it just builds the Google Test library and
-a sample test. You can use it as a starting point for your own build
-script.
-
-If the default settings are correct for your environment, the
-following commands should succeed:
-
- cd ${GTEST_DIR}/make
- make
- ./sample1_unittest
-
-If you see errors, try to tweak the contents of make/Makefile to make
-them go away. There are instructions in make/Makefile on how to do
-it.
-
-### Using CMake ###
-
-Google Test comes with a CMake build script (CMakeLists.txt) that can
-be used on a wide range of platforms ("C" stands for cross-platofrm.).
-If you don't have CMake installed already, you can download it for
-free from http://www.cmake.org/.
-
-CMake works by generating native makefiles or build projects that can
-be used in the compiler environment of your choice. The typical
-workflow starts with:
-
- mkdir mybuild # Create a directory to hold the build output.
- cd mybuild
- cmake ${GTEST_DIR} # Generate native build scripts.
-
-If you want to build Google Test's samples, you should replace the
-last command with
-
- cmake -Dbuild_gtest_samples=ON ${GTEST_DIR}
-
-If you are on a *nix system, you should now see a Makefile in the
-current directory. Just type 'make' to build gtest.
-
-If you use Windows and have Vistual Studio installed, a gtest.sln file
-and several .vcproj files will be created. You can then build them
-using Visual Studio.
-
-On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
-
-### Legacy Build Scripts ###
-
-Before settling on CMake, we have been providing hand-maintained build
-projects/scripts for Visual Studio, Xcode, and Autotools. While we
-continue to provide them for convenience, they are not actively
-maintained any more. We highly recommend that you follow the
-instructions in the previous two sections to integrate Google Test
-with your existing build system.
-
-If you still need to use the legacy build scripts, here's how:
-
-The msvc\ folder contains two solutions with Visual C++ projects.
-Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
-are ready to build Google Test the same way you build any Visual
-Studio project. Files that have names ending with -md use DLL
-versions of Microsoft runtime libraries (the /MD or the /MDd compiler
-option). Files without that suffix use static versions of the runtime
-libraries (the /MT or the /MTd option). Please note that one must use
-the same option to compile both gtest and the test code. If you use
-Visual Studio 2005 or above, we recommend the -md version as /MD is
-the default for new projects in these versions of Visual Studio.
-
-On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
-Xcode. Build the "gtest" target. The universal binary framework will
-end up in your selected build directory (selected in the Xcode
-"Preferences..." -> "Building" pane and defaults to xcode/build).
-Alternatively, at the command line, enter:
-
- xcodebuild
-
-This will build the "Release" configuration of gtest.framework in your
-default build location. See the "xcodebuild" man page for more
-information about building different configurations and building in
-different locations.
-
-Tweaking Google Test
---------------------
-
-Google Test can be used in diverse environments. The default
-configuration may not work (or may not work well) out of the box in
-some environments. However, you can easily tweak Google Test by
-defining control macros on the compiler command line. Generally,
-these macros are named like GTEST_XYZ and you define them to either 1
-or 0 to enable or disable a certain feature.
-
-We list the most frequently used macros below. For a complete list,
-see file include/gtest/internal/gtest-port.h.
-
-### Choosing a TR1 Tuple Library ###
-
-Some Google Test features require the C++ Technical Report 1 (TR1)
-tuple library, which is not yet available with all compilers. The
-good news is that Google Test implements a subset of TR1 tuple that's
-enough for its own need, and will automatically use this when the
-compiler doesn't provide TR1 tuple.
-
-Usually you don't need to care about which tuple library Google Test
-uses. However, if your project already uses TR1 tuple, you need to
-tell Google Test to use the same TR1 tuple library the rest of your
-project uses, or the two tuple implementations will clash. To do
-that, add
-
- -DGTEST_USE_OWN_TR1_TUPLE=0
-
-to the compiler flags while compiling Google Test and your tests. If
-you want to force Google Test to use its own tuple library, just add
-
- -DGTEST_USE_OWN_TR1_TUPLE=1
-
-to the compiler flags instead.
-
-If you don't want Google Test to use tuple at all, add
-
- -DGTEST_HAS_TR1_TUPLE=0
-
-and all features using tuple will be disabled.
-
-### Multi-threaded Tests ###
-
-Google Test is thread-safe where the pthread library is available.
-After #include <gtest/gtest.h>, you can check the GTEST_IS_THREADSAFE
-macro to see whether this is the case (yes if the macro is #defined to
-1, no if it's undefined.).
-
-If Google Test doesn't correctly detect whether pthread is available
-in your environment, you can force it with
-
- -DGTEST_HAS_PTHREAD=1
-
-or
-
- -DGTEST_HAS_PTHREAD=0
-
-When Google Test uses pthread, you may need to add flags to your
-compiler and/or linker to select the pthread library, or you'll get
-link errors. If you use the CMake script or the deprecated Autotools
-script, this is taken care of for you. If you use your own build
-script, you'll need to read your compiler and linker's manual to
-figure out what flags to add.
-
-### As a Shared Library (DLL) ###
-
-Google Test is compact, so most users can build and link it as a
-static library for the simplicity. You can choose to use Google Test
-as a shared library (known as a DLL on Windows) if you prefer.
-
-To compile gtest as a shared library, add
-
- -DGTEST_CREATE_SHARED_LIBRARY=1
-
-to the compiler flags. You'll also need to tell the linker to produce
-a shared library instead - consult your linker's manual for how to do
-it.
-
-To compile your tests that use the gtest shared library, add
-
- -DGTEST_LINKED_AS_SHARED_LIBRARY=1
-
-to the compiler flags.
-
-### Avoiding Macro Name Clashes ###
-
-In C++, macros don't obey namespaces. Therefore two libraries that
-both define a macro of the same name will clash if you #include both
-definitions. In case a Google Test macro clashes with another
-library, you can force Google Test to rename its macro to avoid the
-conflict.
-
-Specifically, if both Google Test and some other code define macro
-FOO, you can add
-
- -DGTEST_DONT_DEFINE_FOO=1
-
-to the compiler flags to tell Google Test to change the macro's name
-from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
-For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
-
- GTEST_TEST(SomeTest, DoesThis) { ... }
-
-instead of
-
- TEST(SomeTest, DoesThis) { ... }
-
-in order to define a test.
-
-Upgrating from an Earlier Version
----------------------------------
-
-We strive to keep Google Test releases backward compatible.
-Sometimes, though, we have to make some breaking changes for the
-users' long-term benefits. This section describes what you'll need to
-do if you are upgrading from an earlier version of Google Test.
-
-### Upgrading from 1.3.0 or Earlier ###
-
-You may need to explicitly enable or disable Google Test's own TR1
-tuple library. See the instructions in section "Choosing a TR1 Tuple
-Library".
-
-### Upgrading from 1.4.0 or Earlier ###
-
-The Autotools build script (configure + make) is no longer officially
-supportted. You are encouraged to migrate to your own build system or
-use CMake. If you still need to use Autotools, you can find
-instructions in the README file from Google Test 1.4.0.
-
-On platforms where the pthread library is available, Google Test uses
-it in order to be thread-safe. See the "Multi-threaded Tests" section
-for what this means to your build script.
-
-If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
-Test will no longer compile. This should affect very few people, as a
-large portion of STL (including <string>) doesn't compile in this mode
-anyway. We decided to stop supporting it in order to greatly simplify
-Google Test's implementation.
-
-Developing Google Test
-----------------------
-
-This section discusses how to make your own changes to Google Test.
-
-### Testing Google Test Itself ###
-
-To make sure your changes work as intended and don't break existing
-functionality, you'll want to compile and run Google Test's own tests.
-For that you can use CMake:
-
- mkdir mybuild
- cd mybuild
- cmake -Dbuild_all_gtest_tests=ON ${GTEST_DIR}
-
-Make sure you have Python installed, as some of Google Test's tests
-are written in Python. If the cmake command complains about not being
-able to find Python ("Could NOT find PythonInterp (missing:
-PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
-executable can be found:
-
- cmake -DPYTHON_EXECUTABLE=path/to/python -Dbuild_all_gtest_tests=ON \
- ${GTEST_DIR}
-
-Next, you can build Google Test and all of its own tests. On *nix,
-this is usually done by 'make'. To run the tests, do
-
- make test
-
-All tests should pass.
-
-### Regenerating Source Files ###
-
-Some of Google Test's source files are generated from templates (not
-in the C++ sense) using a script. A template file is named FOO.pump,
-where FOO is the name of the file it will generate. For example, the
-file include/gtest/internal/gtest-type-util.h.pump is used to generate
-gtest-type-util.h in the same directory.
-
-Normally you don't need to worry about regenerating the source files,
-unless you need to modify them. In that case, you should modify the
-corresponding .pump files instead and run the pump.py Python script to
-regenerate them. You can find pump.py in the scripts/ directory.
-Read the Pump manual [2] for how to use it.
-
- [2] http://code.google.com/p/googletest/wiki/PumpManual
-
-### Contributing a Patch ###
-
-We welcome patches. Please read the Google Test developer's guide [3]
-for how you can contribute. In particular, make sure you have signed
-the Contributor License Agreement, or we won't be able to accept the
-patch.
-
- [3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
-
-Happy testing!
+++ /dev/null
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file defines the public API for Google Test. It should be
-// included by any test program that uses Google Test.
-//
-// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
-// leave some internal implementation details in this header file.
-// They are clearly marked by comments like this:
-//
-// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-//
-// Such code is NOT meant to be used by a user directly, and is subject
-// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
-// program!
-//
-// Acknowledgment: Google Test borrowed the idea of automatic test
-// registration from Barthelemy Dagenais' (barthelemy@prologique.com)
-// easyUnit framework.
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_H_
-
-#include <limits>
-#include <vector>
-
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file declares functions and macros used internally by
-// Google Test. They are subject to change without notice.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
-
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: wan@google.com (Zhanyong Wan)
-//
-// Low-level types and utilities for porting Google Test to various
-// platforms. They are subject to change without notice. DO NOT USE
-// THEM IN USER CODE.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
-
-// The user can define the following macros in the build script to
-// control Google Test's behavior. If the user doesn't define a macro
-// in this list, Google Test will define it.
-//
-// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2)
-// is/isn't available.
-// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions
-// are enabled.
-// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string
-// is/isn't available (some systems define
-// ::string, which is different to std::string).
-// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string
-// is/isn't available (some systems define
-// ::wstring, which is different to std::wstring).
-// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that <pthread.h>
-// is/isn't available.
-// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't
-// enabled.
-// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that
-// std::wstring does/doesn't work (Google Test can
-// be used where std::wstring is unavailable).
-// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple
-// is/isn't available.
-// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the
-// compiler supports Microsoft's "Structured
-// Exception Handling".
-// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google
-// Test's own tr1 tuple implementation should be
-// used. Unused when the user sets
-// GTEST_HAS_TR1_TUPLE to 0.
-// GTEST_LINKED_AS_SHARED_LIBRARY
-// - Define to 1 when compiling tests that use
-// Google Test as a shared library (known as
-// DLL on Windows).
-// GTEST_CREATE_SHARED_LIBRARY
-// - Define to 1 when compiling Google Test itself
-// as a shared library.
-
-// This header defines the following utilities:
-//
-// Macros indicating the current platform (defined to 1 if compiled on
-// the given platform; otherwise undefined):
-// GTEST_OS_AIX - IBM AIX
-// GTEST_OS_CYGWIN - Cygwin
-// GTEST_OS_LINUX - Linux
-// GTEST_OS_MAC - Mac OS X
-// GTEST_OS_SOLARIS - Sun Solaris
-// GTEST_OS_SYMBIAN - Symbian
-// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile)
-// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop
-// GTEST_OS_WINDOWS_MINGW - MinGW
-// GTEST_OS_WINDOWS_MOBILE - Windows Mobile
-// GTEST_OS_ZOS - z/OS
-//
-// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the
-// most stable support. Since core members of the Google Test project
-// don't have access to other platforms, support for them may be less
-// stable. If you notice any problems on your platform, please notify
-// googletestframework@googlegroups.com (patches for fixing them are
-// even more welcome!).
-//
-// Note that it is possible that none of the GTEST_OS_* macros are defined.
-//
-// Macros indicating available Google Test features (defined to 1 if
-// the corresponding feature is supported; otherwise undefined):
-// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized
-// tests)
-// GTEST_HAS_DEATH_TEST - death tests
-// GTEST_HAS_PARAM_TEST - value-parameterized tests
-// GTEST_HAS_TYPED_TEST - typed tests
-// GTEST_HAS_TYPED_TEST_P - type-parameterized tests
-// GTEST_USES_POSIX_RE - enhanced POSIX regex is used.
-// GTEST_USES_SIMPLE_RE - our own simple regex is used;
-// the above two are mutually exclusive.
-// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ().
-//
-// Macros for basic C++ coding:
-// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning.
-// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a
-// variable don't have to be used.
-// GTEST_DISALLOW_ASSIGN_ - disables operator=.
-// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=.
-// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used.
-//
-// Synchronization:
-// Mutex, MutexLock, ThreadLocal, GetThreadCount()
-// - synchronization primitives.
-// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above
-// synchronization primitives have real implementations
-// and Google Test is thread-safe; or 0 otherwise.
-//
-// Template meta programming:
-// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only.
-//
-// Smart pointers:
-// scoped_ptr - as in TR2.
-//
-// Regular expressions:
-// RE - a simple regular expression class using the POSIX
-// Extended Regular Expression syntax. Not available on
-// Windows.
-//
-// Logging:
-// GTEST_LOG_() - logs messages at the specified severity level.
-// LogToStderr() - directs all log messages to stderr.
-// FlushInfoLog() - flushes informational log messages.
-//
-// Stdout and stderr capturing:
-// CaptureStdout() - starts capturing stdout.
-// GetCapturedStdout() - stops capturing stdout and returns the captured
-// string.
-// CaptureStderr() - starts capturing stderr.
-// GetCapturedStderr() - stops capturing stderr and returns the captured
-// string.
-//
-// Integer types:
-// TypeWithSize - maps an integer to a int type.
-// Int32, UInt32, Int64, UInt64, TimeInMillis
-// - integers of known sizes.
-// BiggestInt - the biggest signed integer type.
-//
-// Command-line utilities:
-// GTEST_FLAG() - references a flag.
-// GTEST_DECLARE_*() - declares a flag.
-// GTEST_DEFINE_*() - defines a flag.
-// GetArgvs() - returns the command line as a vector of strings.
-//
-// Environment variable utilities:
-// GetEnv() - gets the value of an environment variable.
-// BoolFromGTestEnv() - parses a bool environment variable.
-// Int32FromGTestEnv() - parses an Int32 environment variable.
-// StringFromGTestEnv() - parses a string environment variable.
-
-#include <stddef.h> // For ptrdiff_t
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#ifndef _WIN32_WCE
-#include <sys/stat.h>
-#endif // !_WIN32_WCE
-
-#include <iostream> // NOLINT
-#include <sstream> // NOLINT
-#include <string> // NOLINT
-
-#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
-#define GTEST_FLAG_PREFIX_ "gtest_"
-#define GTEST_FLAG_PREFIX_DASH_ "gtest-"
-#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_"
-#define GTEST_NAME_ "Google Test"
-#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/"
-
-// Determines the version of gcc that is used to compile this.
-#ifdef __GNUC__
-// 40302 means version 4.3.2.
-#define GTEST_GCC_VER_ \
- (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__)
-#endif // __GNUC__
-
-// Determines the platform on which Google Test is compiled.
-#ifdef __CYGWIN__
-#define GTEST_OS_CYGWIN 1
-#elif defined __SYMBIAN32__
-#define GTEST_OS_SYMBIAN 1
-#elif defined _WIN32
-#define GTEST_OS_WINDOWS 1
-#ifdef _WIN32_WCE
-#define GTEST_OS_WINDOWS_MOBILE 1
-#elif defined(__MINGW__) || defined(__MINGW32__)
-#define GTEST_OS_WINDOWS_MINGW 1
-#else
-#define GTEST_OS_WINDOWS_DESKTOP 1
-#endif // _WIN32_WCE
-#elif defined __APPLE__
-#define GTEST_OS_MAC 1
-#elif defined __linux__
-#define GTEST_OS_LINUX 1
-#elif defined __MVS__
-#define GTEST_OS_ZOS 1
-#elif defined(__sun) && defined(__SVR4)
-#define GTEST_OS_SOLARIS 1
-#elif defined(_AIX)
-#define GTEST_OS_AIX 1
-#endif // __CYGWIN__
-
-#if GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_SYMBIAN || \
- GTEST_OS_SOLARIS || GTEST_OS_AIX
-
-// On some platforms, <regex.h> needs someone to define size_t, and
-// won't compile otherwise. We can #include it here as we already
-// included <stdlib.h>, which is guaranteed to define size_t through
-// <stddef.h>.
-#include <regex.h> // NOLINT
-#include <strings.h> // NOLINT
-#include <sys/types.h> // NOLINT
-#include <time.h> // NOLINT
-#include <unistd.h> // NOLINT
-
-#define GTEST_USES_POSIX_RE 1
-
-#elif GTEST_OS_WINDOWS
-
-#if !GTEST_OS_WINDOWS_MOBILE
-#include <direct.h> // NOLINT
-#include <io.h> // NOLINT
-#endif
-
-// <regex.h> is not available on Windows. Use our own simple regex
-// implementation instead.
-#define GTEST_USES_SIMPLE_RE 1
-
-#else
-
-// <regex.h> may not be available on this platform. Use our own
-// simple regex implementation instead.
-#define GTEST_USES_SIMPLE_RE 1
-
-#endif // GTEST_OS_CYGWIN || GTEST_OS_LINUX || GTEST_OS_MAC ||
- // GTEST_OS_SYMBIAN || GTEST_OS_SOLARIS || GTEST_OS_AIX
-
-#ifndef GTEST_HAS_EXCEPTIONS
-// The user didn't tell us whether exceptions are enabled, so we need
-// to figure it out.
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS
-// macro to enable exceptions, so we'll do the same.
-// Assumes that exceptions are enabled by default.
-#ifndef _HAS_EXCEPTIONS
-#define _HAS_EXCEPTIONS 1
-#endif // _HAS_EXCEPTIONS
-#define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS
-#elif defined(__GNUC__) && __EXCEPTIONS
-// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled.
-#define GTEST_HAS_EXCEPTIONS 1
-#elif defined(__SUNPRO_CC)
-// Sun Pro CC supports exceptions. However, there is no compile-time way of
-// detecting whether they are enabled or not. Therefore, we assume that
-// they are enabled unless the user tells us otherwise.
-#define GTEST_HAS_EXCEPTIONS 1
-#elif defined(__IBMCPP__) && __EXCEPTIONS
-// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled.
-#define GTEST_HAS_EXCEPTIONS 1
-#else
-// For other compilers, we assume exceptions are disabled to be
-// conservative.
-#define GTEST_HAS_EXCEPTIONS 0
-#endif // defined(_MSC_VER) || defined(__BORLANDC__)
-#endif // GTEST_HAS_EXCEPTIONS
-
-#if !defined(GTEST_HAS_STD_STRING)
-// Even though we don't use this macro any longer, we keep it in case
-// some clients still depend on it.
-#define GTEST_HAS_STD_STRING 1
-#elif !GTEST_HAS_STD_STRING
-// The user told us that ::std::string isn't available.
-#error "Google Test cannot be used where ::std::string isn't available."
-#endif // !defined(GTEST_HAS_STD_STRING)
-
-#ifndef GTEST_HAS_GLOBAL_STRING
-// The user didn't tell us whether ::string is available, so we need
-// to figure it out.
-
-#define GTEST_HAS_GLOBAL_STRING 0
-
-#endif // GTEST_HAS_GLOBAL_STRING
-
-#ifndef GTEST_HAS_STD_WSTRING
-// The user didn't tell us whether ::std::wstring is available, so we need
-// to figure it out.
-// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring
-// is available.
-
-// Cygwin 1.5 and below doesn't support ::std::wstring.
-// Cygwin 1.7 might add wstring support; this should be updated when clear.
-// Solaris' libc++ doesn't support it either.
-#define GTEST_HAS_STD_WSTRING (!(GTEST_OS_CYGWIN || GTEST_OS_SOLARIS))
-
-#endif // GTEST_HAS_STD_WSTRING
-
-#ifndef GTEST_HAS_GLOBAL_WSTRING
-// The user didn't tell us whether ::wstring is available, so we need
-// to figure it out.
-#define GTEST_HAS_GLOBAL_WSTRING \
- (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING)
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-// Determines whether RTTI is available.
-#ifndef GTEST_HAS_RTTI
-// The user didn't tell us whether RTTI is enabled, so we need to
-// figure it out.
-
-#ifdef _MSC_VER
-
-#ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled.
-#define GTEST_HAS_RTTI 1
-#else
-#define GTEST_HAS_RTTI 0
-#endif
-
-// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled.
-#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302)
-
-#ifdef __GXX_RTTI
-#define GTEST_HAS_RTTI 1
-#else
-#define GTEST_HAS_RTTI 0
-#endif // __GXX_RTTI
-
-// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if
-// both the typeid and dynamic_cast features are present.
-#elif defined(__IBMCPP__) && (__IBMCPP__ >= 900)
-
-#ifdef __RTTI_ALL__
-#define GTEST_HAS_RTTI 1
-#else
-#define GTEST_HAS_RTTI 0
-#endif
-
-#else
-
-// For all other compilers, we assume RTTI is enabled.
-#define GTEST_HAS_RTTI 1
-
-#endif // _MSC_VER
-
-#endif // GTEST_HAS_RTTI
-
-// It's this header's responsibility to #include <typeinfo> when RTTI
-// is enabled.
-#if GTEST_HAS_RTTI
-#include <typeinfo>
-#endif
-
-// Determines whether Google Test can use the pthreads library.
-#ifndef GTEST_HAS_PTHREAD
-// The user didn't tell us explicitly, so we assume pthreads support is
-// available on Linux and Mac.
-//
-// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0
-// to your compiler flags.
-#define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC)
-#endif // GTEST_HAS_PTHREAD
-
-// Determines whether Google Test can use tr1/tuple. You can define
-// this macro to 0 to prevent Google Test from using tuple (any
-// feature depending on tuple with be disabled in this mode).
-#ifndef GTEST_HAS_TR1_TUPLE
-// The user didn't tell us not to do it, so we assume it's OK.
-#define GTEST_HAS_TR1_TUPLE 1
-#endif // GTEST_HAS_TR1_TUPLE
-
-// Determines whether Google Test's own tr1 tuple implementation
-// should be used.
-#ifndef GTEST_USE_OWN_TR1_TUPLE
-// The user didn't tell us, so we need to figure it out.
-
-// We use our own TR1 tuple if we aren't sure the user has an
-// implementation of it already. At this time, GCC 4.0.0+ and MSVC
-// 2010 are the only mainstream compilers that come with a TR1 tuple
-// implementation. NVIDIA's CUDA NVCC compiler pretends to be GCC by
-// defining __GNUC__ and friends, but cannot compile GCC's tuple
-// implementation. MSVC 2008 (9.0) provides TR1 tuple in a 323 MB
-// Feature Pack download, which we cannot assume the user has.
-#if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000)) \
- || _MSC_VER >= 1600
-#define GTEST_USE_OWN_TR1_TUPLE 0
-#else
-#define GTEST_USE_OWN_TR1_TUPLE 1
-#endif
-
-#endif // GTEST_USE_OWN_TR1_TUPLE
-
-// To avoid conditional compilation everywhere, we make it
-// gtest-port.h's responsibility to #include the header implementing
-// tr1/tuple.
-#if GTEST_HAS_TR1_TUPLE
-
-#if GTEST_USE_OWN_TR1_TUPLE
-// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
-
-// Copyright 2009 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
-
-#include <utility> // For ::std::pair.
-
-// The compiler used in Symbian has a bug that prevents us from declaring the
-// tuple template as a friend (it complains that tuple is redefined). This
-// hack bypasses the bug by declaring the members that should otherwise be
-// private as public.
-// Sun Studio versions < 12 also have the above bug.
-#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
-#define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
-#else
-#define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
- template <GTEST_10_TYPENAMES_(U)> friend class tuple; \
- private:
-#endif
-
-// GTEST_n_TUPLE_(T) is the type of an n-tuple.
-#define GTEST_0_TUPLE_(T) tuple<>
-#define GTEST_1_TUPLE_(T) tuple<T##0, void, void, void, void, void, void, \
- void, void, void>
-#define GTEST_2_TUPLE_(T) tuple<T##0, T##1, void, void, void, void, void, \
- void, void, void>
-#define GTEST_3_TUPLE_(T) tuple<T##0, T##1, T##2, void, void, void, void, \
- void, void, void>
-#define GTEST_4_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, void, void, void, \
- void, void, void>
-#define GTEST_5_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, void, void, \
- void, void, void>
-#define GTEST_6_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, void, \
- void, void, void>
-#define GTEST_7_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- void, void, void>
-#define GTEST_8_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, void, void>
-#define GTEST_9_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, T##8, void>
-#define GTEST_10_TUPLE_(T) tuple<T##0, T##1, T##2, T##3, T##4, T##5, T##6, \
- T##7, T##8, T##9>
-
-// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
-#define GTEST_0_TYPENAMES_(T)
-#define GTEST_1_TYPENAMES_(T) typename T##0
-#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1
-#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2
-#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3
-#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4
-#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5
-#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6
-#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, typename T##7
-#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, \
- typename T##7, typename T##8
-#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \
- typename T##3, typename T##4, typename T##5, typename T##6, \
- typename T##7, typename T##8, typename T##9
-
-// In theory, defining stuff in the ::std namespace is undefined
-// behavior. We can do this as we are playing the role of a standard
-// library vendor.
-namespace std {
-namespace tr1 {
-
-template <typename T0 = void, typename T1 = void, typename T2 = void,
- typename T3 = void, typename T4 = void, typename T5 = void,
- typename T6 = void, typename T7 = void, typename T8 = void,
- typename T9 = void>
-class tuple;
-
-// Anything in namespace gtest_internal is Google Test's INTERNAL
-// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
-namespace gtest_internal {
-
-// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
-template <typename T>
-struct ByRef { typedef const T& type; }; // NOLINT
-template <typename T>
-struct ByRef<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper for ByRef.
-#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
-
-// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
-// is the same as tr1::add_reference<T>::type.
-template <typename T>
-struct AddRef { typedef T& type; }; // NOLINT
-template <typename T>
-struct AddRef<T&> { typedef T& type; }; // NOLINT
-
-// A handy wrapper for AddRef.
-#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
-
-// A helper for implementing get<k>().
-template <int k> class Get;
-
-// A helper for implementing tuple_element<k, T>. kIndexValid is true
-// iff k < the number of fields in tuple type T.
-template <bool kIndexValid, int kIndex, class Tuple>
-struct TupleElement;
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 0, GTEST_10_TUPLE_(T)> { typedef T0 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 1, GTEST_10_TUPLE_(T)> { typedef T1 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 2, GTEST_10_TUPLE_(T)> { typedef T2 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 3, GTEST_10_TUPLE_(T)> { typedef T3 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 4, GTEST_10_TUPLE_(T)> { typedef T4 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 5, GTEST_10_TUPLE_(T)> { typedef T5 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 6, GTEST_10_TUPLE_(T)> { typedef T6 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 7, GTEST_10_TUPLE_(T)> { typedef T7 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 8, GTEST_10_TUPLE_(T)> { typedef T8 type; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct TupleElement<true, 9, GTEST_10_TUPLE_(T)> { typedef T9 type; };
-
-} // namespace gtest_internal
-
-template <>
-class tuple<> {
- public:
- tuple() {}
- tuple(const tuple& /* t */) {}
- tuple& operator=(const tuple& /* t */) { return *this; }
-};
-
-template <GTEST_1_TYPENAMES_(T)>
-class GTEST_1_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {}
-
- tuple(const tuple& t) : f0_(t.f0_) {}
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple& operator=(const GTEST_1_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_1_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) {
- f0_ = t.f0_;
- return *this;
- }
-
- T0 f0_;
-};
-
-template <GTEST_2_TYPENAMES_(T)>
-class GTEST_2_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0),
- f1_(f1) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {}
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {}
- template <typename U0, typename U1>
- tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple& operator=(const GTEST_2_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
- template <typename U0, typename U1>
- tuple& operator=(const ::std::pair<U0, U1>& p) {
- f0_ = p.first;
- f1_ = p.second;
- return *this;
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_2_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
-};
-
-template <GTEST_3_TYPENAMES_(T)>
-class GTEST_3_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple& operator=(const GTEST_3_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_3_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
-};
-
-template <GTEST_4_TYPENAMES_(T)>
-class GTEST_4_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {}
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple& operator=(const GTEST_4_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_4_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
-};
-
-template <GTEST_5_TYPENAMES_(T)>
-class GTEST_5_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3,
- GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_) {}
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple& operator=(const GTEST_5_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_5_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
-};
-
-template <GTEST_6_TYPENAMES_(T)>
-class GTEST_6_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_) {}
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple& operator=(const GTEST_6_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_6_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
-};
-
-template <GTEST_7_TYPENAMES_(T)>
-class GTEST_7_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3), f4_(f4), f5_(f5), f6_(f6) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple& operator=(const GTEST_7_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_7_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
-};
-
-template <GTEST_8_TYPENAMES_(T)>
-class GTEST_8_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6,
- GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5), f6_(f6), f7_(f7) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple& operator=(const GTEST_8_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_8_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
-};
-
-template <GTEST_9_TYPENAMES_(T)>
-class GTEST_9_TUPLE_(T) {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
- GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4),
- f5_(f5), f6_(f6), f7_(f7), f8_(f8) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple& operator=(const GTEST_9_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_9_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- f8_ = t.f8_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
- T8 f8_;
-};
-
-template <GTEST_10_TYPENAMES_(T)>
-class tuple {
- public:
- template <int k> friend class gtest_internal::Get;
-
- tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(),
- f9_() {}
-
- explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1,
- GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4,
- GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7,
- GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2),
- f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {}
-
- tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_),
- f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {}
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_),
- f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_),
- f9_(t.f9_) {}
-
- tuple& operator=(const tuple& t) { return CopyFrom(t); }
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple& operator=(const GTEST_10_TUPLE_(U)& t) {
- return CopyFrom(t);
- }
-
- GTEST_DECLARE_TUPLE_AS_FRIEND_
-
- template <GTEST_10_TYPENAMES_(U)>
- tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) {
- f0_ = t.f0_;
- f1_ = t.f1_;
- f2_ = t.f2_;
- f3_ = t.f3_;
- f4_ = t.f4_;
- f5_ = t.f5_;
- f6_ = t.f6_;
- f7_ = t.f7_;
- f8_ = t.f8_;
- f9_ = t.f9_;
- return *this;
- }
-
- T0 f0_;
- T1 f1_;
- T2 f2_;
- T3 f3_;
- T4 f4_;
- T5 f5_;
- T6 f6_;
- T7 f7_;
- T8 f8_;
- T9 f9_;
-};
-
-// 6.1.3.2 Tuple creation functions.
-
-// Known limitations: we don't support passing an
-// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
-// implement tie().
-
-inline tuple<> make_tuple() { return tuple<>(); }
-
-template <GTEST_1_TYPENAMES_(T)>
-inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) {
- return GTEST_1_TUPLE_(T)(f0);
-}
-
-template <GTEST_2_TYPENAMES_(T)>
-inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) {
- return GTEST_2_TUPLE_(T)(f0, f1);
-}
-
-template <GTEST_3_TYPENAMES_(T)>
-inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) {
- return GTEST_3_TUPLE_(T)(f0, f1, f2);
-}
-
-template <GTEST_4_TYPENAMES_(T)>
-inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3) {
- return GTEST_4_TUPLE_(T)(f0, f1, f2, f3);
-}
-
-template <GTEST_5_TYPENAMES_(T)>
-inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4) {
- return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4);
-}
-
-template <GTEST_6_TYPENAMES_(T)>
-inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5) {
- return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5);
-}
-
-template <GTEST_7_TYPENAMES_(T)>
-inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6) {
- return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6);
-}
-
-template <GTEST_8_TYPENAMES_(T)>
-inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) {
- return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7);
-}
-
-template <GTEST_9_TYPENAMES_(T)>
-inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
- const T8& f8) {
- return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8);
-}
-
-template <GTEST_10_TYPENAMES_(T)>
-inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2,
- const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7,
- const T8& f8, const T9& f9) {
- return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);
-}
-
-// 6.1.3.3 Tuple helper classes.
-
-template <typename Tuple> struct tuple_size;
-
-template <GTEST_0_TYPENAMES_(T)>
-struct tuple_size<GTEST_0_TUPLE_(T)> { static const int value = 0; };
-
-template <GTEST_1_TYPENAMES_(T)>
-struct tuple_size<GTEST_1_TUPLE_(T)> { static const int value = 1; };
-
-template <GTEST_2_TYPENAMES_(T)>
-struct tuple_size<GTEST_2_TUPLE_(T)> { static const int value = 2; };
-
-template <GTEST_3_TYPENAMES_(T)>
-struct tuple_size<GTEST_3_TUPLE_(T)> { static const int value = 3; };
-
-template <GTEST_4_TYPENAMES_(T)>
-struct tuple_size<GTEST_4_TUPLE_(T)> { static const int value = 4; };
-
-template <GTEST_5_TYPENAMES_(T)>
-struct tuple_size<GTEST_5_TUPLE_(T)> { static const int value = 5; };
-
-template <GTEST_6_TYPENAMES_(T)>
-struct tuple_size<GTEST_6_TUPLE_(T)> { static const int value = 6; };
-
-template <GTEST_7_TYPENAMES_(T)>
-struct tuple_size<GTEST_7_TUPLE_(T)> { static const int value = 7; };
-
-template <GTEST_8_TYPENAMES_(T)>
-struct tuple_size<GTEST_8_TUPLE_(T)> { static const int value = 8; };
-
-template <GTEST_9_TYPENAMES_(T)>
-struct tuple_size<GTEST_9_TUPLE_(T)> { static const int value = 9; };
-
-template <GTEST_10_TYPENAMES_(T)>
-struct tuple_size<GTEST_10_TUPLE_(T)> { static const int value = 10; };
-
-template <int k, class Tuple>
-struct tuple_element {
- typedef typename gtest_internal::TupleElement<
- k < (tuple_size<Tuple>::value), k, Tuple>::type type;
-};
-
-#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
-
-// 6.1.3.4 Element access.
-
-namespace gtest_internal {
-
-template <>
-class Get<0> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
- Field(Tuple& t) { return t.f0_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple))
- ConstField(const Tuple& t) { return t.f0_; }
-};
-
-template <>
-class Get<1> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
- Field(Tuple& t) { return t.f1_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple))
- ConstField(const Tuple& t) { return t.f1_; }
-};
-
-template <>
-class Get<2> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
- Field(Tuple& t) { return t.f2_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple))
- ConstField(const Tuple& t) { return t.f2_; }
-};
-
-template <>
-class Get<3> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
- Field(Tuple& t) { return t.f3_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple))
- ConstField(const Tuple& t) { return t.f3_; }
-};
-
-template <>
-class Get<4> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
- Field(Tuple& t) { return t.f4_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple))
- ConstField(const Tuple& t) { return t.f4_; }
-};
-
-template <>
-class Get<5> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
- Field(Tuple& t) { return t.f5_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple))
- ConstField(const Tuple& t) { return t.f5_; }
-};
-
-template <>
-class Get<6> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
- Field(Tuple& t) { return t.f6_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple))
- ConstField(const Tuple& t) { return t.f6_; }
-};
-
-template <>
-class Get<7> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
- Field(Tuple& t) { return t.f7_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple))
- ConstField(const Tuple& t) { return t.f7_; }
-};
-
-template <>
-class Get<8> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
- Field(Tuple& t) { return t.f8_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple))
- ConstField(const Tuple& t) { return t.f8_; }
-};
-
-template <>
-class Get<9> {
- public:
- template <class Tuple>
- static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
- Field(Tuple& t) { return t.f9_; } // NOLINT
-
- template <class Tuple>
- static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple))
- ConstField(const Tuple& t) { return t.f9_; }
-};
-
-} // namespace gtest_internal
-
-template <int k, GTEST_10_TYPENAMES_(T)>
-GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
-get(GTEST_10_TUPLE_(T)& t) {
- return gtest_internal::Get<k>::Field(t);
-}
-
-template <int k, GTEST_10_TYPENAMES_(T)>
-GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T)))
-get(const GTEST_10_TUPLE_(T)& t) {
- return gtest_internal::Get<k>::ConstField(t);
-}
-
-// 6.1.3.5 Relational operators
-
-// We only implement == and !=, as we don't have a need for the rest yet.
-
-namespace gtest_internal {
-
-// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
-// first k fields of t1 equals the first k fields of t2.
-// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
-// k1 != k2.
-template <int kSize1, int kSize2>
-struct SameSizeTuplePrefixComparator;
-
-template <>
-struct SameSizeTuplePrefixComparator<0, 0> {
- template <class Tuple1, class Tuple2>
- static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
- return true;
- }
-};
-
-template <int k>
-struct SameSizeTuplePrefixComparator<k, k> {
- template <class Tuple1, class Tuple2>
- static bool Eq(const Tuple1& t1, const Tuple2& t2) {
- return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
- ::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
- }
-};
-
-} // namespace gtest_internal
-
-template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
-inline bool operator==(const GTEST_10_TUPLE_(T)& t,
- const GTEST_10_TUPLE_(U)& u) {
- return gtest_internal::SameSizeTuplePrefixComparator<
- tuple_size<GTEST_10_TUPLE_(T)>::value,
- tuple_size<GTEST_10_TUPLE_(U)>::value>::Eq(t, u);
-}
-
-template <GTEST_10_TYPENAMES_(T), GTEST_10_TYPENAMES_(U)>
-inline bool operator!=(const GTEST_10_TUPLE_(T)& t,
- const GTEST_10_TUPLE_(U)& u) { return !(t == u); }
-
-// 6.1.4 Pairs.
-// Unimplemented.
-
-} // namespace tr1
-} // namespace std
-
-#undef GTEST_0_TUPLE_
-#undef GTEST_1_TUPLE_
-#undef GTEST_2_TUPLE_
-#undef GTEST_3_TUPLE_
-#undef GTEST_4_TUPLE_
-#undef GTEST_5_TUPLE_
-#undef GTEST_6_TUPLE_
-#undef GTEST_7_TUPLE_
-#undef GTEST_8_TUPLE_
-#undef GTEST_9_TUPLE_
-#undef GTEST_10_TUPLE_
-
-#undef GTEST_0_TYPENAMES_
-#undef GTEST_1_TYPENAMES_
-#undef GTEST_2_TYPENAMES_
-#undef GTEST_3_TYPENAMES_
-#undef GTEST_4_TYPENAMES_
-#undef GTEST_5_TYPENAMES_
-#undef GTEST_6_TYPENAMES_
-#undef GTEST_7_TYPENAMES_
-#undef GTEST_8_TYPENAMES_
-#undef GTEST_9_TYPENAMES_
-#undef GTEST_10_TYPENAMES_
-
-#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
-#undef GTEST_BY_REF_
-#undef GTEST_ADD_REF_
-#undef GTEST_TUPLE_ELEMENT_
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
-#elif GTEST_OS_SYMBIAN
-
-// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to
-// use STLport's tuple implementation, which unfortunately doesn't
-// work as the copy of STLport distributed with Symbian is incomplete.
-// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to
-// use its own tuple implementation.
-#ifdef BOOST_HAS_TR1_TUPLE
-#undef BOOST_HAS_TR1_TUPLE
-#endif // BOOST_HAS_TR1_TUPLE
-
-// This prevents <boost/tr1/detail/config.hpp>, which defines
-// BOOST_HAS_TR1_TUPLE, from being #included by Boost's <tuple>.
-#define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED
-#include <tuple>
-
-#elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000)
-// GCC 4.0+ implements tr1/tuple in the <tr1/tuple> header. This does
-// not conform to the TR1 spec, which requires the header to be <tuple>.
-
-#if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
-// Until version 4.3.2, gcc has a bug that causes <tr1/functional>,
-// which is #included by <tr1/tuple>, to not compile when RTTI is
-// disabled. _TR1_FUNCTIONAL is the header guard for
-// <tr1/functional>. Hence the following #define is a hack to prevent
-// <tr1/functional> from being included.
-#define _TR1_FUNCTIONAL 1
-#include <tr1/tuple>
-#undef _TR1_FUNCTIONAL // Allows the user to #include
- // <tr1/functional> if he chooses to.
-#else
-#include <tr1/tuple> // NOLINT
-#endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302
-
-#else
-// If the compiler is not GCC 4.0+, we assume the user is using a
-// spec-conforming TR1 implementation.
-#include <tuple> // NOLINT
-#endif // GTEST_USE_OWN_TR1_TUPLE
-
-#endif // GTEST_HAS_TR1_TUPLE
-
-// Determines whether clone(2) is supported.
-// Usually it will only be available on Linux, excluding
-// Linux on the Itanium architecture.
-// Also see http://linux.die.net/man/2/clone.
-#ifndef GTEST_HAS_CLONE
-// The user didn't tell us, so we need to figure it out.
-
-#if GTEST_OS_LINUX && !defined(__ia64__)
-#define GTEST_HAS_CLONE 1
-#else
-#define GTEST_HAS_CLONE 0
-#endif // GTEST_OS_LINUX && !defined(__ia64__)
-
-#endif // GTEST_HAS_CLONE
-
-// Determines whether to support stream redirection. This is used to test
-// output correctness and to implement death tests.
-#if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
-#define GTEST_HAS_STREAM_REDIRECTION_ 1
-#endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN
-
-// Determines whether to support death tests.
-// Google Test does not support death tests for VC 7.1 and earlier as
-// abort() in a VC 7.1 application compiled as GUI in debug config
-// pops up a dialog window that cannot be suppressed programmatically.
-#if (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \
- (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \
- GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX)
-#define GTEST_HAS_DEATH_TEST 1
-#include <vector> // NOLINT
-#endif
-
-// We don't support MSVC 7.1 with exceptions disabled now. Therefore
-// all the compilers we care about are adequate for supporting
-// value-parameterized tests.
-#define GTEST_HAS_PARAM_TEST 1
-
-// Determines whether to support type-driven tests.
-
-// Typed tests need <typeinfo> and variadic macros, which GCC, VC++ 8.0,
-// Sun Pro CC, and IBM Visual Age support.
-#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \
- defined(__IBMCPP__)
-#define GTEST_HAS_TYPED_TEST 1
-#define GTEST_HAS_TYPED_TEST_P 1
-#endif
-
-// Determines whether to support Combine(). This only makes sense when
-// value-parameterized tests are enabled. The implementation doesn't
-// work on Sun Studio since it doesn't understand templated conversion
-// operators.
-#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC)
-#define GTEST_HAS_COMBINE 1
-#endif
-
-// Determines whether the system compiler uses UTF-16 for encoding wide strings.
-#define GTEST_WIDE_STRING_USES_UTF16_ \
- (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX)
-
-// Defines some utility macros.
-
-// The GNU compiler emits a warning if nested "if" statements are followed by
-// an "else" statement and braces are not used to explicitly disambiguate the
-// "else" binding. This leads to problems with code like:
-//
-// if (gate)
-// ASSERT_*(condition) << "Some message";
-//
-// The "switch (0) case 0:" idiom is used to suppress this.
-#ifdef __INTEL_COMPILER
-#define GTEST_AMBIGUOUS_ELSE_BLOCKER_
-#else
-#define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: // NOLINT
-#endif
-
-// Use this annotation at the end of a struct/class definition to
-// prevent the compiler from optimizing away instances that are never
-// used. This is useful when all interesting logic happens inside the
-// c'tor and / or d'tor. Example:
-//
-// struct Foo {
-// Foo() { ... }
-// } GTEST_ATTRIBUTE_UNUSED_;
-//
-// Also use it after a variable or parameter declaration to tell the
-// compiler the variable/parameter does not have to be used.
-#if defined(__GNUC__) && !defined(COMPILER_ICC)
-#define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused))
-#else
-#define GTEST_ATTRIBUTE_UNUSED_
-#endif
-
-// A macro to disallow operator=
-// This should be used in the private: declarations for a class.
-#define GTEST_DISALLOW_ASSIGN_(type)\
- void operator=(type const &)
-
-// A macro to disallow copy constructor and operator=
-// This should be used in the private: declarations for a class.
-#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\
- type(type const &);\
- GTEST_DISALLOW_ASSIGN_(type)
-
-// Tell the compiler to warn about unused return values for functions declared
-// with this macro. The macro should be used on function declarations
-// following the argument list:
-//
-// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_;
-#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC)
-#define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result))
-#else
-#define GTEST_MUST_USE_RESULT_
-#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC
-
-// Determine whether the compiler supports Microsoft's Structured Exception
-// Handling. This is supported by several Windows compilers but generally
-// does not exist on any other system.
-#ifndef GTEST_HAS_SEH
-// The user didn't tell us, so we need to figure it out.
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-// These two compilers are known to support SEH.
-#define GTEST_HAS_SEH 1
-#else
-// Assume no SEH.
-#define GTEST_HAS_SEH 0
-#endif
-
-#endif // GTEST_HAS_SEH
-
-#ifdef _MSC_VER
-
-#if GTEST_LINKED_AS_SHARED_LIBRARY
-#define GTEST_API_ __declspec(dllimport)
-#elif GTEST_CREATE_SHARED_LIBRARY
-#define GTEST_API_ __declspec(dllexport)
-#endif
-
-#endif // _MSC_VER
-
-#ifndef GTEST_API_
-#define GTEST_API_
-#endif
-
-namespace testing {
-
-class Message;
-
-namespace internal {
-
-class String;
-
-typedef ::std::stringstream StrStream;
-
-// A helper for suppressing warnings on constant condition. It just
-// returns 'condition'.
-GTEST_API_ bool IsTrue(bool condition);
-
-// Defines scoped_ptr.
-
-// This implementation of scoped_ptr is PARTIAL - it only contains
-// enough stuff to satisfy Google Test's need.
-template <typename T>
-class scoped_ptr {
- public:
- typedef T element_type;
-
- explicit scoped_ptr(T* p = NULL) : ptr_(p) {}
- ~scoped_ptr() { reset(); }
-
- T& operator*() const { return *ptr_; }
- T* operator->() const { return ptr_; }
- T* get() const { return ptr_; }
-
- T* release() {
- T* const ptr = ptr_;
- ptr_ = NULL;
- return ptr;
- }
-
- void reset(T* p = NULL) {
- if (p != ptr_) {
- if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type.
- delete ptr_;
- }
- ptr_ = p;
- }
- }
- private:
- T* ptr_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr);
-};
-
-// Defines RE.
-
-// A simple C++ wrapper for <regex.h>. It uses the POSIX Extended
-// Regular Expression syntax.
-class GTEST_API_ RE {
- public:
- // A copy constructor is required by the Standard to initialize object
- // references from r-values.
- RE(const RE& other) { Init(other.pattern()); }
-
- // Constructs an RE from a string.
- RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT
-
-#if GTEST_HAS_GLOBAL_STRING
- RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT
-#endif // GTEST_HAS_GLOBAL_STRING
-
- RE(const char* regex) { Init(regex); } // NOLINT
- ~RE();
-
- // Returns the string representation of the regex.
- const char* pattern() const { return pattern_; }
-
- // FullMatch(str, re) returns true iff regular expression re matches
- // the entire str.
- // PartialMatch(str, re) returns true iff regular expression re
- // matches a substring of str (including str itself).
- //
- // TODO(wan@google.com): make FullMatch() and PartialMatch() work
- // when str contains NUL characters.
- static bool FullMatch(const ::std::string& str, const RE& re) {
- return FullMatch(str.c_str(), re);
- }
- static bool PartialMatch(const ::std::string& str, const RE& re) {
- return PartialMatch(str.c_str(), re);
- }
-
-#if GTEST_HAS_GLOBAL_STRING
- static bool FullMatch(const ::string& str, const RE& re) {
- return FullMatch(str.c_str(), re);
- }
- static bool PartialMatch(const ::string& str, const RE& re) {
- return PartialMatch(str.c_str(), re);
- }
-#endif // GTEST_HAS_GLOBAL_STRING
-
- static bool FullMatch(const char* str, const RE& re);
- static bool PartialMatch(const char* str, const RE& re);
-
- private:
- void Init(const char* regex);
-
- // We use a const char* instead of a string, as Google Test may be used
- // where string is not available. We also do not use Google Test's own
- // String type here, in order to simplify dependencies between the
- // files.
- const char* pattern_;
- bool is_valid_;
-#if GTEST_USES_POSIX_RE
- regex_t full_regex_; // For FullMatch().
- regex_t partial_regex_; // For PartialMatch().
-#else // GTEST_USES_SIMPLE_RE
- const char* full_pattern_; // For FullMatch();
-#endif
-
- GTEST_DISALLOW_ASSIGN_(RE);
-};
-
-// Defines logging utilities:
-// GTEST_LOG_(severity) - logs messages at the specified severity level. The
-// message itself is streamed into the macro.
-// LogToStderr() - directs all log messages to stderr.
-// FlushInfoLog() - flushes informational log messages.
-
-enum GTestLogSeverity {
- GTEST_INFO,
- GTEST_WARNING,
- GTEST_ERROR,
- GTEST_FATAL
-};
-
-// Formats log entry severity, provides a stream object for streaming the
-// log message, and terminates the message with a newline when going out of
-// scope.
-class GTEST_API_ GTestLog {
- public:
- GTestLog(GTestLogSeverity severity, const char* file, int line);
-
- // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
- ~GTestLog();
-
- ::std::ostream& GetStream() { return ::std::cerr; }
-
- private:
- const GTestLogSeverity severity_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog);
-};
-
-#define GTEST_LOG_(severity) \
- ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \
- __FILE__, __LINE__).GetStream()
-
-inline void LogToStderr() {}
-inline void FlushInfoLog() { fflush(NULL); }
-
-// INTERNAL IMPLEMENTATION - DO NOT USE.
-//
-// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition
-// is not satisfied.
-// Synopsys:
-// GTEST_CHECK_(boolean_condition);
-// or
-// GTEST_CHECK_(boolean_condition) << "Additional message";
-//
-// This checks the condition and if the condition is not satisfied
-// it prints message about the condition violation, including the
-// condition itself, plus additional message streamed into it, if any,
-// and then it aborts the program. It aborts the program irrespective of
-// whether it is built in the debug mode or not.
-#define GTEST_CHECK_(condition) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (::testing::internal::IsTrue(condition)) \
- ; \
- else \
- GTEST_LOG_(FATAL) << "Condition " #condition " failed. "
-
-// An all-mode assert to verify that the given POSIX-style function
-// call returns 0 (indicating success). Known limitation: this
-// doesn't expand to a balanced 'if' statement, so enclose the macro
-// in {} if you need to use it as the only statement in an 'if'
-// branch.
-#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \
- if (const int gtest_error = (posix_call)) \
- GTEST_LOG_(FATAL) << #posix_call << "failed with error " \
- << gtest_error
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Downcasts the pointer of type Base to Derived.
-// Derived must be a subclass of Base. The parameter MUST
-// point to a class of type Derived, not any subclass of it.
-// When RTTI is available, the function performs a runtime
-// check to enforce this.
-template <class Derived, class Base>
-Derived* CheckedDowncastToActualType(Base* base) {
-#if GTEST_HAS_RTTI
- GTEST_CHECK_(typeid(*base) == typeid(Derived));
- return dynamic_cast<Derived*>(base); // NOLINT
-#else
- return static_cast<Derived*>(base); // Poor man's downcast.
-#endif
-}
-
-#if GTEST_HAS_STREAM_REDIRECTION_
-
-// Defines the stderr capturer:
-// CaptureStdout - starts capturing stdout.
-// GetCapturedStdout - stops capturing stdout and returns the captured string.
-// CaptureStderr - starts capturing stderr.
-// GetCapturedStderr - stops capturing stderr and returns the captured string.
-//
-GTEST_API_ void CaptureStdout();
-GTEST_API_ String GetCapturedStdout();
-GTEST_API_ void CaptureStderr();
-GTEST_API_ String GetCapturedStderr();
-
-#endif // GTEST_HAS_STREAM_REDIRECTION_
-
-
-#if GTEST_HAS_DEATH_TEST
-
-// A copy of all command line arguments. Set by InitGoogleTest().
-extern ::std::vector<String> g_argvs;
-
-// GTEST_HAS_DEATH_TEST implies we have ::std::string.
-const ::std::vector<String>& GetArgvs();
-
-#endif // GTEST_HAS_DEATH_TEST
-
-// Defines synchronization primitives.
-
-#if GTEST_HAS_PTHREAD
-
-// Sleeps for (roughly) n milli-seconds. This function is only for
-// testing Google Test's own constructs. Don't use it in user tests,
-// either directly or indirectly.
-inline void SleepMilliseconds(int n) {
- const timespec time = {
- 0, // 0 seconds.
- n * 1000L * 1000L, // And n ms.
- };
- nanosleep(&time, NULL);
-}
-
-// Allows a controller thread to pause execution of newly created
-// threads until notified. Instances of this class must be created
-// and destroyed in the controller thread.
-//
-// This class is only for testing Google Test's own constructs. Do not
-// use it in user tests, either directly or indirectly.
-class Notification {
- public:
- Notification() : notified_(false) {}
-
- // Notifies all threads created with this notification to start. Must
- // be called from the controller thread.
- void Notify() { notified_ = true; }
-
- // Blocks until the controller thread notifies. Must be called from a test
- // thread.
- void WaitForNotification() {
- while(!notified_) {
- SleepMilliseconds(10);
- }
- }
-
- private:
- volatile bool notified_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification);
-};
-
-// As a C-function, ThreadFuncWithCLinkage cannot be templated itself.
-// Consequently, it cannot select a correct instantiation of ThreadWithParam
-// in order to call its Run(). Introducing ThreadWithParamBase as a
-// non-templated base class for ThreadWithParam allows us to bypass this
-// problem.
-class ThreadWithParamBase {
- public:
- virtual ~ThreadWithParamBase() {}
- virtual void Run() = 0;
-};
-
-// pthread_create() accepts a pointer to a function type with the C linkage.
-// According to the Standard (7.5/1), function types with different linkages
-// are different even if they are otherwise identical. Some compilers (for
-// example, SunStudio) treat them as different types. Since class methods
-// cannot be defined with C-linkage we need to define a free C-function to
-// pass into pthread_create().
-extern "C" inline void* ThreadFuncWithCLinkage(void* thread) {
- static_cast<ThreadWithParamBase*>(thread)->Run();
- return NULL;
-}
-
-// Helper class for testing Google Test's multi-threading constructs.
-// To use it, write:
-//
-// void ThreadFunc(int param) { /* Do things with param */ }
-// Notification thread_can_start;
-// ...
-// // The thread_can_start parameter is optional; you can supply NULL.
-// ThreadWithParam<int> thread(&ThreadFunc, 5, &thread_can_start);
-// thread_can_start.Notify();
-//
-// These classes are only for testing Google Test's own constructs. Do
-// not use them in user tests, either directly or indirectly.
-template <typename T>
-class ThreadWithParam : public ThreadWithParamBase {
- public:
- typedef void (*UserThreadFunc)(T);
-
- ThreadWithParam(
- UserThreadFunc func, T param, Notification* thread_can_start)
- : func_(func),
- param_(param),
- thread_can_start_(thread_can_start),
- finished_(false) {
- ThreadWithParamBase* const base = this;
- // The thread can be created only after all fields except thread_
- // have been initialized.
- GTEST_CHECK_POSIX_SUCCESS_(
- pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base));
- }
- ~ThreadWithParam() { Join(); }
-
- void Join() {
- if (!finished_) {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0));
- finished_ = true;
- }
- }
-
- virtual void Run() {
- if (thread_can_start_ != NULL)
- thread_can_start_->WaitForNotification();
- func_(param_);
- }
-
- private:
- const UserThreadFunc func_; // User-supplied thread function.
- const T param_; // User-supplied parameter to the thread function.
- // When non-NULL, used to block execution until the controller thread
- // notifies.
- Notification* const thread_can_start_;
- bool finished_; // true iff we know that the thread function has finished.
- pthread_t thread_; // The native thread object.
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam);
-};
-
-// gtest-port.h guarantees to #include <pthread.h> when GTEST_HAS_PTHREAD is
-// true.
-#include <pthread.h>
-
-// MutexBase and Mutex implement mutex on pthreads-based platforms. They
-// are used in conjunction with class MutexLock:
-//
-// Mutex mutex;
-// ...
-// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end
-// // of the current scope.
-//
-// MutexBase implements behavior for both statically and dynamically
-// allocated mutexes. Do not use MutexBase directly. Instead, write
-// the following to define a static mutex:
-//
-// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex);
-//
-// You can forward declare a static mutex like this:
-//
-// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex);
-//
-// To create a dynamic mutex, just define an object of type Mutex.
-class MutexBase {
- public:
- // Acquires this mutex.
- void Lock() {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_));
- owner_ = pthread_self();
- }
-
- // Releases this mutex.
- void Unlock() {
- // We don't protect writing to owner_ here, as it's the caller's
- // responsibility to ensure that the current thread holds the
- // mutex when this is called.
- owner_ = 0;
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_));
- }
-
- // Does nothing if the current thread holds the mutex. Otherwise, crashes
- // with high probability.
- void AssertHeld() const {
- GTEST_CHECK_(owner_ == pthread_self())
- << "The current thread is not holding the mutex @" << this;
- }
-
- // A static mutex may be used before main() is entered. It may even
- // be used before the dynamic initialization stage. Therefore we
- // must be able to initialize a static mutex object at link time.
- // This means MutexBase has to be a POD and its member variables
- // have to be public.
- public:
- pthread_mutex_t mutex_; // The underlying pthread mutex.
- pthread_t owner_; // The thread holding the mutex; 0 means no one holds it.
-};
-
-// Forward-declares a static mutex.
-#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
- extern ::testing::internal::MutexBase mutex
-
-// Defines and statically (i.e. at link time) initializes a static mutex.
-#define GTEST_DEFINE_STATIC_MUTEX_(mutex) \
- ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, 0 }
-
-// The Mutex class can only be used for mutexes created at runtime. It
-// shares its API with MutexBase otherwise.
-class Mutex : public MutexBase {
- public:
- Mutex() {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL));
- owner_ = 0;
- }
- ~Mutex() {
- GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_));
- }
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex);
-};
-
-// We cannot name this class MutexLock as the ctor declaration would
-// conflict with a macro named MutexLock, which is defined on some
-// platforms. Hence the typedef trick below.
-class GTestMutexLock {
- public:
- explicit GTestMutexLock(MutexBase* mutex)
- : mutex_(mutex) { mutex_->Lock(); }
-
- ~GTestMutexLock() { mutex_->Unlock(); }
-
- private:
- MutexBase* const mutex_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock);
-};
-
-typedef GTestMutexLock MutexLock;
-
-// Helpers for ThreadLocal.
-
-// pthread_key_create() requires DeleteThreadLocalValue() to have
-// C-linkage. Therefore it cannot be templatized to access
-// ThreadLocal<T>. Hence the need for class
-// ThreadLocalValueHolderBase.
-class ThreadLocalValueHolderBase {
- public:
- virtual ~ThreadLocalValueHolderBase() {}
-};
-
-// Called by pthread to delete thread-local data stored by
-// pthread_setspecific().
-extern "C" inline void DeleteThreadLocalValue(void* value_holder) {
- delete static_cast<ThreadLocalValueHolderBase*>(value_holder);
-}
-
-// Implements thread-local storage on pthreads-based systems.
-//
-// // Thread 1
-// ThreadLocal<int> tl(100); // 100 is the default value for each thread.
-//
-// // Thread 2
-// tl.set(150); // Changes the value for thread 2 only.
-// EXPECT_EQ(150, tl.get());
-//
-// // Thread 1
-// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value.
-// tl.set(200);
-// EXPECT_EQ(200, tl.get());
-//
-// The template type argument T must have a public copy constructor.
-// In addition, the default ThreadLocal constructor requires T to have
-// a public default constructor.
-//
-// An object managed for a thread by a ThreadLocal instance is deleted
-// when the thread exits. Or, if the ThreadLocal instance dies in
-// that thread, when the ThreadLocal dies. It's the user's
-// responsibility to ensure that all other threads using a ThreadLocal
-// have exited when it dies, or the per-thread objects for those
-// threads will not be deleted.
-//
-// Google Test only uses global ThreadLocal objects. That means they
-// will die after main() has returned. Therefore, no per-thread
-// object managed by Google Test will be leaked as long as all threads
-// using Google Test have exited when main() returns.
-template <typename T>
-class ThreadLocal {
- public:
- ThreadLocal() : key_(CreateKey()),
- default_() {}
- explicit ThreadLocal(const T& value) : key_(CreateKey()),
- default_(value) {}
-
- ~ThreadLocal() {
- // Destroys the managed object for the current thread, if any.
- DeleteThreadLocalValue(pthread_getspecific(key_));
-
- // Releases resources associated with the key. This will *not*
- // delete managed objects for other threads.
- GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_));
- }
-
- T* pointer() { return GetOrCreateValue(); }
- const T* pointer() const { return GetOrCreateValue(); }
- const T& get() const { return *pointer(); }
- void set(const T& value) { *pointer() = value; }
-
- private:
- // Holds a value of type T.
- class ValueHolder : public ThreadLocalValueHolderBase {
- public:
- explicit ValueHolder(const T& value) : value_(value) {}
-
- T* pointer() { return &value_; }
-
- private:
- T value_;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder);
- };
-
- static pthread_key_t CreateKey() {
- pthread_key_t key;
- // When a thread exits, DeleteThreadLocalValue() will be called on
- // the object managed for that thread.
- GTEST_CHECK_POSIX_SUCCESS_(
- pthread_key_create(&key, &DeleteThreadLocalValue));
- return key;
- }
-
- T* GetOrCreateValue() const {
- ThreadLocalValueHolderBase* const holder =
- static_cast<ThreadLocalValueHolderBase*>(pthread_getspecific(key_));
- if (holder != NULL) {
- return CheckedDowncastToActualType<ValueHolder>(holder)->pointer();
- }
-
- ValueHolder* const new_holder = new ValueHolder(default_);
- ThreadLocalValueHolderBase* const holder_base = new_holder;
- GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base));
- return new_holder->pointer();
- }
-
- // A key pthreads uses for looking up per-thread values.
- const pthread_key_t key_;
- const T default_; // The default value for each thread.
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal);
-};
-
-#define GTEST_IS_THREADSAFE 1
-
-#else // GTEST_HAS_PTHREAD
-
-// A dummy implementation of synchronization primitives (mutex, lock,
-// and thread-local variable). Necessary for compiling Google Test where
-// mutex is not supported - using Google Test in multiple threads is not
-// supported on such platforms.
-
-class Mutex {
- public:
- Mutex() {}
- void AssertHeld() const {}
-};
-
-#define GTEST_DECLARE_STATIC_MUTEX_(mutex) \
- extern ::testing::internal::Mutex mutex
-
-#define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex
-
-class GTestMutexLock {
- public:
- explicit GTestMutexLock(Mutex*) {} // NOLINT
-};
-
-typedef GTestMutexLock MutexLock;
-
-template <typename T>
-class ThreadLocal {
- public:
- ThreadLocal() : value_() {}
- explicit ThreadLocal(const T& value) : value_(value) {}
- T* pointer() { return &value_; }
- const T* pointer() const { return &value_; }
- const T& get() const { return value_; }
- void set(const T& value) { value_ = value; }
- private:
- T value_;
-};
-
-// The above synchronization primitives have dummy implementations.
-// Therefore Google Test is not thread-safe.
-#define GTEST_IS_THREADSAFE 0
-
-#endif // GTEST_HAS_PTHREAD
-
-// Returns the number of threads running in the process, or 0 to indicate that
-// we cannot detect it.
-GTEST_API_ size_t GetThreadCount();
-
-// Passing non-POD classes through ellipsis (...) crashes the ARM
-// compiler and generates a warning in Sun Studio. The Nokia Symbian
-// and the IBM XL C/C++ compiler try to instantiate a copy constructor
-// for objects passed through ellipsis (...), failing for uncopyable
-// objects. We define this to ensure that only POD is passed through
-// ellipsis on these systems.
-#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC)
-// We lose support for NULL detection where the compiler doesn't like
-// passing non-POD classes through ellipsis (...).
-#define GTEST_ELLIPSIS_NEEDS_POD_ 1
-#else
-#define GTEST_CAN_COMPARE_NULL 1
-#endif
-
-// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between
-// const T& and const T* in a function template. These compilers
-// _can_ decide between class template specializations for T and T*,
-// so a tr1::type_traits-like is_pointer works.
-#if defined(__SYMBIAN32__) || defined(__IBMCPP__)
-#define GTEST_NEEDS_IS_POINTER_ 1
-#endif
-
-template <bool bool_value>
-struct bool_constant {
- typedef bool_constant<bool_value> type;
- static const bool value = bool_value;
-};
-template <bool bool_value> const bool bool_constant<bool_value>::value;
-
-typedef bool_constant<false> false_type;
-typedef bool_constant<true> true_type;
-
-template <typename T>
-struct is_pointer : public false_type {};
-
-template <typename T>
-struct is_pointer<T*> : public true_type {};
-
-#if GTEST_OS_WINDOWS
-#define GTEST_PATH_SEP_ "\\"
-#define GTEST_HAS_ALT_PATH_SEP_ 1
-// The biggest signed integer type the compiler supports.
-typedef __int64 BiggestInt;
-#else
-#define GTEST_PATH_SEP_ "/"
-#define GTEST_HAS_ALT_PATH_SEP_ 0
-typedef long long BiggestInt; // NOLINT
-#endif // GTEST_OS_WINDOWS
-
-// The testing::internal::posix namespace holds wrappers for common
-// POSIX functions. These wrappers hide the differences between
-// Windows/MSVC and POSIX systems. Since some compilers define these
-// standard functions as macros, the wrapper cannot have the same name
-// as the wrapped function.
-
-namespace posix {
-
-// Functions with a different name on Windows.
-
-#if GTEST_OS_WINDOWS
-
-typedef struct _stat StatStruct;
-
-#ifdef __BORLANDC__
-inline int IsATTY(int fd) { return isatty(fd); }
-inline int StrCaseCmp(const char* s1, const char* s2) {
- return stricmp(s1, s2);
-}
-inline char* StrDup(const char* src) { return strdup(src); }
-#else // !__BORLANDC__
-#if GTEST_OS_WINDOWS_MOBILE
-inline int IsATTY(int /* fd */) { return 0; }
-#else
-inline int IsATTY(int fd) { return _isatty(fd); }
-#endif // GTEST_OS_WINDOWS_MOBILE
-inline int StrCaseCmp(const char* s1, const char* s2) {
- return _stricmp(s1, s2);
-}
-inline char* StrDup(const char* src) { return _strdup(src); }
-#endif // __BORLANDC__
-
-#if GTEST_OS_WINDOWS_MOBILE
-inline int FileNo(FILE* file) { return reinterpret_cast<int>(_fileno(file)); }
-// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this
-// time and thus not defined there.
-#else
-inline int FileNo(FILE* file) { return _fileno(file); }
-inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); }
-inline int RmDir(const char* dir) { return _rmdir(dir); }
-inline bool IsDir(const StatStruct& st) {
- return (_S_IFDIR & st.st_mode) != 0;
-}
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-#else
-
-typedef struct stat StatStruct;
-
-inline int FileNo(FILE* file) { return fileno(file); }
-inline int IsATTY(int fd) { return isatty(fd); }
-inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); }
-inline int StrCaseCmp(const char* s1, const char* s2) {
- return strcasecmp(s1, s2);
-}
-inline char* StrDup(const char* src) { return strdup(src); }
-inline int RmDir(const char* dir) { return rmdir(dir); }
-inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); }
-
-#endif // GTEST_OS_WINDOWS
-
-// Functions deprecated by MSVC 8.0.
-
-#ifdef _MSC_VER
-// Temporarily disable warning 4996 (deprecated function).
-#pragma warning(push)
-#pragma warning(disable:4996)
-#endif
-
-inline const char* StrNCpy(char* dest, const char* src, size_t n) {
- return strncpy(dest, src, n);
-}
-
-// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and
-// StrError() aren't needed on Windows CE at this time and thus not
-// defined there.
-
-#if !GTEST_OS_WINDOWS_MOBILE
-inline int ChDir(const char* dir) { return chdir(dir); }
-#endif
-inline FILE* FOpen(const char* path, const char* mode) {
- return fopen(path, mode);
-}
-#if !GTEST_OS_WINDOWS_MOBILE
-inline FILE *FReopen(const char* path, const char* mode, FILE* stream) {
- return freopen(path, mode, stream);
-}
-inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); }
-#endif
-inline int FClose(FILE* fp) { return fclose(fp); }
-#if !GTEST_OS_WINDOWS_MOBILE
-inline int Read(int fd, void* buf, unsigned int count) {
- return static_cast<int>(read(fd, buf, count));
-}
-inline int Write(int fd, const void* buf, unsigned int count) {
- return static_cast<int>(write(fd, buf, count));
-}
-inline int Close(int fd) { return close(fd); }
-inline const char* StrError(int errnum) { return strerror(errnum); }
-#endif
-inline const char* GetEnv(const char* name) {
-#if GTEST_OS_WINDOWS_MOBILE
- // We are on Windows CE, which has no environment variables.
- return NULL;
-#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9)
- // Environment variables which we programmatically clear will be set to the
- // empty string rather than unset (NULL). Handle that case.
- const char* const env = getenv(name);
- return (env != NULL && env[0] != '\0') ? env : NULL;
-#else
- return getenv(name);
-#endif
-}
-
-#ifdef _MSC_VER
-#pragma warning(pop) // Restores the warning state.
-#endif
-
-#if GTEST_OS_WINDOWS_MOBILE
-// Windows CE has no C library. The abort() function is used in
-// several places in Google Test. This implementation provides a reasonable
-// imitation of standard behaviour.
-void Abort();
-#else
-inline void Abort() { abort(); }
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-} // namespace posix
-
-// The maximum number a BiggestInt can represent. This definition
-// works no matter BiggestInt is represented in one's complement or
-// two's complement.
-//
-// We cannot rely on numeric_limits in STL, as __int64 and long long
-// are not part of standard C++ and numeric_limits doesn't need to be
-// defined for them.
-const BiggestInt kMaxBiggestInt =
- ~(static_cast<BiggestInt>(1) << (8*sizeof(BiggestInt) - 1));
-
-// This template class serves as a compile-time function from size to
-// type. It maps a size in bytes to a primitive type with that
-// size. e.g.
-//
-// TypeWithSize<4>::UInt
-//
-// is typedef-ed to be unsigned int (unsigned integer made up of 4
-// bytes).
-//
-// Such functionality should belong to STL, but I cannot find it
-// there.
-//
-// Google Test uses this class in the implementation of floating-point
-// comparison.
-//
-// For now it only handles UInt (unsigned int) as that's all Google Test
-// needs. Other types can be easily added in the future if need
-// arises.
-template <size_t size>
-class TypeWithSize {
- public:
- // This prevents the user from using TypeWithSize<N> with incorrect
- // values of N.
- typedef void UInt;
-};
-
-// The specialization for size 4.
-template <>
-class TypeWithSize<4> {
- public:
- // unsigned int has size 4 in both gcc and MSVC.
- //
- // As base/basictypes.h doesn't compile on Windows, we cannot use
- // uint32, uint64, and etc here.
- typedef int Int;
- typedef unsigned int UInt;
-};
-
-// The specialization for size 8.
-template <>
-class TypeWithSize<8> {
- public:
-#if GTEST_OS_WINDOWS
- typedef __int64 Int;
- typedef unsigned __int64 UInt;
-#else
- typedef long long Int; // NOLINT
- typedef unsigned long long UInt; // NOLINT
-#endif // GTEST_OS_WINDOWS
-};
-
-// Integer types of known sizes.
-typedef TypeWithSize<4>::Int Int32;
-typedef TypeWithSize<4>::UInt UInt32;
-typedef TypeWithSize<8>::Int Int64;
-typedef TypeWithSize<8>::UInt UInt64;
-typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds.
-
-// Utilities for command line flags and environment variables.
-
-// Macro for referencing flags.
-#define GTEST_FLAG(name) FLAGS_gtest_##name
-
-// Macros for declaring flags.
-#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name)
-#define GTEST_DECLARE_int32_(name) \
- GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name)
-#define GTEST_DECLARE_string_(name) \
- GTEST_API_ extern ::testing::internal::String GTEST_FLAG(name)
-
-// Macros for defining flags.
-#define GTEST_DEFINE_bool_(name, default_val, doc) \
- GTEST_API_ bool GTEST_FLAG(name) = (default_val)
-#define GTEST_DEFINE_int32_(name, default_val, doc) \
- GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val)
-#define GTEST_DEFINE_string_(name, default_val, doc) \
- GTEST_API_ ::testing::internal::String GTEST_FLAG(name) = (default_val)
-
-// Parses 'str' for a 32-bit signed integer. If successful, writes the result
-// to *value and returns true; otherwise leaves *value unchanged and returns
-// false.
-// TODO(chandlerc): Find a better way to refactor flag and environment parsing
-// out of both gtest-port.cc and gtest.cc to avoid exporting this utility
-// function.
-bool ParseInt32(const Message& src_text, const char* str, Int32* value);
-
-// Parses a bool/Int32/string from the environment variable
-// corresponding to the given Google Test flag.
-bool BoolFromGTestEnv(const char* flag, bool default_val);
-GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val);
-const char* StringFromGTestEnv(const char* flag, const char* default_val);
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_
-
-#if GTEST_OS_LINUX
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#endif // GTEST_OS_LINUX
-
-#include <ctype.h>
-#include <string.h>
-#include <iomanip>
-#include <limits>
-#include <set>
-
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file declares the String class and functions used internally by
-// Google Test. They are subject to change without notice. They should not used
-// by code external to Google Test.
-//
-// This header file is #included by <gtest/internal/gtest-internal.h>.
-// It should not be #included by other files.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
-
-#ifdef __BORLANDC__
-// string.h is not guaranteed to provide strcpy on C++ Builder.
-#include <mem.h>
-#endif
-
-#include <string.h>
-
-#include <string>
-
-namespace testing {
-namespace internal {
-
-// String - a UTF-8 string class.
-//
-// For historic reasons, we don't use std::string.
-//
-// TODO(wan@google.com): replace this class with std::string or
-// implement it in terms of the latter.
-//
-// Note that String can represent both NULL and the empty string,
-// while std::string cannot represent NULL.
-//
-// NULL and the empty string are considered different. NULL is less
-// than anything (including the empty string) except itself.
-//
-// This class only provides minimum functionality necessary for
-// implementing Google Test. We do not intend to implement a full-fledged
-// string class here.
-//
-// Since the purpose of this class is to provide a substitute for
-// std::string on platforms where it cannot be used, we define a copy
-// constructor and assignment operators such that we don't need
-// conditional compilation in a lot of places.
-//
-// In order to make the representation efficient, the d'tor of String
-// is not virtual. Therefore DO NOT INHERIT FROM String.
-class GTEST_API_ String {
- public:
- // Static utility methods
-
- // Returns the input enclosed in double quotes if it's not NULL;
- // otherwise returns "(null)". For example, "\"Hello\"" is returned
- // for input "Hello".
- //
- // This is useful for printing a C string in the syntax of a literal.
- //
- // Known issue: escape sequences are not handled yet.
- static String ShowCStringQuoted(const char* c_str);
-
- // Clones a 0-terminated C string, allocating memory using new. The
- // caller is responsible for deleting the return value using
- // delete[]. Returns the cloned string, or NULL if the input is
- // NULL.
- //
- // This is different from strdup() in string.h, which allocates
- // memory using malloc().
- static const char* CloneCString(const char* c_str);
-
-#if GTEST_OS_WINDOWS_MOBILE
- // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
- // able to pass strings to Win32 APIs on CE we need to convert them
- // to 'Unicode', UTF-16.
-
- // Creates a UTF-16 wide string from the given ANSI string, allocating
- // memory using new. The caller is responsible for deleting the return
- // value using delete[]. Returns the wide string, or NULL if the
- // input is NULL.
- //
- // The wide string is created using the ANSI codepage (CP_ACP) to
- // match the behaviour of the ANSI versions of Win32 calls and the
- // C runtime.
- static LPCWSTR AnsiToUtf16(const char* c_str);
-
- // Creates an ANSI string from the given wide string, allocating
- // memory using new. The caller is responsible for deleting the return
- // value using delete[]. Returns the ANSI string, or NULL if the
- // input is NULL.
- //
- // The returned string is created using the ANSI codepage (CP_ACP) to
- // match the behaviour of the ANSI versions of Win32 calls and the
- // C runtime.
- static const char* Utf16ToAnsi(LPCWSTR utf16_str);
-#endif
-
- // Compares two C strings. Returns true iff they have the same content.
- //
- // Unlike strcmp(), this function can handle NULL argument(s). A
- // NULL C string is considered different to any non-NULL C string,
- // including the empty string.
- static bool CStringEquals(const char* lhs, const char* rhs);
-
- // Converts a wide C string to a String using the UTF-8 encoding.
- // NULL will be converted to "(null)". If an error occurred during
- // the conversion, "(failed to convert from wide string)" is
- // returned.
- static String ShowWideCString(const wchar_t* wide_c_str);
-
- // Similar to ShowWideCString(), except that this function encloses
- // the converted string in double quotes.
- static String ShowWideCStringQuoted(const wchar_t* wide_c_str);
-
- // Compares two wide C strings. Returns true iff they have the same
- // content.
- //
- // Unlike wcscmp(), this function can handle NULL argument(s). A
- // NULL C string is considered different to any non-NULL C string,
- // including the empty string.
- static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
-
- // Compares two C strings, ignoring case. Returns true iff they
- // have the same content.
- //
- // Unlike strcasecmp(), this function can handle NULL argument(s).
- // A NULL C string is considered different to any non-NULL C string,
- // including the empty string.
- static bool CaseInsensitiveCStringEquals(const char* lhs,
- const char* rhs);
-
- // Compares two wide C strings, ignoring case. Returns true iff they
- // have the same content.
- //
- // Unlike wcscasecmp(), this function can handle NULL argument(s).
- // A NULL C string is considered different to any non-NULL wide C string,
- // including the empty string.
- // NB: The implementations on different platforms slightly differ.
- // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
- // environment variable. On GNU platform this method uses wcscasecmp
- // which compares according to LC_CTYPE category of the current locale.
- // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
- // current locale.
- static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
- const wchar_t* rhs);
-
- // Formats a list of arguments to a String, using the same format
- // spec string as for printf.
- //
- // We do not use the StringPrintf class as it is not universally
- // available.
- //
- // The result is limited to 4096 characters (including the tailing
- // 0). If 4096 characters are not enough to format the input,
- // "<buffer exceeded>" is returned.
- static String Format(const char* format, ...);
-
- // C'tors
-
- // The default c'tor constructs a NULL string.
- String() : c_str_(NULL), length_(0) {}
-
- // Constructs a String by cloning a 0-terminated C string.
- String(const char* a_c_str) { // NOLINT
- if (a_c_str == NULL) {
- c_str_ = NULL;
- length_ = 0;
- } else {
- ConstructNonNull(a_c_str, strlen(a_c_str));
- }
- }
-
- // Constructs a String by copying a given number of chars from a
- // buffer. E.g. String("hello", 3) creates the string "hel",
- // String("a\0bcd", 4) creates "a\0bc", String(NULL, 0) creates "",
- // and String(NULL, 1) results in access violation.
- String(const char* buffer, size_t a_length) {
- ConstructNonNull(buffer, a_length);
- }
-
- // The copy c'tor creates a new copy of the string. The two
- // String objects do not share content.
- String(const String& str) : c_str_(NULL), length_(0) { *this = str; }
-
- // D'tor. String is intended to be a final class, so the d'tor
- // doesn't need to be virtual.
- ~String() { delete[] c_str_; }
-
- // Allows a String to be implicitly converted to an ::std::string or
- // ::string, and vice versa. Converting a String containing a NULL
- // pointer to ::std::string or ::string is undefined behavior.
- // Converting a ::std::string or ::string containing an embedded NUL
- // character to a String will result in the prefix up to the first
- // NUL character.
- String(const ::std::string& str) {
- ConstructNonNull(str.c_str(), str.length());
- }
-
- operator ::std::string() const { return ::std::string(c_str(), length()); }
-
-#if GTEST_HAS_GLOBAL_STRING
- String(const ::string& str) {
- ConstructNonNull(str.c_str(), str.length());
- }
-
- operator ::string() const { return ::string(c_str(), length()); }
-#endif // GTEST_HAS_GLOBAL_STRING
-
- // Returns true iff this is an empty string (i.e. "").
- bool empty() const { return (c_str() != NULL) && (length() == 0); }
-
- // Compares this with another String.
- // Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
- // if this is greater than rhs.
- int Compare(const String& rhs) const;
-
- // Returns true iff this String equals the given C string. A NULL
- // string and a non-NULL string are considered not equal.
- bool operator==(const char* a_c_str) const { return Compare(a_c_str) == 0; }
-
- // Returns true iff this String is less than the given String. A
- // NULL string is considered less than "".
- bool operator<(const String& rhs) const { return Compare(rhs) < 0; }
-
- // Returns true iff this String doesn't equal the given C string. A NULL
- // string and a non-NULL string are considered not equal.
- bool operator!=(const char* a_c_str) const { return !(*this == a_c_str); }
-
- // Returns true iff this String ends with the given suffix. *Any*
- // String is considered to end with a NULL or empty suffix.
- bool EndsWith(const char* suffix) const;
-
- // Returns true iff this String ends with the given suffix, not considering
- // case. Any String is considered to end with a NULL or empty suffix.
- bool EndsWithCaseInsensitive(const char* suffix) const;
-
- // Returns the length of the encapsulated string, or 0 if the
- // string is NULL.
- size_t length() const { return length_; }
-
- // Gets the 0-terminated C string this String object represents.
- // The String object still owns the string. Therefore the caller
- // should NOT delete the return value.
- const char* c_str() const { return c_str_; }
-
- // Assigns a C string to this object. Self-assignment works.
- const String& operator=(const char* a_c_str) {
- return *this = String(a_c_str);
- }
-
- // Assigns a String object to this object. Self-assignment works.
- const String& operator=(const String& rhs) {
- if (this != &rhs) {
- delete[] c_str_;
- if (rhs.c_str() == NULL) {
- c_str_ = NULL;
- length_ = 0;
- } else {
- ConstructNonNull(rhs.c_str(), rhs.length());
- }
- }
-
- return *this;
- }
-
- private:
- // Constructs a non-NULL String from the given content. This
- // function can only be called when data_ has not been allocated.
- // ConstructNonNull(NULL, 0) results in an empty string ("").
- // ConstructNonNull(NULL, non_zero) is undefined behavior.
- void ConstructNonNull(const char* buffer, size_t a_length) {
- char* const str = new char[a_length + 1];
- memcpy(str, buffer, a_length);
- str[a_length] = '\0';
- c_str_ = str;
- length_ = a_length;
- }
-
- const char* c_str_;
- size_t length_;
-}; // class String
-
-// Streams a String to an ostream. Each '\0' character in the String
-// is replaced with "\\0".
-inline ::std::ostream& operator<<(::std::ostream& os, const String& str) {
- if (str.c_str() == NULL) {
- os << "(null)";
- } else {
- const char* const c_str = str.c_str();
- for (size_t i = 0; i != str.length(); i++) {
- if (c_str[i] == '\0') {
- os << "\\0";
- } else {
- os << c_str[i];
- }
- }
- }
- return os;
-}
-
-// Gets the content of the StrStream's buffer as a String. Each '\0'
-// character in the buffer is replaced with "\\0".
-GTEST_API_ String StrStreamToString(StrStream* stream);
-
-// Converts a streamable value to a String. A NULL pointer is
-// converted to "(null)". When the input value is a ::string,
-// ::std::string, ::wstring, or ::std::wstring object, each NUL
-// character in it is replaced with "\\0".
-
-// Declared here but defined in gtest.h, so that it has access
-// to the definition of the Message class, required by the ARM
-// compiler.
-template <typename T>
-String StreamableToString(const T& streamable);
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: keith.ray@gmail.com (Keith Ray)
-//
-// Google Test filepath utilities
-//
-// This header file declares classes and functions used internally by
-// Google Test. They are subject to change without notice.
-//
-// This file is #included in <gtest/internal/gtest-internal.h>.
-// Do not include this header file separately!
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
-
-
-namespace testing {
-namespace internal {
-
-// FilePath - a class for file and directory pathname manipulation which
-// handles platform-specific conventions (like the pathname separator).
-// Used for helper functions for naming files in a directory for xml output.
-// Except for Set methods, all methods are const or static, which provides an
-// "immutable value object" -- useful for peace of mind.
-// A FilePath with a value ending in a path separator ("like/this/") represents
-// a directory, otherwise it is assumed to represent a file. In either case,
-// it may or may not represent an actual file or directory in the file system.
-// Names are NOT checked for syntax correctness -- no checking for illegal
-// characters, malformed paths, etc.
-
-class GTEST_API_ FilePath {
- public:
- FilePath() : pathname_("") { }
- FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
-
- explicit FilePath(const char* pathname) : pathname_(pathname) {
- Normalize();
- }
-
- explicit FilePath(const String& pathname) : pathname_(pathname) {
- Normalize();
- }
-
- FilePath& operator=(const FilePath& rhs) {
- Set(rhs);
- return *this;
- }
-
- void Set(const FilePath& rhs) {
- pathname_ = rhs.pathname_;
- }
-
- String ToString() const { return pathname_; }
- const char* c_str() const { return pathname_.c_str(); }
-
- // Returns the current working directory, or "" if unsuccessful.
- static FilePath GetCurrentDir();
-
- // Given directory = "dir", base_name = "test", number = 0,
- // extension = "xml", returns "dir/test.xml". If number is greater
- // than zero (e.g., 12), returns "dir/test_12.xml".
- // On Windows platform, uses \ as the separator rather than /.
- static FilePath MakeFileName(const FilePath& directory,
- const FilePath& base_name,
- int number,
- const char* extension);
-
- // Given directory = "dir", relative_path = "test.xml",
- // returns "dir/test.xml".
- // On Windows, uses \ as the separator rather than /.
- static FilePath ConcatPaths(const FilePath& directory,
- const FilePath& relative_path);
-
- // Returns a pathname for a file that does not currently exist. The pathname
- // will be directory/base_name.extension or
- // directory/base_name_<number>.extension if directory/base_name.extension
- // already exists. The number will be incremented until a pathname is found
- // that does not already exist.
- // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
- // There could be a race condition if two or more processes are calling this
- // function at the same time -- they could both pick the same filename.
- static FilePath GenerateUniqueFileName(const FilePath& directory,
- const FilePath& base_name,
- const char* extension);
-
- // Returns true iff the path is NULL or "".
- bool IsEmpty() const { return c_str() == NULL || *c_str() == '\0'; }
-
- // If input name has a trailing separator character, removes it and returns
- // the name, otherwise return the name string unmodified.
- // On Windows platform, uses \ as the separator, other platforms use /.
- FilePath RemoveTrailingPathSeparator() const;
-
- // Returns a copy of the FilePath with the directory part removed.
- // Example: FilePath("path/to/file").RemoveDirectoryName() returns
- // FilePath("file"). If there is no directory part ("just_a_file"), it returns
- // the FilePath unmodified. If there is no file part ("just_a_dir/") it
- // returns an empty FilePath ("").
- // On Windows platform, '\' is the path separator, otherwise it is '/'.
- FilePath RemoveDirectoryName() const;
-
- // RemoveFileName returns the directory path with the filename removed.
- // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
- // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
- // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
- // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
- // On Windows platform, '\' is the path separator, otherwise it is '/'.
- FilePath RemoveFileName() const;
-
- // Returns a copy of the FilePath with the case-insensitive extension removed.
- // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
- // FilePath("dir/file"). If a case-insensitive extension is not
- // found, returns a copy of the original FilePath.
- FilePath RemoveExtension(const char* extension) const;
-
- // Creates directories so that path exists. Returns true if successful or if
- // the directories already exist; returns false if unable to create
- // directories for any reason. Will also return false if the FilePath does
- // not represent a directory (that is, it doesn't end with a path separator).
- bool CreateDirectoriesRecursively() const;
-
- // Create the directory so that path exists. Returns true if successful or
- // if the directory already exists; returns false if unable to create the
- // directory for any reason, including if the parent directory does not
- // exist. Not named "CreateDirectory" because that's a macro on Windows.
- bool CreateFolder() const;
-
- // Returns true if FilePath describes something in the file-system,
- // either a file, directory, or whatever, and that something exists.
- bool FileOrDirectoryExists() const;
-
- // Returns true if pathname describes a directory in the file-system
- // that exists.
- bool DirectoryExists() const;
-
- // Returns true if FilePath ends with a path separator, which indicates that
- // it is intended to represent a directory. Returns false otherwise.
- // This does NOT check that a directory (or file) actually exists.
- bool IsDirectory() const;
-
- // Returns true if pathname describes a root directory. (Windows has one
- // root directory per disk drive.)
- bool IsRootDirectory() const;
-
- // Returns true if pathname describes an absolute path.
- bool IsAbsolutePath() const;
-
- private:
- // Replaces multiple consecutive separators with a single separator.
- // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
- // redundancies that might be in a pathname involving "." or "..".
- //
- // A pathname with multiple consecutive separators may occur either through
- // user error or as a result of some scripts or APIs that generate a pathname
- // with a trailing separator. On other platforms the same API or script
- // may NOT generate a pathname with a trailing "/". Then elsewhere that
- // pathname may have another "/" and pathname components added to it,
- // without checking for the separator already being there.
- // The script language and operating system may allow paths like "foo//bar"
- // but some of the functions in FilePath will not handle that correctly. In
- // particular, RemoveTrailingPathSeparator() only removes one separator, and
- // it is called in CreateDirectoriesRecursively() assuming that it will change
- // a pathname from directory syntax (trailing separator) to filename syntax.
- //
- // On Windows this method also replaces the alternate path separator '/' with
- // the primary path separator '\\', so that for example "bar\\/\\foo" becomes
- // "bar\\foo".
-
- void Normalize();
-
- // Returns a pointer to the last occurence of a valid path separator in
- // the FilePath. On Windows, for example, both '/' and '\' are valid path
- // separators. Returns NULL if no path separator was found.
- const char* FindLastPathSeparator() const;
-
- String pathname_;
-}; // class FilePath
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
-// This file was GENERATED by command:
-// pump.py gtest-type-util.h.pump
-// DO NOT EDIT BY HAND!!!
-
-// Copyright 2008 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-// Type utilities needed for implementing typed and type-parameterized
-// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
-//
-// Currently we support at most 50 types in a list, and at most 50
-// type-parameterized tests in one type-parameterized test case.
-// Please contact googletestframework@googlegroups.com if you need
-// more.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
-
-
-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
-// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
-// libstdc++ (which is where cxxabi.h comes from).
-#ifdef __GLIBCXX__
-#include <cxxabi.h>
-#endif // __GLIBCXX__
-
-namespace testing {
-namespace internal {
-
-// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
-// type. This can be used as a compile-time assertion to ensure that
-// two types are equal.
-
-template <typename T1, typename T2>
-struct AssertTypeEq;
-
-template <typename T>
-struct AssertTypeEq<T, T> {
- typedef bool type;
-};
-
-// GetTypeName<T>() returns a human-readable name of type T.
-template <typename T>
-String GetTypeName() {
-#if GTEST_HAS_RTTI
-
- const char* const name = typeid(T).name();
-#ifdef __GLIBCXX__
- int status = 0;
- // gcc's implementation of typeid(T).name() mangles the type name,
- // so we have to demangle it.
- char* const readable_name = abi::__cxa_demangle(name, 0, 0, &status);
- const String name_str(status == 0 ? readable_name : name);
- free(readable_name);
- return name_str;
-#else
- return name;
-#endif // __GLIBCXX__
-
-#else
- return "<type>";
-#endif // GTEST_HAS_RTTI
-}
-
-// A unique type used as the default value for the arguments of class
-// template Types. This allows us to simulate variadic templates
-// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
-// support directly.
-struct None {};
-
-// The following family of struct and struct templates are used to
-// represent type lists. In particular, TypesN<T1, T2, ..., TN>
-// represents a type list with N types (T1, T2, ..., and TN) in it.
-// Except for Types0, every struct in the family has two member types:
-// Head for the first type in the list, and Tail for the rest of the
-// list.
-
-// The empty type list.
-struct Types0 {};
-
-// Type lists of length 1, 2, 3, and so on.
-
-template <typename T1>
-struct Types1 {
- typedef T1 Head;
- typedef Types0 Tail;
-};
-template <typename T1, typename T2>
-struct Types2 {
- typedef T1 Head;
- typedef Types1<T2> Tail;
-};
-
-template <typename T1, typename T2, typename T3>
-struct Types3 {
- typedef T1 Head;
- typedef Types2<T2, T3> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4>
-struct Types4 {
- typedef T1 Head;
- typedef Types3<T2, T3, T4> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-struct Types5 {
- typedef T1 Head;
- typedef Types4<T2, T3, T4, T5> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-struct Types6 {
- typedef T1 Head;
- typedef Types5<T2, T3, T4, T5, T6> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-struct Types7 {
- typedef T1 Head;
- typedef Types6<T2, T3, T4, T5, T6, T7> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-struct Types8 {
- typedef T1 Head;
- typedef Types7<T2, T3, T4, T5, T6, T7, T8> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-struct Types9 {
- typedef T1 Head;
- typedef Types8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-struct Types10 {
- typedef T1 Head;
- typedef Types9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-struct Types11 {
- typedef T1 Head;
- typedef Types10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-struct Types12 {
- typedef T1 Head;
- typedef Types11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-struct Types13 {
- typedef T1 Head;
- typedef Types12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-struct Types14 {
- typedef T1 Head;
- typedef Types13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-struct Types15 {
- typedef T1 Head;
- typedef Types14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-struct Types16 {
- typedef T1 Head;
- typedef Types15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-struct Types17 {
- typedef T1 Head;
- typedef Types16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-struct Types18 {
- typedef T1 Head;
- typedef Types17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-struct Types19 {
- typedef T1 Head;
- typedef Types18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-struct Types20 {
- typedef T1 Head;
- typedef Types19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-struct Types21 {
- typedef T1 Head;
- typedef Types20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-struct Types22 {
- typedef T1 Head;
- typedef Types21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-struct Types23 {
- typedef T1 Head;
- typedef Types22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-struct Types24 {
- typedef T1 Head;
- typedef Types23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-struct Types25 {
- typedef T1 Head;
- typedef Types24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-struct Types26 {
- typedef T1 Head;
- typedef Types25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-struct Types27 {
- typedef T1 Head;
- typedef Types26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-struct Types28 {
- typedef T1 Head;
- typedef Types27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-struct Types29 {
- typedef T1 Head;
- typedef Types28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-struct Types30 {
- typedef T1 Head;
- typedef Types29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-struct Types31 {
- typedef T1 Head;
- typedef Types30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-struct Types32 {
- typedef T1 Head;
- typedef Types31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-struct Types33 {
- typedef T1 Head;
- typedef Types32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-struct Types34 {
- typedef T1 Head;
- typedef Types33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-struct Types35 {
- typedef T1 Head;
- typedef Types34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-struct Types36 {
- typedef T1 Head;
- typedef Types35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-struct Types37 {
- typedef T1 Head;
- typedef Types36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-struct Types38 {
- typedef T1 Head;
- typedef Types37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-struct Types39 {
- typedef T1 Head;
- typedef Types38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-struct Types40 {
- typedef T1 Head;
- typedef Types39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-struct Types41 {
- typedef T1 Head;
- typedef Types40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-struct Types42 {
- typedef T1 Head;
- typedef Types41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-struct Types43 {
- typedef T1 Head;
- typedef Types42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-struct Types44 {
- typedef T1 Head;
- typedef Types43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-struct Types45 {
- typedef T1 Head;
- typedef Types44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-struct Types46 {
- typedef T1 Head;
- typedef Types45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-struct Types47 {
- typedef T1 Head;
- typedef Types46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-struct Types48 {
- typedef T1 Head;
- typedef Types47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-struct Types49 {
- typedef T1 Head;
- typedef Types48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49> Tail;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-struct Types50 {
- typedef T1 Head;
- typedef Types49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49, T50> Tail;
-};
-
-
-} // namespace internal
-
-// We don't want to require the users to write TypesN<...> directly,
-// as that would require them to count the length. Types<...> is much
-// easier to write, but generates horrible messages when there is a
-// compiler error, as gcc insists on printing out each template
-// argument, even if it has the default value (this means Types<int>
-// will appear as Types<int, None, None, ..., None> in the compiler
-// errors).
-//
-// Our solution is to combine the best part of the two approaches: a
-// user would write Types<T1, ..., TN>, and Google Test will translate
-// that to TypesN<T1, ..., TN> internally to make error messages
-// readable. The translation is done by the 'type' member of the
-// Types template.
-template <typename T1 = internal::None, typename T2 = internal::None,
- typename T3 = internal::None, typename T4 = internal::None,
- typename T5 = internal::None, typename T6 = internal::None,
- typename T7 = internal::None, typename T8 = internal::None,
- typename T9 = internal::None, typename T10 = internal::None,
- typename T11 = internal::None, typename T12 = internal::None,
- typename T13 = internal::None, typename T14 = internal::None,
- typename T15 = internal::None, typename T16 = internal::None,
- typename T17 = internal::None, typename T18 = internal::None,
- typename T19 = internal::None, typename T20 = internal::None,
- typename T21 = internal::None, typename T22 = internal::None,
- typename T23 = internal::None, typename T24 = internal::None,
- typename T25 = internal::None, typename T26 = internal::None,
- typename T27 = internal::None, typename T28 = internal::None,
- typename T29 = internal::None, typename T30 = internal::None,
- typename T31 = internal::None, typename T32 = internal::None,
- typename T33 = internal::None, typename T34 = internal::None,
- typename T35 = internal::None, typename T36 = internal::None,
- typename T37 = internal::None, typename T38 = internal::None,
- typename T39 = internal::None, typename T40 = internal::None,
- typename T41 = internal::None, typename T42 = internal::None,
- typename T43 = internal::None, typename T44 = internal::None,
- typename T45 = internal::None, typename T46 = internal::None,
- typename T47 = internal::None, typename T48 = internal::None,
- typename T49 = internal::None, typename T50 = internal::None>
-struct Types {
- typedef internal::Types50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
-};
-
-template <>
-struct Types<internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types0 type;
-};
-template <typename T1>
-struct Types<T1, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types1<T1> type;
-};
-template <typename T1, typename T2>
-struct Types<T1, T2, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types2<T1, T2> type;
-};
-template <typename T1, typename T2, typename T3>
-struct Types<T1, T2, T3, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types3<T1, T2, T3> type;
-};
-template <typename T1, typename T2, typename T3, typename T4>
-struct Types<T1, T2, T3, T4, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types4<T1, T2, T3, T4> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-struct Types<T1, T2, T3, T4, T5, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types5<T1, T2, T3, T4, T5> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-struct Types<T1, T2, T3, T4, T5, T6, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types6<T1, T2, T3, T4, T5, T6> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-struct Types<T1, T2, T3, T4, T5, T6, T7, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types7<T1, T2, T3, T4, T5, T6, T7> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types8<T1, T2, T3, T4, T5, T6, T7, T8> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, internal::None,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None, internal::None> {
- typedef internal::Types43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- internal::None, internal::None, internal::None, internal::None,
- internal::None, internal::None> {
- typedef internal::Types44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
- internal::None, internal::None, internal::None, internal::None,
- internal::None> {
- typedef internal::Types45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
- T46, internal::None, internal::None, internal::None, internal::None> {
- typedef internal::Types46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
- T46, T47, internal::None, internal::None, internal::None> {
- typedef internal::Types47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46, T47> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
- T46, T47, T48, internal::None, internal::None> {
- typedef internal::Types48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46, T47, T48> type;
-};
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-struct Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15,
- T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29, T30,
- T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44, T45,
- T46, T47, T48, T49, internal::None> {
- typedef internal::Types49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46, T47, T48, T49> type;
-};
-
-namespace internal {
-
-#define GTEST_TEMPLATE_ template <typename T> class
-
-// The template "selector" struct TemplateSel<Tmpl> is used to
-// represent Tmpl, which must be a class template with one type
-// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
-// as the type Tmpl<T>. This allows us to actually instantiate the
-// template "selected" by TemplateSel<Tmpl>.
-//
-// This trick is necessary for simulating typedef for class templates,
-// which C++ doesn't support directly.
-template <GTEST_TEMPLATE_ Tmpl>
-struct TemplateSel {
- template <typename T>
- struct Bind {
- typedef Tmpl<T> type;
- };
-};
-
-#define GTEST_BIND_(TmplSel, T) \
- TmplSel::template Bind<T>::type
-
-// A unique struct template used as the default value for the
-// arguments of class template Templates. This allows us to simulate
-// variadic templates (e.g. Templates<int>, Templates<int, double>,
-// and etc), which C++ doesn't support directly.
-template <typename T>
-struct NoneT {};
-
-// The following family of struct and struct templates are used to
-// represent template lists. In particular, TemplatesN<T1, T2, ...,
-// TN> represents a list of N templates (T1, T2, ..., and TN). Except
-// for Templates0, every struct in the family has two member types:
-// Head for the selector of the first template in the list, and Tail
-// for the rest of the list.
-
-// The empty template list.
-struct Templates0 {};
-
-// Template lists of length 1, 2, 3, and so on.
-
-template <GTEST_TEMPLATE_ T1>
-struct Templates1 {
- typedef TemplateSel<T1> Head;
- typedef Templates0 Tail;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
-struct Templates2 {
- typedef TemplateSel<T1> Head;
- typedef Templates1<T2> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
-struct Templates3 {
- typedef TemplateSel<T1> Head;
- typedef Templates2<T2, T3> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4>
-struct Templates4 {
- typedef TemplateSel<T1> Head;
- typedef Templates3<T2, T3, T4> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
-struct Templates5 {
- typedef TemplateSel<T1> Head;
- typedef Templates4<T2, T3, T4, T5> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
-struct Templates6 {
- typedef TemplateSel<T1> Head;
- typedef Templates5<T2, T3, T4, T5, T6> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7>
-struct Templates7 {
- typedef TemplateSel<T1> Head;
- typedef Templates6<T2, T3, T4, T5, T6, T7> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
-struct Templates8 {
- typedef TemplateSel<T1> Head;
- typedef Templates7<T2, T3, T4, T5, T6, T7, T8> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
-struct Templates9 {
- typedef TemplateSel<T1> Head;
- typedef Templates8<T2, T3, T4, T5, T6, T7, T8, T9> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10>
-struct Templates10 {
- typedef TemplateSel<T1> Head;
- typedef Templates9<T2, T3, T4, T5, T6, T7, T8, T9, T10> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
-struct Templates11 {
- typedef TemplateSel<T1> Head;
- typedef Templates10<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
-struct Templates12 {
- typedef TemplateSel<T1> Head;
- typedef Templates11<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13>
-struct Templates13 {
- typedef TemplateSel<T1> Head;
- typedef Templates12<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
-struct Templates14 {
- typedef TemplateSel<T1> Head;
- typedef Templates13<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
-struct Templates15 {
- typedef TemplateSel<T1> Head;
- typedef Templates14<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16>
-struct Templates16 {
- typedef TemplateSel<T1> Head;
- typedef Templates15<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
-struct Templates17 {
- typedef TemplateSel<T1> Head;
- typedef Templates16<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
-struct Templates18 {
- typedef TemplateSel<T1> Head;
- typedef Templates17<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19>
-struct Templates19 {
- typedef TemplateSel<T1> Head;
- typedef Templates18<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
-struct Templates20 {
- typedef TemplateSel<T1> Head;
- typedef Templates19<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
-struct Templates21 {
- typedef TemplateSel<T1> Head;
- typedef Templates20<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22>
-struct Templates22 {
- typedef TemplateSel<T1> Head;
- typedef Templates21<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
-struct Templates23 {
- typedef TemplateSel<T1> Head;
- typedef Templates22<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
-struct Templates24 {
- typedef TemplateSel<T1> Head;
- typedef Templates23<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25>
-struct Templates25 {
- typedef TemplateSel<T1> Head;
- typedef Templates24<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
-struct Templates26 {
- typedef TemplateSel<T1> Head;
- typedef Templates25<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
-struct Templates27 {
- typedef TemplateSel<T1> Head;
- typedef Templates26<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28>
-struct Templates28 {
- typedef TemplateSel<T1> Head;
- typedef Templates27<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
-struct Templates29 {
- typedef TemplateSel<T1> Head;
- typedef Templates28<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
-struct Templates30 {
- typedef TemplateSel<T1> Head;
- typedef Templates29<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31>
-struct Templates31 {
- typedef TemplateSel<T1> Head;
- typedef Templates30<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
-struct Templates32 {
- typedef TemplateSel<T1> Head;
- typedef Templates31<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
-struct Templates33 {
- typedef TemplateSel<T1> Head;
- typedef Templates32<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34>
-struct Templates34 {
- typedef TemplateSel<T1> Head;
- typedef Templates33<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
-struct Templates35 {
- typedef TemplateSel<T1> Head;
- typedef Templates34<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
-struct Templates36 {
- typedef TemplateSel<T1> Head;
- typedef Templates35<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37>
-struct Templates37 {
- typedef TemplateSel<T1> Head;
- typedef Templates36<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
-struct Templates38 {
- typedef TemplateSel<T1> Head;
- typedef Templates37<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
-struct Templates39 {
- typedef TemplateSel<T1> Head;
- typedef Templates38<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40>
-struct Templates40 {
- typedef TemplateSel<T1> Head;
- typedef Templates39<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
-struct Templates41 {
- typedef TemplateSel<T1> Head;
- typedef Templates40<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
-struct Templates42 {
- typedef TemplateSel<T1> Head;
- typedef Templates41<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43>
-struct Templates43 {
- typedef TemplateSel<T1> Head;
- typedef Templates42<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
-struct Templates44 {
- typedef TemplateSel<T1> Head;
- typedef Templates43<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
-struct Templates45 {
- typedef TemplateSel<T1> Head;
- typedef Templates44<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46>
-struct Templates46 {
- typedef TemplateSel<T1> Head;
- typedef Templates45<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45, T46> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
-struct Templates47 {
- typedef TemplateSel<T1> Head;
- typedef Templates46<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45, T46, T47> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
-struct Templates48 {
- typedef TemplateSel<T1> Head;
- typedef Templates47<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45, T46, T47, T48> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
- GTEST_TEMPLATE_ T49>
-struct Templates49 {
- typedef TemplateSel<T1> Head;
- typedef Templates48<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45, T46, T47, T48, T49> Tail;
-};
-
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
- GTEST_TEMPLATE_ T49, GTEST_TEMPLATE_ T50>
-struct Templates50 {
- typedef TemplateSel<T1> Head;
- typedef Templates49<T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43, T44, T45, T46, T47, T48, T49, T50> Tail;
-};
-
-
-// We don't want to require the users to write TemplatesN<...> directly,
-// as that would require them to count the length. Templates<...> is much
-// easier to write, but generates horrible messages when there is a
-// compiler error, as gcc insists on printing out each template
-// argument, even if it has the default value (this means Templates<list>
-// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
-// errors).
-//
-// Our solution is to combine the best part of the two approaches: a
-// user would write Templates<T1, ..., TN>, and Google Test will translate
-// that to TemplatesN<T1, ..., TN> internally to make error messages
-// readable. The translation is done by the 'type' member of the
-// Templates template.
-template <GTEST_TEMPLATE_ T1 = NoneT, GTEST_TEMPLATE_ T2 = NoneT,
- GTEST_TEMPLATE_ T3 = NoneT, GTEST_TEMPLATE_ T4 = NoneT,
- GTEST_TEMPLATE_ T5 = NoneT, GTEST_TEMPLATE_ T6 = NoneT,
- GTEST_TEMPLATE_ T7 = NoneT, GTEST_TEMPLATE_ T8 = NoneT,
- GTEST_TEMPLATE_ T9 = NoneT, GTEST_TEMPLATE_ T10 = NoneT,
- GTEST_TEMPLATE_ T11 = NoneT, GTEST_TEMPLATE_ T12 = NoneT,
- GTEST_TEMPLATE_ T13 = NoneT, GTEST_TEMPLATE_ T14 = NoneT,
- GTEST_TEMPLATE_ T15 = NoneT, GTEST_TEMPLATE_ T16 = NoneT,
- GTEST_TEMPLATE_ T17 = NoneT, GTEST_TEMPLATE_ T18 = NoneT,
- GTEST_TEMPLATE_ T19 = NoneT, GTEST_TEMPLATE_ T20 = NoneT,
- GTEST_TEMPLATE_ T21 = NoneT, GTEST_TEMPLATE_ T22 = NoneT,
- GTEST_TEMPLATE_ T23 = NoneT, GTEST_TEMPLATE_ T24 = NoneT,
- GTEST_TEMPLATE_ T25 = NoneT, GTEST_TEMPLATE_ T26 = NoneT,
- GTEST_TEMPLATE_ T27 = NoneT, GTEST_TEMPLATE_ T28 = NoneT,
- GTEST_TEMPLATE_ T29 = NoneT, GTEST_TEMPLATE_ T30 = NoneT,
- GTEST_TEMPLATE_ T31 = NoneT, GTEST_TEMPLATE_ T32 = NoneT,
- GTEST_TEMPLATE_ T33 = NoneT, GTEST_TEMPLATE_ T34 = NoneT,
- GTEST_TEMPLATE_ T35 = NoneT, GTEST_TEMPLATE_ T36 = NoneT,
- GTEST_TEMPLATE_ T37 = NoneT, GTEST_TEMPLATE_ T38 = NoneT,
- GTEST_TEMPLATE_ T39 = NoneT, GTEST_TEMPLATE_ T40 = NoneT,
- GTEST_TEMPLATE_ T41 = NoneT, GTEST_TEMPLATE_ T42 = NoneT,
- GTEST_TEMPLATE_ T43 = NoneT, GTEST_TEMPLATE_ T44 = NoneT,
- GTEST_TEMPLATE_ T45 = NoneT, GTEST_TEMPLATE_ T46 = NoneT,
- GTEST_TEMPLATE_ T47 = NoneT, GTEST_TEMPLATE_ T48 = NoneT,
- GTEST_TEMPLATE_ T49 = NoneT, GTEST_TEMPLATE_ T50 = NoneT>
-struct Templates {
- typedef Templates50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45, T46, T47, T48, T49, T50> type;
-};
-
-template <>
-struct Templates<NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT> {
- typedef Templates0 type;
-};
-template <GTEST_TEMPLATE_ T1>
-struct Templates<T1, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT> {
- typedef Templates1<T1> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2>
-struct Templates<T1, T2, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT> {
- typedef Templates2<T1, T2> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3>
-struct Templates<T1, T2, T3, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates3<T1, T2, T3> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4>
-struct Templates<T1, T2, T3, T4, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates4<T1, T2, T3, T4> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5>
-struct Templates<T1, T2, T3, T4, T5, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates5<T1, T2, T3, T4, T5> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6>
-struct Templates<T1, T2, T3, T4, T5, T6, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates6<T1, T2, T3, T4, T5, T6> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates7<T1, T2, T3, T4, T5, T6, T7> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates8<T1, T2, T3, T4, T5, T6, T7, T8> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates9<T1, T2, T3, T4, T5, T6, T7, T8, T9> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT> {
- typedef Templates18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT> {
- typedef Templates19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT> {
- typedef Templates20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT> {
- typedef Templates21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT> {
- typedef Templates22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT> {
- typedef Templates23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT> {
- typedef Templates24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT> {
- typedef Templates25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT> {
- typedef Templates26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT> {
- typedef Templates27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT> {
- typedef Templates28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT> {
- typedef Templates29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, NoneT, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, NoneT, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, NoneT, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, NoneT, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, NoneT,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- NoneT, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- T45, NoneT, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- T45, T46, NoneT, NoneT, NoneT, NoneT> {
- typedef Templates46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45, T46> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- T45, T46, T47, NoneT, NoneT, NoneT> {
- typedef Templates47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45, T46, T47> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- T45, T46, T47, T48, NoneT, NoneT> {
- typedef Templates48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45, T46, T47, T48> type;
-};
-template <GTEST_TEMPLATE_ T1, GTEST_TEMPLATE_ T2, GTEST_TEMPLATE_ T3,
- GTEST_TEMPLATE_ T4, GTEST_TEMPLATE_ T5, GTEST_TEMPLATE_ T6,
- GTEST_TEMPLATE_ T7, GTEST_TEMPLATE_ T8, GTEST_TEMPLATE_ T9,
- GTEST_TEMPLATE_ T10, GTEST_TEMPLATE_ T11, GTEST_TEMPLATE_ T12,
- GTEST_TEMPLATE_ T13, GTEST_TEMPLATE_ T14, GTEST_TEMPLATE_ T15,
- GTEST_TEMPLATE_ T16, GTEST_TEMPLATE_ T17, GTEST_TEMPLATE_ T18,
- GTEST_TEMPLATE_ T19, GTEST_TEMPLATE_ T20, GTEST_TEMPLATE_ T21,
- GTEST_TEMPLATE_ T22, GTEST_TEMPLATE_ T23, GTEST_TEMPLATE_ T24,
- GTEST_TEMPLATE_ T25, GTEST_TEMPLATE_ T26, GTEST_TEMPLATE_ T27,
- GTEST_TEMPLATE_ T28, GTEST_TEMPLATE_ T29, GTEST_TEMPLATE_ T30,
- GTEST_TEMPLATE_ T31, GTEST_TEMPLATE_ T32, GTEST_TEMPLATE_ T33,
- GTEST_TEMPLATE_ T34, GTEST_TEMPLATE_ T35, GTEST_TEMPLATE_ T36,
- GTEST_TEMPLATE_ T37, GTEST_TEMPLATE_ T38, GTEST_TEMPLATE_ T39,
- GTEST_TEMPLATE_ T40, GTEST_TEMPLATE_ T41, GTEST_TEMPLATE_ T42,
- GTEST_TEMPLATE_ T43, GTEST_TEMPLATE_ T44, GTEST_TEMPLATE_ T45,
- GTEST_TEMPLATE_ T46, GTEST_TEMPLATE_ T47, GTEST_TEMPLATE_ T48,
- GTEST_TEMPLATE_ T49>
-struct Templates<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14,
- T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28, T29,
- T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44,
- T45, T46, T47, T48, T49, NoneT> {
- typedef Templates49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42, T43, T44, T45, T46, T47, T48, T49> type;
-};
-
-// The TypeList template makes it possible to use either a single type
-// or a Types<...> list in TYPED_TEST_CASE() and
-// INSTANTIATE_TYPED_TEST_CASE_P().
-
-template <typename T>
-struct TypeList { typedef Types1<T> type; };
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49, T50> > {
- typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
-};
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
-
-// Due to C++ preprocessor weirdness, we need double indirection to
-// concatenate two tokens when one of them is __LINE__. Writing
-//
-// foo ## __LINE__
-//
-// will result in the token foo__LINE__, instead of foo followed by
-// the current line number. For more details, see
-// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6
-#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar)
-#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar
-
-// Google Test defines the testing::Message class to allow construction of
-// test messages via the << operator. The idea is that anything
-// streamable to std::ostream can be streamed to a testing::Message.
-// This allows a user to use his own types in Google Test assertions by
-// overloading the << operator.
-//
-// util/gtl/stl_logging-inl.h overloads << for STL containers. These
-// overloads cannot be defined in the std namespace, as that will be
-// undefined behavior. Therefore, they are defined in the global
-// namespace instead.
-//
-// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
-// overloads are visible in either the std namespace or the global
-// namespace, but not other namespaces, including the testing
-// namespace which Google Test's Message class is in.
-//
-// To allow STL containers (and other types that has a << operator
-// defined in the global namespace) to be used in Google Test assertions,
-// testing::Message must access the custom << operator from the global
-// namespace. Hence this helper function.
-//
-// Note: Jeffrey Yasskin suggested an alternative fix by "using
-// ::operator<<;" in the definition of Message's operator<<. That fix
-// doesn't require a helper function, but unfortunately doesn't
-// compile with MSVC.
-template <typename T>
-inline void GTestStreamToHelper(std::ostream* os, const T& val) {
- *os << val;
-}
-
-namespace testing {
-
-// Forward declaration of classes.
-
-class AssertionResult; // Result of an assertion.
-class Message; // Represents a failure message.
-class Test; // Represents a test.
-class TestInfo; // Information about a test.
-class TestPartResult; // Result of a test part.
-class UnitTest; // A collection of test cases.
-
-namespace internal {
-
-struct TraceInfo; // Information about a trace point.
-class ScopedTrace; // Implements scoped trace.
-class TestInfoImpl; // Opaque implementation of TestInfo
-class UnitTestImpl; // Opaque implementation of UnitTest
-
-// How many times InitGoogleTest() has been called.
-extern int g_init_gtest_count;
-
-// The text used in failure messages to indicate the start of the
-// stack trace.
-GTEST_API_ extern const char kStackTraceMarker[];
-
-// A secret type that Google Test users don't know about. It has no
-// definition on purpose. Therefore it's impossible to create a
-// Secret object, which is what we want.
-class Secret;
-
-// Two overloaded helpers for checking at compile time whether an
-// expression is a null pointer literal (i.e. NULL or any 0-valued
-// compile-time integral constant). Their return values have
-// different sizes, so we can use sizeof() to test which version is
-// picked by the compiler. These helpers have no implementations, as
-// we only need their signatures.
-//
-// Given IsNullLiteralHelper(x), the compiler will pick the first
-// version if x can be implicitly converted to Secret*, and pick the
-// second version otherwise. Since Secret is a secret and incomplete
-// type, the only expression a user can write that has type Secret* is
-// a null pointer literal. Therefore, we know that x is a null
-// pointer literal if and only if the first version is picked by the
-// compiler.
-char IsNullLiteralHelper(Secret* p);
-char (&IsNullLiteralHelper(...))[2]; // NOLINT
-
-// A compile-time bool constant that is true if and only if x is a
-// null pointer literal (i.e. NULL or any 0-valued compile-time
-// integral constant).
-#ifdef GTEST_ELLIPSIS_NEEDS_POD_
-// We lose support for NULL detection where the compiler doesn't like
-// passing non-POD classes through ellipsis (...).
-#define GTEST_IS_NULL_LITERAL_(x) false
-#else
-#define GTEST_IS_NULL_LITERAL_(x) \
- (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1)
-#endif // GTEST_ELLIPSIS_NEEDS_POD_
-
-// Appends the user-supplied message to the Google-Test-generated message.
-GTEST_API_ String AppendUserMessage(const String& gtest_msg,
- const Message& user_msg);
-
-// A helper class for creating scoped traces in user programs.
-class GTEST_API_ ScopedTrace {
- public:
- // The c'tor pushes the given source file location and message onto
- // a trace stack maintained by Google Test.
- ScopedTrace(const char* file, int line, const Message& message);
-
- // The d'tor pops the info pushed by the c'tor.
- //
- // Note that the d'tor is not virtual in order to be efficient.
- // Don't inherit from ScopedTrace!
- ~ScopedTrace();
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace);
-} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its
- // c'tor and d'tor. Therefore it doesn't
- // need to be used otherwise.
-
-// Converts a streamable value to a String. A NULL pointer is
-// converted to "(null)". When the input value is a ::string,
-// ::std::string, ::wstring, or ::std::wstring object, each NUL
-// character in it is replaced with "\\0".
-// Declared here but defined in gtest.h, so that it has access
-// to the definition of the Message class, required by the ARM
-// compiler.
-template <typename T>
-String StreamableToString(const T& streamable);
-
-// Formats a value to be used in a failure message.
-
-#ifdef GTEST_NEEDS_IS_POINTER_
-
-// These are needed as the Nokia Symbian and IBM XL C/C++ compilers
-// cannot decide between const T& and const T* in a function template.
-// These compilers _can_ decide between class template specializations
-// for T and T*, so a tr1::type_traits-like is_pointer works, and we
-// can overload on that.
-
-// This overload makes sure that all pointers (including
-// those to char or wchar_t) are printed as raw pointers.
-template <typename T>
-inline String FormatValueForFailureMessage(internal::true_type /*dummy*/,
- T* pointer) {
- return StreamableToString(static_cast<const void*>(pointer));
-}
-
-template <typename T>
-inline String FormatValueForFailureMessage(internal::false_type /*dummy*/,
- const T& value) {
- return StreamableToString(value);
-}
-
-template <typename T>
-inline String FormatForFailureMessage(const T& value) {
- return FormatValueForFailureMessage(
- typename internal::is_pointer<T>::type(), value);
-}
-
-#else
-
-// These are needed as the above solution using is_pointer has the
-// limitation that T cannot be a type without external linkage, when
-// compiled using MSVC.
-
-template <typename T>
-inline String FormatForFailureMessage(const T& value) {
- return StreamableToString(value);
-}
-
-// This overload makes sure that all pointers (including
-// those to char or wchar_t) are printed as raw pointers.
-template <typename T>
-inline String FormatForFailureMessage(T* pointer) {
- return StreamableToString(static_cast<const void*>(pointer));
-}
-
-#endif // GTEST_NEEDS_IS_POINTER_
-
-// These overloaded versions handle narrow and wide characters.
-GTEST_API_ String FormatForFailureMessage(char ch);
-GTEST_API_ String FormatForFailureMessage(wchar_t wchar);
-
-// When this operand is a const char* or char*, and the other operand
-// is a ::std::string or ::string, we print this operand as a C string
-// rather than a pointer. We do the same for wide strings.
-
-// This internal macro is used to avoid duplicated code.
-#define GTEST_FORMAT_IMPL_(operand2_type, operand1_printer)\
-inline String FormatForComparisonFailureMessage(\
- operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
- return operand1_printer(str);\
-}\
-inline String FormatForComparisonFailureMessage(\
- const operand2_type::value_type* str, const operand2_type& /*operand2*/) {\
- return operand1_printer(str);\
-}
-
-GTEST_FORMAT_IMPL_(::std::string, String::ShowCStringQuoted)
-#if GTEST_HAS_STD_WSTRING
-GTEST_FORMAT_IMPL_(::std::wstring, String::ShowWideCStringQuoted)
-#endif // GTEST_HAS_STD_WSTRING
-
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_FORMAT_IMPL_(::string, String::ShowCStringQuoted)
-#endif // GTEST_HAS_GLOBAL_STRING
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_FORMAT_IMPL_(::wstring, String::ShowWideCStringQuoted)
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-#undef GTEST_FORMAT_IMPL_
-
-// Constructs and returns the message for an equality assertion
-// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
-//
-// The first four parameters are the expressions used in the assertion
-// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
-// where foo is 5 and bar is 6, we have:
-//
-// expected_expression: "foo"
-// actual_expression: "bar"
-// expected_value: "5"
-// actual_value: "6"
-//
-// The ignoring_case parameter is true iff the assertion is a
-// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
-// be inserted into the message.
-GTEST_API_ AssertionResult EqFailure(const char* expected_expression,
- const char* actual_expression,
- const String& expected_value,
- const String& actual_value,
- bool ignoring_case);
-
-// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
-GTEST_API_ String GetBoolAssertionFailureMessage(
- const AssertionResult& assertion_result,
- const char* expression_text,
- const char* actual_predicate_value,
- const char* expected_predicate_value);
-
-// This template class represents an IEEE floating-point number
-// (either single-precision or double-precision, depending on the
-// template parameters).
-//
-// The purpose of this class is to do more sophisticated number
-// comparison. (Due to round-off error, etc, it's very unlikely that
-// two floating-points will be equal exactly. Hence a naive
-// comparison by the == operation often doesn't work.)
-//
-// Format of IEEE floating-point:
-//
-// The most-significant bit being the leftmost, an IEEE
-// floating-point looks like
-//
-// sign_bit exponent_bits fraction_bits
-//
-// Here, sign_bit is a single bit that designates the sign of the
-// number.
-//
-// For float, there are 8 exponent bits and 23 fraction bits.
-//
-// For double, there are 11 exponent bits and 52 fraction bits.
-//
-// More details can be found at
-// http://en.wikipedia.org/wiki/IEEE_floating-point_standard.
-//
-// Template parameter:
-//
-// RawType: the raw floating-point type (either float or double)
-template <typename RawType>
-class FloatingPoint {
- public:
- // Defines the unsigned integer type that has the same size as the
- // floating point number.
- typedef typename TypeWithSize<sizeof(RawType)>::UInt Bits;
-
- // Constants.
-
- // # of bits in a number.
- static const size_t kBitCount = 8*sizeof(RawType);
-
- // # of fraction bits in a number.
- static const size_t kFractionBitCount =
- std::numeric_limits<RawType>::digits - 1;
-
- // # of exponent bits in a number.
- static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount;
-
- // The mask for the sign bit.
- static const Bits kSignBitMask = static_cast<Bits>(1) << (kBitCount - 1);
-
- // The mask for the fraction bits.
- static const Bits kFractionBitMask =
- ~static_cast<Bits>(0) >> (kExponentBitCount + 1);
-
- // The mask for the exponent bits.
- static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask);
-
- // How many ULP's (Units in the Last Place) we want to tolerate when
- // comparing two numbers. The larger the value, the more error we
- // allow. A 0 value means that two numbers must be exactly the same
- // to be considered equal.
- //
- // The maximum error of a single floating-point operation is 0.5
- // units in the last place. On Intel CPU's, all floating-point
- // calculations are done with 80-bit precision, while double has 64
- // bits. Therefore, 4 should be enough for ordinary use.
- //
- // See the following article for more details on ULP:
- // http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm.
- static const size_t kMaxUlps = 4;
-
- // Constructs a FloatingPoint from a raw floating-point number.
- //
- // On an Intel CPU, passing a non-normalized NAN (Not a Number)
- // around may change its bits, although the new value is guaranteed
- // to be also a NAN. Therefore, don't expect this constructor to
- // preserve the bits in x when x is a NAN.
- explicit FloatingPoint(const RawType& x) { u_.value_ = x; }
-
- // Static methods
-
- // Reinterprets a bit pattern as a floating-point number.
- //
- // This function is needed to test the AlmostEquals() method.
- static RawType ReinterpretBits(const Bits bits) {
- FloatingPoint fp(0);
- fp.u_.bits_ = bits;
- return fp.u_.value_;
- }
-
- // Returns the floating-point number that represent positive infinity.
- static RawType Infinity() {
- return ReinterpretBits(kExponentBitMask);
- }
-
- // Non-static methods
-
- // Returns the bits that represents this number.
- const Bits &bits() const { return u_.bits_; }
-
- // Returns the exponent bits of this number.
- Bits exponent_bits() const { return kExponentBitMask & u_.bits_; }
-
- // Returns the fraction bits of this number.
- Bits fraction_bits() const { return kFractionBitMask & u_.bits_; }
-
- // Returns the sign bit of this number.
- Bits sign_bit() const { return kSignBitMask & u_.bits_; }
-
- // Returns true iff this is NAN (not a number).
- bool is_nan() const {
- // It's a NAN if the exponent bits are all ones and the fraction
- // bits are not entirely zeros.
- return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0);
- }
-
- // Returns true iff this number is at most kMaxUlps ULP's away from
- // rhs. In particular, this function:
- //
- // - returns false if either number is (or both are) NAN.
- // - treats really large numbers as almost equal to infinity.
- // - thinks +0.0 and -0.0 are 0 DLP's apart.
- bool AlmostEquals(const FloatingPoint& rhs) const {
- // The IEEE standard says that any comparison operation involving
- // a NAN must return false.
- if (is_nan() || rhs.is_nan()) return false;
-
- return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_)
- <= kMaxUlps;
- }
-
- private:
- // The data type used to store the actual floating-point number.
- union FloatingPointUnion {
- RawType value_; // The raw floating-point number.
- Bits bits_; // The bits that represent the number.
- };
-
- // Converts an integer from the sign-and-magnitude representation to
- // the biased representation. More precisely, let N be 2 to the
- // power of (kBitCount - 1), an integer x is represented by the
- // unsigned number x + N.
- //
- // For instance,
- //
- // -N + 1 (the most negative number representable using
- // sign-and-magnitude) is represented by 1;
- // 0 is represented by N; and
- // N - 1 (the biggest number representable using
- // sign-and-magnitude) is represented by 2N - 1.
- //
- // Read http://en.wikipedia.org/wiki/Signed_number_representations
- // for more details on signed number representations.
- static Bits SignAndMagnitudeToBiased(const Bits &sam) {
- if (kSignBitMask & sam) {
- // sam represents a negative number.
- return ~sam + 1;
- } else {
- // sam represents a positive number.
- return kSignBitMask | sam;
- }
- }
-
- // Given two numbers in the sign-and-magnitude representation,
- // returns the distance between them as an unsigned number.
- static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1,
- const Bits &sam2) {
- const Bits biased1 = SignAndMagnitudeToBiased(sam1);
- const Bits biased2 = SignAndMagnitudeToBiased(sam2);
- return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
- }
-
- FloatingPointUnion u_;
-};
-
-// Typedefs the instances of the FloatingPoint template class that we
-// care to use.
-typedef FloatingPoint<float> Float;
-typedef FloatingPoint<double> Double;
-
-// In order to catch the mistake of putting tests that use different
-// test fixture classes in the same test case, we need to assign
-// unique IDs to fixture classes and compare them. The TypeId type is
-// used to hold such IDs. The user should treat TypeId as an opaque
-// type: the only operation allowed on TypeId values is to compare
-// them for equality using the == operator.
-typedef const void* TypeId;
-
-template <typename T>
-class TypeIdHelper {
- public:
- // dummy_ must not have a const type. Otherwise an overly eager
- // compiler (e.g. MSVC 7.1 & 8.0) may try to merge
- // TypeIdHelper<T>::dummy_ for different Ts as an "optimization".
- static bool dummy_;
-};
-
-template <typename T>
-bool TypeIdHelper<T>::dummy_ = false;
-
-// GetTypeId<T>() returns the ID of type T. Different values will be
-// returned for different types. Calling the function twice with the
-// same type argument is guaranteed to return the same ID.
-template <typename T>
-TypeId GetTypeId() {
- // The compiler is required to allocate a different
- // TypeIdHelper<T>::dummy_ variable for each T used to instantiate
- // the template. Therefore, the address of dummy_ is guaranteed to
- // be unique.
- return &(TypeIdHelper<T>::dummy_);
-}
-
-// Returns the type ID of ::testing::Test. Always call this instead
-// of GetTypeId< ::testing::Test>() to get the type ID of
-// ::testing::Test, as the latter may give the wrong result due to a
-// suspected linker bug when compiling Google Test as a Mac OS X
-// framework.
-GTEST_API_ TypeId GetTestTypeId();
-
-// Defines the abstract factory interface that creates instances
-// of a Test object.
-class TestFactoryBase {
- public:
- virtual ~TestFactoryBase() {}
-
- // Creates a test instance to run. The instance is both created and destroyed
- // within TestInfoImpl::Run()
- virtual Test* CreateTest() = 0;
-
- protected:
- TestFactoryBase() {}
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase);
-};
-
-// This class provides implementation of TeastFactoryBase interface.
-// It is used in TEST and TEST_F macros.
-template <class TestClass>
-class TestFactoryImpl : public TestFactoryBase {
- public:
- virtual Test* CreateTest() { return new TestClass; }
-};
-
-#if GTEST_OS_WINDOWS
-
-// Predicate-formatters for implementing the HRESULT checking macros
-// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}
-// We pass a long instead of HRESULT to avoid causing an
-// include dependency for the HRESULT type.
-GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr,
- long hr); // NOLINT
-GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr,
- long hr); // NOLINT
-
-#endif // GTEST_OS_WINDOWS
-
-// Formats a source file path and a line number as they would appear
-// in a compiler error message.
-inline String FormatFileLocation(const char* file, int line) {
- const char* const file_name = file == NULL ? "unknown file" : file;
- if (line < 0) {
- return String::Format("%s:", file_name);
- }
-#ifdef _MSC_VER
- return String::Format("%s(%d):", file_name, line);
-#else
- return String::Format("%s:%d:", file_name, line);
-#endif // _MSC_VER
-}
-
-// Types of SetUpTestCase() and TearDownTestCase() functions.
-typedef void (*SetUpTestCaseFunc)();
-typedef void (*TearDownTestCaseFunc)();
-
-// Creates a new TestInfo object and registers it with Google Test;
-// returns the created object.
-//
-// Arguments:
-//
-// test_case_name: name of the test case
-// name: name of the test
-// test_case_comment: a comment on the test case that will be included in
-// the test output
-// comment: a comment on the test that will be included in the
-// test output
-// fixture_class_id: ID of the test fixture class
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-// factory: pointer to the factory that creates a test object.
-// The newly created TestInfo instance will assume
-// ownership of the factory object.
-GTEST_API_ TestInfo* MakeAndRegisterTestInfo(
- const char* test_case_name, const char* name,
- const char* test_case_comment, const char* comment,
- TypeId fixture_class_id,
- SetUpTestCaseFunc set_up_tc,
- TearDownTestCaseFunc tear_down_tc,
- TestFactoryBase* factory);
-
-// If *pstr starts with the given prefix, modifies *pstr to be right
-// past the prefix and returns true; otherwise leaves *pstr unchanged
-// and returns false. None of pstr, *pstr, and prefix can be NULL.
-bool SkipPrefix(const char* prefix, const char** pstr);
-
-#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
-// State of the definition of a type-parameterized test case.
-class GTEST_API_ TypedTestCasePState {
- public:
- TypedTestCasePState() : registered_(false) {}
-
- // Adds the given test name to defined_test_names_ and return true
- // if the test case hasn't been registered; otherwise aborts the
- // program.
- bool AddTestName(const char* file, int line, const char* case_name,
- const char* test_name) {
- if (registered_) {
- fprintf(stderr, "%s Test %s must be defined before "
- "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n",
- FormatFileLocation(file, line).c_str(), test_name, case_name);
- fflush(stderr);
- posix::Abort();
- }
- defined_test_names_.insert(test_name);
- return true;
- }
-
- // Verifies that registered_tests match the test names in
- // defined_test_names_; returns registered_tests if successful, or
- // aborts the program otherwise.
- const char* VerifyRegisteredTestNames(
- const char* file, int line, const char* registered_tests);
-
- private:
- bool registered_;
- ::std::set<const char*> defined_test_names_;
-};
-
-// Skips to the first non-space char after the first comma in 'str';
-// returns NULL if no comma is found in 'str'.
-inline const char* SkipComma(const char* str) {
- const char* comma = strchr(str, ',');
- if (comma == NULL) {
- return NULL;
- }
- while (isspace(*(++comma))) {}
- return comma;
-}
-
-// Returns the prefix of 'str' before the first comma in it; returns
-// the entire string if it contains no comma.
-inline String GetPrefixUntilComma(const char* str) {
- const char* comma = strchr(str, ',');
- return comma == NULL ? String(str) : String(str, comma - str);
-}
-
-// TypeParameterizedTest<Fixture, TestSel, Types>::Register()
-// registers a list of type-parameterized tests with Google Test. The
-// return value is insignificant - we just need to return something
-// such that we can call this function in a namespace scope.
-//
-// Implementation note: The GTEST_TEMPLATE_ macro declares a template
-// template parameter. It's defined in gtest-type-util.h.
-template <GTEST_TEMPLATE_ Fixture, class TestSel, typename Types>
-class TypeParameterizedTest {
- public:
- // 'index' is the index of the test in the type list 'Types'
- // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase,
- // Types). Valid values for 'index' are [0, N - 1] where N is the
- // length of Types.
- static bool Register(const char* prefix, const char* case_name,
- const char* test_names, int index) {
- typedef typename Types::Head Type;
- typedef Fixture<Type> FixtureClass;
- typedef typename GTEST_BIND_(TestSel, Type) TestClass;
-
- // First, registers the first type-parameterized test in the type
- // list.
- MakeAndRegisterTestInfo(
- String::Format("%s%s%s/%d", prefix, prefix[0] == '\0' ? "" : "/",
- case_name, index).c_str(),
- GetPrefixUntilComma(test_names).c_str(),
- String::Format("TypeParam = %s", GetTypeName<Type>().c_str()).c_str(),
- "",
- GetTypeId<FixtureClass>(),
- TestClass::SetUpTestCase,
- TestClass::TearDownTestCase,
- new TestFactoryImpl<TestClass>);
-
- // Next, recurses (at compile time) with the tail of the type list.
- return TypeParameterizedTest<Fixture, TestSel, typename Types::Tail>
- ::Register(prefix, case_name, test_names, index + 1);
- }
-};
-
-// The base case for the compile time recursion.
-template <GTEST_TEMPLATE_ Fixture, class TestSel>
-class TypeParameterizedTest<Fixture, TestSel, Types0> {
- public:
- static bool Register(const char* /*prefix*/, const char* /*case_name*/,
- const char* /*test_names*/, int /*index*/) {
- return true;
- }
-};
-
-// TypeParameterizedTestCase<Fixture, Tests, Types>::Register()
-// registers *all combinations* of 'Tests' and 'Types' with Google
-// Test. The return value is insignificant - we just need to return
-// something such that we can call this function in a namespace scope.
-template <GTEST_TEMPLATE_ Fixture, typename Tests, typename Types>
-class TypeParameterizedTestCase {
- public:
- static bool Register(const char* prefix, const char* case_name,
- const char* test_names) {
- typedef typename Tests::Head Head;
-
- // First, register the first test in 'Test' for each type in 'Types'.
- TypeParameterizedTest<Fixture, Head, Types>::Register(
- prefix, case_name, test_names, 0);
-
- // Next, recurses (at compile time) with the tail of the test list.
- return TypeParameterizedTestCase<Fixture, typename Tests::Tail, Types>
- ::Register(prefix, case_name, SkipComma(test_names));
- }
-};
-
-// The base case for the compile time recursion.
-template <GTEST_TEMPLATE_ Fixture, typename Types>
-class TypeParameterizedTestCase<Fixture, Templates0, Types> {
- public:
- static bool Register(const char* /*prefix*/, const char* /*case_name*/,
- const char* /*test_names*/) {
- return true;
- }
-};
-
-#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
-
-// Returns the current OS stack trace as a String.
-//
-// The maximum number of stack frames to be included is specified by
-// the gtest_stack_trace_depth flag. The skip_count parameter
-// specifies the number of top frames to be skipped, which doesn't
-// count against the number of frames to be included.
-//
-// For example, if Foo() calls Bar(), which in turn calls
-// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
-// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
-GTEST_API_ String GetCurrentOsStackTraceExceptTop(UnitTest* unit_test,
- int skip_count);
-
-// Helpers for suppressing warnings on unreachable code or constant
-// condition.
-
-// Always returns true.
-GTEST_API_ bool AlwaysTrue();
-
-// Always returns false.
-inline bool AlwaysFalse() { return !AlwaysTrue(); }
-
-// A simple Linear Congruential Generator for generating random
-// numbers with a uniform distribution. Unlike rand() and srand(), it
-// doesn't use global state (and therefore can't interfere with user
-// code). Unlike rand_r(), it's portable. An LCG isn't very random,
-// but it's good enough for our purposes.
-class GTEST_API_ Random {
- public:
- static const UInt32 kMaxRange = 1u << 31;
-
- explicit Random(UInt32 seed) : state_(seed) {}
-
- void Reseed(UInt32 seed) { state_ = seed; }
-
- // Generates a random number from [0, range). Crashes if 'range' is
- // 0 or greater than kMaxRange.
- UInt32 Generate(UInt32 range);
-
- private:
- UInt32 state_;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Random);
-};
-
-} // namespace internal
-} // namespace testing
-
-#define GTEST_MESSAGE_(message, result_type) \
- ::testing::internal::AssertHelper(result_type, __FILE__, __LINE__, message) \
- = ::testing::Message()
-
-#define GTEST_FATAL_FAILURE_(message) \
- return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)
-
-#define GTEST_NONFATAL_FAILURE_(message) \
- GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)
-
-#define GTEST_SUCCESS_(message) \
- GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess)
-
-// Suppresses MSVC warnings 4072 (unreachable code) for the code following
-// statement if it returns or throws (or doesn't return or throw in some
-// situations).
-#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \
- if (::testing::internal::AlwaysTrue()) { statement; }
-
-#define GTEST_TEST_THROW_(statement, expected_exception, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
- bool gtest_caught_expected = false; \
- try { \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- } \
- catch (expected_exception const&) { \
- gtest_caught_expected = true; \
- } \
- catch (...) { \
- gtest_msg = "Expected: " #statement " throws an exception of type " \
- #expected_exception ".\n Actual: it throws a different " \
- "type."; \
- goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
- } \
- if (!gtest_caught_expected) { \
- gtest_msg = "Expected: " #statement " throws an exception of type " \
- #expected_exception ".\n Actual: it throws nothing."; \
- goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \
- fail(gtest_msg)
-
-#define GTEST_TEST_NO_THROW_(statement, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
- try { \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- } \
- catch (...) { \
- gtest_msg = "Expected: " #statement " doesn't throw an exception.\n" \
- " Actual: it throws."; \
- goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \
- fail(gtest_msg)
-
-#define GTEST_TEST_ANY_THROW_(statement, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
- bool gtest_caught_any = false; \
- try { \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- } \
- catch (...) { \
- gtest_caught_any = true; \
- } \
- if (!gtest_caught_any) { \
- gtest_msg = "Expected: " #statement " throws an exception.\n" \
- " Actual: it doesn't."; \
- goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \
- fail(gtest_msg)
-
-
-// Implements Boolean test assertions such as EXPECT_TRUE. expression can be
-// either a boolean expression or an AssertionResult. text is a textual
-// represenation of expression as it was passed into the EXPECT_TRUE.
-#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const ::testing::AssertionResult gtest_ar_ = \
- ::testing::AssertionResult(expression)) \
- ; \
- else \
- fail(::testing::internal::GetBoolAssertionFailureMessage(\
- gtest_ar_, text, #actual, #expected).c_str())
-
-#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const char* gtest_msg = "") { \
- ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \
- gtest_msg = "Expected: " #statement " doesn't generate new fatal " \
- "failures in the current thread.\n" \
- " Actual: it does."; \
- goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \
- fail(gtest_msg)
-
-// Expands to the name of the class that implements the given test.
-#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
- test_case_name##_##test_name##_Test
-
-// Helper macro for defining tests.
-#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\
-class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\
- public:\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\
- private:\
- virtual void TestBody();\
- static ::testing::TestInfo* const test_info_;\
- GTEST_DISALLOW_COPY_AND_ASSIGN_(\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\
-};\
-\
-::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\
- ::test_info_ =\
- ::testing::internal::MakeAndRegisterTestInfo(\
- #test_case_name, #test_name, "", "", \
- (parent_id), \
- parent_class::SetUpTestCase, \
- parent_class::TearDownTestCase, \
- new ::testing::internal::TestFactoryImpl<\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\
-void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file defines the public API for death tests. It is
-// #included by gtest.h so a user doesn't need to include this
-// directly.
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
-
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file defines internal utilities needed for implementing
-// death tests. They are subject to change without notice.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
-
-
-namespace testing {
-namespace internal {
-
-GTEST_DECLARE_string_(internal_run_death_test);
-
-// Names of the flags (needed for parsing Google Test flags).
-const char kDeathTestStyleFlag[] = "death_test_style";
-const char kDeathTestUseFork[] = "death_test_use_fork";
-const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
-
-#if GTEST_HAS_DEATH_TEST
-
-// DeathTest is a class that hides much of the complexity of the
-// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
-// returns a concrete class that depends on the prevailing death test
-// style, as defined by the --gtest_death_test_style and/or
-// --gtest_internal_run_death_test flags.
-
-// In describing the results of death tests, these terms are used with
-// the corresponding definitions:
-//
-// exit status: The integer exit information in the format specified
-// by wait(2)
-// exit code: The integer code passed to exit(3), _exit(2), or
-// returned from main()
-class GTEST_API_ DeathTest {
- public:
- // Create returns false if there was an error determining the
- // appropriate action to take for the current death test; for example,
- // if the gtest_death_test_style flag is set to an invalid value.
- // The LastMessage method will return a more detailed message in that
- // case. Otherwise, the DeathTest pointer pointed to by the "test"
- // argument is set. If the death test should be skipped, the pointer
- // is set to NULL; otherwise, it is set to the address of a new concrete
- // DeathTest object that controls the execution of the current test.
- static bool Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test);
- DeathTest();
- virtual ~DeathTest() { }
-
- // A helper class that aborts a death test when it's deleted.
- class ReturnSentinel {
- public:
- explicit ReturnSentinel(DeathTest* test) : test_(test) { }
- ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
- private:
- DeathTest* const test_;
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
- } GTEST_ATTRIBUTE_UNUSED_;
-
- // An enumeration of possible roles that may be taken when a death
- // test is encountered. EXECUTE means that the death test logic should
- // be executed immediately. OVERSEE means that the program should prepare
- // the appropriate environment for a child process to execute the death
- // test, then wait for it to complete.
- enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
-
- // An enumeration of the two reasons that a test might be aborted.
- enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_DID_NOT_DIE };
-
- // Assumes one of the above roles.
- virtual TestRole AssumeRole() = 0;
-
- // Waits for the death test to finish and returns its status.
- virtual int Wait() = 0;
-
- // Returns true if the death test passed; that is, the test process
- // exited during the test, its exit status matches a user-supplied
- // predicate, and its stderr output matches a user-supplied regular
- // expression.
- // The user-supplied predicate may be a macro expression rather
- // than a function pointer or functor, or else Wait and Passed could
- // be combined.
- virtual bool Passed(bool exit_status_ok) = 0;
-
- // Signals that the death test did not die as expected.
- virtual void Abort(AbortReason reason) = 0;
-
- // Returns a human-readable outcome message regarding the outcome of
- // the last death test.
- static const char* LastMessage();
-
- static void set_last_death_test_message(const String& message);
-
- private:
- // A string containing a description of the outcome of the last death test.
- static String last_death_test_message_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
-};
-
-// Factory interface for death tests. May be mocked out for testing.
-class DeathTestFactory {
- public:
- virtual ~DeathTestFactory() { }
- virtual bool Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test) = 0;
-};
-
-// A concrete DeathTestFactory implementation for normal use.
-class DefaultDeathTestFactory : public DeathTestFactory {
- public:
- virtual bool Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test);
-};
-
-// Returns true if exit_status describes a process that was terminated
-// by a signal, or exited normally with a nonzero exit code.
-GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
-
-// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
-// ASSERT_EXIT*, and EXPECT_EXIT*.
-#define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (::testing::internal::AlwaysTrue()) { \
- const ::testing::internal::RE& gtest_regex = (regex); \
- ::testing::internal::DeathTest* gtest_dt; \
- if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
- __FILE__, __LINE__, >est_dt)) { \
- goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
- } \
- if (gtest_dt != NULL) { \
- ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
- gtest_dt_ptr(gtest_dt); \
- switch (gtest_dt->AssumeRole()) { \
- case ::testing::internal::DeathTest::OVERSEE_TEST: \
- if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
- goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
- } \
- break; \
- case ::testing::internal::DeathTest::EXECUTE_TEST: { \
- ::testing::internal::DeathTest::ReturnSentinel \
- gtest_sentinel(gtest_dt); \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
- break; \
- } \
- } \
- } \
- } else \
- GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
- fail(::testing::internal::DeathTest::LastMessage())
-// The symbol "fail" here expands to something into which a message
-// can be streamed.
-
-// A class representing the parsed contents of the
-// --gtest_internal_run_death_test flag, as it existed when
-// RUN_ALL_TESTS was called.
-class InternalRunDeathTestFlag {
- public:
- InternalRunDeathTestFlag(const String& a_file,
- int a_line,
- int an_index,
- int a_write_fd)
- : file_(a_file), line_(a_line), index_(an_index),
- write_fd_(a_write_fd) {}
-
- ~InternalRunDeathTestFlag() {
- if (write_fd_ >= 0)
- posix::Close(write_fd_);
- }
-
- String file() const { return file_; }
- int line() const { return line_; }
- int index() const { return index_; }
- int write_fd() const { return write_fd_; }
-
- private:
- String file_;
- int line_;
- int index_;
- int write_fd_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
-};
-
-// Returns a newly created InternalRunDeathTestFlag object with fields
-// initialized from the GTEST_FLAG(internal_run_death_test) flag if
-// the flag is specified; otherwise returns NULL.
-InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
-
-#else // GTEST_HAS_DEATH_TEST
-
-// This macro is used for implementing macros such as
-// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
-// death tests are not supported. Those macros must compile on such systems
-// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
-// systems that support death tests. This allows one to write such a macro
-// on a system that does not support death tests and be sure that it will
-// compile on a death-test supporting system.
-//
-// Parameters:
-// statement - A statement that a macro such as EXPECT_DEATH would test
-// for program termination. This macro has to make sure this
-// statement is compiled but not executed, to ensure that
-// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
-// parameter iff EXPECT_DEATH compiles with it.
-// regex - A regex that a macro such as EXPECT_DEATH would use to test
-// the output of statement. This parameter has to be
-// compiled but not evaluated by this macro, to ensure that
-// this macro only accepts expressions that a macro such as
-// EXPECT_DEATH would accept.
-// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
-// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
-// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
-// compile inside functions where ASSERT_DEATH doesn't
-// compile.
-//
-// The branch that has an always false condition is used to ensure that
-// statement and regex are compiled (and thus syntactically correct) but
-// never executed. The unreachable code macro protects the terminator
-// statement from generating an 'unreachable code' warning in case
-// statement unconditionally returns or throws. The Message constructor at
-// the end allows the syntax of streaming additional messages into the
-// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
-#define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (::testing::internal::AlwaysTrue()) { \
- GTEST_LOG_(WARNING) \
- << "Death tests are not supported on this platform.\n" \
- << "Statement '" #statement "' cannot be verified."; \
- } else if (::testing::internal::AlwaysFalse()) { \
- ::testing::internal::RE::PartialMatch(".*", (regex)); \
- GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
- terminator; \
- } else \
- ::testing::Message()
-
-#endif // GTEST_HAS_DEATH_TEST
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
-
-namespace testing {
-
-// This flag controls the style of death tests. Valid values are "threadsafe",
-// meaning that the death test child process will re-execute the test binary
-// from the start, running only a single death test, or "fast",
-// meaning that the child process will execute the test logic immediately
-// after forking.
-GTEST_DECLARE_string_(death_test_style);
-
-#if GTEST_HAS_DEATH_TEST
-
-// The following macros are useful for writing death tests.
-
-// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
-// executed:
-//
-// 1. It generates a warning if there is more than one active
-// thread. This is because it's safe to fork() or clone() only
-// when there is a single thread.
-//
-// 2. The parent process clone()s a sub-process and runs the death
-// test in it; the sub-process exits with code 0 at the end of the
-// death test, if it hasn't exited already.
-//
-// 3. The parent process waits for the sub-process to terminate.
-//
-// 4. The parent process checks the exit code and error message of
-// the sub-process.
-//
-// Examples:
-//
-// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
-// for (int i = 0; i < 5; i++) {
-// EXPECT_DEATH(server.ProcessRequest(i),
-// "Invalid request .* in ProcessRequest()")
-// << "Failed to die on request " << i);
-// }
-//
-// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
-//
-// bool KilledBySIGHUP(int exit_code) {
-// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
-// }
-//
-// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
-//
-// On the regular expressions used in death tests:
-//
-// On POSIX-compliant systems (*nix), we use the <regex.h> library,
-// which uses the POSIX extended regex syntax.
-//
-// On other platforms (e.g. Windows), we only support a simple regex
-// syntax implemented as part of Google Test. This limited
-// implementation should be enough most of the time when writing
-// death tests; though it lacks many features you can find in PCRE
-// or POSIX extended regex syntax. For example, we don't support
-// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
-// repetition count ("x{5,7}"), among others.
-//
-// Below is the syntax that we do support. We chose it to be a
-// subset of both PCRE and POSIX extended regex, so it's easy to
-// learn wherever you come from. In the following: 'A' denotes a
-// literal character, period (.), or a single \\ escape sequence;
-// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
-// natural numbers.
-//
-// c matches any literal character c
-// \\d matches any decimal digit
-// \\D matches any character that's not a decimal digit
-// \\f matches \f
-// \\n matches \n
-// \\r matches \r
-// \\s matches any ASCII whitespace, including \n
-// \\S matches any character that's not a whitespace
-// \\t matches \t
-// \\v matches \v
-// \\w matches any letter, _, or decimal digit
-// \\W matches any character that \\w doesn't match
-// \\c matches any literal character c, which must be a punctuation
-// . matches any single character except \n
-// A? matches 0 or 1 occurrences of A
-// A* matches 0 or many occurrences of A
-// A+ matches 1 or many occurrences of A
-// ^ matches the beginning of a string (not that of each line)
-// $ matches the end of a string (not that of each line)
-// xy matches x followed by y
-//
-// If you accidentally use PCRE or POSIX extended regex features
-// not implemented by us, you will get a run-time failure. In that
-// case, please try to rewrite your regular expression within the
-// above syntax.
-//
-// This implementation is *not* meant to be as highly tuned or robust
-// as a compiled regex library, but should perform well enough for a
-// death test, which already incurs significant overhead by launching
-// a child process.
-//
-// Known caveats:
-//
-// A "threadsafe" style death test obtains the path to the test
-// program from argv[0] and re-executes it in the sub-process. For
-// simplicity, the current implementation doesn't search the PATH
-// when launching the sub-process. This means that the user must
-// invoke the test program via a path that contains at least one
-// path separator (e.g. path/to/foo_test and
-// /absolute/path/to/bar_test are fine, but foo_test is not). This
-// is rarely a problem as people usually don't put the test binary
-// directory in PATH.
-//
-// TODO(wan@google.com): make thread-safe death tests search the PATH.
-
-// Asserts that a given statement causes the program to exit, with an
-// integer exit status that satisfies predicate, and emitting error output
-// that matches regex.
-#define ASSERT_EXIT(statement, predicate, regex) \
- GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
-
-// Like ASSERT_EXIT, but continues on to successive tests in the
-// test case, if any:
-#define EXPECT_EXIT(statement, predicate, regex) \
- GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
-
-// Asserts that a given statement causes the program to exit, either by
-// explicitly exiting with a nonzero exit code or being killed by a
-// signal, and emitting error output that matches regex.
-#define ASSERT_DEATH(statement, regex) \
- ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
-
-// Like ASSERT_DEATH, but continues on to successive tests in the
-// test case, if any:
-#define EXPECT_DEATH(statement, regex) \
- EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
-
-// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
-
-// Tests that an exit code describes a normal exit with a given exit code.
-class GTEST_API_ ExitedWithCode {
- public:
- explicit ExitedWithCode(int exit_code);
- bool operator()(int exit_status) const;
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ExitedWithCode& other);
-
- const int exit_code_;
-};
-
-#if !GTEST_OS_WINDOWS
-// Tests that an exit code describes an exit due to termination by a
-// given signal.
-class GTEST_API_ KilledBySignal {
- public:
- explicit KilledBySignal(int signum);
- bool operator()(int exit_status) const;
- private:
- const int signum_;
-};
-#endif // !GTEST_OS_WINDOWS
-
-// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
-// The death testing framework causes this to have interesting semantics,
-// since the sideeffects of the call are only visible in opt mode, and not
-// in debug mode.
-//
-// In practice, this can be used to test functions that utilize the
-// LOG(DFATAL) macro using the following style:
-//
-// int DieInDebugOr12(int* sideeffect) {
-// if (sideeffect) {
-// *sideeffect = 12;
-// }
-// LOG(DFATAL) << "death";
-// return 12;
-// }
-//
-// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
-// int sideeffect = 0;
-// // Only asserts in dbg.
-// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
-//
-// #ifdef NDEBUG
-// // opt-mode has sideeffect visible.
-// EXPECT_EQ(12, sideeffect);
-// #else
-// // dbg-mode no visible sideeffect.
-// EXPECT_EQ(0, sideeffect);
-// #endif
-// }
-//
-// This will assert that DieInDebugReturn12InOpt() crashes in debug
-// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
-// appropriate fallback value (12 in this case) in opt mode. If you
-// need to test that a function has appropriate side-effects in opt
-// mode, include assertions against the side-effects. A general
-// pattern for this is:
-//
-// EXPECT_DEBUG_DEATH({
-// // Side-effects here will have an effect after this statement in
-// // opt mode, but none in debug mode.
-// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
-// }, "death");
-//
-#ifdef NDEBUG
-
-#define EXPECT_DEBUG_DEATH(statement, regex) \
- do { statement; } while (::testing::internal::AlwaysFalse())
-
-#define ASSERT_DEBUG_DEATH(statement, regex) \
- do { statement; } while (::testing::internal::AlwaysFalse())
-
-#else
-
-#define EXPECT_DEBUG_DEATH(statement, regex) \
- EXPECT_DEATH(statement, regex)
-
-#define ASSERT_DEBUG_DEATH(statement, regex) \
- ASSERT_DEATH(statement, regex)
-
-#endif // NDEBUG for EXPECT_DEBUG_DEATH
-#endif // GTEST_HAS_DEATH_TEST
-
-// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
-// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
-// death tests are supported; otherwise they just issue a warning. This is
-// useful when you are combining death test assertions with normal test
-// assertions in one test.
-#if GTEST_HAS_DEATH_TEST
-#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
- EXPECT_DEATH(statement, regex)
-#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
- ASSERT_DEATH(statement, regex)
-#else
-#define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
- GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
-#define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
- GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
-#endif
-
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
-//
-// This header file defines the Message class.
-//
-// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
-// leave some internal implementation details in this header file.
-// They are clearly marked by comments like this:
-//
-// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-//
-// Such code is NOT meant to be used by a user directly, and is subject
-// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
-// program!
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
-#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
-
-#include <limits>
-
-
-namespace testing {
-
-// The Message class works like an ostream repeater.
-//
-// Typical usage:
-//
-// 1. You stream a bunch of values to a Message object.
-// It will remember the text in a StrStream.
-// 2. Then you stream the Message object to an ostream.
-// This causes the text in the Message to be streamed
-// to the ostream.
-//
-// For example;
-//
-// testing::Message foo;
-// foo << 1 << " != " << 2;
-// std::cout << foo;
-//
-// will print "1 != 2".
-//
-// Message is not intended to be inherited from. In particular, its
-// destructor is not virtual.
-//
-// Note that StrStream behaves differently in gcc and in MSVC. You
-// can stream a NULL char pointer to it in the former, but not in the
-// latter (it causes an access violation if you do). The Message
-// class hides this difference by treating a NULL char pointer as
-// "(null)".
-class GTEST_API_ Message {
- private:
- // The type of basic IO manipulators (endl, ends, and flush) for
- // narrow streams.
- typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
-
- public:
- // Constructs an empty Message.
- // We allocate the StrStream separately because it otherwise each use of
- // ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's
- // stack frame leading to huge stack frames in some cases; gcc does not reuse
- // the stack space.
- Message() : ss_(new internal::StrStream) {
- // By default, we want there to be enough precision when printing
- // a double to a Message.
- *ss_ << std::setprecision(std::numeric_limits<double>::digits10 + 2);
- }
-
- // Copy constructor.
- Message(const Message& msg) : ss_(new internal::StrStream) { // NOLINT
- *ss_ << msg.GetString();
- }
-
- // Constructs a Message from a C-string.
- explicit Message(const char* str) : ss_(new internal::StrStream) {
- *ss_ << str;
- }
-
- ~Message() { delete ss_; }
-#if GTEST_OS_SYMBIAN
- // Streams a value (either a pointer or not) to this object.
- template <typename T>
- inline Message& operator <<(const T& value) {
- StreamHelper(typename internal::is_pointer<T>::type(), value);
- return *this;
- }
-#else
- // Streams a non-pointer value to this object.
- template <typename T>
- inline Message& operator <<(const T& val) {
- ::GTestStreamToHelper(ss_, val);
- return *this;
- }
-
- // Streams a pointer value to this object.
- //
- // This function is an overload of the previous one. When you
- // stream a pointer to a Message, this definition will be used as it
- // is more specialized. (The C++ Standard, section
- // [temp.func.order].) If you stream a non-pointer, then the
- // previous definition will be used.
- //
- // The reason for this overload is that streaming a NULL pointer to
- // ostream is undefined behavior. Depending on the compiler, you
- // may get "0", "(nil)", "(null)", or an access violation. To
- // ensure consistent result across compilers, we always treat NULL
- // as "(null)".
- template <typename T>
- inline Message& operator <<(T* const& pointer) { // NOLINT
- if (pointer == NULL) {
- *ss_ << "(null)";
- } else {
- ::GTestStreamToHelper(ss_, pointer);
- }
- return *this;
- }
-#endif // GTEST_OS_SYMBIAN
-
- // Since the basic IO manipulators are overloaded for both narrow
- // and wide streams, we have to provide this specialized definition
- // of operator <<, even though its body is the same as the
- // templatized version above. Without this definition, streaming
- // endl or other basic IO manipulators to Message will confuse the
- // compiler.
- Message& operator <<(BasicNarrowIoManip val) {
- *ss_ << val;
- return *this;
- }
-
- // Instead of 1/0, we want to see true/false for bool values.
- Message& operator <<(bool b) {
- return *this << (b ? "true" : "false");
- }
-
- // These two overloads allow streaming a wide C string to a Message
- // using the UTF-8 encoding.
- Message& operator <<(const wchar_t* wide_c_str) {
- return *this << internal::String::ShowWideCString(wide_c_str);
- }
- Message& operator <<(wchar_t* wide_c_str) {
- return *this << internal::String::ShowWideCString(wide_c_str);
- }
-
-#if GTEST_HAS_STD_WSTRING
- // Converts the given wide string to a narrow string using the UTF-8
- // encoding, and streams the result to this Message object.
- Message& operator <<(const ::std::wstring& wstr);
-#endif // GTEST_HAS_STD_WSTRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
- // Converts the given wide string to a narrow string using the UTF-8
- // encoding, and streams the result to this Message object.
- Message& operator <<(const ::wstring& wstr);
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
- // Gets the text streamed to this object so far as a String.
- // Each '\0' character in the buffer is replaced with "\\0".
- //
- // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
- internal::String GetString() const {
- return internal::StrStreamToString(ss_);
- }
-
- private:
-#if GTEST_OS_SYMBIAN
- // These are needed as the Nokia Symbian Compiler cannot decide between
- // const T& and const T* in a function template. The Nokia compiler _can_
- // decide between class template specializations for T and T*, so a
- // tr1::type_traits-like is_pointer works, and we can overload on that.
- template <typename T>
- inline void StreamHelper(internal::true_type /*dummy*/, T* pointer) {
- if (pointer == NULL) {
- *ss_ << "(null)";
- } else {
- ::GTestStreamToHelper(ss_, pointer);
- }
- }
- template <typename T>
- inline void StreamHelper(internal::false_type /*dummy*/, const T& value) {
- ::GTestStreamToHelper(ss_, value);
- }
-#endif // GTEST_OS_SYMBIAN
-
- // We'll hold the text streamed to this object here.
- internal::StrStream* const ss_;
-
- // We declare (but don't implement) this to prevent the compiler
- // from implementing the assignment operator.
- void operator=(const Message&);
-};
-
-// Streams a Message to an ostream.
-inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
- return os << sb.GetString();
-}
-
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
-// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
-
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: vladl@google.com (Vlad Losev)
-//
-// Macros and functions for implementing parameterized tests
-// in Google C++ Testing Framework (Google Test)
-//
-// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
-//
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
-
-
-// Value-parameterized tests allow you to test your code with different
-// parameters without writing multiple copies of the same test.
-//
-// Here is how you use value-parameterized tests:
-
-#if 0
-
-// To write value-parameterized tests, first you should define a fixture
-// class. It must be derived from testing::TestWithParam<T>, where T is
-// the type of your parameter values. TestWithParam<T> is itself derived
-// from testing::Test. T can be any copyable type. If it's a raw pointer,
-// you are responsible for managing the lifespan of the pointed values.
-
-class FooTest : public ::testing::TestWithParam<const char*> {
- // You can implement all the usual class fixture members here.
-};
-
-// Then, use the TEST_P macro to define as many parameterized tests
-// for this fixture as you want. The _P suffix is for "parameterized"
-// or "pattern", whichever you prefer to think.
-
-TEST_P(FooTest, DoesBlah) {
- // Inside a test, access the test parameter with the GetParam() method
- // of the TestWithParam<T> class:
- EXPECT_TRUE(foo.Blah(GetParam()));
- ...
-}
-
-TEST_P(FooTest, HasBlahBlah) {
- ...
-}
-
-// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
-// case with any set of parameters you want. Google Test defines a number
-// of functions for generating test parameters. They return what we call
-// (surprise!) parameter generators. Here is a summary of them, which
-// are all in the testing namespace:
-//
-//
-// Range(begin, end [, step]) - Yields values {begin, begin+step,
-// begin+step+step, ...}. The values do not
-// include end. step defaults to 1.
-// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
-// ValuesIn(container) - Yields values from a C-style array, an STL
-// ValuesIn(begin,end) container, or an iterator range [begin, end).
-// Bool() - Yields sequence {false, true}.
-// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
-// for the math savvy) of the values generated
-// by the N generators.
-//
-// For more details, see comments at the definitions of these functions below
-// in this file.
-//
-// The following statement will instantiate tests from the FooTest test case
-// each with parameter values "meeny", "miny", and "moe".
-
-INSTANTIATE_TEST_CASE_P(InstantiationName,
- FooTest,
- Values("meeny", "miny", "moe"));
-
-// To distinguish different instances of the pattern, (yes, you
-// can instantiate it more then once) the first argument to the
-// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
-// actual test case name. Remember to pick unique prefixes for different
-// instantiations. The tests from the instantiation above will have
-// these names:
-//
-// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
-// * InstantiationName/FooTest.DoesBlah/1 for "miny"
-// * InstantiationName/FooTest.DoesBlah/2 for "moe"
-// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
-// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
-// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
-//
-// You can use these names in --gtest_filter.
-//
-// This statement will instantiate all tests from FooTest again, each
-// with parameter values "cat" and "dog":
-
-const char* pets[] = {"cat", "dog"};
-INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
-
-// The tests from the instantiation above will have these names:
-//
-// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
-// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
-// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
-// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
-//
-// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
-// in the given test case, whether their definitions come before or
-// AFTER the INSTANTIATE_TEST_CASE_P statement.
-//
-// Please also note that generator expressions (including parameters to the
-// generators) are evaluated in InitGoogleTest(), after main() has started.
-// This allows the user on one hand, to adjust generator parameters in order
-// to dynamically determine a set of tests to run and on the other hand,
-// give the user a chance to inspect the generated tests with Google Test
-// reflection API before RUN_ALL_TESTS() is executed.
-//
-// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
-// for more examples.
-//
-// In the future, we plan to publish the API for defining new parameter
-// generators. But for now this interface remains part of the internal
-// implementation and is subject to change.
-
-#endif // 0
-
-
-#if !GTEST_OS_SYMBIAN
-#include <utility>
-#endif
-
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
-// Copyright 2008 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: vladl@google.com (Vlad Losev)
-
-// Type and function utilities for implementing parameterized tests.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
-
-#include <iterator>
-#include <utility>
-#include <vector>
-
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
-// Copyright 2003 Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: Dan Egnor (egnor@google.com)
-//
-// A "smart" pointer type with reference tracking. Every pointer to a
-// particular object is kept on a circular linked list. When the last pointer
-// to an object is destroyed or reassigned, the object is deleted.
-//
-// Used properly, this deletes the object when the last reference goes away.
-// There are several caveats:
-// - Like all reference counting schemes, cycles lead to leaks.
-// - Each smart pointer is actually two pointers (8 bytes instead of 4).
-// - Every time a pointer is assigned, the entire list of pointers to that
-// object is traversed. This class is therefore NOT SUITABLE when there
-// will often be more than two or three pointers to a particular object.
-// - References are only tracked as long as linked_ptr<> objects are copied.
-// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
-// will happen (double deletion).
-//
-// A good use of this class is storing object references in STL containers.
-// You can safely put linked_ptr<> in a vector<>.
-// Other uses may not be as good.
-//
-// Note: If you use an incomplete type with linked_ptr<>, the class
-// *containing* linked_ptr<> must have a constructor and destructor (even
-// if they do nothing!).
-//
-// Bill Gibbons suggested we use something like this.
-//
-// Thread Safety:
-// Unlike other linked_ptr implementations, in this implementation
-// a linked_ptr object is thread-safe in the sense that:
-// - it's safe to copy linked_ptr objects concurrently,
-// - it's safe to copy *from* a linked_ptr and read its underlying
-// raw pointer (e.g. via get()) concurrently, and
-// - it's safe to write to two linked_ptrs that point to the same
-// shared object concurrently.
-// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
-// confusion with normal linked_ptr.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
-
-#include <stdlib.h>
-#include <assert.h>
-
-
-namespace testing {
-namespace internal {
-
-// Protects copying of all linked_ptr objects.
-GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
-
-// This is used internally by all instances of linked_ptr<>. It needs to be
-// a non-template class because different types of linked_ptr<> can refer to
-// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
-// So, it needs to be possible for different types of linked_ptr to participate
-// in the same circular linked list, so we need a single class type here.
-//
-// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
-class linked_ptr_internal {
- public:
- // Create a new circle that includes only this instance.
- void join_new() {
- next_ = this;
- }
-
- // Many linked_ptr operations may change p.link_ for some linked_ptr
- // variable p in the same circle as this object. Therefore we need
- // to prevent two such operations from occurring concurrently.
- //
- // Note that different types of linked_ptr objects can coexist in a
- // circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
- // linked_ptr<Derived2>). Therefore we must use a single mutex to
- // protect all linked_ptr objects. This can create serious
- // contention in production code, but is acceptable in a testing
- // framework.
-
- // Join an existing circle.
- // L < g_linked_ptr_mutex
- void join(linked_ptr_internal const* ptr) {
- MutexLock lock(&g_linked_ptr_mutex);
-
- linked_ptr_internal const* p = ptr;
- while (p->next_ != ptr) p = p->next_;
- p->next_ = this;
- next_ = ptr;
- }
-
- // Leave whatever circle we're part of. Returns true if we were the
- // last member of the circle. Once this is done, you can join() another.
- // L < g_linked_ptr_mutex
- bool depart() {
- MutexLock lock(&g_linked_ptr_mutex);
-
- if (next_ == this) return true;
- linked_ptr_internal const* p = next_;
- while (p->next_ != this) p = p->next_;
- p->next_ = next_;
- return false;
- }
-
- private:
- mutable linked_ptr_internal const* next_;
-};
-
-template <typename T>
-class linked_ptr {
- public:
- typedef T element_type;
-
- // Take over ownership of a raw pointer. This should happen as soon as
- // possible after the object is created.
- explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
- ~linked_ptr() { depart(); }
-
- // Copy an existing linked_ptr<>, adding ourselves to the list of references.
- template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
- linked_ptr(linked_ptr const& ptr) { // NOLINT
- assert(&ptr != this);
- copy(&ptr);
- }
-
- // Assignment releases the old value and acquires the new.
- template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
- depart();
- copy(&ptr);
- return *this;
- }
-
- linked_ptr& operator=(linked_ptr const& ptr) {
- if (&ptr != this) {
- depart();
- copy(&ptr);
- }
- return *this;
- }
-
- // Smart pointer members.
- void reset(T* ptr = NULL) {
- depart();
- capture(ptr);
- }
- T* get() const { return value_; }
- T* operator->() const { return value_; }
- T& operator*() const { return *value_; }
- // Release ownership of the pointed object and returns it.
- // Sole ownership by this linked_ptr object is required.
- T* release() {
- bool last = link_.depart();
- assert(last);
- T* v = value_;
- value_ = NULL;
- return v;
- }
-
- bool operator==(T* p) const { return value_ == p; }
- bool operator!=(T* p) const { return value_ != p; }
- template <typename U>
- bool operator==(linked_ptr<U> const& ptr) const {
- return value_ == ptr.get();
- }
- template <typename U>
- bool operator!=(linked_ptr<U> const& ptr) const {
- return value_ != ptr.get();
- }
-
- private:
- template <typename U>
- friend class linked_ptr;
-
- T* value_;
- linked_ptr_internal link_;
-
- void depart() {
- if (link_.depart()) delete value_;
- }
-
- void capture(T* ptr) {
- value_ = ptr;
- link_.join_new();
- }
-
- template <typename U> void copy(linked_ptr<U> const* ptr) {
- value_ = ptr->get();
- if (value_)
- link_.join(&ptr->link_);
- else
- link_.join_new();
- }
-};
-
-template<typename T> inline
-bool operator==(T* ptr, const linked_ptr<T>& x) {
- return ptr == x.get();
-}
-
-template<typename T> inline
-bool operator!=(T* ptr, const linked_ptr<T>& x) {
- return ptr != x.get();
-}
-
-// A function to convert T* into linked_ptr<T>
-// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
-// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
-template <typename T>
-linked_ptr<T> make_linked_ptr(T* ptr) {
- return linked_ptr<T>(ptr);
-}
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
-
-#if GTEST_HAS_PARAM_TEST
-
-namespace testing {
-namespace internal {
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Outputs a message explaining invalid registration of different
-// fixture class for the same test case. This may happen when
-// TEST_P macro is used to define two tests with the same name
-// but in different namespaces.
-GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
- const char* file, int line);
-
-template <typename> class ParamGeneratorInterface;
-template <typename> class ParamGenerator;
-
-// Interface for iterating over elements provided by an implementation
-// of ParamGeneratorInterface<T>.
-template <typename T>
-class ParamIteratorInterface {
- public:
- virtual ~ParamIteratorInterface() {}
- // A pointer to the base generator instance.
- // Used only for the purposes of iterator comparison
- // to make sure that two iterators belong to the same generator.
- virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
- // Advances iterator to point to the next element
- // provided by the generator. The caller is responsible
- // for not calling Advance() on an iterator equal to
- // BaseGenerator()->End().
- virtual void Advance() = 0;
- // Clones the iterator object. Used for implementing copy semantics
- // of ParamIterator<T>.
- virtual ParamIteratorInterface* Clone() const = 0;
- // Dereferences the current iterator and provides (read-only) access
- // to the pointed value. It is the caller's responsibility not to call
- // Current() on an iterator equal to BaseGenerator()->End().
- // Used for implementing ParamGenerator<T>::operator*().
- virtual const T* Current() const = 0;
- // Determines whether the given iterator and other point to the same
- // element in the sequence generated by the generator.
- // Used for implementing ParamGenerator<T>::operator==().
- virtual bool Equals(const ParamIteratorInterface& other) const = 0;
-};
-
-// Class iterating over elements provided by an implementation of
-// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
-// and implements the const forward iterator concept.
-template <typename T>
-class ParamIterator {
- public:
- typedef T value_type;
- typedef const T& reference;
- typedef ptrdiff_t difference_type;
-
- // ParamIterator assumes ownership of the impl_ pointer.
- ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
- ParamIterator& operator=(const ParamIterator& other) {
- if (this != &other)
- impl_.reset(other.impl_->Clone());
- return *this;
- }
-
- const T& operator*() const { return *impl_->Current(); }
- const T* operator->() const { return impl_->Current(); }
- // Prefix version of operator++.
- ParamIterator& operator++() {
- impl_->Advance();
- return *this;
- }
- // Postfix version of operator++.
- ParamIterator operator++(int /*unused*/) {
- ParamIteratorInterface<T>* clone = impl_->Clone();
- impl_->Advance();
- return ParamIterator(clone);
- }
- bool operator==(const ParamIterator& other) const {
- return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
- }
- bool operator!=(const ParamIterator& other) const {
- return !(*this == other);
- }
-
- private:
- friend class ParamGenerator<T>;
- explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
- scoped_ptr<ParamIteratorInterface<T> > impl_;
-};
-
-// ParamGeneratorInterface<T> is the binary interface to access generators
-// defined in other translation units.
-template <typename T>
-class ParamGeneratorInterface {
- public:
- typedef T ParamType;
-
- virtual ~ParamGeneratorInterface() {}
-
- // Generator interface definition
- virtual ParamIteratorInterface<T>* Begin() const = 0;
- virtual ParamIteratorInterface<T>* End() const = 0;
-};
-
-// Wraps ParamGeneratorInterface<T> and provides general generator syntax
-// compatible with the STL Container concept.
-// This class implements copy initialization semantics and the contained
-// ParamGeneratorInterface<T> instance is shared among all copies
-// of the original object. This is possible because that instance is immutable.
-template<typename T>
-class ParamGenerator {
- public:
- typedef ParamIterator<T> iterator;
-
- explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
- ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
-
- ParamGenerator& operator=(const ParamGenerator& other) {
- impl_ = other.impl_;
- return *this;
- }
-
- iterator begin() const { return iterator(impl_->Begin()); }
- iterator end() const { return iterator(impl_->End()); }
-
- private:
- ::testing::internal::linked_ptr<const ParamGeneratorInterface<T> > impl_;
-};
-
-// Generates values from a range of two comparable values. Can be used to
-// generate sequences of user-defined types that implement operator+() and
-// operator<().
-// This class is used in the Range() function.
-template <typename T, typename IncrementT>
-class RangeGenerator : public ParamGeneratorInterface<T> {
- public:
- RangeGenerator(T begin, T end, IncrementT step)
- : begin_(begin), end_(end),
- step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
- virtual ~RangeGenerator() {}
-
- virtual ParamIteratorInterface<T>* Begin() const {
- return new Iterator(this, begin_, 0, step_);
- }
- virtual ParamIteratorInterface<T>* End() const {
- return new Iterator(this, end_, end_index_, step_);
- }
-
- private:
- class Iterator : public ParamIteratorInterface<T> {
- public:
- Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
- IncrementT step)
- : base_(base), value_(value), index_(index), step_(step) {}
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
- return base_;
- }
- virtual void Advance() {
- value_ = value_ + step_;
- index_++;
- }
- virtual ParamIteratorInterface<T>* Clone() const {
- return new Iterator(*this);
- }
- virtual const T* Current() const { return &value_; }
- virtual bool Equals(const ParamIteratorInterface<T>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const int other_index =
- CheckedDowncastToActualType<const Iterator>(&other)->index_;
- return index_ == other_index;
- }
-
- private:
- Iterator(const Iterator& other)
- : ParamIteratorInterface<T>(),
- base_(other.base_), value_(other.value_), index_(other.index_),
- step_(other.step_) {}
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<T>* const base_;
- T value_;
- int index_;
- const IncrementT step_;
- }; // class RangeGenerator::Iterator
-
- static int CalculateEndIndex(const T& begin,
- const T& end,
- const IncrementT& step) {
- int end_index = 0;
- for (T i = begin; i < end; i = i + step)
- end_index++;
- return end_index;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const RangeGenerator& other);
-
- const T begin_;
- const T end_;
- const IncrementT step_;
- // The index for the end() iterator. All the elements in the generated
- // sequence are indexed (0-based) to aid iterator comparison.
- const int end_index_;
-}; // class RangeGenerator
-
-
-// Generates values from a pair of STL-style iterators. Used in the
-// ValuesIn() function. The elements are copied from the source range
-// since the source can be located on the stack, and the generator
-// is likely to persist beyond that stack frame.
-template <typename T>
-class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
- public:
- template <typename ForwardIterator>
- ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
- : container_(begin, end) {}
- virtual ~ValuesInIteratorRangeGenerator() {}
-
- virtual ParamIteratorInterface<T>* Begin() const {
- return new Iterator(this, container_.begin());
- }
- virtual ParamIteratorInterface<T>* End() const {
- return new Iterator(this, container_.end());
- }
-
- private:
- typedef typename ::std::vector<T> ContainerType;
-
- class Iterator : public ParamIteratorInterface<T> {
- public:
- Iterator(const ParamGeneratorInterface<T>* base,
- typename ContainerType::const_iterator iterator)
- : base_(base), iterator_(iterator) {}
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
- return base_;
- }
- virtual void Advance() {
- ++iterator_;
- value_.reset();
- }
- virtual ParamIteratorInterface<T>* Clone() const {
- return new Iterator(*this);
- }
- // We need to use cached value referenced by iterator_ because *iterator_
- // can return a temporary object (and of type other then T), so just
- // having "return &*iterator_;" doesn't work.
- // value_ is updated here and not in Advance() because Advance()
- // can advance iterator_ beyond the end of the range, and we cannot
- // detect that fact. The client code, on the other hand, is
- // responsible for not calling Current() on an out-of-range iterator.
- virtual const T* Current() const {
- if (value_.get() == NULL)
- value_.reset(new T(*iterator_));
- return value_.get();
- }
- virtual bool Equals(const ParamIteratorInterface<T>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- return iterator_ ==
- CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
- }
-
- private:
- Iterator(const Iterator& other)
- // The explicit constructor call suppresses a false warning
- // emitted by gcc when supplied with the -Wextra option.
- : ParamIteratorInterface<T>(),
- base_(other.base_),
- iterator_(other.iterator_) {}
-
- const ParamGeneratorInterface<T>* const base_;
- typename ContainerType::const_iterator iterator_;
- // A cached value of *iterator_. We keep it here to allow access by
- // pointer in the wrapping iterator's operator->().
- // value_ needs to be mutable to be accessed in Current().
- // Use of scoped_ptr helps manage cached value's lifetime,
- // which is bound by the lifespan of the iterator itself.
- mutable scoped_ptr<const T> value_;
- }; // class ValuesInIteratorRangeGenerator::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const ValuesInIteratorRangeGenerator& other);
-
- const ContainerType container_;
-}; // class ValuesInIteratorRangeGenerator
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Stores a parameter value and later creates tests parameterized with that
-// value.
-template <class TestClass>
-class ParameterizedTestFactory : public TestFactoryBase {
- public:
- typedef typename TestClass::ParamType ParamType;
- explicit ParameterizedTestFactory(ParamType parameter) :
- parameter_(parameter) {}
- virtual Test* CreateTest() {
- TestClass::SetParam(¶meter_);
- return new TestClass();
- }
-
- private:
- const ParamType parameter_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
-};
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// TestMetaFactoryBase is a base class for meta-factories that create
-// test factories for passing into MakeAndRegisterTestInfo function.
-template <class ParamType>
-class TestMetaFactoryBase {
- public:
- virtual ~TestMetaFactoryBase() {}
-
- virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
-};
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// TestMetaFactory creates test factories for passing into
-// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
-// ownership of test factory pointer, same factory object cannot be passed
-// into that method twice. But ParameterizedTestCaseInfo is going to call
-// it for each Test/Parameter value combination. Thus it needs meta factory
-// creator class.
-template <class TestCase>
-class TestMetaFactory
- : public TestMetaFactoryBase<typename TestCase::ParamType> {
- public:
- typedef typename TestCase::ParamType ParamType;
-
- TestMetaFactory() {}
-
- virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
- return new ParameterizedTestFactory<TestCase>(parameter);
- }
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
-};
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// ParameterizedTestCaseInfoBase is a generic interface
-// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
-// accumulates test information provided by TEST_P macro invocations
-// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
-// and uses that information to register all resulting test instances
-// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
-// a collection of pointers to the ParameterizedTestCaseInfo objects
-// and calls RegisterTests() on each of them when asked.
-class ParameterizedTestCaseInfoBase {
- public:
- virtual ~ParameterizedTestCaseInfoBase() {}
-
- // Base part of test case name for display purposes.
- virtual const String& GetTestCaseName() const = 0;
- // Test case id to verify identity.
- virtual TypeId GetTestCaseTypeId() const = 0;
- // UnitTest class invokes this method to register tests in this
- // test case right before running them in RUN_ALL_TESTS macro.
- // This method should not be called more then once on any single
- // instance of a ParameterizedTestCaseInfoBase derived class.
- virtual void RegisterTests() = 0;
-
- protected:
- ParameterizedTestCaseInfoBase() {}
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
-};
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
-// macro invocations for a particular test case and generators
-// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
-// test case. It registers tests with all values generated by all
-// generators when asked.
-template <class TestCase>
-class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
- public:
- // ParamType and GeneratorCreationFunc are private types but are required
- // for declarations of public methods AddTestPattern() and
- // AddTestCaseInstantiation().
- typedef typename TestCase::ParamType ParamType;
- // A function that returns an instance of appropriate generator type.
- typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
-
- explicit ParameterizedTestCaseInfo(const char* name)
- : test_case_name_(name) {}
-
- // Test case base name for display purposes.
- virtual const String& GetTestCaseName() const { return test_case_name_; }
- // Test case id to verify identity.
- virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
- // TEST_P macro uses AddTestPattern() to record information
- // about a single test in a LocalTestInfo structure.
- // test_case_name is the base name of the test case (without invocation
- // prefix). test_base_name is the name of an individual test without
- // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
- // test case base name and DoBar is test base name.
- void AddTestPattern(const char* test_case_name,
- const char* test_base_name,
- TestMetaFactoryBase<ParamType>* meta_factory) {
- tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
- test_base_name,
- meta_factory)));
- }
- // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
- // about a generator.
- int AddTestCaseInstantiation(const char* instantiation_name,
- GeneratorCreationFunc* func,
- const char* /* file */,
- int /* line */) {
- instantiations_.push_back(::std::make_pair(instantiation_name, func));
- return 0; // Return value used only to run this method in namespace scope.
- }
- // UnitTest class invokes this method to register tests in this test case
- // test cases right before running tests in RUN_ALL_TESTS macro.
- // This method should not be called more then once on any single
- // instance of a ParameterizedTestCaseInfoBase derived class.
- // UnitTest has a guard to prevent from calling this method more then once.
- virtual void RegisterTests() {
- for (typename TestInfoContainer::iterator test_it = tests_.begin();
- test_it != tests_.end(); ++test_it) {
- linked_ptr<TestInfo> test_info = *test_it;
- for (typename InstantiationContainer::iterator gen_it =
- instantiations_.begin(); gen_it != instantiations_.end();
- ++gen_it) {
- const String& instantiation_name = gen_it->first;
- ParamGenerator<ParamType> generator((*gen_it->second)());
-
- Message test_case_name_stream;
- if ( !instantiation_name.empty() )
- test_case_name_stream << instantiation_name.c_str() << "/";
- test_case_name_stream << test_info->test_case_base_name.c_str();
-
- int i = 0;
- for (typename ParamGenerator<ParamType>::iterator param_it =
- generator.begin();
- param_it != generator.end(); ++param_it, ++i) {
- Message test_name_stream;
- test_name_stream << test_info->test_base_name.c_str() << "/" << i;
- ::testing::internal::MakeAndRegisterTestInfo(
- test_case_name_stream.GetString().c_str(),
- test_name_stream.GetString().c_str(),
- "", // test_case_comment
- "", // comment; TODO(vladl@google.com): provide parameter value
- // representation.
- GetTestCaseTypeId(),
- TestCase::SetUpTestCase,
- TestCase::TearDownTestCase,
- test_info->test_meta_factory->CreateTestFactory(*param_it));
- } // for param_it
- } // for gen_it
- } // for test_it
- } // RegisterTests
-
- private:
- // LocalTestInfo structure keeps information about a single test registered
- // with TEST_P macro.
- struct TestInfo {
- TestInfo(const char* a_test_case_base_name,
- const char* a_test_base_name,
- TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
- test_case_base_name(a_test_case_base_name),
- test_base_name(a_test_base_name),
- test_meta_factory(a_test_meta_factory) {}
-
- const String test_case_base_name;
- const String test_base_name;
- const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
- };
- typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
- // Keeps pairs of <Instantiation name, Sequence generator creation function>
- // received from INSTANTIATE_TEST_CASE_P macros.
- typedef ::std::vector<std::pair<String, GeneratorCreationFunc*> >
- InstantiationContainer;
-
- const String test_case_name_;
- TestInfoContainer tests_;
- InstantiationContainer instantiations_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
-}; // class ParameterizedTestCaseInfo
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
-// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
-// macros use it to locate their corresponding ParameterizedTestCaseInfo
-// descriptors.
-class ParameterizedTestCaseRegistry {
- public:
- ParameterizedTestCaseRegistry() {}
- ~ParameterizedTestCaseRegistry() {
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- delete *it;
- }
- }
-
- // Looks up or creates and returns a structure containing information about
- // tests and instantiations of a particular test case.
- template <class TestCase>
- ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
- const char* test_case_name,
- const char* file,
- int line) {
- ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- if ((*it)->GetTestCaseName() == test_case_name) {
- if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
- // Complain about incorrect usage of Google Test facilities
- // and terminate the program since we cannot guaranty correct
- // test case setup and tear-down in this case.
- ReportInvalidTestCaseType(test_case_name, file, line);
- abort();
- } else {
- // At this point we are sure that the object we found is of the same
- // type we are looking for, so we downcast it to that type
- // without further checks.
- typed_test_info = CheckedDowncastToActualType<
- ParameterizedTestCaseInfo<TestCase> >(*it);
- }
- break;
- }
- }
- if (typed_test_info == NULL) {
- typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
- test_case_infos_.push_back(typed_test_info);
- }
- return typed_test_info;
- }
- void RegisterTests() {
- for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
- it != test_case_infos_.end(); ++it) {
- (*it)->RegisterTests();
- }
- }
-
- private:
- typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
-
- TestCaseInfoContainer test_case_infos_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
-};
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_HAS_PARAM_TEST
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
-// This file was GENERATED by a script. DO NOT EDIT BY HAND!!!
-
-// Copyright 2008 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: vladl@google.com (Vlad Losev)
-
-// Type and function utilities for implementing parameterized tests.
-// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
-//
-// Currently Google Test supports at most 50 arguments in Values,
-// and at most 10 arguments in Combine. Please contact
-// googletestframework@googlegroups.com if you need more.
-// Please note that the number of arguments to Combine is limited
-// by the maximum arity of the implementation of tr1::tuple which is
-// currently set at 10.
-
-#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
-#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
-
-// scripts/fuse_gtest.py depends on gtest's own header being #included
-// *unconditionally*. Therefore these #includes cannot be moved
-// inside #if GTEST_HAS_PARAM_TEST.
-
-#if GTEST_HAS_PARAM_TEST
-
-namespace testing {
-
-// Forward declarations of ValuesIn(), which is implemented in
-// include/gtest/gtest-param-test.h.
-template <typename ForwardIterator>
-internal::ParamGenerator<
- typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
- ForwardIterator begin, ForwardIterator end);
-
-template <typename T, size_t N>
-internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
-
-template <class Container>
-internal::ParamGenerator<typename Container::value_type> ValuesIn(
- const Container& container);
-
-namespace internal {
-
-// Used in the Values() function to provide polymorphic capabilities.
-template <typename T1>
-class ValueArray1 {
- public:
- explicit ValueArray1(T1 v1) : v1_(v1) {}
-
- template <typename T>
- operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray1& other);
-
- const T1 v1_;
-};
-
-template <typename T1, typename T2>
-class ValueArray2 {
- public:
- ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray2& other);
-
- const T1 v1_;
- const T2 v2_;
-};
-
-template <typename T1, typename T2, typename T3>
-class ValueArray3 {
- public:
- ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray3& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4>
-class ValueArray4 {
- public:
- ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray4& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-class ValueArray5 {
- public:
- ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray5& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-class ValueArray6 {
- public:
- ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray6& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-class ValueArray7 {
- public:
- ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray7& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-class ValueArray8 {
- public:
- ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray8& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-class ValueArray9 {
- public:
- ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray9& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-class ValueArray10 {
- public:
- ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray10& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-class ValueArray11 {
- public:
- ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray11& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-class ValueArray12 {
- public:
- ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray12& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-class ValueArray13 {
- public:
- ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray13& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-class ValueArray14 {
- public:
- ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray14& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-class ValueArray15 {
- public:
- ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray15& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-class ValueArray16 {
- public:
- ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray16& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-class ValueArray17 {
- public:
- ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray17& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-class ValueArray18 {
- public:
- ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray18& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-class ValueArray19 {
- public:
- ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray19& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-class ValueArray20 {
- public:
- ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray20& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-class ValueArray21 {
- public:
- ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray21& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-class ValueArray22 {
- public:
- ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray22& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-class ValueArray23 {
- public:
- ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_,
- v23_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray23& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-class ValueArray24 {
- public:
- ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray24& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-class ValueArray25 {
- public:
- ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray25& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-class ValueArray26 {
- public:
- ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray26& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-class ValueArray27 {
- public:
- ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray27& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-class ValueArray28 {
- public:
- ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray28& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-class ValueArray29 {
- public:
- ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray29& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-class ValueArray30 {
- public:
- ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray30& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-class ValueArray31 {
- public:
- ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray31& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-class ValueArray32 {
- public:
- ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray32& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-class ValueArray33 {
- public:
- ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
- T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray33& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-class ValueArray34 {
- public:
- ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray34& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-class ValueArray35 {
- public:
- ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
- v32_(v32), v33_(v33), v34_(v34), v35_(v35) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_,
- v35_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray35& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-class ValueArray36 {
- public:
- ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
- v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray36& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-class ValueArray37 {
- public:
- ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
- v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
- v36_(v36), v37_(v37) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray37& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-class ValueArray38 {
- public:
- ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray38& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-class ValueArray39 {
- public:
- ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray39& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-class ValueArray40 {
- public:
- ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
- v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
- v40_(v40) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray40& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-class ValueArray41 {
- public:
- ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
- T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray41& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-class ValueArray42 {
- public:
- ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray42& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-class ValueArray43 {
- public:
- ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6),
- v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13),
- v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19),
- v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25),
- v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31),
- v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37),
- v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray43& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-class ValueArray44 {
- public:
- ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5),
- v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12),
- v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18),
- v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24),
- v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30),
- v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36),
- v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42),
- v43_(v43), v44_(v44) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray44& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-class ValueArray45 {
- public:
- ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4),
- v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11),
- v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17),
- v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23),
- v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29),
- v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35),
- v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41),
- v42_(v42), v43_(v43), v44_(v44), v45_(v45) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray45& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-class ValueArray46 {
- public:
- ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3),
- v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
- v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray46& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-class ValueArray47 {
- public:
- ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2),
- v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10),
- v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16),
- v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22),
- v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28),
- v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34),
- v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40),
- v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46),
- v47_(v47) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_,
- v47_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray47& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-class ValueArray48 {
- public:
- ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1),
- v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9),
- v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15),
- v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21),
- v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27),
- v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33),
- v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39),
- v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45),
- v46_(v46), v47_(v47), v48_(v48) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
- v48_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray48& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-class ValueArray49 {
- public:
- ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48,
- T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
- v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
- v48_, v49_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray49& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
- const T49 v49_;
-};
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-class ValueArray50 {
- public:
- ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49,
- T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7),
- v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14),
- v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20),
- v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26),
- v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32),
- v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38),
- v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44),
- v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {}
-
- template <typename T>
- operator ParamGenerator<T>() const {
- const T array[] = {v1_, v2_, v3_, v4_, v5_, v6_, v7_, v8_, v9_, v10_, v11_,
- v12_, v13_, v14_, v15_, v16_, v17_, v18_, v19_, v20_, v21_, v22_, v23_,
- v24_, v25_, v26_, v27_, v28_, v29_, v30_, v31_, v32_, v33_, v34_, v35_,
- v36_, v37_, v38_, v39_, v40_, v41_, v42_, v43_, v44_, v45_, v46_, v47_,
- v48_, v49_, v50_};
- return ValuesIn(array);
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const ValueArray50& other);
-
- const T1 v1_;
- const T2 v2_;
- const T3 v3_;
- const T4 v4_;
- const T5 v5_;
- const T6 v6_;
- const T7 v7_;
- const T8 v8_;
- const T9 v9_;
- const T10 v10_;
- const T11 v11_;
- const T12 v12_;
- const T13 v13_;
- const T14 v14_;
- const T15 v15_;
- const T16 v16_;
- const T17 v17_;
- const T18 v18_;
- const T19 v19_;
- const T20 v20_;
- const T21 v21_;
- const T22 v22_;
- const T23 v23_;
- const T24 v24_;
- const T25 v25_;
- const T26 v26_;
- const T27 v27_;
- const T28 v28_;
- const T29 v29_;
- const T30 v30_;
- const T31 v31_;
- const T32 v32_;
- const T33 v33_;
- const T34 v34_;
- const T35 v35_;
- const T36 v36_;
- const T37 v37_;
- const T38 v38_;
- const T39 v39_;
- const T40 v40_;
- const T41 v41_;
- const T42 v42_;
- const T43 v43_;
- const T44 v44_;
- const T45 v45_;
- const T46 v46_;
- const T47 v47_;
- const T48 v48_;
- const T49 v49_;
- const T50 v50_;
-};
-
-#if GTEST_HAS_COMBINE
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Generates values from the Cartesian product of values produced
-// by the argument generators.
-//
-template <typename T1, typename T2>
-class CartesianProductGenerator2
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2> > {
- public:
- typedef ::std::tr1::tuple<T1, T2> ParamType;
-
- CartesianProductGenerator2(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2)
- : g1_(g1), g2_(g2) {}
- virtual ~CartesianProductGenerator2() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current2_;
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- ParamType current_value_;
- }; // class CartesianProductGenerator2::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator2& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
-}; // class CartesianProductGenerator2
-
-
-template <typename T1, typename T2, typename T3>
-class CartesianProductGenerator3
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3> ParamType;
-
- CartesianProductGenerator3(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3)
- : g1_(g1), g2_(g2), g3_(g3) {}
- virtual ~CartesianProductGenerator3() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current3_;
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- ParamType current_value_;
- }; // class CartesianProductGenerator3::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator3& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
-}; // class CartesianProductGenerator3
-
-
-template <typename T1, typename T2, typename T3, typename T4>
-class CartesianProductGenerator4
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4> ParamType;
-
- CartesianProductGenerator4(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
- virtual ~CartesianProductGenerator4() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current4_;
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- ParamType current_value_;
- }; // class CartesianProductGenerator4::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator4& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
-}; // class CartesianProductGenerator4
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-class CartesianProductGenerator5
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5> ParamType;
-
- CartesianProductGenerator5(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
- virtual ~CartesianProductGenerator5() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current5_;
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- ParamType current_value_;
- }; // class CartesianProductGenerator5::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator5& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
-}; // class CartesianProductGenerator5
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-class CartesianProductGenerator6
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5,
- T6> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> ParamType;
-
- CartesianProductGenerator6(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
- virtual ~CartesianProductGenerator6() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current6_;
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- ParamType current_value_;
- }; // class CartesianProductGenerator6::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator6& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
-}; // class CartesianProductGenerator6
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-class CartesianProductGenerator7
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
- T7> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> ParamType;
-
- CartesianProductGenerator7(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
- virtual ~CartesianProductGenerator7() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current7_;
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- ParamType current_value_;
- }; // class CartesianProductGenerator7::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator7& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
-}; // class CartesianProductGenerator7
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-class CartesianProductGenerator8
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> ParamType;
-
- CartesianProductGenerator8(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
- g8_(g8) {}
- virtual ~CartesianProductGenerator8() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current8_;
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- ParamType current_value_;
- }; // class CartesianProductGenerator8::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator8& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
-}; // class CartesianProductGenerator8
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-class CartesianProductGenerator9
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8, T9> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9> ParamType;
-
- CartesianProductGenerator9(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9) {}
- virtual ~CartesianProductGenerator9() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end(), g9_, g9_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8,
- const ParamGenerator<T9>& g9,
- const typename ParamGenerator<T9>::iterator& current9)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
- begin9_(g9.begin()), end9_(g9.end()), current9_(current9) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current9_;
- if (current9_ == end9_) {
- current9_ = begin9_;
- ++current8_;
- }
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_ &&
- current9_ == typed_other->current9_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_),
- begin9_(other.begin9_),
- end9_(other.end9_),
- current9_(other.current9_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_,
- *current9_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_ ||
- current9_ == end9_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- const typename ParamGenerator<T9>::iterator begin9_;
- const typename ParamGenerator<T9>::iterator end9_;
- typename ParamGenerator<T9>::iterator current9_;
- ParamType current_value_;
- }; // class CartesianProductGenerator9::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator9& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
- const ParamGenerator<T9> g9_;
-}; // class CartesianProductGenerator9
-
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-class CartesianProductGenerator10
- : public ParamGeneratorInterface< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
- T7, T8, T9, T10> > {
- public:
- typedef ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> ParamType;
-
- CartesianProductGenerator10(const ParamGenerator<T1>& g1,
- const ParamGenerator<T2>& g2, const ParamGenerator<T3>& g3,
- const ParamGenerator<T4>& g4, const ParamGenerator<T5>& g5,
- const ParamGenerator<T6>& g6, const ParamGenerator<T7>& g7,
- const ParamGenerator<T8>& g8, const ParamGenerator<T9>& g9,
- const ParamGenerator<T10>& g10)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9), g10_(g10) {}
- virtual ~CartesianProductGenerator10() {}
-
- virtual ParamIteratorInterface<ParamType>* Begin() const {
- return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_,
- g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_,
- g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin());
- }
- virtual ParamIteratorInterface<ParamType>* End() const {
- return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(),
- g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_,
- g8_.end(), g9_, g9_.end(), g10_, g10_.end());
- }
-
- private:
- class Iterator : public ParamIteratorInterface<ParamType> {
- public:
- Iterator(const ParamGeneratorInterface<ParamType>* base,
- const ParamGenerator<T1>& g1,
- const typename ParamGenerator<T1>::iterator& current1,
- const ParamGenerator<T2>& g2,
- const typename ParamGenerator<T2>::iterator& current2,
- const ParamGenerator<T3>& g3,
- const typename ParamGenerator<T3>::iterator& current3,
- const ParamGenerator<T4>& g4,
- const typename ParamGenerator<T4>::iterator& current4,
- const ParamGenerator<T5>& g5,
- const typename ParamGenerator<T5>::iterator& current5,
- const ParamGenerator<T6>& g6,
- const typename ParamGenerator<T6>::iterator& current6,
- const ParamGenerator<T7>& g7,
- const typename ParamGenerator<T7>::iterator& current7,
- const ParamGenerator<T8>& g8,
- const typename ParamGenerator<T8>::iterator& current8,
- const ParamGenerator<T9>& g9,
- const typename ParamGenerator<T9>::iterator& current9,
- const ParamGenerator<T10>& g10,
- const typename ParamGenerator<T10>::iterator& current10)
- : base_(base),
- begin1_(g1.begin()), end1_(g1.end()), current1_(current1),
- begin2_(g2.begin()), end2_(g2.end()), current2_(current2),
- begin3_(g3.begin()), end3_(g3.end()), current3_(current3),
- begin4_(g4.begin()), end4_(g4.end()), current4_(current4),
- begin5_(g5.begin()), end5_(g5.end()), current5_(current5),
- begin6_(g6.begin()), end6_(g6.end()), current6_(current6),
- begin7_(g7.begin()), end7_(g7.end()), current7_(current7),
- begin8_(g8.begin()), end8_(g8.end()), current8_(current8),
- begin9_(g9.begin()), end9_(g9.end()), current9_(current9),
- begin10_(g10.begin()), end10_(g10.end()), current10_(current10) {
- ComputeCurrentValue();
- }
- virtual ~Iterator() {}
-
- virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
- return base_;
- }
- // Advance should not be called on beyond-of-range iterators
- // so no component iterators must be beyond end of range, either.
- virtual void Advance() {
- assert(!AtEnd());
- ++current10_;
- if (current10_ == end10_) {
- current10_ = begin10_;
- ++current9_;
- }
- if (current9_ == end9_) {
- current9_ = begin9_;
- ++current8_;
- }
- if (current8_ == end8_) {
- current8_ = begin8_;
- ++current7_;
- }
- if (current7_ == end7_) {
- current7_ = begin7_;
- ++current6_;
- }
- if (current6_ == end6_) {
- current6_ = begin6_;
- ++current5_;
- }
- if (current5_ == end5_) {
- current5_ = begin5_;
- ++current4_;
- }
- if (current4_ == end4_) {
- current4_ = begin4_;
- ++current3_;
- }
- if (current3_ == end3_) {
- current3_ = begin3_;
- ++current2_;
- }
- if (current2_ == end2_) {
- current2_ = begin2_;
- ++current1_;
- }
- ComputeCurrentValue();
- }
- virtual ParamIteratorInterface<ParamType>* Clone() const {
- return new Iterator(*this);
- }
- virtual const ParamType* Current() const { return ¤t_value_; }
- virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
- // Having the same base generator guarantees that the other
- // iterator is of the same type and we can downcast.
- GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
- << "The program attempted to compare iterators "
- << "from different generators." << std::endl;
- const Iterator* typed_other =
- CheckedDowncastToActualType<const Iterator>(&other);
- // We must report iterators equal if they both point beyond their
- // respective ranges. That can happen in a variety of fashions,
- // so we have to consult AtEnd().
- return (AtEnd() && typed_other->AtEnd()) ||
- (
- current1_ == typed_other->current1_ &&
- current2_ == typed_other->current2_ &&
- current3_ == typed_other->current3_ &&
- current4_ == typed_other->current4_ &&
- current5_ == typed_other->current5_ &&
- current6_ == typed_other->current6_ &&
- current7_ == typed_other->current7_ &&
- current8_ == typed_other->current8_ &&
- current9_ == typed_other->current9_ &&
- current10_ == typed_other->current10_);
- }
-
- private:
- Iterator(const Iterator& other)
- : base_(other.base_),
- begin1_(other.begin1_),
- end1_(other.end1_),
- current1_(other.current1_),
- begin2_(other.begin2_),
- end2_(other.end2_),
- current2_(other.current2_),
- begin3_(other.begin3_),
- end3_(other.end3_),
- current3_(other.current3_),
- begin4_(other.begin4_),
- end4_(other.end4_),
- current4_(other.current4_),
- begin5_(other.begin5_),
- end5_(other.end5_),
- current5_(other.current5_),
- begin6_(other.begin6_),
- end6_(other.end6_),
- current6_(other.current6_),
- begin7_(other.begin7_),
- end7_(other.end7_),
- current7_(other.current7_),
- begin8_(other.begin8_),
- end8_(other.end8_),
- current8_(other.current8_),
- begin9_(other.begin9_),
- end9_(other.end9_),
- current9_(other.current9_),
- begin10_(other.begin10_),
- end10_(other.end10_),
- current10_(other.current10_) {
- ComputeCurrentValue();
- }
-
- void ComputeCurrentValue() {
- if (!AtEnd())
- current_value_ = ParamType(*current1_, *current2_, *current3_,
- *current4_, *current5_, *current6_, *current7_, *current8_,
- *current9_, *current10_);
- }
- bool AtEnd() const {
- // We must report iterator past the end of the range when either of the
- // component iterators has reached the end of its range.
- return
- current1_ == end1_ ||
- current2_ == end2_ ||
- current3_ == end3_ ||
- current4_ == end4_ ||
- current5_ == end5_ ||
- current6_ == end6_ ||
- current7_ == end7_ ||
- current8_ == end8_ ||
- current9_ == end9_ ||
- current10_ == end10_;
- }
-
- // No implementation - assignment is unsupported.
- void operator=(const Iterator& other);
-
- const ParamGeneratorInterface<ParamType>* const base_;
- // begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
- // current[i]_ is the actual traversing iterator.
- const typename ParamGenerator<T1>::iterator begin1_;
- const typename ParamGenerator<T1>::iterator end1_;
- typename ParamGenerator<T1>::iterator current1_;
- const typename ParamGenerator<T2>::iterator begin2_;
- const typename ParamGenerator<T2>::iterator end2_;
- typename ParamGenerator<T2>::iterator current2_;
- const typename ParamGenerator<T3>::iterator begin3_;
- const typename ParamGenerator<T3>::iterator end3_;
- typename ParamGenerator<T3>::iterator current3_;
- const typename ParamGenerator<T4>::iterator begin4_;
- const typename ParamGenerator<T4>::iterator end4_;
- typename ParamGenerator<T4>::iterator current4_;
- const typename ParamGenerator<T5>::iterator begin5_;
- const typename ParamGenerator<T5>::iterator end5_;
- typename ParamGenerator<T5>::iterator current5_;
- const typename ParamGenerator<T6>::iterator begin6_;
- const typename ParamGenerator<T6>::iterator end6_;
- typename ParamGenerator<T6>::iterator current6_;
- const typename ParamGenerator<T7>::iterator begin7_;
- const typename ParamGenerator<T7>::iterator end7_;
- typename ParamGenerator<T7>::iterator current7_;
- const typename ParamGenerator<T8>::iterator begin8_;
- const typename ParamGenerator<T8>::iterator end8_;
- typename ParamGenerator<T8>::iterator current8_;
- const typename ParamGenerator<T9>::iterator begin9_;
- const typename ParamGenerator<T9>::iterator end9_;
- typename ParamGenerator<T9>::iterator current9_;
- const typename ParamGenerator<T10>::iterator begin10_;
- const typename ParamGenerator<T10>::iterator end10_;
- typename ParamGenerator<T10>::iterator current10_;
- ParamType current_value_;
- }; // class CartesianProductGenerator10::Iterator
-
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductGenerator10& other);
-
- const ParamGenerator<T1> g1_;
- const ParamGenerator<T2> g2_;
- const ParamGenerator<T3> g3_;
- const ParamGenerator<T4> g4_;
- const ParamGenerator<T5> g5_;
- const ParamGenerator<T6> g6_;
- const ParamGenerator<T7> g7_;
- const ParamGenerator<T8> g8_;
- const ParamGenerator<T9> g9_;
- const ParamGenerator<T10> g10_;
-}; // class CartesianProductGenerator10
-
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Helper classes providing Combine() with polymorphic features. They allow
-// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
-// convertible to U.
-//
-template <class Generator1, class Generator2>
-class CartesianProductHolder2 {
- public:
-CartesianProductHolder2(const Generator1& g1, const Generator2& g2)
- : g1_(g1), g2_(g2) {}
- template <typename T1, typename T2>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2> >(
- new CartesianProductGenerator2<T1, T2>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder2& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
-}; // class CartesianProductHolder2
-
-template <class Generator1, class Generator2, class Generator3>
-class CartesianProductHolder3 {
- public:
-CartesianProductHolder3(const Generator1& g1, const Generator2& g2,
- const Generator3& g3)
- : g1_(g1), g2_(g2), g3_(g3) {}
- template <typename T1, typename T2, typename T3>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3> >(
- new CartesianProductGenerator3<T1, T2, T3>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder3& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
-}; // class CartesianProductHolder3
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4>
-class CartesianProductHolder4 {
- public:
-CartesianProductHolder4(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {}
- template <typename T1, typename T2, typename T3, typename T4>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4> >(
- new CartesianProductGenerator4<T1, T2, T3, T4>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder4& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
-}; // class CartesianProductHolder4
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5>
-class CartesianProductHolder5 {
- public:
-CartesianProductHolder5(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5> >(
- new CartesianProductGenerator5<T1, T2, T3, T4, T5>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder5& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
-}; // class CartesianProductHolder5
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6>
-class CartesianProductHolder6 {
- public:
-CartesianProductHolder6(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6> >(
- new CartesianProductGenerator6<T1, T2, T3, T4, T5, T6>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder6& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
-}; // class CartesianProductHolder6
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7>
-class CartesianProductHolder7 {
- public:
-CartesianProductHolder7(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6,
- T7> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7> >(
- new CartesianProductGenerator7<T1, T2, T3, T4, T5, T6, T7>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder7& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
-}; // class CartesianProductHolder7
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8>
-class CartesianProductHolder8 {
- public:
-CartesianProductHolder8(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7),
- g8_(g8) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7,
- T8> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8> >(
- new CartesianProductGenerator8<T1, T2, T3, T4, T5, T6, T7, T8>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder8& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
-}; // class CartesianProductHolder8
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8, class Generator9>
-class CartesianProductHolder9 {
- public:
-CartesianProductHolder9(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8,
- const Generator9& g9)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9> >(
- new CartesianProductGenerator9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_),
- static_cast<ParamGenerator<T9> >(g9_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder9& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
- const Generator9 g9_;
-}; // class CartesianProductHolder9
-
-template <class Generator1, class Generator2, class Generator3,
- class Generator4, class Generator5, class Generator6, class Generator7,
- class Generator8, class Generator9, class Generator10>
-class CartesianProductHolder10 {
- public:
-CartesianProductHolder10(const Generator1& g1, const Generator2& g2,
- const Generator3& g3, const Generator4& g4, const Generator5& g5,
- const Generator6& g6, const Generator7& g7, const Generator8& g8,
- const Generator9& g9, const Generator10& g10)
- : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8),
- g9_(g9), g10_(g10) {}
- template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
- operator ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9, T10> >() const {
- return ParamGenerator< ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8,
- T9, T10> >(
- new CartesianProductGenerator10<T1, T2, T3, T4, T5, T6, T7, T8, T9,
- T10>(
- static_cast<ParamGenerator<T1> >(g1_),
- static_cast<ParamGenerator<T2> >(g2_),
- static_cast<ParamGenerator<T3> >(g3_),
- static_cast<ParamGenerator<T4> >(g4_),
- static_cast<ParamGenerator<T5> >(g5_),
- static_cast<ParamGenerator<T6> >(g6_),
- static_cast<ParamGenerator<T7> >(g7_),
- static_cast<ParamGenerator<T8> >(g8_),
- static_cast<ParamGenerator<T9> >(g9_),
- static_cast<ParamGenerator<T10> >(g10_)));
- }
-
- private:
- // No implementation - assignment is unsupported.
- void operator=(const CartesianProductHolder10& other);
-
- const Generator1 g1_;
- const Generator2 g2_;
- const Generator3 g3_;
- const Generator4 g4_;
- const Generator5 g5_;
- const Generator6 g6_;
- const Generator7 g7_;
- const Generator8 g8_;
- const Generator9 g9_;
- const Generator10 g10_;
-}; // class CartesianProductHolder10
-
-#endif // GTEST_HAS_COMBINE
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_HAS_PARAM_TEST
-
-#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
-
-#if GTEST_HAS_PARAM_TEST
-
-namespace testing {
-
-// Functions producing parameter generators.
-//
-// Google Test uses these generators to produce parameters for value-
-// parameterized tests. When a parameterized test case is instantiated
-// with a particular generator, Google Test creates and runs tests
-// for each element in the sequence produced by the generator.
-//
-// In the following sample, tests from test case FooTest are instantiated
-// each three times with parameter values 3, 5, and 8:
-//
-// class FooTest : public TestWithParam<int> { ... };
-//
-// TEST_P(FooTest, TestThis) {
-// }
-// TEST_P(FooTest, TestThat) {
-// }
-// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
-//
-
-// Range() returns generators providing sequences of values in a range.
-//
-// Synopsis:
-// Range(start, end)
-// - returns a generator producing a sequence of values {start, start+1,
-// start+2, ..., }.
-// Range(start, end, step)
-// - returns a generator producing a sequence of values {start, start+step,
-// start+step+step, ..., }.
-// Notes:
-// * The generated sequences never include end. For example, Range(1, 5)
-// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
-// returns a generator producing {1, 3, 5, 7}.
-// * start and end must have the same type. That type may be any integral or
-// floating-point type or a user defined type satisfying these conditions:
-// * It must be assignable (have operator=() defined).
-// * It must have operator+() (operator+(int-compatible type) for
-// two-operand version).
-// * It must have operator<() defined.
-// Elements in the resulting sequences will also have that type.
-// * Condition start < end must be satisfied in order for resulting sequences
-// to contain any elements.
-//
-template <typename T, typename IncrementT>
-internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
- return internal::ParamGenerator<T>(
- new internal::RangeGenerator<T, IncrementT>(start, end, step));
-}
-
-template <typename T>
-internal::ParamGenerator<T> Range(T start, T end) {
- return Range(start, end, 1);
-}
-
-// ValuesIn() function allows generation of tests with parameters coming from
-// a container.
-//
-// Synopsis:
-// ValuesIn(const T (&array)[N])
-// - returns a generator producing sequences with elements from
-// a C-style array.
-// ValuesIn(const Container& container)
-// - returns a generator producing sequences with elements from
-// an STL-style container.
-// ValuesIn(Iterator begin, Iterator end)
-// - returns a generator producing sequences with elements from
-// a range [begin, end) defined by a pair of STL-style iterators. These
-// iterators can also be plain C pointers.
-//
-// Please note that ValuesIn copies the values from the containers
-// passed in and keeps them to generate tests in RUN_ALL_TESTS().
-//
-// Examples:
-//
-// This instantiates tests from test case StringTest
-// each with C-string values of "foo", "bar", and "baz":
-//
-// const char* strings[] = {"foo", "bar", "baz"};
-// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
-//
-// This instantiates tests from test case StlStringTest
-// each with STL strings with values "a" and "b":
-//
-// ::std::vector< ::std::string> GetParameterStrings() {
-// ::std::vector< ::std::string> v;
-// v.push_back("a");
-// v.push_back("b");
-// return v;
-// }
-//
-// INSTANTIATE_TEST_CASE_P(CharSequence,
-// StlStringTest,
-// ValuesIn(GetParameterStrings()));
-//
-//
-// This will also instantiate tests from CharTest
-// each with parameter values 'a' and 'b':
-//
-// ::std::list<char> GetParameterChars() {
-// ::std::list<char> list;
-// list.push_back('a');
-// list.push_back('b');
-// return list;
-// }
-// ::std::list<char> l = GetParameterChars();
-// INSTANTIATE_TEST_CASE_P(CharSequence2,
-// CharTest,
-// ValuesIn(l.begin(), l.end()));
-//
-template <typename ForwardIterator>
-internal::ParamGenerator<
- typename ::std::iterator_traits<ForwardIterator>::value_type> ValuesIn(
- ForwardIterator begin,
- ForwardIterator end) {
- typedef typename ::std::iterator_traits<ForwardIterator>::value_type
- ParamType;
- return internal::ParamGenerator<ParamType>(
- new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
-}
-
-template <typename T, size_t N>
-internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
- return ValuesIn(array, array + N);
-}
-
-template <class Container>
-internal::ParamGenerator<typename Container::value_type> ValuesIn(
- const Container& container) {
- return ValuesIn(container.begin(), container.end());
-}
-
-// Values() allows generating tests from explicitly specified list of
-// parameters.
-//
-// Synopsis:
-// Values(T v1, T v2, ..., T vN)
-// - returns a generator producing sequences with elements v1, v2, ..., vN.
-//
-// For example, this instantiates tests from test case BarTest each
-// with values "one", "two", and "three":
-//
-// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
-//
-// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
-// The exact type of values will depend on the type of parameter in BazTest.
-//
-// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
-//
-// Currently, Values() supports from 1 to 50 parameters.
-//
-template <typename T1>
-internal::ValueArray1<T1> Values(T1 v1) {
- return internal::ValueArray1<T1>(v1);
-}
-
-template <typename T1, typename T2>
-internal::ValueArray2<T1, T2> Values(T1 v1, T2 v2) {
- return internal::ValueArray2<T1, T2>(v1, v2);
-}
-
-template <typename T1, typename T2, typename T3>
-internal::ValueArray3<T1, T2, T3> Values(T1 v1, T2 v2, T3 v3) {
- return internal::ValueArray3<T1, T2, T3>(v1, v2, v3);
-}
-
-template <typename T1, typename T2, typename T3, typename T4>
-internal::ValueArray4<T1, T2, T3, T4> Values(T1 v1, T2 v2, T3 v3, T4 v4) {
- return internal::ValueArray4<T1, T2, T3, T4>(v1, v2, v3, v4);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5>
-internal::ValueArray5<T1, T2, T3, T4, T5> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5) {
- return internal::ValueArray5<T1, T2, T3, T4, T5>(v1, v2, v3, v4, v5);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6>
-internal::ValueArray6<T1, T2, T3, T4, T5, T6> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6) {
- return internal::ValueArray6<T1, T2, T3, T4, T5, T6>(v1, v2, v3, v4, v5, v6);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7>
-internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7) {
- return internal::ValueArray7<T1, T2, T3, T4, T5, T6, T7>(v1, v2, v3, v4, v5,
- v6, v7);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8>
-internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) {
- return internal::ValueArray8<T1, T2, T3, T4, T5, T6, T7, T8>(v1, v2, v3, v4,
- v5, v6, v7, v8);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9>
-internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) {
- return internal::ValueArray9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(v1, v2, v3,
- v4, v5, v6, v7, v8, v9);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10>
-internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) {
- return internal::ValueArray10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(v1,
- v2, v3, v4, v5, v6, v7, v8, v9, v10);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11>
-internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
- T11> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11) {
- return internal::ValueArray11<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10,
- T11>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12>
-internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12) {
- return internal::ValueArray12<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13>
-internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
- T13> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13) {
- return internal::ValueArray13<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14>
-internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) {
- return internal::ValueArray14<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
- v14);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15>
-internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) {
- return internal::ValueArray15<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
- v13, v14, v15);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16>
-internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16) {
- return internal::ValueArray16<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
- v12, v13, v14, v15, v16);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17>
-internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17) {
- return internal::ValueArray17<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
- v11, v12, v13, v14, v15, v16, v17);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18>
-internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18) {
- return internal::ValueArray18<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
- v10, v11, v12, v13, v14, v15, v16, v17, v18);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19>
-internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) {
- return internal::ValueArray19<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19>(v1, v2, v3, v4, v5, v6, v7, v8,
- v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20>
-internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) {
- return internal::ValueArray20<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20>(v1, v2, v3, v4, v5, v6, v7,
- v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21>
-internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) {
- return internal::ValueArray21<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21>(v1, v2, v3, v4, v5, v6,
- v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22>
-internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22) {
- return internal::ValueArray22<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22>(v1, v2, v3, v4,
- v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23>
-internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23) {
- return internal::ValueArray23<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23>(v1, v2, v3,
- v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22, v23);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24>
-internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24) {
- return internal::ValueArray24<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24>(v1, v2,
- v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
- v19, v20, v21, v22, v23, v24);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25>
-internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
- T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
- T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) {
- return internal::ValueArray25<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25>(v1,
- v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
- v18, v19, v20, v21, v22, v23, v24, v25);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26>
-internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26) {
- return internal::ValueArray26<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
- v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27>
-internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
- T27> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27) {
- return internal::ValueArray27<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
- v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28>
-internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27,
- T28> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28) {
- return internal::ValueArray28<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
- v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
- v28);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29>
-internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29) {
- return internal::ValueArray29<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
- v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
- v27, v28, v29);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30>
-internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) {
- return internal::ValueArray30<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
- v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
- v26, v27, v28, v29, v30);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31>
-internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) {
- return internal::ValueArray31<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
- v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
- v25, v26, v27, v28, v29, v30, v31);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32>
-internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32) {
- return internal::ValueArray32<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
- v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
- v24, v25, v26, v27, v28, v29, v30, v31, v32);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33>
-internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33) {
- return internal::ValueArray33<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33>(v1, v2, v3, v4, v5, v6, v7, v8,
- v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
- v24, v25, v26, v27, v28, v29, v30, v31, v32, v33);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34>
-internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
- T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
- T31 v31, T32 v32, T33 v33, T34 v34) {
- return internal::ValueArray34<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34>(v1, v2, v3, v4, v5, v6, v7,
- v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
- v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35>
-internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) {
- return internal::ValueArray35<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35>(v1, v2, v3, v4, v5, v6,
- v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
- v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36>
-internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) {
- return internal::ValueArray36<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36>(v1, v2, v3, v4,
- v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
- v34, v35, v36);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37>
-internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37> Values(T1 v1, T2 v2, T3 v3,
- T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37) {
- return internal::ValueArray37<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37>(v1, v2, v3,
- v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
- v34, v35, v36, v37);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38>
-internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37, T38 v38) {
- return internal::ValueArray38<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38>(v1, v2,
- v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18,
- v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32,
- v33, v34, v35, v36, v37, v38);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39>
-internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39> Values(T1 v1, T2 v2,
- T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12,
- T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20,
- T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28,
- T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36,
- T37 v37, T38 v38, T39 v39) {
- return internal::ValueArray39<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39>(v1,
- v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17,
- v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31,
- v32, v33, v34, v35, v36, v37, v38, v39);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40>
-internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40> Values(T1 v1,
- T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11,
- T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19,
- T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27,
- T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35,
- T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) {
- return internal::ValueArray40<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15,
- v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29,
- v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41>
-internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
- T41> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) {
- return internal::ValueArray41<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14,
- v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28,
- v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42>
-internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41,
- T42> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42) {
- return internal::ValueArray42<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13,
- v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27,
- v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41,
- v42);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43>
-internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42,
- T43> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43) {
- return internal::ValueArray43<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12,
- v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26,
- v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
- v41, v42, v43);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44>
-internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9,
- T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17,
- T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25,
- T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33,
- T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41,
- T42 v42, T43 v43, T44 v44) {
- return internal::ValueArray44<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11,
- v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25,
- v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39,
- v40, v41, v42, v43, v44);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45>
-internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8,
- T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16,
- T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24,
- T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32,
- T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40,
- T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) {
- return internal::ValueArray45<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45>(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
- v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24,
- v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38,
- v39, v40, v41, v42, v43, v44, v45);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46>
-internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) {
- return internal::ValueArray46<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46>(v1, v2, v3, v4, v5, v6, v7, v8, v9,
- v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
- v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
- v38, v39, v40, v41, v42, v43, v44, v45, v46);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47>
-internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7,
- T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) {
- return internal::ValueArray47<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47>(v1, v2, v3, v4, v5, v6, v7, v8,
- v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23,
- v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37,
- v38, v39, v40, v41, v42, v43, v44, v45, v46, v47);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48>
-internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6,
- T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15,
- T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23,
- T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31,
- T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39,
- T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47,
- T48 v48) {
- return internal::ValueArray48<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48>(v1, v2, v3, v4, v5, v6, v7,
- v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,
- v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36,
- v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49>
-internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49> Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5,
- T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14,
- T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22,
- T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30,
- T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38,
- T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46,
- T47 v47, T48 v48, T49 v49) {
- return internal::ValueArray49<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48, T49>(v1, v2, v3, v4, v5, v6,
- v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,
- v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35,
- v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49);
-}
-
-template <typename T1, typename T2, typename T3, typename T4, typename T5,
- typename T6, typename T7, typename T8, typename T9, typename T10,
- typename T11, typename T12, typename T13, typename T14, typename T15,
- typename T16, typename T17, typename T18, typename T19, typename T20,
- typename T21, typename T22, typename T23, typename T24, typename T25,
- typename T26, typename T27, typename T28, typename T29, typename T30,
- typename T31, typename T32, typename T33, typename T34, typename T35,
- typename T36, typename T37, typename T38, typename T39, typename T40,
- typename T41, typename T42, typename T43, typename T44, typename T45,
- typename T46, typename T47, typename T48, typename T49, typename T50>
-internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
- T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
- T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
- T44, T45, T46, T47, T48, T49, T50> Values(T1 v1, T2 v2, T3 v3, T4 v4,
- T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13,
- T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21,
- T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29,
- T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37,
- T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45,
- T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) {
- return internal::ValueArray50<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11,
- T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25,
- T26, T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39,
- T40, T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>(v1, v2, v3, v4,
- v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19,
- v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33,
- v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47,
- v48, v49, v50);
-}
-
-// Bool() allows generating tests with parameters in a set of (false, true).
-//
-// Synopsis:
-// Bool()
-// - returns a generator producing sequences with elements {false, true}.
-//
-// It is useful when testing code that depends on Boolean flags. Combinations
-// of multiple flags can be tested when several Bool()'s are combined using
-// Combine() function.
-//
-// In the following example all tests in the test case FlagDependentTest
-// will be instantiated twice with parameters false and true.
-//
-// class FlagDependentTest : public testing::TestWithParam<bool> {
-// virtual void SetUp() {
-// external_flag = GetParam();
-// }
-// }
-// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
-//
-inline internal::ParamGenerator<bool> Bool() {
- return Values(false, true);
-}
-
-#if GTEST_HAS_COMBINE
-// Combine() allows the user to combine two or more sequences to produce
-// values of a Cartesian product of those sequences' elements.
-//
-// Synopsis:
-// Combine(gen1, gen2, ..., genN)
-// - returns a generator producing sequences with elements coming from
-// the Cartesian product of elements from the sequences generated by
-// gen1, gen2, ..., genN. The sequence elements will have a type of
-// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
-// of elements from sequences produces by gen1, gen2, ..., genN.
-//
-// Combine can have up to 10 arguments. This number is currently limited
-// by the maximum number of elements in the tuple implementation used by Google
-// Test.
-//
-// Example:
-//
-// This will instantiate tests in test case AnimalTest each one with
-// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
-// tuple("dog", BLACK), and tuple("dog", WHITE):
-//
-// enum Color { BLACK, GRAY, WHITE };
-// class AnimalTest
-// : public testing::TestWithParam<tuple<const char*, Color> > {...};
-//
-// TEST_P(AnimalTest, AnimalLooksNice) {...}
-//
-// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
-// Combine(Values("cat", "dog"),
-// Values(BLACK, WHITE)));
-//
-// This will instantiate tests in FlagDependentTest with all variations of two
-// Boolean flags:
-//
-// class FlagDependentTest
-// : public testing::TestWithParam<tuple(bool, bool)> > {
-// virtual void SetUp() {
-// // Assigns external_flag_1 and external_flag_2 values from the tuple.
-// tie(external_flag_1, external_flag_2) = GetParam();
-// }
-// };
-//
-// TEST_P(FlagDependentTest, TestFeature1) {
-// // Test your code using external_flag_1 and external_flag_2 here.
-// }
-// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
-// Combine(Bool(), Bool()));
-//
-template <typename Generator1, typename Generator2>
-internal::CartesianProductHolder2<Generator1, Generator2> Combine(
- const Generator1& g1, const Generator2& g2) {
- return internal::CartesianProductHolder2<Generator1, Generator2>(
- g1, g2);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3>
-internal::CartesianProductHolder3<Generator1, Generator2, Generator3> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3) {
- return internal::CartesianProductHolder3<Generator1, Generator2, Generator3>(
- g1, g2, g3);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4>
-internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
- Generator4> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4) {
- return internal::CartesianProductHolder4<Generator1, Generator2, Generator3,
- Generator4>(
- g1, g2, g3, g4);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5>
-internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
- Generator4, Generator5> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5) {
- return internal::CartesianProductHolder5<Generator1, Generator2, Generator3,
- Generator4, Generator5>(
- g1, g2, g3, g4, g5);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6>
-internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6) {
- return internal::CartesianProductHolder6<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6>(
- g1, g2, g3, g4, g5, g6);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7>
-internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7) {
- return internal::CartesianProductHolder7<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7>(
- g1, g2, g3, g4, g5, g6, g7);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8>
-internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8) {
- return internal::CartesianProductHolder8<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8>(
- g1, g2, g3, g4, g5, g6, g7, g8);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8, typename Generator9>
-internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8,
- Generator9> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8, const Generator9& g9) {
- return internal::CartesianProductHolder9<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9>(
- g1, g2, g3, g4, g5, g6, g7, g8, g9);
-}
-
-template <typename Generator1, typename Generator2, typename Generator3,
- typename Generator4, typename Generator5, typename Generator6,
- typename Generator7, typename Generator8, typename Generator9,
- typename Generator10>
-internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
- Generator10> Combine(
- const Generator1& g1, const Generator2& g2, const Generator3& g3,
- const Generator4& g4, const Generator5& g5, const Generator6& g6,
- const Generator7& g7, const Generator8& g8, const Generator9& g9,
- const Generator10& g10) {
- return internal::CartesianProductHolder10<Generator1, Generator2, Generator3,
- Generator4, Generator5, Generator6, Generator7, Generator8, Generator9,
- Generator10>(
- g1, g2, g3, g4, g5, g6, g7, g8, g9, g10);
-}
-#endif // GTEST_HAS_COMBINE
-
-
-
-#define TEST_P(test_case_name, test_name) \
- class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
- : public test_case_name { \
- public: \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
- virtual void TestBody(); \
- private: \
- static int AddToRegistry() { \
- ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
- GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, __FILE__, __LINE__)->AddTestPattern(\
- #test_case_name, \
- #test_name, \
- new ::testing::internal::TestMetaFactory< \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
- return 0; \
- } \
- static int gtest_registering_dummy_; \
- GTEST_DISALLOW_COPY_AND_ASSIGN_(\
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
- }; \
- int GTEST_TEST_CLASS_NAME_(test_case_name, \
- test_name)::gtest_registering_dummy_ = \
- GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
- void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
-
-#define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
- ::testing::internal::ParamGenerator<test_case_name::ParamType> \
- gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
- int gtest_##prefix##test_case_name##_dummy_ = \
- ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
- GetTestCasePatternHolder<test_case_name>(\
- #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
- #prefix, \
- >est_##prefix##test_case_name##_EvalGenerator_, \
- __FILE__, __LINE__)
-
-} // namespace testing
-
-#endif // GTEST_HAS_PARAM_TEST
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
-// Copyright 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// Google C++ Testing Framework definitions useful in production code.
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
-
-// When you need to test the private or protected members of a class,
-// use the FRIEND_TEST macro to declare your tests as friends of the
-// class. For example:
-//
-// class MyClass {
-// private:
-// void MyMethod();
-// FRIEND_TEST(MyClassTest, MyMethod);
-// };
-//
-// class MyClassTest : public testing::Test {
-// // ...
-// };
-//
-// TEST_F(MyClassTest, MyMethod) {
-// // Can call MyClass::MyMethod() here.
-// }
-
-#define FRIEND_TEST(test_case_name, test_name)\
-friend class test_case_name##_##test_name##_Test
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mheule@google.com (Markus Heule)
-//
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
-#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
-
-#include <iosfwd>
-#include <vector>
-
-namespace testing {
-
-// A copyable object representing the result of a test part (i.e. an
-// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
-//
-// Don't inherit from TestPartResult as its destructor is not virtual.
-class GTEST_API_ TestPartResult {
- public:
- // The possible outcomes of a test part (i.e. an assertion or an
- // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
- enum Type {
- kSuccess, // Succeeded.
- kNonFatalFailure, // Failed but the test can continue.
- kFatalFailure // Failed and the test should be terminated.
- };
-
- // C'tor. TestPartResult does NOT have a default constructor.
- // Always use this constructor (with parameters) to create a
- // TestPartResult object.
- TestPartResult(Type a_type,
- const char* a_file_name,
- int a_line_number,
- const char* a_message)
- : type_(a_type),
- file_name_(a_file_name),
- line_number_(a_line_number),
- summary_(ExtractSummary(a_message)),
- message_(a_message) {
- }
-
- // Gets the outcome of the test part.
- Type type() const { return type_; }
-
- // Gets the name of the source file where the test part took place, or
- // NULL if it's unknown.
- const char* file_name() const { return file_name_.c_str(); }
-
- // Gets the line in the source file where the test part took place,
- // or -1 if it's unknown.
- int line_number() const { return line_number_; }
-
- // Gets the summary of the failure message.
- const char* summary() const { return summary_.c_str(); }
-
- // Gets the message associated with the test part.
- const char* message() const { return message_.c_str(); }
-
- // Returns true iff the test part passed.
- bool passed() const { return type_ == kSuccess; }
-
- // Returns true iff the test part failed.
- bool failed() const { return type_ != kSuccess; }
-
- // Returns true iff the test part non-fatally failed.
- bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
-
- // Returns true iff the test part fatally failed.
- bool fatally_failed() const { return type_ == kFatalFailure; }
- private:
- Type type_;
-
- // Gets the summary of the failure message by omitting the stack
- // trace in it.
- static internal::String ExtractSummary(const char* message);
-
- // The name of the source file where the test part took place, or
- // NULL if the source file is unknown.
- internal::String file_name_;
- // The line in the source file where the test part took place, or -1
- // if the line number is unknown.
- int line_number_;
- internal::String summary_; // The test failure summary.
- internal::String message_; // The test failure message.
-};
-
-// Prints a TestPartResult object.
-std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
-
-// An array of TestPartResult objects.
-//
-// Don't inherit from TestPartResultArray as its destructor is not
-// virtual.
-class GTEST_API_ TestPartResultArray {
- public:
- TestPartResultArray() {}
-
- // Appends the given TestPartResult to the array.
- void Append(const TestPartResult& result);
-
- // Returns the TestPartResult at the given index (0-based).
- const TestPartResult& GetTestPartResult(int index) const;
-
- // Returns the number of TestPartResult objects in the array.
- int size() const;
-
- private:
- std::vector<TestPartResult> array_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
-};
-
-// This interface knows how to report a test part result.
-class TestPartResultReporterInterface {
- public:
- virtual ~TestPartResultReporterInterface() {}
-
- virtual void ReportTestPartResult(const TestPartResult& result) = 0;
-};
-
-namespace internal {
-
-// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
-// statement generates new fatal failures. To do so it registers itself as the
-// current test part result reporter. Besides checking if fatal failures were
-// reported, it only delegates the reporting to the former result reporter.
-// The original result reporter is restored in the destructor.
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-class GTEST_API_ HasNewFatalFailureHelper
- : public TestPartResultReporterInterface {
- public:
- HasNewFatalFailureHelper();
- virtual ~HasNewFatalFailureHelper();
- virtual void ReportTestPartResult(const TestPartResult& result);
- bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
- private:
- bool has_new_fatal_failure_;
- TestPartResultReporterInterface* original_reporter_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
-};
-
-} // namespace internal
-
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
-// Copyright 2008 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
-#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
-
-// This header implements typed tests and type-parameterized tests.
-
-// Typed (aka type-driven) tests repeat the same test for types in a
-// list. You must know which types you want to test with when writing
-// typed tests. Here's how you do it:
-
-#if 0
-
-// First, define a fixture class template. It should be parameterized
-// by a type. Remember to derive it from testing::Test.
-template <typename T>
-class FooTest : public testing::Test {
- public:
- ...
- typedef std::list<T> List;
- static T shared_;
- T value_;
-};
-
-// Next, associate a list of types with the test case, which will be
-// repeated for each type in the list. The typedef is necessary for
-// the macro to parse correctly.
-typedef testing::Types<char, int, unsigned int> MyTypes;
-TYPED_TEST_CASE(FooTest, MyTypes);
-
-// If the type list contains only one type, you can write that type
-// directly without Types<...>:
-// TYPED_TEST_CASE(FooTest, int);
-
-// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
-// tests for this test case as you want.
-TYPED_TEST(FooTest, DoesBlah) {
- // Inside a test, refer to TypeParam to get the type parameter.
- // Since we are inside a derived class template, C++ requires use to
- // visit the members of FooTest via 'this'.
- TypeParam n = this->value_;
-
- // To visit static members of the fixture, add the TestFixture::
- // prefix.
- n += TestFixture::shared_;
-
- // To refer to typedefs in the fixture, add the "typename
- // TestFixture::" prefix.
- typename TestFixture::List values;
- values.push_back(n);
- ...
-}
-
-TYPED_TEST(FooTest, HasPropertyA) { ... }
-
-#endif // 0
-
-// Type-parameterized tests are abstract test patterns parameterized
-// by a type. Compared with typed tests, type-parameterized tests
-// allow you to define the test pattern without knowing what the type
-// parameters are. The defined pattern can be instantiated with
-// different types any number of times, in any number of translation
-// units.
-//
-// If you are designing an interface or concept, you can define a
-// suite of type-parameterized tests to verify properties that any
-// valid implementation of the interface/concept should have. Then,
-// each implementation can easily instantiate the test suite to verify
-// that it conforms to the requirements, without having to write
-// similar tests repeatedly. Here's an example:
-
-#if 0
-
-// First, define a fixture class template. It should be parameterized
-// by a type. Remember to derive it from testing::Test.
-template <typename T>
-class FooTest : public testing::Test {
- ...
-};
-
-// Next, declare that you will define a type-parameterized test case
-// (the _P suffix is for "parameterized" or "pattern", whichever you
-// prefer):
-TYPED_TEST_CASE_P(FooTest);
-
-// Then, use TYPED_TEST_P() to define as many type-parameterized tests
-// for this type-parameterized test case as you want.
-TYPED_TEST_P(FooTest, DoesBlah) {
- // Inside a test, refer to TypeParam to get the type parameter.
- TypeParam n = 0;
- ...
-}
-
-TYPED_TEST_P(FooTest, HasPropertyA) { ... }
-
-// Now the tricky part: you need to register all test patterns before
-// you can instantiate them. The first argument of the macro is the
-// test case name; the rest are the names of the tests in this test
-// case.
-REGISTER_TYPED_TEST_CASE_P(FooTest,
- DoesBlah, HasPropertyA);
-
-// Finally, you are free to instantiate the pattern with the types you
-// want. If you put the above code in a header file, you can #include
-// it in multiple C++ source files and instantiate it multiple times.
-//
-// To distinguish different instances of the pattern, the first
-// argument to the INSTANTIATE_* macro is a prefix that will be added
-// to the actual test case name. Remember to pick unique prefixes for
-// different instances.
-typedef testing::Types<char, int, unsigned int> MyTypes;
-INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
-
-// If the type list contains only one type, you can write that type
-// directly without Types<...>:
-// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
-
-#endif // 0
-
-
-// Implements typed tests.
-
-#if GTEST_HAS_TYPED_TEST
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Expands to the name of the typedef for the type parameters of the
-// given test case.
-#define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
-
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
-#define TYPED_TEST_CASE(CaseName, Types) \
- typedef ::testing::internal::TypeList< Types >::type \
- GTEST_TYPE_PARAMS_(CaseName)
-
-#define TYPED_TEST(CaseName, TestName) \
- template <typename gtest_TypeParam_> \
- class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
- : public CaseName<gtest_TypeParam_> { \
- private: \
- typedef CaseName<gtest_TypeParam_> TestFixture; \
- typedef gtest_TypeParam_ TypeParam; \
- virtual void TestBody(); \
- }; \
- bool gtest_##CaseName##_##TestName##_registered_ = \
- ::testing::internal::TypeParameterizedTest< \
- CaseName, \
- ::testing::internal::TemplateSel< \
- GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
- GTEST_TYPE_PARAMS_(CaseName)>::Register(\
- "", #CaseName, #TestName, 0); \
- template <typename gtest_TypeParam_> \
- void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
-
-#endif // GTEST_HAS_TYPED_TEST
-
-// Implements type-parameterized tests.
-
-#if GTEST_HAS_TYPED_TEST_P
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Expands to the namespace name that the type-parameterized tests for
-// the given type-parameterized test case are defined in. The exact
-// name of the namespace is subject to change without notice.
-#define GTEST_CASE_NAMESPACE_(TestCaseName) \
- gtest_case_##TestCaseName##_
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-//
-// Expands to the name of the variable used to remember the names of
-// the defined tests in the given test case.
-#define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
- gtest_typed_test_case_p_state_##TestCaseName##_
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
-//
-// Expands to the name of the variable used to remember the names of
-// the registered tests in the given test case.
-#define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
- gtest_registered_test_names_##TestCaseName##_
-
-// The variables defined in the type-parameterized test macros are
-// static as typically these macros are used in a .h file that can be
-// #included in multiple translation units linked together.
-#define TYPED_TEST_CASE_P(CaseName) \
- static ::testing::internal::TypedTestCasePState \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
-
-#define TYPED_TEST_P(CaseName, TestName) \
- namespace GTEST_CASE_NAMESPACE_(CaseName) { \
- template <typename gtest_TypeParam_> \
- class TestName : public CaseName<gtest_TypeParam_> { \
- private: \
- typedef CaseName<gtest_TypeParam_> TestFixture; \
- typedef gtest_TypeParam_ TypeParam; \
- virtual void TestBody(); \
- }; \
- static bool gtest_##TestName##_defined_ = \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
- __FILE__, __LINE__, #CaseName, #TestName); \
- } \
- template <typename gtest_TypeParam_> \
- void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
-
-#define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
- namespace GTEST_CASE_NAMESPACE_(CaseName) { \
- typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
- } \
- static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
- GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
- __FILE__, __LINE__, #__VA_ARGS__)
-
-// The 'Types' template argument below must have spaces around it
-// since some compilers may choke on '>>' when passing a template
-// instance (e.g. Types<int>)
-#define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
- bool gtest_##Prefix##_##CaseName = \
- ::testing::internal::TypeParameterizedTestCase<CaseName, \
- GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
- ::testing::internal::TypeList< Types >::type>::Register(\
- #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
-
-#endif // GTEST_HAS_TYPED_TEST_P
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
-
-// Depending on the platform, different string classes are available.
-// On Linux, in addition to ::std::string, Google also makes use of
-// class ::string, which has the same interface as ::std::string, but
-// has a different implementation.
-//
-// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that
-// ::string is available AND is a distinct type to ::std::string, or
-// define it to 0 to indicate otherwise.
-//
-// If the user's ::std::string and ::string are the same class due to
-// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0.
-//
-// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined
-// heuristically.
-
-namespace testing {
-
-// Declares the flags.
-
-// This flag temporary enables the disabled tests.
-GTEST_DECLARE_bool_(also_run_disabled_tests);
-
-// This flag brings the debugger on an assertion failure.
-GTEST_DECLARE_bool_(break_on_failure);
-
-// This flag controls whether Google Test catches all test-thrown exceptions
-// and logs them as failures.
-GTEST_DECLARE_bool_(catch_exceptions);
-
-// This flag enables using colors in terminal output. Available values are
-// "yes" to enable colors, "no" (disable colors), or "auto" (the default)
-// to let Google Test decide.
-GTEST_DECLARE_string_(color);
-
-// This flag sets up the filter to select by name using a glob pattern
-// the tests to run. If the filter is not given all tests are executed.
-GTEST_DECLARE_string_(filter);
-
-// This flag causes the Google Test to list tests. None of the tests listed
-// are actually run if the flag is provided.
-GTEST_DECLARE_bool_(list_tests);
-
-// This flag controls whether Google Test emits a detailed XML report to a file
-// in addition to its normal textual output.
-GTEST_DECLARE_string_(output);
-
-// This flags control whether Google Test prints the elapsed time for each
-// test.
-GTEST_DECLARE_bool_(print_time);
-
-// This flag specifies the random number seed.
-GTEST_DECLARE_int32_(random_seed);
-
-// This flag sets how many times the tests are repeated. The default value
-// is 1. If the value is -1 the tests are repeating forever.
-GTEST_DECLARE_int32_(repeat);
-
-// This flag controls whether Google Test includes Google Test internal
-// stack frames in failure stack traces.
-GTEST_DECLARE_bool_(show_internal_stack_frames);
-
-// When this flag is specified, tests' order is randomized on every iteration.
-GTEST_DECLARE_bool_(shuffle);
-
-// This flag specifies the maximum number of stack frames to be
-// printed in a failure message.
-GTEST_DECLARE_int32_(stack_trace_depth);
-
-// When this flag is specified, a failed assertion will throw an
-// exception if exceptions are enabled, or exit the program with a
-// non-zero code otherwise.
-GTEST_DECLARE_bool_(throw_on_failure);
-
-// The upper limit for valid stack trace depths.
-const int kMaxStackTraceDepth = 100;
-
-namespace internal {
-
-class AssertHelper;
-class DefaultGlobalTestPartResultReporter;
-class ExecDeathTest;
-class NoExecDeathTest;
-class FinalSuccessChecker;
-class GTestFlagSaver;
-class TestInfoImpl;
-class TestResultAccessor;
-class TestEventListenersAccessor;
-class TestEventRepeater;
-class WindowsDeathTest;
-class UnitTestImpl* GetUnitTestImpl();
-void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
- const String& message);
-class PrettyUnitTestResultPrinter;
-class XmlUnitTestResultPrinter;
-
-// Converts a streamable value to a String. A NULL pointer is
-// converted to "(null)". When the input value is a ::string,
-// ::std::string, ::wstring, or ::std::wstring object, each NUL
-// character in it is replaced with "\\0".
-// Declared in gtest-internal.h but defined here, so that it has access
-// to the definition of the Message class, required by the ARM
-// compiler.
-template <typename T>
-String StreamableToString(const T& streamable) {
- return (Message() << streamable).GetString();
-}
-
-} // namespace internal
-
-// A class for indicating whether an assertion was successful. When
-// the assertion wasn't successful, the AssertionResult object
-// remembers a non-empty message that describes how it failed.
-//
-// To create an instance of this class, use one of the factory functions
-// (AssertionSuccess() and AssertionFailure()).
-//
-// This class is useful for two purposes:
-// 1. Defining predicate functions to be used with Boolean test assertions
-// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts
-// 2. Defining predicate-format functions to be
-// used with predicate assertions (ASSERT_PRED_FORMAT*, etc).
-//
-// For example, if you define IsEven predicate:
-//
-// testing::AssertionResult IsEven(int n) {
-// if ((n % 2) == 0)
-// return testing::AssertionSuccess();
-// else
-// return testing::AssertionFailure() << n << " is odd";
-// }
-//
-// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5)))
-// will print the message
-//
-// Value of: IsEven(Fib(5))
-// Actual: false (5 is odd)
-// Expected: true
-//
-// instead of a more opaque
-//
-// Value of: IsEven(Fib(5))
-// Actual: false
-// Expected: true
-//
-// in case IsEven is a simple Boolean predicate.
-//
-// If you expect your predicate to be reused and want to support informative
-// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up
-// about half as often as positive ones in our tests), supply messages for
-// both success and failure cases:
-//
-// testing::AssertionResult IsEven(int n) {
-// if ((n % 2) == 0)
-// return testing::AssertionSuccess() << n << " is even";
-// else
-// return testing::AssertionFailure() << n << " is odd";
-// }
-//
-// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print
-//
-// Value of: IsEven(Fib(6))
-// Actual: true (8 is even)
-// Expected: false
-//
-// NB: Predicates that support negative Boolean assertions have reduced
-// performance in positive ones so be careful not to use them in tests
-// that have lots (tens of thousands) of positive Boolean assertions.
-//
-// To use this class with EXPECT_PRED_FORMAT assertions such as:
-//
-// // Verifies that Foo() returns an even number.
-// EXPECT_PRED_FORMAT1(IsEven, Foo());
-//
-// you need to define:
-//
-// testing::AssertionResult IsEven(const char* expr, int n) {
-// if ((n % 2) == 0)
-// return testing::AssertionSuccess();
-// else
-// return testing::AssertionFailure()
-// << "Expected: " << expr << " is even\n Actual: it's " << n;
-// }
-//
-// If Foo() returns 5, you will see the following message:
-//
-// Expected: Foo() is even
-// Actual: it's 5
-//
-class GTEST_API_ AssertionResult {
- public:
- // Copy constructor.
- // Used in EXPECT_TRUE/FALSE(assertion_result).
- AssertionResult(const AssertionResult& other);
- // Used in the EXPECT_TRUE/FALSE(bool_expression).
- explicit AssertionResult(bool success) : success_(success) {}
-
- // Returns true iff the assertion succeeded.
- operator bool() const { return success_; } // NOLINT
-
- // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
- AssertionResult operator!() const;
-
- // Returns the text streamed into this AssertionResult. Test assertions
- // use it when they fail (i.e., the predicate's outcome doesn't match the
- // assertion's expectation). When nothing has been streamed into the
- // object, returns an empty string.
- const char* message() const {
- return message_.get() != NULL && message_->c_str() != NULL ?
- message_->c_str() : "";
- }
- // TODO(vladl@google.com): Remove this after making sure no clients use it.
- // Deprecated; please use message() instead.
- const char* failure_message() const { return message(); }
-
- // Streams a custom failure message into this object.
- template <typename T> AssertionResult& operator<<(const T& value);
-
- private:
- // No implementation - we want AssertionResult to be
- // copy-constructible but not assignable.
- void operator=(const AssertionResult& other);
-
- // Stores result of the assertion predicate.
- bool success_;
- // Stores the message describing the condition in case the expectation
- // construct is not satisfied with the predicate's outcome.
- // Referenced via a pointer to avoid taking too much stack frame space
- // with test assertions.
- internal::scoped_ptr<internal::String> message_;
-}; // class AssertionResult
-
-// Streams a custom failure message into this object.
-template <typename T>
-AssertionResult& AssertionResult::operator<<(const T& value) {
- Message msg;
- if (message_.get() != NULL)
- msg << *message_;
- msg << value;
- message_.reset(new internal::String(msg.GetString()));
- return *this;
-}
-
-// Makes a successful assertion result.
-GTEST_API_ AssertionResult AssertionSuccess();
-
-// Makes a failed assertion result.
-GTEST_API_ AssertionResult AssertionFailure();
-
-// Makes a failed assertion result with the given failure message.
-// Deprecated; use AssertionFailure() << msg.
-GTEST_API_ AssertionResult AssertionFailure(const Message& msg);
-
-// The abstract class that all tests inherit from.
-//
-// In Google Test, a unit test program contains one or many TestCases, and
-// each TestCase contains one or many Tests.
-//
-// When you define a test using the TEST macro, you don't need to
-// explicitly derive from Test - the TEST macro automatically does
-// this for you.
-//
-// The only time you derive from Test is when defining a test fixture
-// to be used a TEST_F. For example:
-//
-// class FooTest : public testing::Test {
-// protected:
-// virtual void SetUp() { ... }
-// virtual void TearDown() { ... }
-// ...
-// };
-//
-// TEST_F(FooTest, Bar) { ... }
-// TEST_F(FooTest, Baz) { ... }
-//
-// Test is not copyable.
-class GTEST_API_ Test {
- public:
- friend class internal::TestInfoImpl;
-
- // Defines types for pointers to functions that set up and tear down
- // a test case.
- typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc;
- typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc;
-
- // The d'tor is virtual as we intend to inherit from Test.
- virtual ~Test();
-
- // Sets up the stuff shared by all tests in this test case.
- //
- // Google Test will call Foo::SetUpTestCase() before running the first
- // test in test case Foo. Hence a sub-class can define its own
- // SetUpTestCase() method to shadow the one defined in the super
- // class.
- static void SetUpTestCase() {}
-
- // Tears down the stuff shared by all tests in this test case.
- //
- // Google Test will call Foo::TearDownTestCase() after running the last
- // test in test case Foo. Hence a sub-class can define its own
- // TearDownTestCase() method to shadow the one defined in the super
- // class.
- static void TearDownTestCase() {}
-
- // Returns true iff the current test has a fatal failure.
- static bool HasFatalFailure();
-
- // Returns true iff the current test has a non-fatal failure.
- static bool HasNonfatalFailure();
-
- // Returns true iff the current test has a (either fatal or
- // non-fatal) failure.
- static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); }
-
- // Logs a property for the current test. Only the last value for a given
- // key is remembered.
- // These are public static so they can be called from utility functions
- // that are not members of the test fixture.
- // The arguments are const char* instead strings, as Google Test is used
- // on platforms where string doesn't compile.
- //
- // Note that a driving consideration for these RecordProperty methods
- // was to produce xml output suited to the Greenspan charting utility,
- // which at present will only chart values that fit in a 32-bit int. It
- // is the user's responsibility to restrict their values to 32-bit ints
- // if they intend them to be used with Greenspan.
- static void RecordProperty(const char* key, const char* value);
- static void RecordProperty(const char* key, int value);
-
- protected:
- // Creates a Test object.
- Test();
-
- // Sets up the test fixture.
- virtual void SetUp();
-
- // Tears down the test fixture.
- virtual void TearDown();
-
- private:
- // Returns true iff the current test has the same fixture class as
- // the first test in the current test case.
- static bool HasSameFixtureClass();
-
- // Runs the test after the test fixture has been set up.
- //
- // A sub-class must implement this to define the test logic.
- //
- // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM.
- // Instead, use the TEST or TEST_F macro.
- virtual void TestBody() = 0;
-
- // Sets up, executes, and tears down the test.
- void Run();
-
- // Uses a GTestFlagSaver to save and restore all Google Test flags.
- const internal::GTestFlagSaver* const gtest_flag_saver_;
-
- // Often a user mis-spells SetUp() as Setup() and spends a long time
- // wondering why it is never called by Google Test. The declaration of
- // the following method is solely for catching such an error at
- // compile time:
- //
- // - The return type is deliberately chosen to be not void, so it
- // will be a conflict if a user declares void Setup() in his test
- // fixture.
- //
- // - This method is private, so it will be another compiler error
- // if a user calls it from his test fixture.
- //
- // DO NOT OVERRIDE THIS FUNCTION.
- //
- // If you see an error about overriding the following function or
- // about it being private, you have mis-spelled SetUp() as Setup().
- struct Setup_should_be_spelled_SetUp {};
- virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
-
- // We disallow copying Tests.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(Test);
-};
-
-typedef internal::TimeInMillis TimeInMillis;
-
-// A copyable object representing a user specified test property which can be
-// output as a key/value string pair.
-//
-// Don't inherit from TestProperty as its destructor is not virtual.
-class TestProperty {
- public:
- // C'tor. TestProperty does NOT have a default constructor.
- // Always use this constructor (with parameters) to create a
- // TestProperty object.
- TestProperty(const char* a_key, const char* a_value) :
- key_(a_key), value_(a_value) {
- }
-
- // Gets the user supplied key.
- const char* key() const {
- return key_.c_str();
- }
-
- // Gets the user supplied value.
- const char* value() const {
- return value_.c_str();
- }
-
- // Sets a new value, overriding the one supplied in the constructor.
- void SetValue(const char* new_value) {
- value_ = new_value;
- }
-
- private:
- // The key supplied by the user.
- internal::String key_;
- // The value supplied by the user.
- internal::String value_;
-};
-
-// The result of a single Test. This includes a list of
-// TestPartResults, a list of TestProperties, a count of how many
-// death tests there are in the Test, and how much time it took to run
-// the Test.
-//
-// TestResult is not copyable.
-class GTEST_API_ TestResult {
- public:
- // Creates an empty TestResult.
- TestResult();
-
- // D'tor. Do not inherit from TestResult.
- ~TestResult();
-
- // Gets the number of all test parts. This is the sum of the number
- // of successful test parts and the number of failed test parts.
- int total_part_count() const;
-
- // Returns the number of the test properties.
- int test_property_count() const;
-
- // Returns true iff the test passed (i.e. no test part failed).
- bool Passed() const { return !Failed(); }
-
- // Returns true iff the test failed.
- bool Failed() const;
-
- // Returns true iff the test fatally failed.
- bool HasFatalFailure() const;
-
- // Returns true iff the test has a non-fatal failure.
- bool HasNonfatalFailure() const;
-
- // Returns the elapsed time, in milliseconds.
- TimeInMillis elapsed_time() const { return elapsed_time_; }
-
- // Returns the i-th test part result among all the results. i can range
- // from 0 to test_property_count() - 1. If i is not in that range, aborts
- // the program.
- const TestPartResult& GetTestPartResult(int i) const;
-
- // Returns the i-th test property. i can range from 0 to
- // test_property_count() - 1. If i is not in that range, aborts the
- // program.
- const TestProperty& GetTestProperty(int i) const;
-
- private:
- friend class TestInfo;
- friend class UnitTest;
- friend class internal::DefaultGlobalTestPartResultReporter;
- friend class internal::ExecDeathTest;
- friend class internal::TestInfoImpl;
- friend class internal::TestResultAccessor;
- friend class internal::UnitTestImpl;
- friend class internal::WindowsDeathTest;
-
- // Gets the vector of TestPartResults.
- const std::vector<TestPartResult>& test_part_results() const {
- return test_part_results_;
- }
-
- // Gets the vector of TestProperties.
- const std::vector<TestProperty>& test_properties() const {
- return test_properties_;
- }
-
- // Sets the elapsed time.
- void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; }
-
- // Adds a test property to the list. The property is validated and may add
- // a non-fatal failure if invalid (e.g., if it conflicts with reserved
- // key names). If a property is already recorded for the same key, the
- // value will be updated, rather than storing multiple values for the same
- // key.
- void RecordProperty(const TestProperty& test_property);
-
- // Adds a failure if the key is a reserved attribute of Google Test
- // testcase tags. Returns true if the property is valid.
- // TODO(russr): Validate attribute names are legal and human readable.
- static bool ValidateTestProperty(const TestProperty& test_property);
-
- // Adds a test part result to the list.
- void AddTestPartResult(const TestPartResult& test_part_result);
-
- // Returns the death test count.
- int death_test_count() const { return death_test_count_; }
-
- // Increments the death test count, returning the new count.
- int increment_death_test_count() { return ++death_test_count_; }
-
- // Clears the test part results.
- void ClearTestPartResults();
-
- // Clears the object.
- void Clear();
-
- // Protects mutable state of the property vector and of owned
- // properties, whose values may be updated.
- internal::Mutex test_properites_mutex_;
-
- // The vector of TestPartResults
- std::vector<TestPartResult> test_part_results_;
- // The vector of TestProperties
- std::vector<TestProperty> test_properties_;
- // Running count of death tests.
- int death_test_count_;
- // The elapsed time, in milliseconds.
- TimeInMillis elapsed_time_;
-
- // We disallow copying TestResult.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult);
-}; // class TestResult
-
-// A TestInfo object stores the following information about a test:
-//
-// Test case name
-// Test name
-// Whether the test should be run
-// A function pointer that creates the test object when invoked
-// Test result
-//
-// The constructor of TestInfo registers itself with the UnitTest
-// singleton such that the RUN_ALL_TESTS() macro knows which tests to
-// run.
-class GTEST_API_ TestInfo {
- public:
- // Destructs a TestInfo object. This function is not virtual, so
- // don't inherit from TestInfo.
- ~TestInfo();
-
- // Returns the test case name.
- const char* test_case_name() const;
-
- // Returns the test name.
- const char* name() const;
-
- // Returns the test case comment.
- const char* test_case_comment() const;
-
- // Returns the test comment.
- const char* comment() const;
-
- // Returns true if this test should run, that is if the test is not disabled
- // (or it is disabled but the also_run_disabled_tests flag has been specified)
- // and its full name matches the user-specified filter.
- //
- // Google Test allows the user to filter the tests by their full names.
- // The full name of a test Bar in test case Foo is defined as
- // "Foo.Bar". Only the tests that match the filter will run.
- //
- // A filter is a colon-separated list of glob (not regex) patterns,
- // optionally followed by a '-' and a colon-separated list of
- // negative patterns (tests to exclude). A test is run if it
- // matches one of the positive patterns and does not match any of
- // the negative patterns.
- //
- // For example, *A*:Foo.* is a filter that matches any string that
- // contains the character 'A' or starts with "Foo.".
- bool should_run() const;
-
- // Returns the result of the test.
- const TestResult* result() const;
-
- private:
-#if GTEST_HAS_DEATH_TEST
- friend class internal::DefaultDeathTestFactory;
-#endif // GTEST_HAS_DEATH_TEST
- friend class Test;
- friend class TestCase;
- friend class internal::TestInfoImpl;
- friend class internal::UnitTestImpl;
- friend TestInfo* internal::MakeAndRegisterTestInfo(
- const char* test_case_name, const char* name,
- const char* test_case_comment, const char* comment,
- internal::TypeId fixture_class_id,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc,
- internal::TestFactoryBase* factory);
-
- // Returns true if this test matches the user-specified filter.
- bool matches_filter() const;
-
- // Increments the number of death tests encountered in this test so
- // far.
- int increment_death_test_count();
-
- // Accessors for the implementation object.
- internal::TestInfoImpl* impl() { return impl_; }
- const internal::TestInfoImpl* impl() const { return impl_; }
-
- // Constructs a TestInfo object. The newly constructed instance assumes
- // ownership of the factory object.
- TestInfo(const char* test_case_name, const char* name,
- const char* test_case_comment, const char* comment,
- internal::TypeId fixture_class_id,
- internal::TestFactoryBase* factory);
-
- // An opaque implementation object.
- internal::TestInfoImpl* impl_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
-};
-
-// A test case, which consists of a vector of TestInfos.
-//
-// TestCase is not copyable.
-class GTEST_API_ TestCase {
- public:
- // Creates a TestCase with the given name.
- //
- // TestCase does NOT have a default constructor. Always use this
- // constructor to create a TestCase object.
- //
- // Arguments:
- //
- // name: name of the test case
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- TestCase(const char* name, const char* comment,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc);
-
- // Destructor of TestCase.
- virtual ~TestCase();
-
- // Gets the name of the TestCase.
- const char* name() const { return name_.c_str(); }
-
- // Returns the test case comment.
- const char* comment() const { return comment_.c_str(); }
-
- // Returns true if any test in this test case should run.
- bool should_run() const { return should_run_; }
-
- // Gets the number of successful tests in this test case.
- int successful_test_count() const;
-
- // Gets the number of failed tests in this test case.
- int failed_test_count() const;
-
- // Gets the number of disabled tests in this test case.
- int disabled_test_count() const;
-
- // Get the number of tests in this test case that should run.
- int test_to_run_count() const;
-
- // Gets the number of all tests in this test case.
- int total_test_count() const;
-
- // Returns true iff the test case passed.
- bool Passed() const { return !Failed(); }
-
- // Returns true iff the test case failed.
- bool Failed() const { return failed_test_count() > 0; }
-
- // Returns the elapsed time, in milliseconds.
- TimeInMillis elapsed_time() const { return elapsed_time_; }
-
- // Returns the i-th test among all the tests. i can range from 0 to
- // total_test_count() - 1. If i is not in that range, returns NULL.
- const TestInfo* GetTestInfo(int i) const;
-
- private:
- friend class Test;
- friend class internal::UnitTestImpl;
-
- // Gets the (mutable) vector of TestInfos in this TestCase.
- std::vector<TestInfo*>& test_info_list() { return test_info_list_; }
-
- // Gets the (immutable) vector of TestInfos in this TestCase.
- const std::vector<TestInfo*>& test_info_list() const {
- return test_info_list_;
- }
-
- // Returns the i-th test among all the tests. i can range from 0 to
- // total_test_count() - 1. If i is not in that range, returns NULL.
- TestInfo* GetMutableTestInfo(int i);
-
- // Sets the should_run member.
- void set_should_run(bool should) { should_run_ = should; }
-
- // Adds a TestInfo to this test case. Will delete the TestInfo upon
- // destruction of the TestCase object.
- void AddTestInfo(TestInfo * test_info);
-
- // Clears the results of all tests in this test case.
- void ClearResult();
-
- // Clears the results of all tests in the given test case.
- static void ClearTestCaseResult(TestCase* test_case) {
- test_case->ClearResult();
- }
-
- // Runs every test in this TestCase.
- void Run();
-
- // Returns true iff test passed.
- static bool TestPassed(const TestInfo * test_info);
-
- // Returns true iff test failed.
- static bool TestFailed(const TestInfo * test_info);
-
- // Returns true iff test is disabled.
- static bool TestDisabled(const TestInfo * test_info);
-
- // Returns true if the given test should run.
- static bool ShouldRunTest(const TestInfo *test_info);
-
- // Shuffles the tests in this test case.
- void ShuffleTests(internal::Random* random);
-
- // Restores the test order to before the first shuffle.
- void UnshuffleTests();
-
- // Name of the test case.
- internal::String name_;
- // Comment on the test case.
- internal::String comment_;
- // The vector of TestInfos in their original order. It owns the
- // elements in the vector.
- std::vector<TestInfo*> test_info_list_;
- // Provides a level of indirection for the test list to allow easy
- // shuffling and restoring the test order. The i-th element in this
- // vector is the index of the i-th test in the shuffled test list.
- std::vector<int> test_indices_;
- // Pointer to the function that sets up the test case.
- Test::SetUpTestCaseFunc set_up_tc_;
- // Pointer to the function that tears down the test case.
- Test::TearDownTestCaseFunc tear_down_tc_;
- // True iff any test in this test case should run.
- bool should_run_;
- // Elapsed time, in milliseconds.
- TimeInMillis elapsed_time_;
-
- // We disallow copying TestCases.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase);
-};
-
-// An Environment object is capable of setting up and tearing down an
-// environment. The user should subclass this to define his own
-// environment(s).
-//
-// An Environment object does the set-up and tear-down in virtual
-// methods SetUp() and TearDown() instead of the constructor and the
-// destructor, as:
-//
-// 1. You cannot safely throw from a destructor. This is a problem
-// as in some cases Google Test is used where exceptions are enabled, and
-// we may want to implement ASSERT_* using exceptions where they are
-// available.
-// 2. You cannot use ASSERT_* directly in a constructor or
-// destructor.
-class Environment {
- public:
- // The d'tor is virtual as we need to subclass Environment.
- virtual ~Environment() {}
-
- // Override this to define how to set up the environment.
- virtual void SetUp() {}
-
- // Override this to define how to tear down the environment.
- virtual void TearDown() {}
- private:
- // If you see an error about overriding the following function or
- // about it being private, you have mis-spelled SetUp() as Setup().
- struct Setup_should_be_spelled_SetUp {};
- virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; }
-};
-
-// The interface for tracing execution of tests. The methods are organized in
-// the order the corresponding events are fired.
-class TestEventListener {
- public:
- virtual ~TestEventListener() {}
-
- // Fired before any test activity starts.
- virtual void OnTestProgramStart(const UnitTest& unit_test) = 0;
-
- // Fired before each iteration of tests starts. There may be more than
- // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration
- // index, starting from 0.
- virtual void OnTestIterationStart(const UnitTest& unit_test,
- int iteration) = 0;
-
- // Fired before environment set-up for each iteration of tests starts.
- virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0;
-
- // Fired after environment set-up for each iteration of tests ends.
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0;
-
- // Fired before the test case starts.
- virtual void OnTestCaseStart(const TestCase& test_case) = 0;
-
- // Fired before the test starts.
- virtual void OnTestStart(const TestInfo& test_info) = 0;
-
- // Fired after a failed assertion or a SUCCESS().
- virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0;
-
- // Fired after the test ends.
- virtual void OnTestEnd(const TestInfo& test_info) = 0;
-
- // Fired after the test case ends.
- virtual void OnTestCaseEnd(const TestCase& test_case) = 0;
-
- // Fired before environment tear-down for each iteration of tests starts.
- virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0;
-
- // Fired after environment tear-down for each iteration of tests ends.
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0;
-
- // Fired after each iteration of tests finishes.
- virtual void OnTestIterationEnd(const UnitTest& unit_test,
- int iteration) = 0;
-
- // Fired after all test activities have ended.
- virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0;
-};
-
-// The convenience class for users who need to override just one or two
-// methods and are not concerned that a possible change to a signature of
-// the methods they override will not be caught during the build. For
-// comments about each method please see the definition of TestEventListener
-// above.
-class EmptyTestEventListener : public TestEventListener {
- public:
- virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationStart(const UnitTest& /*unit_test*/,
- int /*iteration*/) {}
- virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {}
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestCaseStart(const TestCase& /*test_case*/) {}
- virtual void OnTestStart(const TestInfo& /*test_info*/) {}
- virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {}
- virtual void OnTestEnd(const TestInfo& /*test_info*/) {}
- virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {}
- virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {}
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/,
- int /*iteration*/) {}
- virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
-};
-
-// TestEventListeners lets users add listeners to track events in Google Test.
-class GTEST_API_ TestEventListeners {
- public:
- TestEventListeners();
- ~TestEventListeners();
-
- // Appends an event listener to the end of the list. Google Test assumes
- // the ownership of the listener (i.e. it will delete the listener when
- // the test program finishes).
- void Append(TestEventListener* listener);
-
- // Removes the given event listener from the list and returns it. It then
- // becomes the caller's responsibility to delete the listener. Returns
- // NULL if the listener is not found in the list.
- TestEventListener* Release(TestEventListener* listener);
-
- // Returns the standard listener responsible for the default console
- // output. Can be removed from the listeners list to shut down default
- // console output. Note that removing this object from the listener list
- // with Release transfers its ownership to the caller and makes this
- // function return NULL the next time.
- TestEventListener* default_result_printer() const {
- return default_result_printer_;
- }
-
- // Returns the standard listener responsible for the default XML output
- // controlled by the --gtest_output=xml flag. Can be removed from the
- // listeners list by users who want to shut down the default XML output
- // controlled by this flag and substitute it with custom one. Note that
- // removing this object from the listener list with Release transfers its
- // ownership to the caller and makes this function return NULL the next
- // time.
- TestEventListener* default_xml_generator() const {
- return default_xml_generator_;
- }
-
- private:
- friend class TestCase;
- friend class internal::DefaultGlobalTestPartResultReporter;
- friend class internal::NoExecDeathTest;
- friend class internal::TestEventListenersAccessor;
- friend class internal::TestInfoImpl;
- friend class internal::UnitTestImpl;
-
- // Returns repeater that broadcasts the TestEventListener events to all
- // subscribers.
- TestEventListener* repeater();
-
- // Sets the default_result_printer attribute to the provided listener.
- // The listener is also added to the listener list and previous
- // default_result_printer is removed from it and deleted. The listener can
- // also be NULL in which case it will not be added to the list. Does
- // nothing if the previous and the current listener objects are the same.
- void SetDefaultResultPrinter(TestEventListener* listener);
-
- // Sets the default_xml_generator attribute to the provided listener. The
- // listener is also added to the listener list and previous
- // default_xml_generator is removed from it and deleted. The listener can
- // also be NULL in which case it will not be added to the list. Does
- // nothing if the previous and the current listener objects are the same.
- void SetDefaultXmlGenerator(TestEventListener* listener);
-
- // Controls whether events will be forwarded by the repeater to the
- // listeners in the list.
- bool EventForwardingEnabled() const;
- void SuppressEventForwarding();
-
- // The actual list of listeners.
- internal::TestEventRepeater* repeater_;
- // Listener responsible for the standard result output.
- TestEventListener* default_result_printer_;
- // Listener responsible for the creation of the XML output file.
- TestEventListener* default_xml_generator_;
-
- // We disallow copying TestEventListeners.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners);
-};
-
-// A UnitTest consists of a vector of TestCases.
-//
-// This is a singleton class. The only instance of UnitTest is
-// created when UnitTest::GetInstance() is first called. This
-// instance is never deleted.
-//
-// UnitTest is not copyable.
-//
-// This class is thread-safe as long as the methods are called
-// according to their specification.
-class GTEST_API_ UnitTest {
- public:
- // Gets the singleton UnitTest object. The first time this method
- // is called, a UnitTest object is constructed and returned.
- // Consecutive calls will return the same object.
- static UnitTest* GetInstance();
-
- // Runs all tests in this UnitTest object and prints the result.
- // Returns 0 if successful, or 1 otherwise.
- //
- // This method can only be called from the main thread.
- //
- // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
- int Run() GTEST_MUST_USE_RESULT_;
-
- // Returns the working directory when the first TEST() or TEST_F()
- // was executed. The UnitTest object owns the string.
- const char* original_working_dir() const;
-
- // Returns the TestCase object for the test that's currently running,
- // or NULL if no test is running.
- const TestCase* current_test_case() const;
-
- // Returns the TestInfo object for the test that's currently running,
- // or NULL if no test is running.
- const TestInfo* current_test_info() const;
-
- // Returns the random seed used at the start of the current test run.
- int random_seed() const;
-
-#if GTEST_HAS_PARAM_TEST
- // Returns the ParameterizedTestCaseRegistry object used to keep track of
- // value-parameterized tests and instantiate and register them.
- //
- // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
- internal::ParameterizedTestCaseRegistry& parameterized_test_registry();
-#endif // GTEST_HAS_PARAM_TEST
-
- // Gets the number of successful test cases.
- int successful_test_case_count() const;
-
- // Gets the number of failed test cases.
- int failed_test_case_count() const;
-
- // Gets the number of all test cases.
- int total_test_case_count() const;
-
- // Gets the number of all test cases that contain at least one test
- // that should run.
- int test_case_to_run_count() const;
-
- // Gets the number of successful tests.
- int successful_test_count() const;
-
- // Gets the number of failed tests.
- int failed_test_count() const;
-
- // Gets the number of disabled tests.
- int disabled_test_count() const;
-
- // Gets the number of all tests.
- int total_test_count() const;
-
- // Gets the number of tests that should run.
- int test_to_run_count() const;
-
- // Gets the elapsed time, in milliseconds.
- TimeInMillis elapsed_time() const;
-
- // Returns true iff the unit test passed (i.e. all test cases passed).
- bool Passed() const;
-
- // Returns true iff the unit test failed (i.e. some test case failed
- // or something outside of all tests failed).
- bool Failed() const;
-
- // Gets the i-th test case among all the test cases. i can range from 0 to
- // total_test_case_count() - 1. If i is not in that range, returns NULL.
- const TestCase* GetTestCase(int i) const;
-
- // Returns the list of event listeners that can be used to track events
- // inside Google Test.
- TestEventListeners& listeners();
-
- private:
- // Registers and returns a global test environment. When a test
- // program is run, all global test environments will be set-up in
- // the order they were registered. After all tests in the program
- // have finished, all global test environments will be torn-down in
- // the *reverse* order they were registered.
- //
- // The UnitTest object takes ownership of the given environment.
- //
- // This method can only be called from the main thread.
- Environment* AddEnvironment(Environment* env);
-
- // Adds a TestPartResult to the current TestResult object. All
- // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc)
- // eventually call this to report their results. The user code
- // should use the assertion macros instead of calling this directly.
- void AddTestPartResult(TestPartResult::Type result_type,
- const char* file_name,
- int line_number,
- const internal::String& message,
- const internal::String& os_stack_trace);
-
- // Adds a TestProperty to the current TestResult object. If the result already
- // contains a property with the same key, the value will be updated.
- void RecordPropertyForCurrentTest(const char* key, const char* value);
-
- // Gets the i-th test case among all the test cases. i can range from 0 to
- // total_test_case_count() - 1. If i is not in that range, returns NULL.
- TestCase* GetMutableTestCase(int i);
-
- // Accessors for the implementation object.
- internal::UnitTestImpl* impl() { return impl_; }
- const internal::UnitTestImpl* impl() const { return impl_; }
-
- // These classes and funcions are friends as they need to access private
- // members of UnitTest.
- friend class Test;
- friend class internal::AssertHelper;
- friend class internal::ScopedTrace;
- friend Environment* AddGlobalTestEnvironment(Environment* env);
- friend internal::UnitTestImpl* internal::GetUnitTestImpl();
- friend void internal::ReportFailureInUnknownLocation(
- TestPartResult::Type result_type,
- const internal::String& message);
-
- // Creates an empty UnitTest.
- UnitTest();
-
- // D'tor
- virtual ~UnitTest();
-
- // Pushes a trace defined by SCOPED_TRACE() on to the per-thread
- // Google Test trace stack.
- void PushGTestTrace(const internal::TraceInfo& trace);
-
- // Pops a trace from the per-thread Google Test trace stack.
- void PopGTestTrace();
-
- // Protects mutable state in *impl_. This is mutable as some const
- // methods need to lock it too.
- mutable internal::Mutex mutex_;
-
- // Opaque implementation object. This field is never changed once
- // the object is constructed. We don't mark it as const here, as
- // doing so will cause a warning in the constructor of UnitTest.
- // Mutable state in *impl_ is protected by mutex_.
- internal::UnitTestImpl* impl_;
-
- // We disallow copying UnitTest.
- GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest);
-};
-
-// A convenient wrapper for adding an environment for the test
-// program.
-//
-// You should call this before RUN_ALL_TESTS() is called, probably in
-// main(). If you use gtest_main, you need to call this before main()
-// starts for it to take effect. For example, you can define a global
-// variable like this:
-//
-// testing::Environment* const foo_env =
-// testing::AddGlobalTestEnvironment(new FooEnvironment);
-//
-// However, we strongly recommend you to write your own main() and
-// call AddGlobalTestEnvironment() there, as relying on initialization
-// of global variables makes the code harder to read and may cause
-// problems when you register multiple environments from different
-// translation units and the environments have dependencies among them
-// (remember that the compiler doesn't guarantee the order in which
-// global variables from different translation units are initialized).
-inline Environment* AddGlobalTestEnvironment(Environment* env) {
- return UnitTest::GetInstance()->AddEnvironment(env);
-}
-
-// Initializes Google Test. This must be called before calling
-// RUN_ALL_TESTS(). In particular, it parses a command line for the
-// flags that Google Test recognizes. Whenever a Google Test flag is
-// seen, it is removed from argv, and *argc is decremented.
-//
-// No value is returned. Instead, the Google Test flag variables are
-// updated.
-//
-// Calling the function for the second time has no user-visible effect.
-GTEST_API_ void InitGoogleTest(int* argc, char** argv);
-
-// This overloaded version can be used in Windows programs compiled in
-// UNICODE mode.
-GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv);
-
-namespace internal {
-
-// These overloaded versions handle ::std::string and ::std::wstring.
-GTEST_API_ inline String FormatForFailureMessage(const ::std::string& str) {
- return (Message() << '"' << str << '"').GetString();
-}
-
-#if GTEST_HAS_STD_WSTRING
-GTEST_API_ inline String FormatForFailureMessage(const ::std::wstring& wstr) {
- return (Message() << "L\"" << wstr << '"').GetString();
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-// These overloaded versions handle ::string and ::wstring.
-#if GTEST_HAS_GLOBAL_STRING
-GTEST_API_ inline String FormatForFailureMessage(const ::string& str) {
- return (Message() << '"' << str << '"').GetString();
-}
-#endif // GTEST_HAS_GLOBAL_STRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
-GTEST_API_ inline String FormatForFailureMessage(const ::wstring& wstr) {
- return (Message() << "L\"" << wstr << '"').GetString();
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
-// operand to be used in a failure message. The type (but not value)
-// of the other operand may affect the format. This allows us to
-// print a char* as a raw pointer when it is compared against another
-// char*, and print it as a C string when it is compared against an
-// std::string object, for example.
-//
-// The default implementation ignores the type of the other operand.
-// Some specialized versions are used to handle formatting wide or
-// narrow C strings.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-template <typename T1, typename T2>
-String FormatForComparisonFailureMessage(const T1& value,
- const T2& /* other_operand */) {
- return FormatForFailureMessage(value);
-}
-
-// The helper function for {ASSERT|EXPECT}_EQ.
-template <typename T1, typename T2>
-AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual) {
-#ifdef _MSC_VER
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4389) // Temporarily disables warning on
- // signed/unsigned mismatch.
-#endif
-
- if (expected == actual) {
- return AssertionSuccess();
- }
-
-#ifdef _MSC_VER
-#pragma warning(pop) // Restores the warning state.
-#endif
-
- return EqFailure(expected_expression,
- actual_expression,
- FormatForComparisonFailureMessage(expected, actual),
- FormatForComparisonFailureMessage(actual, expected),
- false);
-}
-
-// With this overloaded version, we allow anonymous enums to be used
-// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums
-// can be implicitly cast to BiggestInt.
-GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual);
-
-// The helper class for {ASSERT|EXPECT}_EQ. The template argument
-// lhs_is_null_literal is true iff the first argument to ASSERT_EQ()
-// is a null pointer literal. The following default implementation is
-// for lhs_is_null_literal being false.
-template <bool lhs_is_null_literal>
-class EqHelper {
- public:
- // This templatized version is for the general case.
- template <typename T1, typename T2>
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
- }
-
- // With this overloaded version, we allow anonymous enums to be used
- // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous
- // enums can be implicitly cast to BiggestInt.
- //
- // Even though its body looks the same as the above version, we
- // cannot merge the two, as it will make anonymous enums unhappy.
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
- }
-};
-
-// This specialization is used when the first argument to ASSERT_EQ()
-// is a null pointer literal.
-template <>
-class EqHelper<true> {
- public:
- // We define two overloaded versions of Compare(). The first
- // version will be picked when the second argument to ASSERT_EQ() is
- // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or
- // EXPECT_EQ(false, a_bool).
- template <typename T1, typename T2>
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- const T1& expected,
- const T2& actual) {
- return CmpHelperEQ(expected_expression, actual_expression, expected,
- actual);
- }
-
- // This version will be picked when the second argument to
- // ASSERT_EQ() is a pointer, e.g. ASSERT_EQ(NULL, a_pointer).
- template <typename T1, typename T2>
- static AssertionResult Compare(const char* expected_expression,
- const char* actual_expression,
- const T1& /* expected */,
- T2* actual) {
- // We already know that 'expected' is a null pointer.
- return CmpHelperEQ(expected_expression, actual_expression,
- static_cast<T2*>(NULL), actual);
- }
-};
-
-// A macro for implementing the helper functions needed to implement
-// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste
-// of similar code.
-//
-// For each templatized helper function, we also define an overloaded
-// version for BiggestInt in order to reduce code bloat and allow
-// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled
-// with gcc 4.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
-template <typename T1, typename T2>\
-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
- const T1& val1, const T2& val2) {\
- if (val1 op val2) {\
- return AssertionSuccess();\
- } else {\
- Message msg;\
- msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
- << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
- << " vs " << FormatForComparisonFailureMessage(val2, val1);\
- return AssertionFailure(msg);\
- }\
-}\
-GTEST_API_ AssertionResult CmpHelper##op_name(\
- const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2)
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-
-// Implements the helper function for {ASSERT|EXPECT}_NE
-GTEST_IMPL_CMP_HELPER_(NE, !=);
-// Implements the helper function for {ASSERT|EXPECT}_LE
-GTEST_IMPL_CMP_HELPER_(LE, <=);
-// Implements the helper function for {ASSERT|EXPECT}_LT
-GTEST_IMPL_CMP_HELPER_(LT, < );
-// Implements the helper function for {ASSERT|EXPECT}_GE
-GTEST_IMPL_CMP_HELPER_(GE, >=);
-// Implements the helper function for {ASSERT|EXPECT}_GT
-GTEST_IMPL_CMP_HELPER_(GT, > );
-
-#undef GTEST_IMPL_CMP_HELPER_
-
-// The helper function for {ASSERT|EXPECT}_STREQ.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual);
-
-// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual);
-
-// The helper function for {ASSERT|EXPECT}_STRNE.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
- const char* s2_expression,
- const char* s1,
- const char* s2);
-
-// The helper function for {ASSERT|EXPECT}_STRCASENE.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
- const char* s2_expression,
- const char* s1,
- const char* s2);
-
-
-// Helper function for *_STREQ on wide strings.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const wchar_t* expected,
- const wchar_t* actual);
-
-// Helper function for *_STRNE on wide strings.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression,
- const char* s2_expression,
- const wchar_t* s1,
- const wchar_t* s2);
-
-} // namespace internal
-
-// IsSubstring() and IsNotSubstring() are intended to be used as the
-// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by
-// themselves. They check whether needle is a substring of haystack
-// (NULL is considered a substring of itself only), and return an
-// appropriate error message when they fail.
-//
-// The {needle,haystack}_expr arguments are the stringified
-// expressions that generated the two real arguments.
-GTEST_API_ AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const char* needle, const char* haystack);
-GTEST_API_ AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const wchar_t* needle, const wchar_t* haystack);
-GTEST_API_ AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const char* needle, const char* haystack);
-GTEST_API_ AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const wchar_t* needle, const wchar_t* haystack);
-GTEST_API_ AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::string& needle, const ::std::string& haystack);
-GTEST_API_ AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::string& needle, const ::std::string& haystack);
-
-#if GTEST_HAS_STD_WSTRING
-GTEST_API_ AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::wstring& needle, const ::std::wstring& haystack);
-GTEST_API_ AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::wstring& needle, const ::std::wstring& haystack);
-#endif // GTEST_HAS_STD_WSTRING
-
-namespace internal {
-
-// Helper template function for comparing floating-points.
-//
-// Template parameter:
-//
-// RawType: the raw floating-point type (either float or double)
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-template <typename RawType>
-AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression,
- const char* actual_expression,
- RawType expected,
- RawType actual) {
- const FloatingPoint<RawType> lhs(expected), rhs(actual);
-
- if (lhs.AlmostEquals(rhs)) {
- return AssertionSuccess();
- }
-
- StrStream expected_ss;
- expected_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << expected;
-
- StrStream actual_ss;
- actual_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << actual;
-
- return EqFailure(expected_expression,
- actual_expression,
- StrStreamToString(&expected_ss),
- StrStreamToString(&actual_ss),
- false);
-}
-
-// Helper function for implementing ASSERT_NEAR.
-//
-// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
-GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1,
- const char* expr2,
- const char* abs_error_expr,
- double val1,
- double val2,
- double abs_error);
-
-// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
-// A class that enables one to stream messages to assertion macros
-class GTEST_API_ AssertHelper {
- public:
- // Constructor.
- AssertHelper(TestPartResult::Type type,
- const char* file,
- int line,
- const char* message);
- ~AssertHelper();
-
- // Message assignment is a semantic trick to enable assertion
- // streaming; see the GTEST_MESSAGE_ macro below.
- void operator=(const Message& message) const;
-
- private:
- // We put our data in a struct so that the size of the AssertHelper class can
- // be as small as possible. This is important because gcc is incapable of
- // re-using stack space even for temporary variables, so every EXPECT_EQ
- // reserves stack space for another AssertHelper.
- struct AssertHelperData {
- AssertHelperData(TestPartResult::Type t,
- const char* srcfile,
- int line_num,
- const char* msg)
- : type(t), file(srcfile), line(line_num), message(msg) { }
-
- TestPartResult::Type const type;
- const char* const file;
- int const line;
- String const message;
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData);
- };
-
- AssertHelperData* const data_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper);
-};
-
-} // namespace internal
-
-#if GTEST_HAS_PARAM_TEST
-// The abstract base class that all value-parameterized tests inherit from.
-//
-// This class adds support for accessing the test parameter value via
-// the GetParam() method.
-//
-// Use it with one of the parameter generator defining functions, like Range(),
-// Values(), ValuesIn(), Bool(), and Combine().
-//
-// class FooTest : public ::testing::TestWithParam<int> {
-// protected:
-// FooTest() {
-// // Can use GetParam() here.
-// }
-// virtual ~FooTest() {
-// // Can use GetParam() here.
-// }
-// virtual void SetUp() {
-// // Can use GetParam() here.
-// }
-// virtual void TearDown {
-// // Can use GetParam() here.
-// }
-// };
-// TEST_P(FooTest, DoesBar) {
-// // Can use GetParam() method here.
-// Foo foo;
-// ASSERT_TRUE(foo.DoesBar(GetParam()));
-// }
-// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10));
-
-template <typename T>
-class TestWithParam : public Test {
- public:
- typedef T ParamType;
-
- // The current parameter value. Is also available in the test fixture's
- // constructor.
- const ParamType& GetParam() const { return *parameter_; }
-
- private:
- // Sets parameter value. The caller is responsible for making sure the value
- // remains alive and unchanged throughout the current test.
- static void SetParam(const ParamType* parameter) {
- parameter_ = parameter;
- }
-
- // Static value used for accessing parameter during a test lifetime.
- static const ParamType* parameter_;
-
- // TestClass must be a subclass of TestWithParam<T>.
- template <class TestClass> friend class internal::ParameterizedTestFactory;
-};
-
-template <typename T>
-const T* TestWithParam<T>::parameter_ = NULL;
-
-#endif // GTEST_HAS_PARAM_TEST
-
-// Macros for indicating success/failure in test code.
-
-// ADD_FAILURE unconditionally adds a failure to the current test.
-// SUCCEED generates a success - it doesn't automatically make the
-// current test successful, as a test is only successful when it has
-// no failure.
-//
-// EXPECT_* verifies that a certain condition is satisfied. If not,
-// it behaves like ADD_FAILURE. In particular:
-//
-// EXPECT_TRUE verifies that a Boolean condition is true.
-// EXPECT_FALSE verifies that a Boolean condition is false.
-//
-// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except
-// that they will also abort the current function on failure. People
-// usually want the fail-fast behavior of FAIL and ASSERT_*, but those
-// writing data-driven tests often find themselves using ADD_FAILURE
-// and EXPECT_* more.
-//
-// Examples:
-//
-// EXPECT_TRUE(server.StatusIsOK());
-// ASSERT_FALSE(server.HasPendingRequest(port))
-// << "There are still pending requests " << "on port " << port;
-
-// Generates a nonfatal failure with a generic message.
-#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed")
-
-// Generates a fatal failure with a generic message.
-#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed")
-
-// Define this macro to 1 to omit the definition of FAIL(), which is a
-// generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_FAIL
-#define FAIL() GTEST_FAIL()
-#endif
-
-// Generates a success with a generic message.
-#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded")
-
-// Define this macro to 1 to omit the definition of SUCCEED(), which
-// is a generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_SUCCEED
-#define SUCCEED() GTEST_SUCCEED()
-#endif
-
-// Macros for testing exceptions.
-//
-// * {ASSERT|EXPECT}_THROW(statement, expected_exception):
-// Tests that the statement throws the expected exception.
-// * {ASSERT|EXPECT}_NO_THROW(statement):
-// Tests that the statement doesn't throw any exception.
-// * {ASSERT|EXPECT}_ANY_THROW(statement):
-// Tests that the statement throws an exception.
-
-#define EXPECT_THROW(statement, expected_exception) \
- GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_NO_THROW(statement) \
- GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_ANY_THROW(statement) \
- GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_THROW(statement, expected_exception) \
- GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
-#define ASSERT_NO_THROW(statement) \
- GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
-#define ASSERT_ANY_THROW(statement) \
- GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)
-
-// Boolean assertions. Condition can be either a Boolean expression or an
-// AssertionResult. For more information on how to use AssertionResult with
-// these macros see comments on that class.
-#define EXPECT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
- GTEST_NONFATAL_FAILURE_)
-#define EXPECT_FALSE(condition) \
- GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
- GTEST_NONFATAL_FAILURE_)
-#define ASSERT_TRUE(condition) \
- GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \
- GTEST_FATAL_FAILURE_)
-#define ASSERT_FALSE(condition) \
- GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
- GTEST_FATAL_FAILURE_)
-
-// Includes the auto-generated header that implements a family of
-// generic predicate assertion macros.
-// Copyright 2006, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// This file is AUTOMATICALLY GENERATED on 10/02/2008 by command
-// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
-//
-// Implements a family of generic predicate assertion macros.
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
-#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
-
-// Makes sure this header is not included before gtest.h.
-#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
-#error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
-#endif // GTEST_INCLUDE_GTEST_GTEST_H_
-
-// This header implements a family of generic predicate assertion
-// macros:
-//
-// ASSERT_PRED_FORMAT1(pred_format, v1)
-// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
-// ...
-//
-// where pred_format is a function or functor that takes n (in the
-// case of ASSERT_PRED_FORMATn) values and their source expression
-// text, and returns a testing::AssertionResult. See the definition
-// of ASSERT_EQ in gtest.h for an example.
-//
-// If you don't care about formatting, you can use the more
-// restrictive version:
-//
-// ASSERT_PRED1(pred, v1)
-// ASSERT_PRED2(pred, v1, v2)
-// ...
-//
-// where pred is an n-ary function or functor that returns bool,
-// and the values v1, v2, ..., must support the << operator for
-// streaming to std::ostream.
-//
-// We also define the EXPECT_* variations.
-//
-// For now we only support predicates whose arity is at most 5.
-// Please email googletestframework@googlegroups.com if you need
-// support for higher arities.
-
-// GTEST_ASSERT_ is the basic statement to which all of the assertions
-// in this file reduce. Don't use this in your code.
-
-#define GTEST_ASSERT_(expression, on_failure) \
- GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
- if (const ::testing::AssertionResult gtest_ar = (expression)) \
- ; \
- else \
- on_failure(gtest_ar.failure_message())
-
-
-// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
-// this in your code.
-template <typename Pred,
- typename T1>
-AssertionResult AssertPred1Helper(const char* pred_text,
- const char* e1,
- Pred pred,
- const T1& v1) {
- if (pred(v1)) return AssertionSuccess();
-
- Message msg;
- msg << pred_text << "("
- << e1 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1;
- return AssertionFailure(msg);
-}
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
-// Don't use this in your code.
-#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
- GTEST_ASSERT_(pred_format(#v1, v1),\
- on_failure)
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
-// this in your code.
-#define GTEST_PRED1_(pred, v1, on_failure)\
- GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
- #v1, \
- pred, \
- v1), on_failure)
-
-// Unary predicate assertion macros.
-#define EXPECT_PRED_FORMAT1(pred_format, v1) \
- GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_PRED1(pred, v1) \
- GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_PRED_FORMAT1(pred_format, v1) \
- GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
-#define ASSERT_PRED1(pred, v1) \
- GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
-
-
-
-// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
-// this in your code.
-template <typename Pred,
- typename T1,
- typename T2>
-AssertionResult AssertPred2Helper(const char* pred_text,
- const char* e1,
- const char* e2,
- Pred pred,
- const T1& v1,
- const T2& v2) {
- if (pred(v1, v2)) return AssertionSuccess();
-
- Message msg;
- msg << pred_text << "("
- << e1 << ", "
- << e2 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2;
- return AssertionFailure(msg);
-}
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
-// Don't use this in your code.
-#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
- GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2),\
- on_failure)
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
-// this in your code.
-#define GTEST_PRED2_(pred, v1, v2, on_failure)\
- GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
- #v1, \
- #v2, \
- pred, \
- v1, \
- v2), on_failure)
-
-// Binary predicate assertion macros.
-#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
- GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_PRED2(pred, v1, v2) \
- GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
- GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
-#define ASSERT_PRED2(pred, v1, v2) \
- GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
-
-
-
-// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
-// this in your code.
-template <typename Pred,
- typename T1,
- typename T2,
- typename T3>
-AssertionResult AssertPred3Helper(const char* pred_text,
- const char* e1,
- const char* e2,
- const char* e3,
- Pred pred,
- const T1& v1,
- const T2& v2,
- const T3& v3) {
- if (pred(v1, v2, v3)) return AssertionSuccess();
-
- Message msg;
- msg << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3;
- return AssertionFailure(msg);
-}
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
-// Don't use this in your code.
-#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
- GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3),\
- on_failure)
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
-// this in your code.
-#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
- GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
- #v1, \
- #v2, \
- #v3, \
- pred, \
- v1, \
- v2, \
- v3), on_failure)
-
-// Ternary predicate assertion macros.
-#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
- GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_PRED3(pred, v1, v2, v3) \
- GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
- GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
-#define ASSERT_PRED3(pred, v1, v2, v3) \
- GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
-
-
-
-// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
-// this in your code.
-template <typename Pred,
- typename T1,
- typename T2,
- typename T3,
- typename T4>
-AssertionResult AssertPred4Helper(const char* pred_text,
- const char* e1,
- const char* e2,
- const char* e3,
- const char* e4,
- Pred pred,
- const T1& v1,
- const T2& v2,
- const T3& v3,
- const T4& v4) {
- if (pred(v1, v2, v3, v4)) return AssertionSuccess();
-
- Message msg;
- msg << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ", "
- << e4 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3
- << "\n" << e4 << " evaluates to " << v4;
- return AssertionFailure(msg);
-}
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
-// Don't use this in your code.
-#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
- GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4),\
- on_failure)
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
-// this in your code.
-#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
- GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
- #v1, \
- #v2, \
- #v3, \
- #v4, \
- pred, \
- v1, \
- v2, \
- v3, \
- v4), on_failure)
-
-// 4-ary predicate assertion macros.
-#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
- GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
- GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
- GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
-#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
- GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
-
-
-
-// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
-// this in your code.
-template <typename Pred,
- typename T1,
- typename T2,
- typename T3,
- typename T4,
- typename T5>
-AssertionResult AssertPred5Helper(const char* pred_text,
- const char* e1,
- const char* e2,
- const char* e3,
- const char* e4,
- const char* e5,
- Pred pred,
- const T1& v1,
- const T2& v2,
- const T3& v3,
- const T4& v4,
- const T5& v5) {
- if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
-
- Message msg;
- msg << pred_text << "("
- << e1 << ", "
- << e2 << ", "
- << e3 << ", "
- << e4 << ", "
- << e5 << ") evaluates to false, where"
- << "\n" << e1 << " evaluates to " << v1
- << "\n" << e2 << " evaluates to " << v2
- << "\n" << e3 << " evaluates to " << v3
- << "\n" << e4 << " evaluates to " << v4
- << "\n" << e5 << " evaluates to " << v5;
- return AssertionFailure(msg);
-}
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
-// Don't use this in your code.
-#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
- GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5),\
- on_failure)
-
-// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
-// this in your code.
-#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
- GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
- #v1, \
- #v2, \
- #v3, \
- #v4, \
- #v5, \
- pred, \
- v1, \
- v2, \
- v3, \
- v4, \
- v5), on_failure)
-
-// 5-ary predicate assertion macros.
-#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
- GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
-#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
- GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
-#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
- GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
-#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
- GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
-
-
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
-
-// Macros for testing equalities and inequalities.
-//
-// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual
-// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2
-// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2
-// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2
-// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2
-// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2
-//
-// When they are not, Google Test prints both the tested expressions and
-// their actual values. The values must be compatible built-in types,
-// or you will get a compiler error. By "compatible" we mean that the
-// values can be compared by the respective operator.
-//
-// Note:
-//
-// 1. It is possible to make a user-defined type work with
-// {ASSERT|EXPECT}_??(), but that requires overloading the
-// comparison operators and is thus discouraged by the Google C++
-// Usage Guide. Therefore, you are advised to use the
-// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are
-// equal.
-//
-// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on
-// pointers (in particular, C strings). Therefore, if you use it
-// with two C strings, you are testing how their locations in memory
-// are related, not how their content is related. To compare two C
-// strings by content, use {ASSERT|EXPECT}_STR*().
-//
-// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to
-// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you
-// what the actual value is when it fails, and similarly for the
-// other comparisons.
-//
-// 4. Do not depend on the order in which {ASSERT|EXPECT}_??()
-// evaluate their arguments, which is undefined.
-//
-// 5. These macros evaluate their arguments exactly once.
-//
-// Examples:
-//
-// EXPECT_NE(5, Foo());
-// EXPECT_EQ(NULL, a_pointer);
-// ASSERT_LT(i, array_size);
-// ASSERT_GT(records.size(), 0) << "There is no record left.";
-
-#define EXPECT_EQ(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
- expected, actual)
-#define EXPECT_NE(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual)
-#define EXPECT_LE(val1, val2) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
-#define EXPECT_LT(val1, val2) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
-#define EXPECT_GE(val1, val2) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
-#define EXPECT_GT(val1, val2) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
-
-#define ASSERT_EQ(expected, actual) \
- ASSERT_PRED_FORMAT2(::testing::internal:: \
- EqHelper<GTEST_IS_NULL_LITERAL_(expected)>::Compare, \
- expected, actual)
-#define ASSERT_NE(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2)
-#define ASSERT_LE(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2)
-#define ASSERT_LT(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2)
-#define ASSERT_GE(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2)
-#define ASSERT_GT(val1, val2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2)
-
-// C String Comparisons. All tests treat NULL and any non-NULL string
-// as different. Two NULLs are equal.
-//
-// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2
-// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2
-// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case
-// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case
-//
-// For wide or narrow string objects, you can use the
-// {ASSERT|EXPECT}_??() macros.
-//
-// Don't depend on the order in which the arguments are evaluated,
-// which is undefined.
-//
-// These macros evaluate their arguments exactly once.
-
-#define EXPECT_STREQ(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
-#define EXPECT_STRNE(s1, s2) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define EXPECT_STRCASEEQ(expected, actual) \
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
-#define EXPECT_STRCASENE(s1, s2)\
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
-
-#define ASSERT_STREQ(expected, actual) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual)
-#define ASSERT_STRNE(s1, s2) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2)
-#define ASSERT_STRCASEEQ(expected, actual) \
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual)
-#define ASSERT_STRCASENE(s1, s2)\
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2)
-
-// Macros for comparing floating-point numbers.
-//
-// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual):
-// Tests that two float values are almost equal.
-// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual):
-// Tests that two double values are almost equal.
-// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error):
-// Tests that v1 and v2 are within the given distance to each other.
-//
-// Google Test uses ULP-based comparison to automatically pick a default
-// error bound that is appropriate for the operands. See the
-// FloatingPoint template class in gtest-internal.h if you are
-// interested in the implementation details.
-
-#define EXPECT_FLOAT_EQ(expected, actual)\
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
- expected, actual)
-
-#define EXPECT_DOUBLE_EQ(expected, actual)\
- EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
- expected, actual)
-
-#define ASSERT_FLOAT_EQ(expected, actual)\
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<float>, \
- expected, actual)
-
-#define ASSERT_DOUBLE_EQ(expected, actual)\
- ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ<double>, \
- expected, actual)
-
-#define EXPECT_NEAR(val1, val2, abs_error)\
- EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
- val1, val2, abs_error)
-
-#define ASSERT_NEAR(val1, val2, abs_error)\
- ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \
- val1, val2, abs_error)
-
-// These predicate format functions work on floating-point values, and
-// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g.
-//
-// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0);
-
-// Asserts that val1 is less than, or almost equal to, val2. Fails
-// otherwise. In particular, it fails if either val1 or val2 is NaN.
-GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2,
- float val1, float val2);
-GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2,
- double val1, double val2);
-
-
-#if GTEST_OS_WINDOWS
-
-// Macros that test for HRESULT failure and success, these are only useful
-// on Windows, and rely on Windows SDK macros and APIs to compile.
-//
-// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr)
-//
-// When expr unexpectedly fails or succeeds, Google Test prints the
-// expected result and the actual result with both a human-readable
-// string representation of the error, if available, as well as the
-// hex result code.
-#define EXPECT_HRESULT_SUCCEEDED(expr) \
- EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
-
-#define ASSERT_HRESULT_SUCCEEDED(expr) \
- ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr))
-
-#define EXPECT_HRESULT_FAILED(expr) \
- EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
-
-#define ASSERT_HRESULT_FAILED(expr) \
- ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr))
-
-#endif // GTEST_OS_WINDOWS
-
-// Macros that execute statement and check that it doesn't generate new fatal
-// failures in the current thread.
-//
-// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement);
-//
-// Examples:
-//
-// EXPECT_NO_FATAL_FAILURE(Process());
-// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed";
-//
-#define ASSERT_NO_FATAL_FAILURE(statement) \
- GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_)
-#define EXPECT_NO_FATAL_FAILURE(statement) \
- GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_)
-
-// Causes a trace (including the source file path, the current line
-// number, and the given message) to be included in every test failure
-// message generated by code in the current scope. The effect is
-// undone when the control leaves the current scope.
-//
-// The message argument can be anything streamable to std::ostream.
-//
-// In the implementation, we include the current line number as part
-// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s
-// to appear in the same block - as long as they are on different
-// lines.
-#define SCOPED_TRACE(message) \
- ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\
- __FILE__, __LINE__, ::testing::Message() << (message))
-
-namespace internal {
-
-// This template is declared, but intentionally undefined.
-template <typename T1, typename T2>
-struct StaticAssertTypeEqHelper;
-
-template <typename T>
-struct StaticAssertTypeEqHelper<T, T> {};
-
-} // namespace internal
-
-// Compile-time assertion for type equality.
-// StaticAssertTypeEq<type1, type2>() compiles iff type1 and type2 are
-// the same type. The value it returns is not interesting.
-//
-// Instead of making StaticAssertTypeEq a class template, we make it a
-// function template that invokes a helper class template. This
-// prevents a user from misusing StaticAssertTypeEq<T1, T2> by
-// defining objects of that type.
-//
-// CAVEAT:
-//
-// When used inside a method of a class template,
-// StaticAssertTypeEq<T1, T2>() is effective ONLY IF the method is
-// instantiated. For example, given:
-//
-// template <typename T> class Foo {
-// public:
-// void Bar() { testing::StaticAssertTypeEq<int, T>(); }
-// };
-//
-// the code:
-//
-// void Test1() { Foo<bool> foo; }
-//
-// will NOT generate a compiler error, as Foo<bool>::Bar() is never
-// actually instantiated. Instead, you need:
-//
-// void Test2() { Foo<bool> foo; foo.Bar(); }
-//
-// to cause a compiler error.
-template <typename T1, typename T2>
-bool StaticAssertTypeEq() {
- internal::StaticAssertTypeEqHelper<T1, T2>();
- return true;
-}
-
-// Defines a test.
-//
-// The first parameter is the name of the test case, and the second
-// parameter is the name of the test within the test case.
-//
-// The convention is to end the test case name with "Test". For
-// example, a test case for the Foo class can be named FooTest.
-//
-// The user should put his test code between braces after using this
-// macro. Example:
-//
-// TEST(FooTest, InitializesCorrectly) {
-// Foo foo;
-// EXPECT_TRUE(foo.StatusIsOK());
-// }
-
-// Note that we call GetTestTypeId() instead of GetTypeId<
-// ::testing::Test>() here to get the type ID of testing::Test. This
-// is to work around a suspected linker bug when using Google Test as
-// a framework on Mac OS X. The bug causes GetTypeId<
-// ::testing::Test>() to return different values depending on whether
-// the call is from the Google Test framework itself or from user test
-// code. GetTestTypeId() is guaranteed to always return the same
-// value, as it always calls GetTypeId<>() from the Google Test
-// framework.
-#define GTEST_TEST(test_case_name, test_name)\
- GTEST_TEST_(test_case_name, test_name, \
- ::testing::Test, ::testing::internal::GetTestTypeId())
-
-// Define this macro to 1 to omit the definition of TEST(), which
-// is a generic name and clashes with some other libraries.
-#if !GTEST_DONT_DEFINE_TEST
-#define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name)
-#endif
-
-// Defines a test that uses a test fixture.
-//
-// The first parameter is the name of the test fixture class, which
-// also doubles as the test case name. The second parameter is the
-// name of the test within the test case.
-//
-// A test fixture class must be declared earlier. The user should put
-// his test code between braces after using this macro. Example:
-//
-// class FooTest : public testing::Test {
-// protected:
-// virtual void SetUp() { b_.AddElement(3); }
-//
-// Foo a_;
-// Foo b_;
-// };
-//
-// TEST_F(FooTest, InitializesCorrectly) {
-// EXPECT_TRUE(a_.StatusIsOK());
-// }
-//
-// TEST_F(FooTest, ReturnsElementCountCorrectly) {
-// EXPECT_EQ(0, a_.size());
-// EXPECT_EQ(1, b_.size());
-// }
-
-#define TEST_F(test_fixture, test_name)\
- GTEST_TEST_(test_fixture, test_name, test_fixture, \
- ::testing::internal::GetTypeId<test_fixture>())
-
-// Use this macro in main() to run all tests. It returns 0 if all
-// tests are successful, or 1 otherwise.
-//
-// RUN_ALL_TESTS() should be invoked after the command line has been
-// parsed by InitGoogleTest().
-
-#define RUN_ALL_TESTS()\
- (::testing::UnitTest::GetInstance()->Run())
-
-} // namespace testing
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_H_
+++ /dev/null
-int main(int argc, char **argv)
-{
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
+++ /dev/null
-#ifndef __OPENCV_GTESTCV_HPP__
-#define __OPENCV_GTESTCV_HPP__
-
-#include "opencv2/gtest/gtest.h"
-#include "opencv2/core/core.hpp"
-
-namespace cvtest
-{
-
-using std::vector;
-using cv::RNG;
-using cv::Mat;
-using cv::Scalar;
-using cv::Size;
-using cv::Point;
-using cv::Rect;
-
-enum
-{
- TYPE_MASK_8U = 1 << CV_8U,
- TYPE_MASK_8S = 1 << CV_8S,
- TYPE_MASK_16U = 1 << CV_16U,
- TYPE_MASK_16S = 1 << CV_16S,
- TYPE_MASK_32S = 1 << CV_32S,
- TYPE_MASK_32F = 1 << CV_32F,
- TYPE_MASK_64F = 1 << CV_64F,
- TYPE_MASK_ALL = (TYPE_MASK_64F<<1)-1,
- TYPE_MASK_ALL_BUT_8S = TYPE_MASK_ALL & ~TYPE_MASK_8S
-};
-
-CV_EXPORTS double getMinVal(int depth);
-CV_EXPORTS double getMaxVal(int depth);
-
-CV_EXPORTS Size randomSize(RNG& rng, double maxSizeLog);
-CV_EXPORTS void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector<int>& sz);
-CV_EXPORTS int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels);
-CV_EXPORTS Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi);
-CV_EXPORTS Mat randomMat(RNG& rng, const vector<int>& size, int type, double minVal, double maxVal, bool useRoi);
-CV_EXPORTS void add(const Mat& a, double alpha, const Mat& b, double beta,
- Scalar gamma, Mat& c, int ctype, bool calcAbs=false);
-CV_EXPORTS void convert(const Mat& src, Mat& dst, int dtype, double alpha=1, double beta=0);
-CV_EXPORTS void copy(const Mat& src, Mat& dst, const Mat& mask=Mat(), bool invertMask=false);
-CV_EXPORTS void set(Mat& dst, const Scalar& gamma, const Mat& mask=Mat());
-CV_EXPORTS void erode(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1),
- int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar());
-CV_EXPORTS void dilate(const Mat& src, Mat& dst, const Mat& _kernel, Point anchor=Point(-1,-1),
- int borderType=IPL_BORDER_CONSTANT, const Scalar& borderValue=Scalar());
-CV_EXPORTS void filter2D(const Mat& src, Mat& dst, int ddepth, const Mat& kernel,
- Point anchor, double delta, int borderType,
- const Scalar& borderValue=Scalar());
-CV_EXPORTS void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right,
- int borderType, const Scalar& borderValue=Scalar());
-CV_EXPORTS void minMaxLoc(const Mat& src, double* maxval, double* minval,
- vector<int>* maxloc, vector<int>* minloc, const Mat& mask=Mat());
-CV_EXPORTS double norm(const Mat& src, int normType, const Mat& mask=Mat());
-CV_EXPORTS double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask=Mat());
-CV_EXPORTS bool cmpEps(const Mat& src1, const Mat& src2, int maxDiff, vector<int>* loc);
-CV_EXPORTS void logicOp(const Mat& src1, const Mat& src2, Mat& dst, char c);
-CV_EXPORTS void logicOp(const Mat& src, const Scalar& s, Mat& dst, char c);
-CV_EXPORTS void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop);
-CV_EXPORTS void compare(const Mat& src, double s, Mat& dst, int cmpop);
-CV_EXPORTS void gemm(const Mat& src1, const Mat& src2, double alpha,
- const Mat& src3, double beta, Mat& dst, int flags);
-CV_EXPORTS void crosscorr(const Mat& src1, const Mat& src2, Mat& dst, int dtype);
-
-}
-
-#endif
-
+++ /dev/null
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mheule@google.com (Markus Heule)
-//
-// Google C++ Testing Framework (Google Test)
-//
-// Sometimes it's desirable to build Google Test by compiling a single file.
-// This file serves this purpose.
-
-// This line ensures that gtest.h can be compiled on its own, even
-// when it's fused.
-#include "precomp.hpp"
-
-// The following lines pull in the real gtest *.cc files.
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// The Google C++ Testing Framework (Google Test)
-
-// Copyright 2007, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// Utilities for testing Google Test itself and code that uses Google Test
-// (e.g. frameworks built on top of Google Test).
-
-#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
-#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
-
-
-namespace testing {
-
-// This helper class can be used to mock out Google Test failure reporting
-// so that we can test Google Test or code that builds on Google Test.
-//
-// An object of this class appends a TestPartResult object to the
-// TestPartResultArray object given in the constructor whenever a Google Test
-// failure is reported. It can either intercept only failures that are
-// generated in the same thread that created this object or it can intercept
-// all generated failures. The scope of this mock object can be controlled with
-// the second argument to the two arguments constructor.
-class GTEST_API_ ScopedFakeTestPartResultReporter
- : public TestPartResultReporterInterface {
- public:
- // The two possible mocking modes of this object.
- enum InterceptMode {
- INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
- INTERCEPT_ALL_THREADS // Intercepts all failures.
- };
-
- // The c'tor sets this object as the test part result reporter used
- // by Google Test. The 'result' parameter specifies where to report the
- // results. This reporter will only catch failures generated in the current
- // thread. DEPRECATED
- explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
-
- // Same as above, but you can choose the interception scope of this object.
- ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
- TestPartResultArray* result);
-
- // The d'tor restores the previous test part result reporter.
- virtual ~ScopedFakeTestPartResultReporter();
-
- // Appends the TestPartResult object to the TestPartResultArray
- // received in the constructor.
- //
- // This method is from the TestPartResultReporterInterface
- // interface.
- virtual void ReportTestPartResult(const TestPartResult& result);
- private:
- void Init();
-
- const InterceptMode intercept_mode_;
- TestPartResultReporterInterface* old_reporter_;
- TestPartResultArray* const result_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
-};
-
-namespace internal {
-
-// A helper class for implementing EXPECT_FATAL_FAILURE() and
-// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
-// TestPartResultArray contains exactly one failure that has the given
-// type and contains the given substring. If that's not the case, a
-// non-fatal failure will be generated.
-class GTEST_API_ SingleFailureChecker {
- public:
- // The constructor remembers the arguments.
- SingleFailureChecker(const TestPartResultArray* results,
- TestPartResult::Type type,
- const char* substr);
- ~SingleFailureChecker();
- private:
- const TestPartResultArray* const results_;
- const TestPartResult::Type type_;
- const String substr_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
-};
-
-} // namespace internal
-
-} // namespace testing
-
-// A set of macros for testing Google Test assertions or code that's expected
-// to generate Google Test fatal failures. It verifies that the given
-// statement will cause exactly one fatal Google Test failure with 'substr'
-// being part of the failure message.
-//
-// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
-// affects and considers failures generated in the current thread and
-// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
-//
-// The verification of the assertion is done correctly even when the statement
-// throws an exception or aborts the current function.
-//
-// Known restrictions:
-// - 'statement' cannot reference local non-static variables or
-// non-static members of the current object.
-// - 'statement' cannot return a value.
-// - You cannot stream a failure message to this macro.
-//
-// Note that even though the implementations of the following two
-// macros are much alike, we cannot refactor them to use a common
-// helper macro, due to some peculiarity in how the preprocessor
-// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
-// gtest_unittest.cc will fail to compile if we do that.
-#define EXPECT_FATAL_FAILURE(statement, substr) \
- do { \
- class GTestExpectFatalFailureHelper {\
- public:\
- static void Execute() { statement; }\
- };\
- ::testing::TestPartResultArray gtest_failures;\
- ::testing::internal::SingleFailureChecker gtest_checker(\
- >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
- {\
- ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
- ::testing::ScopedFakeTestPartResultReporter:: \
- INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
- GTestExpectFatalFailureHelper::Execute();\
- }\
- } while (::testing::internal::AlwaysFalse())
-
-#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
- do { \
- class GTestExpectFatalFailureHelper {\
- public:\
- static void Execute() { statement; }\
- };\
- ::testing::TestPartResultArray gtest_failures;\
- ::testing::internal::SingleFailureChecker gtest_checker(\
- >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
- {\
- ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
- ::testing::ScopedFakeTestPartResultReporter:: \
- INTERCEPT_ALL_THREADS, >est_failures);\
- GTestExpectFatalFailureHelper::Execute();\
- }\
- } while (::testing::internal::AlwaysFalse())
-
-// A macro for testing Google Test assertions or code that's expected to
-// generate Google Test non-fatal failures. It asserts that the given
-// statement will cause exactly one non-fatal Google Test failure with 'substr'
-// being part of the failure message.
-//
-// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
-// affects and considers failures generated in the current thread and
-// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
-//
-// 'statement' is allowed to reference local variables and members of
-// the current object.
-//
-// The verification of the assertion is done correctly even when the statement
-// throws an exception or aborts the current function.
-//
-// Known restrictions:
-// - You cannot stream a failure message to this macro.
-//
-// Note that even though the implementations of the following two
-// macros are much alike, we cannot refactor them to use a common
-// helper macro, due to some peculiarity in how the preprocessor
-// works. If we do that, the code won't compile when the user gives
-// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
-// expands to code containing an unprotected comma. The
-// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
-// catches that.
-//
-// For the same reason, we have to write
-// if (::testing::internal::AlwaysTrue()) { statement; }
-// instead of
-// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
-// to avoid an MSVC warning on unreachable code.
-#define EXPECT_NONFATAL_FAILURE(statement, substr) \
- do {\
- ::testing::TestPartResultArray gtest_failures;\
- ::testing::internal::SingleFailureChecker gtest_checker(\
- >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
- (substr));\
- {\
- ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
- ::testing::ScopedFakeTestPartResultReporter:: \
- INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
- if (::testing::internal::AlwaysTrue()) { statement; }\
- }\
- } while (::testing::internal::AlwaysFalse())
-
-#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
- do {\
- ::testing::TestPartResultArray gtest_failures;\
- ::testing::internal::SingleFailureChecker gtest_checker(\
- >est_failures, ::testing::TestPartResult::kNonFatalFailure, \
- (substr));\
- {\
- ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
- ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
- >est_failures);\
- if (::testing::internal::AlwaysTrue()) { statement; }\
- }\
- } while (::testing::internal::AlwaysFalse())
-
-#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
-
-#include <ctype.h>
-#include <math.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <wchar.h>
-#include <wctype.h>
-
-#include <algorithm>
-#include <ostream>
-#include <sstream>
-#include <vector>
-
-#if GTEST_OS_LINUX
-
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
-#define GTEST_HAS_GETTIMEOFDAY_ 1
-
-#include <fcntl.h>
-#include <limits.h>
-#include <sched.h>
-// Declares vsnprintf(). This header is not available on Windows.
-#include <strings.h>
-#include <sys/mman.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <string>
-#include <vector>
-
-#elif GTEST_OS_SYMBIAN
-#define GTEST_HAS_GETTIMEOFDAY_ 1
-#include <sys/time.h> // NOLINT
-
-#elif GTEST_OS_ZOS
-#define GTEST_HAS_GETTIMEOFDAY_ 1
-#include <sys/time.h> // NOLINT
-
-// On z/OS we additionally need strings.h for strcasecmp.
-#include <strings.h> // NOLINT
-
-#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE.
-
-#include <windows.h> // NOLINT
-
-#elif GTEST_OS_WINDOWS // We are on Windows proper.
-
-#include <io.h> // NOLINT
-#include <sys/timeb.h> // NOLINT
-#include <sys/types.h> // NOLINT
-#include <sys/stat.h> // NOLINT
-
-#if GTEST_OS_WINDOWS_MINGW
-// MinGW has gettimeofday() but not _ftime64().
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
-// TODO(kenton@google.com): There are other ways to get the time on
-// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW
-// supports these. consider using them instead.
-#define GTEST_HAS_GETTIMEOFDAY_ 1
-#include <sys/time.h> // NOLINT
-#endif // GTEST_OS_WINDOWS_MINGW
-
-// cpplint thinks that the header is already included, so we want to
-// silence it.
-#include <windows.h> // NOLINT
-
-#else
-
-// Assume other platforms have gettimeofday().
-// TODO(kenton@google.com): Use autoconf to detect availability of
-// gettimeofday().
-#define GTEST_HAS_GETTIMEOFDAY_ 1
-
-// cpplint thinks that the header is already included, so we want to
-// silence it.
-#include <sys/time.h> // NOLINT
-#include <unistd.h> // NOLINT
-
-#endif // GTEST_OS_LINUX
-
-#if GTEST_HAS_EXCEPTIONS
-#include <stdexcept>
-#endif
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
-#define GTEST_IMPLEMENTATION_ 1
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// Utility functions and classes used by the Google C++ testing framework.
-//
-// Author: wan@google.com (Zhanyong Wan)
-//
-// This file contains purely Google Test's internal implementation. Please
-// DO NOT #INCLUDE IT IN A USER PROGRAM.
-
-#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_
-#define GTEST_SRC_GTEST_INTERNAL_INL_H_
-
-// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is
-// part of Google Test's implementation; otherwise it's undefined.
-#if !GTEST_IMPLEMENTATION_
-// A user is trying to include this from his code - just say no.
-#error "gtest-internal-inl.h is part of Google Test's internal implementation."
-#error "It must not be included except by Google Test itself."
-#endif // GTEST_IMPLEMENTATION_
-
-#ifndef _WIN32_WCE
-#include <errno.h>
-#endif // !_WIN32_WCE
-#include <stddef.h>
-#include <stdlib.h> // For strtoll/_strtoul64/malloc/free.
-#include <string.h> // For memmove.
-
-#include <algorithm>
-#include <string>
-#include <vector>
-
-
-#if GTEST_OS_WINDOWS
-#include <windows.h> // For DWORD.
-#endif // GTEST_OS_WINDOWS
-
-
-namespace testing {
-
-// Declares the flags.
-//
-// We don't want the users to modify this flag in the code, but want
-// Google Test's own unit tests to be able to access it. Therefore we
-// declare it here as opposed to in gtest.h.
-GTEST_DECLARE_bool_(death_test_use_fork);
-
-namespace internal {
-
-// The value of GetTestTypeId() as seen from within the Google Test
-// library. This is solely for testing GetTestTypeId().
-GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest;
-
-// Names of the flags (needed for parsing Google Test flags).
-const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests";
-const char kBreakOnFailureFlag[] = "break_on_failure";
-const char kCatchExceptionsFlag[] = "catch_exceptions";
-const char kColorFlag[] = "color";
-const char kFilterFlag[] = "filter";
-const char kListTestsFlag[] = "list_tests";
-const char kOutputFlag[] = "output";
-const char kPrintTimeFlag[] = "print_time";
-const char kRandomSeedFlag[] = "random_seed";
-const char kRepeatFlag[] = "repeat";
-const char kShuffleFlag[] = "shuffle";
-const char kStackTraceDepthFlag[] = "stack_trace_depth";
-const char kThrowOnFailureFlag[] = "throw_on_failure";
-
-// A valid random seed must be in [1, kMaxRandomSeed].
-const int kMaxRandomSeed = 99999;
-
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
-GTEST_API_ extern bool g_help_flag;
-
-// Returns the current time in milliseconds.
-GTEST_API_ TimeInMillis GetTimeInMillis();
-
-// Returns true iff Google Test should use colors in the output.
-GTEST_API_ bool ShouldUseColor(bool stdout_is_tty);
-
-// Formats the given time in milliseconds as seconds.
-GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms);
-
-// Parses a string for an Int32 flag, in the form of "--flag=value".
-//
-// On success, stores the value of the flag in *value, and returns
-// true. On failure, returns false without changing *value.
-GTEST_API_ bool ParseInt32Flag(
- const char* str, const char* flag, Int32* value);
-
-// Returns a random seed in range [1, kMaxRandomSeed] based on the
-// given --gtest_random_seed flag value.
-inline int GetRandomSeedFromFlag(Int32 random_seed_flag) {
- const unsigned int raw_seed = (random_seed_flag == 0) ?
- static_cast<unsigned int>(GetTimeInMillis()) :
- static_cast<unsigned int>(random_seed_flag);
-
- // Normalizes the actual seed to range [1, kMaxRandomSeed] such that
- // it's easy to type.
- const int normalized_seed =
- static_cast<int>((raw_seed - 1U) %
- static_cast<unsigned int>(kMaxRandomSeed)) + 1;
- return normalized_seed;
-}
-
-// Returns the first valid random seed after 'seed'. The behavior is
-// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is
-// considered to be 1.
-inline int GetNextRandomSeed(int seed) {
- GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed)
- << "Invalid random seed " << seed << " - must be in [1, "
- << kMaxRandomSeed << "].";
- const int next_seed = seed + 1;
- return (next_seed > kMaxRandomSeed) ? 1 : next_seed;
-}
-
-// This class saves the values of all Google Test flags in its c'tor, and
-// restores them in its d'tor.
-class GTestFlagSaver {
- public:
- // The c'tor.
- GTestFlagSaver() {
- also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests);
- break_on_failure_ = GTEST_FLAG(break_on_failure);
- catch_exceptions_ = GTEST_FLAG(catch_exceptions);
- color_ = GTEST_FLAG(color);
- death_test_style_ = GTEST_FLAG(death_test_style);
- death_test_use_fork_ = GTEST_FLAG(death_test_use_fork);
- filter_ = GTEST_FLAG(filter);
- internal_run_death_test_ = GTEST_FLAG(internal_run_death_test);
- list_tests_ = GTEST_FLAG(list_tests);
- output_ = GTEST_FLAG(output);
- print_time_ = GTEST_FLAG(print_time);
- random_seed_ = GTEST_FLAG(random_seed);
- repeat_ = GTEST_FLAG(repeat);
- shuffle_ = GTEST_FLAG(shuffle);
- stack_trace_depth_ = GTEST_FLAG(stack_trace_depth);
- throw_on_failure_ = GTEST_FLAG(throw_on_failure);
- }
-
- // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS.
- ~GTestFlagSaver() {
- GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_;
- GTEST_FLAG(break_on_failure) = break_on_failure_;
- GTEST_FLAG(catch_exceptions) = catch_exceptions_;
- GTEST_FLAG(color) = color_;
- GTEST_FLAG(death_test_style) = death_test_style_;
- GTEST_FLAG(death_test_use_fork) = death_test_use_fork_;
- GTEST_FLAG(filter) = filter_;
- GTEST_FLAG(internal_run_death_test) = internal_run_death_test_;
- GTEST_FLAG(list_tests) = list_tests_;
- GTEST_FLAG(output) = output_;
- GTEST_FLAG(print_time) = print_time_;
- GTEST_FLAG(random_seed) = random_seed_;
- GTEST_FLAG(repeat) = repeat_;
- GTEST_FLAG(shuffle) = shuffle_;
- GTEST_FLAG(stack_trace_depth) = stack_trace_depth_;
- GTEST_FLAG(throw_on_failure) = throw_on_failure_;
- }
- private:
- // Fields for saving the original values of flags.
- bool also_run_disabled_tests_;
- bool break_on_failure_;
- bool catch_exceptions_;
- String color_;
- String death_test_style_;
- bool death_test_use_fork_;
- String filter_;
- String internal_run_death_test_;
- bool list_tests_;
- String output_;
- bool print_time_;
- bool pretty_;
- internal::Int32 random_seed_;
- internal::Int32 repeat_;
- bool shuffle_;
- internal::Int32 stack_trace_depth_;
- bool throw_on_failure_;
-} GTEST_ATTRIBUTE_UNUSED_;
-
-// Converts a Unicode code point to a narrow string in UTF-8 encoding.
-// code_point parameter is of type UInt32 because wchar_t may not be
-// wide enough to contain a code point.
-// The output buffer str must containt at least 32 characters.
-// The function returns the address of the output buffer.
-// If the code_point is not a valid Unicode code point
-// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
-// as '(Invalid Unicode 0xXXXXXXXX)'.
-GTEST_API_ char* CodePointToUtf8(UInt32 code_point, char* str);
-
-// Converts a wide string to a narrow string in UTF-8 encoding.
-// The wide string is assumed to have the following encoding:
-// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
-// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
-// Parameter str points to a null-terminated wide string.
-// Parameter num_chars may additionally limit the number
-// of wchar_t characters processed. -1 is used when the entire string
-// should be processed.
-// If the string contains code points that are not valid Unicode code points
-// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
-// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
-// and contains invalid UTF-16 surrogate pairs, values in those pairs
-// will be encoded as individual Unicode characters from Basic Normal Plane.
-GTEST_API_ String WideStringToUtf8(const wchar_t* str, int num_chars);
-
-// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
-// if the variable is present. If a file already exists at this location, this
-// function will write over it. If the variable is present, but the file cannot
-// be created, prints an error and exits.
-void WriteToShardStatusFileIfNeeded();
-
-// Checks whether sharding is enabled by examining the relevant
-// environment variable values. If the variables are present,
-// but inconsistent (e.g., shard_index >= total_shards), prints
-// an error and exits. If in_subprocess_for_death_test, sharding is
-// disabled because it must only be applied to the original test
-// process. Otherwise, we could filter out death tests we intended to execute.
-GTEST_API_ bool ShouldShard(const char* total_shards_str,
- const char* shard_index_str,
- bool in_subprocess_for_death_test);
-
-// Parses the environment variable var as an Int32. If it is unset,
-// returns default_val. If it is not an Int32, prints an error and
-// and aborts.
-GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val);
-
-// Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
-// method. Assumes that 0 <= shard_index < total_shards.
-GTEST_API_ bool ShouldRunTestOnShard(
- int total_shards, int shard_index, int test_id);
-
-// STL container utilities.
-
-// Returns the number of elements in the given container that satisfy
-// the given predicate.
-template <class Container, typename Predicate>
-inline int CountIf(const Container& c, Predicate predicate) {
- return static_cast<int>(std::count_if(c.begin(), c.end(), predicate));
-}
-
-// Applies a function/functor to each element in the container.
-template <class Container, typename Functor>
-void ForEach(const Container& c, Functor functor) {
- std::for_each(c.begin(), c.end(), functor);
-}
-
-// Returns the i-th element of the vector, or default_value if i is not
-// in range [0, v.size()).
-template <typename E>
-inline E GetElementOr(const std::vector<E>& v, int i, E default_value) {
- return (i < 0 || i >= static_cast<int>(v.size())) ? default_value : v[i];
-}
-
-// Performs an in-place shuffle of a range of the vector's elements.
-// 'begin' and 'end' are element indices as an STL-style range;
-// i.e. [begin, end) are shuffled, where 'end' == size() means to
-// shuffle to the end of the vector.
-template <typename E>
-void ShuffleRange(internal::Random* random, int begin, int end,
- std::vector<E>* v) {
- const int size = static_cast<int>(v->size());
- GTEST_CHECK_(0 <= begin && begin <= size)
- << "Invalid shuffle range start " << begin << ": must be in range [0, "
- << size << "].";
- GTEST_CHECK_(begin <= end && end <= size)
- << "Invalid shuffle range finish " << end << ": must be in range ["
- << begin << ", " << size << "].";
-
- // Fisher-Yates shuffle, from
- // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle
- for (int range_width = end - begin; range_width >= 2; range_width--) {
- const int last_in_range = begin + range_width - 1;
- const int selected = begin + random->Generate(range_width);
- std::swap((*v)[selected], (*v)[last_in_range]);
- }
-}
-
-// Performs an in-place shuffle of the vector's elements.
-template <typename E>
-inline void Shuffle(internal::Random* random, std::vector<E>* v) {
- ShuffleRange(random, 0, static_cast<int>(v->size()), v);
-}
-
-// A function for deleting an object. Handy for being used as a
-// functor.
-template <typename T>
-static void Delete(T* x) {
- delete x;
-}
-
-// A predicate that checks the key of a TestProperty against a known key.
-//
-// TestPropertyKeyIs is copyable.
-class TestPropertyKeyIs {
- public:
- // Constructor.
- //
- // TestPropertyKeyIs has NO default constructor.
- explicit TestPropertyKeyIs(const char* key)
- : key_(key) {}
-
- // Returns true iff the test name of test property matches on key_.
- bool operator()(const TestProperty& test_property) const {
- return String(test_property.key()).Compare(key_) == 0;
- }
-
- private:
- String key_;
-};
-
-class TestInfoImpl {
- public:
- TestInfoImpl(TestInfo* parent, const char* test_case_name,
- const char* name, const char* test_case_comment,
- const char* comment, TypeId fixture_class_id,
- internal::TestFactoryBase* factory);
- ~TestInfoImpl();
-
- // Returns true if this test should run.
- bool should_run() const { return should_run_; }
-
- // Sets the should_run member.
- void set_should_run(bool should) { should_run_ = should; }
-
- // Returns true if this test is disabled. Disabled tests are not run.
- bool is_disabled() const { return is_disabled_; }
-
- // Sets the is_disabled member.
- void set_is_disabled(bool is) { is_disabled_ = is; }
-
- // Returns true if this test matches the filter specified by the user.
- bool matches_filter() const { return matches_filter_; }
-
- // Sets the matches_filter member.
- void set_matches_filter(bool matches) { matches_filter_ = matches; }
-
- // Returns the test case name.
- const char* test_case_name() const { return test_case_name_.c_str(); }
-
- // Returns the test name.
- const char* name() const { return name_.c_str(); }
-
- // Returns the test case comment.
- const char* test_case_comment() const { return test_case_comment_.c_str(); }
-
- // Returns the test comment.
- const char* comment() const { return comment_.c_str(); }
-
- // Returns the ID of the test fixture class.
- TypeId fixture_class_id() const { return fixture_class_id_; }
-
- // Returns the test result.
- TestResult* result() { return &result_; }
- const TestResult* result() const { return &result_; }
-
- // Creates the test object, runs it, records its result, and then
- // deletes it.
- void Run();
-
- // Clears the test result.
- void ClearResult() { result_.Clear(); }
-
- // Clears the test result in the given TestInfo object.
- static void ClearTestResult(TestInfo * test_info) {
- test_info->impl()->ClearResult();
- }
-
- private:
- // These fields are immutable properties of the test.
- TestInfo* const parent_; // The owner of this object
- const String test_case_name_; // Test case name
- const String name_; // Test name
- const String test_case_comment_; // Test case comment
- const String comment_; // Test comment
- const TypeId fixture_class_id_; // ID of the test fixture class
- bool should_run_; // True iff this test should run
- bool is_disabled_; // True iff this test is disabled
- bool matches_filter_; // True if this test matches the
- // user-specified filter.
- internal::TestFactoryBase* const factory_; // The factory that creates
- // the test object
-
- // This field is mutable and needs to be reset before running the
- // test for the second time.
- TestResult result_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
-};
-
-// Class UnitTestOptions.
-//
-// This class contains functions for processing options the user
-// specifies when running the tests. It has only static members.
-//
-// In most cases, the user can specify an option using either an
-// environment variable or a command line flag. E.g. you can set the
-// test filter using either GTEST_FILTER or --gtest_filter. If both
-// the variable and the flag are present, the latter overrides the
-// former.
-class GTEST_API_ UnitTestOptions {
- public:
- // Functions for processing the gtest_output flag.
-
- // Returns the output format, or "" for normal printed output.
- static String GetOutputFormat();
-
- // Returns the absolute path of the requested output file, or the
- // default (test_detail.xml in the original working directory) if
- // none was explicitly specified.
- static String GetAbsolutePathToOutputFile();
-
- // Functions for processing the gtest_filter flag.
-
- // Returns true iff the wildcard pattern matches the string. The
- // first ':' or '\0' character in pattern marks the end of it.
- //
- // This recursive algorithm isn't very efficient, but is clear and
- // works well enough for matching test names, which are short.
- static bool PatternMatchesString(const char *pattern, const char *str);
-
- // Returns true iff the user-specified filter matches the test case
- // name and the test name.
- static bool FilterMatchesTest(const String &test_case_name,
- const String &test_name);
-
-#if GTEST_OS_WINDOWS
- // Function for supporting the gtest_catch_exception flag.
-
- // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
- // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
- // This function is useful as an __except condition.
- static int GTestShouldProcessSEH(DWORD exception_code);
-#endif // GTEST_OS_WINDOWS
-
- // Returns true if "name" matches the ':' separated list of glob-style
- // filters in "filter".
- static bool MatchesFilter(const String& name, const char* filter);
-};
-
-// Returns the current application's name, removing directory path if that
-// is present. Used by UnitTestOptions::GetOutputFile.
-GTEST_API_ FilePath GetCurrentExecutableName();
-
-// The role interface for getting the OS stack trace as a string.
-class OsStackTraceGetterInterface {
- public:
- OsStackTraceGetterInterface() {}
- virtual ~OsStackTraceGetterInterface() {}
-
- // Returns the current OS stack trace as a String. Parameters:
- //
- // max_depth - the maximum number of stack frames to be included
- // in the trace.
- // skip_count - the number of top frames to be skipped; doesn't count
- // against max_depth.
- virtual String CurrentStackTrace(int max_depth, int skip_count) = 0;
-
- // UponLeavingGTest() should be called immediately before Google Test calls
- // user code. It saves some information about the current stack that
- // CurrentStackTrace() will use to find and hide Google Test stack frames.
- virtual void UponLeavingGTest() = 0;
-
- private:
- GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface);
-};
-
-// A working implementation of the OsStackTraceGetterInterface interface.
-class OsStackTraceGetter : public OsStackTraceGetterInterface {
- public:
- OsStackTraceGetter() : caller_frame_(NULL) {}
- virtual String CurrentStackTrace(int max_depth, int skip_count);
- virtual void UponLeavingGTest();
-
- // This string is inserted in place of stack frames that are part of
- // Google Test's implementation.
- static const char* const kElidedFramesMarker;
-
- private:
- Mutex mutex_; // protects all internal state
-
- // We save the stack frame below the frame that calls user code.
- // We do this because the address of the frame immediately below
- // the user code changes between the call to UponLeavingGTest()
- // and any calls to CurrentStackTrace() from within the user code.
- void* caller_frame_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter);
-};
-
-// Information about a Google Test trace point.
-struct TraceInfo {
- const char* file;
- int line;
- String message;
-};
-
-// This is the default global test part result reporter used in UnitTestImpl.
-// This class should only be used by UnitTestImpl.
-class DefaultGlobalTestPartResultReporter
- : public TestPartResultReporterInterface {
- public:
- explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test);
- // Implements the TestPartResultReporterInterface. Reports the test part
- // result in the current test.
- virtual void ReportTestPartResult(const TestPartResult& result);
-
- private:
- UnitTestImpl* const unit_test_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter);
-};
-
-// This is the default per thread test part result reporter used in
-// UnitTestImpl. This class should only be used by UnitTestImpl.
-class DefaultPerThreadTestPartResultReporter
- : public TestPartResultReporterInterface {
- public:
- explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test);
- // Implements the TestPartResultReporterInterface. The implementation just
- // delegates to the current global test part result reporter of *unit_test_.
- virtual void ReportTestPartResult(const TestPartResult& result);
-
- private:
- UnitTestImpl* const unit_test_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter);
-};
-
-// The private implementation of the UnitTest class. We don't protect
-// the methods under a mutex, as this class is not accessible by a
-// user and the UnitTest class that delegates work to this class does
-// proper locking.
-class GTEST_API_ UnitTestImpl {
- public:
- explicit UnitTestImpl(UnitTest* parent);
- virtual ~UnitTestImpl();
-
- // There are two different ways to register your own TestPartResultReporter.
- // You can register your own repoter to listen either only for test results
- // from the current thread or for results from all threads.
- // By default, each per-thread test result repoter just passes a new
- // TestPartResult to the global test result reporter, which registers the
- // test part result for the currently running test.
-
- // Returns the global test part result reporter.
- TestPartResultReporterInterface* GetGlobalTestPartResultReporter();
-
- // Sets the global test part result reporter.
- void SetGlobalTestPartResultReporter(
- TestPartResultReporterInterface* reporter);
-
- // Returns the test part result reporter for the current thread.
- TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread();
-
- // Sets the test part result reporter for the current thread.
- void SetTestPartResultReporterForCurrentThread(
- TestPartResultReporterInterface* reporter);
-
- // Gets the number of successful test cases.
- int successful_test_case_count() const;
-
- // Gets the number of failed test cases.
- int failed_test_case_count() const;
-
- // Gets the number of all test cases.
- int total_test_case_count() const;
-
- // Gets the number of all test cases that contain at least one test
- // that should run.
- int test_case_to_run_count() const;
-
- // Gets the number of successful tests.
- int successful_test_count() const;
-
- // Gets the number of failed tests.
- int failed_test_count() const;
-
- // Gets the number of disabled tests.
- int disabled_test_count() const;
-
- // Gets the number of all tests.
- int total_test_count() const;
-
- // Gets the number of tests that should run.
- int test_to_run_count() const;
-
- // Gets the elapsed time, in milliseconds.
- TimeInMillis elapsed_time() const { return elapsed_time_; }
-
- // Returns true iff the unit test passed (i.e. all test cases passed).
- bool Passed() const { return !Failed(); }
-
- // Returns true iff the unit test failed (i.e. some test case failed
- // or something outside of all tests failed).
- bool Failed() const {
- return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed();
- }
-
- // Gets the i-th test case among all the test cases. i can range from 0 to
- // total_test_case_count() - 1. If i is not in that range, returns NULL.
- const TestCase* GetTestCase(int i) const {
- const int index = GetElementOr(test_case_indices_, i, -1);
- return index < 0 ? NULL : test_cases_[i];
- }
-
- // Gets the i-th test case among all the test cases. i can range from 0 to
- // total_test_case_count() - 1. If i is not in that range, returns NULL.
- TestCase* GetMutableTestCase(int i) {
- const int index = GetElementOr(test_case_indices_, i, -1);
- return index < 0 ? NULL : test_cases_[index];
- }
-
- // Provides access to the event listener list.
- TestEventListeners* listeners() { return &listeners_; }
-
- // Returns the TestResult for the test that's currently running, or
- // the TestResult for the ad hoc test if no test is running.
- TestResult* current_test_result();
-
- // Returns the TestResult for the ad hoc test.
- const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; }
-
- // Sets the OS stack trace getter.
- //
- // Does nothing if the input and the current OS stack trace getter
- // are the same; otherwise, deletes the old getter and makes the
- // input the current getter.
- void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter);
-
- // Returns the current OS stack trace getter if it is not NULL;
- // otherwise, creates an OsStackTraceGetter, makes it the current
- // getter, and returns it.
- OsStackTraceGetterInterface* os_stack_trace_getter();
-
- // Returns the current OS stack trace as a String.
- //
- // The maximum number of stack frames to be included is specified by
- // the gtest_stack_trace_depth flag. The skip_count parameter
- // specifies the number of top frames to be skipped, which doesn't
- // count against the number of frames to be included.
- //
- // For example, if Foo() calls Bar(), which in turn calls
- // CurrentOsStackTraceExceptTop(1), Foo() will be included in the
- // trace but Bar() and CurrentOsStackTraceExceptTop() won't.
- String CurrentOsStackTraceExceptTop(int skip_count);
-
- // Finds and returns a TestCase with the given name. If one doesn't
- // exist, creates one and returns it.
- //
- // Arguments:
- //
- // test_case_name: name of the test case
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- TestCase* GetTestCase(const char* test_case_name,
- const char* comment,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc);
-
- // Adds a TestInfo to the unit test.
- //
- // Arguments:
- //
- // set_up_tc: pointer to the function that sets up the test case
- // tear_down_tc: pointer to the function that tears down the test case
- // test_info: the TestInfo object
- void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc,
- TestInfo * test_info) {
- // In order to support thread-safe death tests, we need to
- // remember the original working directory when the test program
- // was first invoked. We cannot do this in RUN_ALL_TESTS(), as
- // the user may have changed the current directory before calling
- // RUN_ALL_TESTS(). Therefore we capture the current directory in
- // AddTestInfo(), which is called to register a TEST or TEST_F
- // before main() is reached.
- if (original_working_dir_.IsEmpty()) {
- original_working_dir_.Set(FilePath::GetCurrentDir());
- GTEST_CHECK_(!original_working_dir_.IsEmpty())
- << "Failed to get the current working directory.";
- }
-
- GetTestCase(test_info->test_case_name(),
- test_info->test_case_comment(),
- set_up_tc,
- tear_down_tc)->AddTestInfo(test_info);
- }
-
-#if GTEST_HAS_PARAM_TEST
- // Returns ParameterizedTestCaseRegistry object used to keep track of
- // value-parameterized tests and instantiate and register them.
- internal::ParameterizedTestCaseRegistry& parameterized_test_registry() {
- return parameterized_test_registry_;
- }
-#endif // GTEST_HAS_PARAM_TEST
-
- // Sets the TestCase object for the test that's currently running.
- void set_current_test_case(TestCase* a_current_test_case) {
- current_test_case_ = a_current_test_case;
- }
-
- // Sets the TestInfo object for the test that's currently running. If
- // current_test_info is NULL, the assertion results will be stored in
- // ad_hoc_test_result_.
- void set_current_test_info(TestInfo* a_current_test_info) {
- current_test_info_ = a_current_test_info;
- }
-
- // Registers all parameterized tests defined using TEST_P and
- // INSTANTIATE_TEST_P, creating regular tests for each test/parameter
- // combination. This method can be called more then once; it has
- // guards protecting from registering the tests more then once.
- // If value-parameterized tests are disabled, RegisterParameterizedTests
- // is present but does nothing.
- void RegisterParameterizedTests();
-
- // Runs all tests in this UnitTest object, prints the result, and
- // returns 0 if all tests are successful, or 1 otherwise. If any
- // exception is thrown during a test on Windows, this test is
- // considered to be failed, but the rest of the tests will still be
- // run. (We disable exceptions on Linux and Mac OS X, so the issue
- // doesn't apply there.)
- int RunAllTests();
-
- // Clears the results of all tests, including the ad hoc test.
- void ClearResult() {
- ForEach(test_cases_, TestCase::ClearTestCaseResult);
- ad_hoc_test_result_.Clear();
- }
-
- enum ReactionToSharding {
- HONOR_SHARDING_PROTOCOL,
- IGNORE_SHARDING_PROTOCOL
- };
-
- // Matches the full name of each test against the user-specified
- // filter to decide whether the test should run, then records the
- // result in each TestCase and TestInfo object.
- // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests
- // based on sharding variables in the environment.
- // Returns the number of tests that should run.
- int FilterTests(ReactionToSharding shard_tests);
-
- // Prints the names of the tests matching the user-specified filter flag.
- void ListTestsMatchingFilter();
-
- const TestCase* current_test_case() const { return current_test_case_; }
- TestInfo* current_test_info() { return current_test_info_; }
- const TestInfo* current_test_info() const { return current_test_info_; }
-
- // Returns the vector of environments that need to be set-up/torn-down
- // before/after the tests are run.
- std::vector<Environment*>& environments() { return environments_; }
-
- // Getters for the per-thread Google Test trace stack.
- std::vector<TraceInfo>& gtest_trace_stack() {
- return *(gtest_trace_stack_.pointer());
- }
- const std::vector<TraceInfo>& gtest_trace_stack() const {
- return gtest_trace_stack_.get();
- }
-
-#if GTEST_HAS_DEATH_TEST
- void InitDeathTestSubprocessControlInfo() {
- internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag());
- }
- // Returns a pointer to the parsed --gtest_internal_run_death_test
- // flag, or NULL if that flag was not specified.
- // This information is useful only in a death test child process.
- // Must not be called before a call to InitGoogleTest.
- const InternalRunDeathTestFlag* internal_run_death_test_flag() const {
- return internal_run_death_test_flag_.get();
- }
-
- // Returns a pointer to the current death test factory.
- internal::DeathTestFactory* death_test_factory() {
- return death_test_factory_.get();
- }
-
- void SuppressTestEventsIfInSubprocess();
-
- friend class ReplaceDeathTestFactory;
-#endif // GTEST_HAS_DEATH_TEST
-
- // Initializes the event listener performing XML output as specified by
- // UnitTestOptions. Must not be called before InitGoogleTest.
- void ConfigureXmlOutput();
-
- // Performs initialization dependent upon flag values obtained in
- // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
- // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
- // this function is also called from RunAllTests. Since this function can be
- // called more than once, it has to be idempotent.
- void PostFlagParsingInit();
-
- // Gets the random seed used at the start of the current test iteration.
- int random_seed() const { return random_seed_; }
-
- // Gets the random number generator.
- internal::Random* random() { return &random_; }
-
- // Shuffles all test cases, and the tests within each test case,
- // making sure that death tests are still run first.
- void ShuffleTests();
-
- // Restores the test cases and tests to their order before the first shuffle.
- void UnshuffleTests();
-
- private:
- friend class ::testing::UnitTest;
-
- // The UnitTest object that owns this implementation object.
- UnitTest* const parent_;
-
- // The working directory when the first TEST() or TEST_F() was
- // executed.
- internal::FilePath original_working_dir_;
-
- // The default test part result reporters.
- DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_;
- DefaultPerThreadTestPartResultReporter
- default_per_thread_test_part_result_reporter_;
-
- // Points to (but doesn't own) the global test part result reporter.
- TestPartResultReporterInterface* global_test_part_result_repoter_;
-
- // Protects read and write access to global_test_part_result_reporter_.
- internal::Mutex global_test_part_result_reporter_mutex_;
-
- // Points to (but doesn't own) the per-thread test part result reporter.
- internal::ThreadLocal<TestPartResultReporterInterface*>
- per_thread_test_part_result_reporter_;
-
- // The vector of environments that need to be set-up/torn-down
- // before/after the tests are run.
- std::vector<Environment*> environments_;
-
- // The vector of TestCases in their original order. It owns the
- // elements in the vector.
- std::vector<TestCase*> test_cases_;
-
- // Provides a level of indirection for the test case list to allow
- // easy shuffling and restoring the test case order. The i-th
- // element of this vector is the index of the i-th test case in the
- // shuffled order.
- std::vector<int> test_case_indices_;
-
-#if GTEST_HAS_PARAM_TEST
- // ParameterizedTestRegistry object used to register value-parameterized
- // tests.
- internal::ParameterizedTestCaseRegistry parameterized_test_registry_;
-
- // Indicates whether RegisterParameterizedTests() has been called already.
- bool parameterized_tests_registered_;
-#endif // GTEST_HAS_PARAM_TEST
-
- // Index of the last death test case registered. Initially -1.
- int last_death_test_case_;
-
- // This points to the TestCase for the currently running test. It
- // changes as Google Test goes through one test case after another.
- // When no test is running, this is set to NULL and Google Test
- // stores assertion results in ad_hoc_test_result_. Initially NULL.
- TestCase* current_test_case_;
-
- // This points to the TestInfo for the currently running test. It
- // changes as Google Test goes through one test after another. When
- // no test is running, this is set to NULL and Google Test stores
- // assertion results in ad_hoc_test_result_. Initially NULL.
- TestInfo* current_test_info_;
-
- // Normally, a user only writes assertions inside a TEST or TEST_F,
- // or inside a function called by a TEST or TEST_F. Since Google
- // Test keeps track of which test is current running, it can
- // associate such an assertion with the test it belongs to.
- //
- // If an assertion is encountered when no TEST or TEST_F is running,
- // Google Test attributes the assertion result to an imaginary "ad hoc"
- // test, and records the result in ad_hoc_test_result_.
- TestResult ad_hoc_test_result_;
-
- // The list of event listeners that can be used to track events inside
- // Google Test.
- TestEventListeners listeners_;
-
- // The OS stack trace getter. Will be deleted when the UnitTest
- // object is destructed. By default, an OsStackTraceGetter is used,
- // but the user can set this field to use a custom getter if that is
- // desired.
- OsStackTraceGetterInterface* os_stack_trace_getter_;
-
- // True iff PostFlagParsingInit() has been called.
- bool post_flag_parse_init_performed_;
-
- // The random number seed used at the beginning of the test run.
- int random_seed_;
-
- // Our random number generator.
- internal::Random random_;
-
- // How long the test took to run, in milliseconds.
- TimeInMillis elapsed_time_;
-
-#if GTEST_HAS_DEATH_TEST
- // The decomposed components of the gtest_internal_run_death_test flag,
- // parsed when RUN_ALL_TESTS is called.
- internal::scoped_ptr<InternalRunDeathTestFlag> internal_run_death_test_flag_;
- internal::scoped_ptr<internal::DeathTestFactory> death_test_factory_;
-#endif // GTEST_HAS_DEATH_TEST
-
- // A per-thread stack of traces created by the SCOPED_TRACE() macro.
- internal::ThreadLocal<std::vector<TraceInfo> > gtest_trace_stack_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl);
-}; // class UnitTestImpl
-
-// Convenience function for accessing the global UnitTest
-// implementation object.
-inline UnitTestImpl* GetUnitTestImpl() {
- return UnitTest::GetInstance()->impl();
-}
-
-// Internal helper functions for implementing the simple regular
-// expression matcher.
-GTEST_API_ bool IsInSet(char ch, const char* str);
-GTEST_API_ bool IsDigit(char ch);
-GTEST_API_ bool IsPunct(char ch);
-GTEST_API_ bool IsRepeat(char ch);
-GTEST_API_ bool IsWhiteSpace(char ch);
-GTEST_API_ bool IsWordChar(char ch);
-GTEST_API_ bool IsValidEscape(char ch);
-GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch);
-GTEST_API_ bool ValidateRegex(const char* regex);
-GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str);
-GTEST_API_ bool MatchRepetitionAndRegexAtHead(
- bool escaped, char ch, char repeat, const char* regex, const char* str);
-GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str);
-
-// Parses the command line for Google Test flags, without initializing
-// other parts of Google Test.
-GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv);
-GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv);
-
-#if GTEST_HAS_DEATH_TEST
-
-// Returns the message describing the last system error, regardless of the
-// platform.
-String GetLastErrnoDescription();
-
-#if GTEST_OS_WINDOWS
-// Provides leak-safe Windows kernel handle ownership.
-class AutoHandle {
- public:
- AutoHandle() : handle_(INVALID_HANDLE_VALUE) {}
- explicit AutoHandle(HANDLE handle) : handle_(handle) {}
-
- ~AutoHandle() { Reset(); }
-
- HANDLE Get() const { return handle_; }
- void Reset() { Reset(INVALID_HANDLE_VALUE); }
- void Reset(HANDLE handle) {
- if (handle != handle_) {
- if (handle_ != INVALID_HANDLE_VALUE)
- ::CloseHandle(handle_);
- handle_ = handle;
- }
- }
-
- private:
- HANDLE handle_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle);
-};
-#endif // GTEST_OS_WINDOWS
-
-// Attempts to parse a string into a positive integer pointed to by the
-// number parameter. Returns true if that is possible.
-// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use
-// it here.
-template <typename Integer>
-bool ParseNaturalNumber(const ::std::string& str, Integer* number) {
- // Fail fast if the given string does not begin with a digit;
- // this bypasses strtoXXX's "optional leading whitespace and plus
- // or minus sign" semantics, which are undesirable here.
- if (str.empty() || !isdigit(str[0])) {
- return false;
- }
- errno = 0;
-
- char* end;
- // BiggestConvertible is the largest integer type that system-provided
- // string-to-number conversion routines can return.
-#if GTEST_OS_WINDOWS && !defined(__GNUC__)
- // MSVC and C++ Builder define __int64 instead of the standard long long.
- typedef unsigned __int64 BiggestConvertible;
- const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10);
-#else
- typedef unsigned long long BiggestConvertible; // NOLINT
- const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10);
-#endif // GTEST_OS_WINDOWS && !defined(__GNUC__)
- const bool parse_success = *end == '\0' && errno == 0;
-
- // TODO(vladl@google.com): Convert this to compile time assertion when it is
- // available.
- GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed));
-
- const Integer result = static_cast<Integer>(parsed);
- if (parse_success && static_cast<BiggestConvertible>(result) == parsed) {
- *number = result;
- return true;
- }
- return false;
-}
-#endif // GTEST_HAS_DEATH_TEST
-
-// TestResult contains some private methods that should be hidden from
-// Google Test user but are required for testing. This class allow our tests
-// to access them.
-//
-// This class is supplied only for the purpose of testing Google Test's own
-// constructs. Do not use it in user tests, either directly or indirectly.
-class TestResultAccessor {
- public:
- static void RecordProperty(TestResult* test_result,
- const TestProperty& property) {
- test_result->RecordProperty(property);
- }
-
- static void ClearTestPartResults(TestResult* test_result) {
- test_result->ClearTestPartResults();
- }
-
- static const std::vector<testing::TestPartResult>& test_part_results(
- const TestResult& test_result) {
- return test_result.test_part_results();
- }
-};
-
-} // namespace internal
-} // namespace testing
-
-#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_
-#undef GTEST_IMPLEMENTATION_
-
-#if GTEST_OS_WINDOWS
-#define vsnprintf _vsnprintf
-#endif // GTEST_OS_WINDOWS
-
-namespace testing {
-
-using internal::CountIf;
-using internal::ForEach;
-using internal::GetElementOr;
-using internal::Shuffle;
-
-// Constants.
-
-// A test whose test case name or test name matches this filter is
-// disabled and not run.
-static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*";
-
-// A test case whose name matches this filter is considered a death
-// test case and will be run before test cases whose name doesn't
-// match this filter.
-static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*";
-
-// A test filter that matches everything.
-static const char kUniversalFilter[] = "*";
-
-// The default output file for XML output.
-static const char kDefaultOutputFile[] = "test_detail.xml";
-
-// The environment variable name for the test shard index.
-static const char kTestShardIndex[] = "GTEST_SHARD_INDEX";
-// The environment variable name for the total number of test shards.
-static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS";
-// The environment variable name for the test shard status file.
-static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE";
-
-namespace internal {
-
-// The text used in failure messages to indicate the start of the
-// stack trace.
-const char kStackTraceMarker[] = "\nStack trace:\n";
-
-// g_help_flag is true iff the --help flag or an equivalent form is
-// specified on the command line.
-bool g_help_flag = false;
-
-} // namespace internal
-
-GTEST_DEFINE_bool_(
- also_run_disabled_tests,
- internal::BoolFromGTestEnv("also_run_disabled_tests", false),
- "Run disabled tests too, in addition to the tests normally being run.");
-
-GTEST_DEFINE_bool_(
- break_on_failure,
- internal::BoolFromGTestEnv("break_on_failure", false),
- "True iff a failed assertion should be a debugger break-point.");
-
-GTEST_DEFINE_bool_(
- catch_exceptions,
- internal::BoolFromGTestEnv("catch_exceptions", false),
- "True iff " GTEST_NAME_
- " should catch exceptions and treat them as test failures.");
-
-GTEST_DEFINE_string_(
- color,
- internal::StringFromGTestEnv("color", "auto"),
- "Whether to use colors in the output. Valid values: yes, no, "
- "and auto. 'auto' means to use colors if the output is "
- "being sent to a terminal and the TERM environment variable "
- "is set to xterm, xterm-color, xterm-256color, linux or cygwin.");
-
-GTEST_DEFINE_string_(
- filter,
- internal::StringFromGTestEnv("filter", kUniversalFilter),
- "A colon-separated list of glob (not regex) patterns "
- "for filtering the tests to run, optionally followed by a "
- "'-' and a : separated list of negative patterns (tests to "
- "exclude). A test is run if it matches one of the positive "
- "patterns and does not match any of the negative patterns.");
-
-GTEST_DEFINE_bool_(list_tests, false,
- "List all tests without running them.");
-
-GTEST_DEFINE_string_(
- output,
- internal::StringFromGTestEnv("output", ""),
- "A format (currently must be \"xml\"), optionally followed "
- "by a colon and an output file name or directory. A directory "
- "is indicated by a trailing pathname separator. "
- "Examples: \"xml:filename.xml\", \"xml::directoryname/\". "
- "If a directory is specified, output files will be created "
- "within that directory, with file-names based on the test "
- "executable's name and, if necessary, made unique by adding "
- "digits.");
-
-GTEST_DEFINE_bool_(
- print_time,
- internal::BoolFromGTestEnv("print_time", true),
- "True iff " GTEST_NAME_
- " should display elapsed time in text output.");
-
-GTEST_DEFINE_int32_(
- random_seed,
- internal::Int32FromGTestEnv("random_seed", 0),
- "Random number seed to use when shuffling test orders. Must be in range "
- "[1, 99999], or 0 to use a seed based on the current time.");
-
-GTEST_DEFINE_int32_(
- repeat,
- internal::Int32FromGTestEnv("repeat", 1),
- "How many times to repeat each test. Specify a negative number "
- "for repeating forever. Useful for shaking out flaky tests.");
-
-GTEST_DEFINE_bool_(
- show_internal_stack_frames, false,
- "True iff " GTEST_NAME_ " should include internal stack frames when "
- "printing test failure stack traces.");
-
-GTEST_DEFINE_bool_(
- shuffle,
- internal::BoolFromGTestEnv("shuffle", false),
- "True iff " GTEST_NAME_
- " should randomize tests' order on every run.");
-
-GTEST_DEFINE_int32_(
- stack_trace_depth,
- internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth),
- "The maximum number of stack frames to print when an "
- "assertion fails. The valid range is 0 through 100, inclusive.");
-
-GTEST_DEFINE_bool_(
- throw_on_failure,
- internal::BoolFromGTestEnv("throw_on_failure", false),
- "When this flag is specified, a failed assertion will throw an exception "
- "if exceptions are enabled or exit the program with a non-zero code "
- "otherwise.");
-
-namespace internal {
-
-// Generates a random number from [0, range), using a Linear
-// Congruential Generator (LCG). Crashes if 'range' is 0 or greater
-// than kMaxRange.
-UInt32 Random::Generate(UInt32 range) {
- // These constants are the same as are used in glibc's rand(3).
- state_ = (1103515245U*state_ + 12345U) % kMaxRange;
-
- GTEST_CHECK_(range > 0)
- << "Cannot generate a number in the range [0, 0).";
- GTEST_CHECK_(range <= kMaxRange)
- << "Generation of a number in [0, " << range << ") was requested, "
- << "but this can only generate numbers in [0, " << kMaxRange << ").";
-
- // Converting via modulus introduces a bit of downward bias, but
- // it's simple, and a linear congruential generator isn't too good
- // to begin with.
- return state_ % range;
-}
-
-// GTestIsInitialized() returns true iff the user has initialized
-// Google Test. Useful for catching the user mistake of not initializing
-// Google Test before calling RUN_ALL_TESTS().
-//
-// A user must call testing::InitGoogleTest() to initialize Google
-// Test. g_init_gtest_count is set to the number of times
-// InitGoogleTest() has been called. We don't protect this variable
-// under a mutex as it is only accessed in the main thread.
-int g_init_gtest_count = 0;
-static bool GTestIsInitialized() { return g_init_gtest_count != 0; }
-
-// Iterates over a vector of TestCases, keeping a running sum of the
-// results of calling a given int-returning method on each.
-// Returns the sum.
-static int SumOverTestCaseList(const std::vector<TestCase*>& case_list,
- int (TestCase::*method)() const) {
- int sum = 0;
- for (size_t i = 0; i < case_list.size(); i++) {
- sum += (case_list[i]->*method)();
- }
- return sum;
-}
-
-// Returns true iff the test case passed.
-static bool TestCasePassed(const TestCase* test_case) {
- return test_case->should_run() && test_case->Passed();
-}
-
-// Returns true iff the test case failed.
-static bool TestCaseFailed(const TestCase* test_case) {
- return test_case->should_run() && test_case->Failed();
-}
-
-// Returns true iff test_case contains at least one test that should
-// run.
-static bool ShouldRunTestCase(const TestCase* test_case) {
- return test_case->should_run();
-}
-
-// AssertHelper constructor.
-AssertHelper::AssertHelper(TestPartResult::Type type,
- const char* file,
- int line,
- const char* message)
- : data_(new AssertHelperData(type, file, line, message)) {
-}
-
-AssertHelper::~AssertHelper() {
- delete data_;
-}
-
-// Message assignment, for assertion streaming support.
-void AssertHelper::operator=(const Message& message) const {
- UnitTest::GetInstance()->
- AddTestPartResult(data_->type, data_->file, data_->line,
- AppendUserMessage(data_->message, message),
- UnitTest::GetInstance()->impl()
- ->CurrentOsStackTraceExceptTop(1)
- // Skips the stack frame for this function itself.
- ); // NOLINT
-}
-
-// Mutex for linked pointers.
-GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex);
-
-// Application pathname gotten in InitGoogleTest.
-String g_executable_path;
-
-// Returns the current application's name, removing directory path if that
-// is present.
-FilePath GetCurrentExecutableName() {
- FilePath result;
-
-#if GTEST_OS_WINDOWS
- result.Set(FilePath(g_executable_path).RemoveExtension("exe"));
-#else
- result.Set(FilePath(g_executable_path));
-#endif // GTEST_OS_WINDOWS
-
- return result.RemoveDirectoryName();
-}
-
-// Functions for processing the gtest_output flag.
-
-// Returns the output format, or "" for normal printed output.
-String UnitTestOptions::GetOutputFormat() {
- const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
- if (gtest_output_flag == NULL) return String("");
-
- const char* const colon = strchr(gtest_output_flag, ':');
- return (colon == NULL) ?
- String(gtest_output_flag) :
- String(gtest_output_flag, colon - gtest_output_flag);
-}
-
-// Returns the name of the requested output file, or the default if none
-// was explicitly specified.
-String UnitTestOptions::GetAbsolutePathToOutputFile() {
- const char* const gtest_output_flag = GTEST_FLAG(output).c_str();
- if (gtest_output_flag == NULL)
- return String("");
-
- const char* const colon = strchr(gtest_output_flag, ':');
- if (colon == NULL)
- return String(internal::FilePath::ConcatPaths(
- internal::FilePath(
- UnitTest::GetInstance()->original_working_dir()),
- internal::FilePath(kDefaultOutputFile)).ToString() );
-
- internal::FilePath output_name(colon + 1);
- if (!output_name.IsAbsolutePath())
- // TODO(wan@google.com): on Windows \some\path is not an absolute
- // path (as its meaning depends on the current drive), yet the
- // following logic for turning it into an absolute path is wrong.
- // Fix it.
- output_name = internal::FilePath::ConcatPaths(
- internal::FilePath(UnitTest::GetInstance()->original_working_dir()),
- internal::FilePath(colon + 1));
-
- if (!output_name.IsDirectory())
- return output_name.ToString();
-
- internal::FilePath result(internal::FilePath::GenerateUniqueFileName(
- output_name, internal::GetCurrentExecutableName(),
- GetOutputFormat().c_str()));
- return result.ToString();
-}
-
-// Returns true iff the wildcard pattern matches the string. The
-// first ':' or '\0' character in pattern marks the end of it.
-//
-// This recursive algorithm isn't very efficient, but is clear and
-// works well enough for matching test names, which are short.
-bool UnitTestOptions::PatternMatchesString(const char *pattern,
- const char *str) {
- switch (*pattern) {
- case '\0':
- case ':': // Either ':' or '\0' marks the end of the pattern.
- return *str == '\0';
- case '?': // Matches any single character.
- return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
- case '*': // Matches any string (possibly empty) of characters.
- return (*str != '\0' && PatternMatchesString(pattern, str + 1)) ||
- PatternMatchesString(pattern + 1, str);
- default: // Non-special character. Matches itself.
- return *pattern == *str &&
- PatternMatchesString(pattern + 1, str + 1);
- }
-}
-
-bool UnitTestOptions::MatchesFilter(const String& name, const char* filter) {
- const char *cur_pattern = filter;
- for (;;) {
- if (PatternMatchesString(cur_pattern, name.c_str())) {
- return true;
- }
-
- // Finds the next pattern in the filter.
- cur_pattern = strchr(cur_pattern, ':');
-
- // Returns if no more pattern can be found.
- if (cur_pattern == NULL) {
- return false;
- }
-
- // Skips the pattern separater (the ':' character).
- cur_pattern++;
- }
-}
-
-// TODO(keithray): move String function implementations to gtest-string.cc.
-
-// Returns true iff the user-specified filter matches the test case
-// name and the test name.
-bool UnitTestOptions::FilterMatchesTest(const String &test_case_name,
- const String &test_name) {
- const String& full_name = String::Format("%s.%s",
- test_case_name.c_str(),
- test_name.c_str());
-
- // Split --gtest_filter at '-', if there is one, to separate into
- // positive filter and negative filter portions
- const char* const p = GTEST_FLAG(filter).c_str();
- const char* const dash = strchr(p, '-');
- String positive;
- String negative;
- if (dash == NULL) {
- positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter
- negative = String("");
- } else {
- positive = String(p, dash - p); // Everything up to the dash
- negative = String(dash+1); // Everything after the dash
- if (positive.empty()) {
- // Treat '-test1' as the same as '*-test1'
- positive = kUniversalFilter;
- }
- }
-
- // A filter is a colon-separated list of patterns. It matches a
- // test if any pattern in it matches the test.
- return (MatchesFilter(full_name, positive.c_str()) &&
- !MatchesFilter(full_name, negative.c_str()));
-}
-
-#if GTEST_OS_WINDOWS
-// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the
-// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
-// This function is useful as an __except condition.
-int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
- // Google Test should handle an exception if:
- // 1. the user wants it to, AND
- // 2. this is not a breakpoint exception.
- return (GTEST_FLAG(catch_exceptions) &&
- exception_code != EXCEPTION_BREAKPOINT) ?
- EXCEPTION_EXECUTE_HANDLER :
- EXCEPTION_CONTINUE_SEARCH;
-}
-#endif // GTEST_OS_WINDOWS
-
-} // namespace internal
-
-// The c'tor sets this object as the test part result reporter used by
-// Google Test. The 'result' parameter specifies where to report the
-// results. Intercepts only failures from the current thread.
-ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
- TestPartResultArray* result)
- : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD),
- result_(result) {
- Init();
-}
-
-// The c'tor sets this object as the test part result reporter used by
-// Google Test. The 'result' parameter specifies where to report the
-// results.
-ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter(
- InterceptMode intercept_mode, TestPartResultArray* result)
- : intercept_mode_(intercept_mode),
- result_(result) {
- Init();
-}
-
-void ScopedFakeTestPartResultReporter::Init() {
- internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
- old_reporter_ = impl->GetGlobalTestPartResultReporter();
- impl->SetGlobalTestPartResultReporter(this);
- } else {
- old_reporter_ = impl->GetTestPartResultReporterForCurrentThread();
- impl->SetTestPartResultReporterForCurrentThread(this);
- }
-}
-
-// The d'tor restores the test part result reporter used by Google Test
-// before.
-ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() {
- internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- if (intercept_mode_ == INTERCEPT_ALL_THREADS) {
- impl->SetGlobalTestPartResultReporter(old_reporter_);
- } else {
- impl->SetTestPartResultReporterForCurrentThread(old_reporter_);
- }
-}
-
-// Increments the test part result count and remembers the result.
-// This method is from the TestPartResultReporterInterface interface.
-void ScopedFakeTestPartResultReporter::ReportTestPartResult(
- const TestPartResult& result) {
- result_->Append(result);
-}
-
-namespace internal {
-
-// Returns the type ID of ::testing::Test. We should always call this
-// instead of GetTypeId< ::testing::Test>() to get the type ID of
-// testing::Test. This is to work around a suspected linker bug when
-// using Google Test as a framework on Mac OS X. The bug causes
-// GetTypeId< ::testing::Test>() to return different values depending
-// on whether the call is from the Google Test framework itself or
-// from user test code. GetTestTypeId() is guaranteed to always
-// return the same value, as it always calls GetTypeId<>() from the
-// gtest.cc, which is within the Google Test framework.
-TypeId GetTestTypeId() {
- return GetTypeId<Test>();
-}
-
-// The value of GetTestTypeId() as seen from within the Google Test
-// library. This is solely for testing GetTestTypeId().
-extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId();
-
-// This predicate-formatter checks that 'results' contains a test part
-// failure of the given type and that the failure message contains the
-// given substring.
-AssertionResult HasOneFailure(const char* /* results_expr */,
- const char* /* type_expr */,
- const char* /* substr_expr */,
- const TestPartResultArray& results,
- TestPartResult::Type type,
- const char* substr) {
- const String expected(type == TestPartResult::kFatalFailure ?
- "1 fatal failure" :
- "1 non-fatal failure");
- Message msg;
- if (results.size() != 1) {
- msg << "Expected: " << expected << "\n"
- << " Actual: " << results.size() << " failures";
- for (int i = 0; i < results.size(); i++) {
- msg << "\n" << results.GetTestPartResult(i);
- }
- return AssertionFailure(msg);
- }
-
- const TestPartResult& r = results.GetTestPartResult(0);
- if (r.type() != type) {
- msg << "Expected: " << expected << "\n"
- << " Actual:\n"
- << r;
- return AssertionFailure(msg);
- }
-
- if (strstr(r.message(), substr) == NULL) {
- msg << "Expected: " << expected << " containing \""
- << substr << "\"\n"
- << " Actual:\n"
- << r;
- return AssertionFailure(msg);
- }
-
- return AssertionSuccess();
-}
-
-// The constructor of SingleFailureChecker remembers where to look up
-// test part results, what type of failure we expect, and what
-// substring the failure message should contain.
-SingleFailureChecker:: SingleFailureChecker(
- const TestPartResultArray* results,
- TestPartResult::Type type,
- const char* substr)
- : results_(results),
- type_(type),
- substr_(substr) {}
-
-// The destructor of SingleFailureChecker verifies that the given
-// TestPartResultArray contains exactly one failure that has the given
-// type and contains the given substring. If that's not the case, a
-// non-fatal failure will be generated.
-SingleFailureChecker::~SingleFailureChecker() {
- EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_.c_str());
-}
-
-DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter(
- UnitTestImpl* unit_test) : unit_test_(unit_test) {}
-
-void DefaultGlobalTestPartResultReporter::ReportTestPartResult(
- const TestPartResult& result) {
- unit_test_->current_test_result()->AddTestPartResult(result);
- unit_test_->listeners()->repeater()->OnTestPartResult(result);
-}
-
-DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter(
- UnitTestImpl* unit_test) : unit_test_(unit_test) {}
-
-void DefaultPerThreadTestPartResultReporter::ReportTestPartResult(
- const TestPartResult& result) {
- unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result);
-}
-
-// Returns the global test part result reporter.
-TestPartResultReporterInterface*
-UnitTestImpl::GetGlobalTestPartResultReporter() {
- internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
- return global_test_part_result_repoter_;
-}
-
-// Sets the global test part result reporter.
-void UnitTestImpl::SetGlobalTestPartResultReporter(
- TestPartResultReporterInterface* reporter) {
- internal::MutexLock lock(&global_test_part_result_reporter_mutex_);
- global_test_part_result_repoter_ = reporter;
-}
-
-// Returns the test part result reporter for the current thread.
-TestPartResultReporterInterface*
-UnitTestImpl::GetTestPartResultReporterForCurrentThread() {
- return per_thread_test_part_result_reporter_.get();
-}
-
-// Sets the test part result reporter for the current thread.
-void UnitTestImpl::SetTestPartResultReporterForCurrentThread(
- TestPartResultReporterInterface* reporter) {
- per_thread_test_part_result_reporter_.set(reporter);
-}
-
-// Gets the number of successful test cases.
-int UnitTestImpl::successful_test_case_count() const {
- return CountIf(test_cases_, TestCasePassed);
-}
-
-// Gets the number of failed test cases.
-int UnitTestImpl::failed_test_case_count() const {
- return CountIf(test_cases_, TestCaseFailed);
-}
-
-// Gets the number of all test cases.
-int UnitTestImpl::total_test_case_count() const {
- return static_cast<int>(test_cases_.size());
-}
-
-// Gets the number of all test cases that contain at least one test
-// that should run.
-int UnitTestImpl::test_case_to_run_count() const {
- return CountIf(test_cases_, ShouldRunTestCase);
-}
-
-// Gets the number of successful tests.
-int UnitTestImpl::successful_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count);
-}
-
-// Gets the number of failed tests.
-int UnitTestImpl::failed_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count);
-}
-
-// Gets the number of disabled tests.
-int UnitTestImpl::disabled_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count);
-}
-
-// Gets the number of all tests.
-int UnitTestImpl::total_test_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::total_test_count);
-}
-
-// Gets the number of tests that should run.
-int UnitTestImpl::test_to_run_count() const {
- return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count);
-}
-
-// Returns the current OS stack trace as a String.
-//
-// The maximum number of stack frames to be included is specified by
-// the gtest_stack_trace_depth flag. The skip_count parameter
-// specifies the number of top frames to be skipped, which doesn't
-// count against the number of frames to be included.
-//
-// For example, if Foo() calls Bar(), which in turn calls
-// CurrentOsStackTraceExceptTop(1), Foo() will be included in the
-// trace but Bar() and CurrentOsStackTraceExceptTop() won't.
-String UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) {
- (void)skip_count;
- return String("");
-}
-
-// Returns the current time in milliseconds.
-TimeInMillis GetTimeInMillis() {
-#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__)
- // Difference between 1970-01-01 and 1601-01-01 in milliseconds.
- // http://analogous.blogspot.com/2005/04/epoch.html
- const TimeInMillis kJavaEpochToWinFileTimeDelta =
- static_cast<TimeInMillis>(116444736UL) * 100000UL;
- const DWORD kTenthMicrosInMilliSecond = 10000;
-
- SYSTEMTIME now_systime;
- FILETIME now_filetime;
- ULARGE_INTEGER now_int64;
- // TODO(kenton@google.com): Shouldn't this just use
- // GetSystemTimeAsFileTime()?
- GetSystemTime(&now_systime);
- if (SystemTimeToFileTime(&now_systime, &now_filetime)) {
- now_int64.LowPart = now_filetime.dwLowDateTime;
- now_int64.HighPart = now_filetime.dwHighDateTime;
- now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) -
- kJavaEpochToWinFileTimeDelta;
- return now_int64.QuadPart;
- }
- return 0;
-#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_
- __timeb64 now;
-#ifdef _MSC_VER
- // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996
- // (deprecated function) there.
- // TODO(kenton@google.com): Use GetTickCount()? Or use
- // SystemTimeToFileTime()
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4996) // Temporarily disables warning 4996.
- _ftime64(&now);
-#pragma warning(pop) // Restores the warning state.
-#else
- _ftime64(&now);
-#endif // _MSC_VER
- return static_cast<TimeInMillis>(now.time) * 1000 + now.millitm;
-#elif GTEST_HAS_GETTIMEOFDAY_
- struct timeval now;
- gettimeofday(&now, NULL);
- return static_cast<TimeInMillis>(now.tv_sec) * 1000 + now.tv_usec / 1000;
-#else
-#error "Don't know how to get the current time on your system."
-#endif
-}
-
-// Utilities
-
-// class String
-
-// Returns the input enclosed in double quotes if it's not NULL;
-// otherwise returns "(null)". For example, "\"Hello\"" is returned
-// for input "Hello".
-//
-// This is useful for printing a C string in the syntax of a literal.
-//
-// Known issue: escape sequences are not handled yet.
-String String::ShowCStringQuoted(const char* c_str) {
- return c_str ? String::Format("\"%s\"", c_str) : String("(null)");
-}
-
-// Copies at most length characters from str into a newly-allocated
-// piece of memory of size length+1. The memory is allocated with new[].
-// A terminating null byte is written to the memory, and a pointer to it
-// is returned. If str is NULL, NULL is returned.
-static char* CloneString(const char* str, size_t length) {
- if (str == NULL) {
- return NULL;
- } else {
- char* const clone = new char[length + 1];
- posix::StrNCpy(clone, str, length);
- clone[length] = '\0';
- return clone;
- }
-}
-
-// Clones a 0-terminated C string, allocating memory using new. The
-// caller is responsible for deleting[] the return value. Returns the
-// cloned string, or NULL if the input is NULL.
-const char * String::CloneCString(const char* c_str) {
- return (c_str == NULL) ?
- NULL : CloneString(c_str, strlen(c_str));
-}
-
-#if GTEST_OS_WINDOWS_MOBILE
-// Creates a UTF-16 wide string from the given ANSI string, allocating
-// memory using new. The caller is responsible for deleting the return
-// value using delete[]. Returns the wide string, or NULL if the
-// input is NULL.
-LPCWSTR String::AnsiToUtf16(const char* ansi) {
- if (!ansi) return NULL;
- const int length = strlen(ansi);
- const int unicode_length =
- MultiByteToWideChar(CP_ACP, 0, ansi, length,
- NULL, 0);
- WCHAR* unicode = new WCHAR[unicode_length + 1];
- MultiByteToWideChar(CP_ACP, 0, ansi, length,
- unicode, unicode_length);
- unicode[unicode_length] = 0;
- return unicode;
-}
-
-// Creates an ANSI string from the given wide string, allocating
-// memory using new. The caller is responsible for deleting the return
-// value using delete[]. Returns the ANSI string, or NULL if the
-// input is NULL.
-const char* String::Utf16ToAnsi(LPCWSTR utf16_str) {
- if (!utf16_str) return NULL;
- const int ansi_length =
- WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
- NULL, 0, NULL, NULL);
- char* ansi = new char[ansi_length + 1];
- WideCharToMultiByte(CP_ACP, 0, utf16_str, -1,
- ansi, ansi_length, NULL, NULL);
- ansi[ansi_length] = 0;
- return ansi;
-}
-
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-// Compares two C strings. Returns true iff they have the same content.
-//
-// Unlike strcmp(), this function can handle NULL argument(s). A NULL
-// C string is considered different to any non-NULL C string,
-// including the empty string.
-bool String::CStringEquals(const char * lhs, const char * rhs) {
- if ( lhs == NULL ) return rhs == NULL;
-
- if ( rhs == NULL ) return false;
-
- return strcmp(lhs, rhs) == 0;
-}
-
-#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
-
-// Converts an array of wide chars to a narrow string using the UTF-8
-// encoding, and streams the result to the given Message object.
-static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length,
- Message* msg) {
- // TODO(wan): consider allowing a testing::String object to
- // contain '\0'. This will make it behave more like std::string,
- // and will allow ToUtf8String() to return the correct encoding
- // for '\0' s.t. we can get rid of the conditional here (and in
- // several other places).
- for (size_t i = 0; i != length; ) { // NOLINT
- if (wstr[i] != L'\0') {
- *msg << WideStringToUtf8(wstr + i, static_cast<int>(length - i));
- while (i != length && wstr[i] != L'\0')
- i++;
- } else {
- *msg << '\0';
- i++;
- }
- }
-}
-
-#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING
-
-} // namespace internal
-
-#if GTEST_HAS_STD_WSTRING
-// Converts the given wide string to a narrow string using the UTF-8
-// encoding, and streams the result to this Message object.
-Message& Message::operator <<(const ::std::wstring& wstr) {
- internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
- return *this;
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-#if GTEST_HAS_GLOBAL_WSTRING
-// Converts the given wide string to a narrow string using the UTF-8
-// encoding, and streams the result to this Message object.
-Message& Message::operator <<(const ::wstring& wstr) {
- internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this);
- return *this;
-}
-#endif // GTEST_HAS_GLOBAL_WSTRING
-
-namespace internal {
-
-// Formats a value to be used in a failure message.
-
-// For a char value, we print it as a C++ char literal and as an
-// unsigned integer (both in decimal and in hexadecimal).
-String FormatForFailureMessage(char ch) {
- const unsigned int ch_as_uint = ch;
- // A String object cannot contain '\0', so we print "\\0" when ch is
- // '\0'.
- return String::Format("'%s' (%u, 0x%X)",
- ch ? String::Format("%c", ch).c_str() : "\\0",
- ch_as_uint, ch_as_uint);
-}
-
-// For a wchar_t value, we print it as a C++ wchar_t literal and as an
-// unsigned integer (both in decimal and in hexidecimal).
-String FormatForFailureMessage(wchar_t wchar) {
- // The C++ standard doesn't specify the exact size of the wchar_t
- // type. It just says that it shall have the same size as another
- // integral type, called its underlying type.
- //
- // Therefore, in order to print a wchar_t value in the numeric form,
- // we first convert it to the largest integral type (UInt64) and
- // then print the converted value.
- //
- // We use streaming to print the value as "%llu" doesn't work
- // correctly with MSVC 7.1.
- const UInt64 wchar_as_uint64 = wchar;
- Message msg;
- // A String object cannot contain '\0', so we print "\\0" when wchar is
- // L'\0'.
- char buffer[32]; // CodePointToUtf8 requires a buffer that big.
- msg << "L'"
- << (wchar ? CodePointToUtf8(static_cast<UInt32>(wchar), buffer) : "\\0")
- << "' (" << wchar_as_uint64 << ", 0x" << ::std::setbase(16)
- << wchar_as_uint64 << ")";
- return msg.GetString();
-}
-
-} // namespace internal
-
-// AssertionResult constructors.
-// Used in EXPECT_TRUE/FALSE(assertion_result).
-AssertionResult::AssertionResult(const AssertionResult& other)
- : success_(other.success_),
- message_(other.message_.get() != NULL ?
- new internal::String(*other.message_) :
- static_cast<internal::String*>(NULL)) {
-}
-
-// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE.
-AssertionResult AssertionResult::operator!() const {
- AssertionResult negation(!success_);
- if (message_.get() != NULL)
- negation << *message_;
- return negation;
-}
-
-// Makes a successful assertion result.
-AssertionResult AssertionSuccess() {
- return AssertionResult(true);
-}
-
-// Makes a failed assertion result.
-AssertionResult AssertionFailure() {
- return AssertionResult(false);
-}
-
-// Makes a failed assertion result with the given failure message.
-// Deprecated; use AssertionFailure() << message.
-AssertionResult AssertionFailure(const Message& message) {
- return AssertionFailure() << message;
-}
-
-namespace internal {
-
-// Constructs and returns the message for an equality assertion
-// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure.
-//
-// The first four parameters are the expressions used in the assertion
-// and their values, as strings. For example, for ASSERT_EQ(foo, bar)
-// where foo is 5 and bar is 6, we have:
-//
-// expected_expression: "foo"
-// actual_expression: "bar"
-// expected_value: "5"
-// actual_value: "6"
-//
-// The ignoring_case parameter is true iff the assertion is a
-// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will
-// be inserted into the message.
-AssertionResult EqFailure(const char* expected_expression,
- const char* actual_expression,
- const String& expected_value,
- const String& actual_value,
- bool ignoring_case) {
- Message msg;
- msg << "Value of: " << actual_expression;
- if (actual_value != actual_expression) {
- msg << "\n Actual: " << actual_value;
- }
-
- msg << "\nExpected: " << expected_expression;
- if (ignoring_case) {
- msg << " (ignoring case)";
- }
- if (expected_value != expected_expression) {
- msg << "\nWhich is: " << expected_value;
- }
-
- return AssertionFailure(msg);
-}
-
-// Constructs a failure message for Boolean assertions such as EXPECT_TRUE.
-String GetBoolAssertionFailureMessage(const AssertionResult& assertion_result,
- const char* expression_text,
- const char* actual_predicate_value,
- const char* expected_predicate_value) {
- const char* actual_message = assertion_result.message();
- Message msg;
- msg << "Value of: " << expression_text
- << "\n Actual: " << actual_predicate_value;
- if (actual_message[0] != '\0')
- msg << " (" << actual_message << ")";
- msg << "\nExpected: " << expected_predicate_value;
- return msg.GetString();
-}
-
-// Helper function for implementing ASSERT_NEAR.
-AssertionResult DoubleNearPredFormat(const char* expr1,
- const char* expr2,
- const char* abs_error_expr,
- double val1,
- double val2,
- double abs_error) {
- const double diff = fabs(val1 - val2);
- if (diff <= abs_error) return AssertionSuccess();
-
- // TODO(wan): do not print the value of an expression if it's
- // already a literal.
- Message msg;
- msg << "The difference between " << expr1 << " and " << expr2
- << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n"
- << expr1 << " evaluates to " << val1 << ",\n"
- << expr2 << " evaluates to " << val2 << ", and\n"
- << abs_error_expr << " evaluates to " << abs_error << ".";
- return AssertionFailure(msg);
-}
-
-
-// Helper template for implementing FloatLE() and DoubleLE().
-template <typename RawType>
-AssertionResult FloatingPointLE(const char* expr1,
- const char* expr2,
- RawType val1,
- RawType val2) {
- // Returns success if val1 is less than val2,
- if (val1 < val2) {
- return AssertionSuccess();
- }
-
- // or if val1 is almost equal to val2.
- const FloatingPoint<RawType> lhs(val1), rhs(val2);
- if (lhs.AlmostEquals(rhs)) {
- return AssertionSuccess();
- }
-
- // Note that the above two checks will both fail if either val1 or
- // val2 is NaN, as the IEEE floating-point standard requires that
- // any predicate involving a NaN must return false.
-
- StrStream val1_ss;
- val1_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << val1;
-
- StrStream val2_ss;
- val2_ss << std::setprecision(std::numeric_limits<RawType>::digits10 + 2)
- << val2;
-
- Message msg;
- msg << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n"
- << " Actual: " << StrStreamToString(&val1_ss) << " vs "
- << StrStreamToString(&val2_ss);
-
- return AssertionFailure(msg);
-}
-
-} // namespace internal
-
-// Asserts that val1 is less than, or almost equal to, val2. Fails
-// otherwise. In particular, it fails if either val1 or val2 is NaN.
-AssertionResult FloatLE(const char* expr1, const char* expr2,
- float val1, float val2) {
- return internal::FloatingPointLE<float>(expr1, expr2, val1, val2);
-}
-
-// Asserts that val1 is less than, or almost equal to, val2. Fails
-// otherwise. In particular, it fails if either val1 or val2 is NaN.
-AssertionResult DoubleLE(const char* expr1, const char* expr2,
- double val1, double val2) {
- return internal::FloatingPointLE<double>(expr1, expr2, val1, val2);
-}
-
-namespace internal {
-
-// The helper function for {ASSERT|EXPECT}_EQ with int or enum
-// arguments.
-AssertionResult CmpHelperEQ(const char* expected_expression,
- const char* actual_expression,
- BiggestInt expected,
- BiggestInt actual) {
- if (expected == actual) {
- return AssertionSuccess();
- }
-
- return EqFailure(expected_expression,
- actual_expression,
- FormatForComparisonFailureMessage(expected, actual),
- FormatForComparisonFailureMessage(actual, expected),
- false);
-}
-
-// A macro for implementing the helper functions needed to implement
-// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here
-// just to avoid copy-and-paste of similar code.
-#define GTEST_IMPL_CMP_HELPER_(op_name, op)\
-AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \
- BiggestInt val1, BiggestInt val2) {\
- if (val1 op val2) {\
- return AssertionSuccess();\
- } else {\
- Message msg;\
- msg << "Expected: (" << expr1 << ") " #op " (" << expr2\
- << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\
- << " vs " << FormatForComparisonFailureMessage(val2, val1);\
- return AssertionFailure(msg);\
- }\
-}
-
-// Implements the helper function for {ASSERT|EXPECT}_NE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(NE, !=)
-// Implements the helper function for {ASSERT|EXPECT}_LE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(LE, <=)
-// Implements the helper function for {ASSERT|EXPECT}_LT with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(LT, < )
-// Implements the helper function for {ASSERT|EXPECT}_GE with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(GE, >=)
-// Implements the helper function for {ASSERT|EXPECT}_GT with int or
-// enum arguments.
-GTEST_IMPL_CMP_HELPER_(GT, > )
-
-#undef GTEST_IMPL_CMP_HELPER_
-
-// The helper function for {ASSERT|EXPECT}_STREQ.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual) {
- if (String::CStringEquals(expected, actual)) {
- return AssertionSuccess();
- }
-
- return EqFailure(expected_expression,
- actual_expression,
- String::ShowCStringQuoted(expected),
- String::ShowCStringQuoted(actual),
- false);
-}
-
-// The helper function for {ASSERT|EXPECT}_STRCASEEQ.
-AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression,
- const char* actual_expression,
- const char* expected,
- const char* actual) {
- if (String::CaseInsensitiveCStringEquals(expected, actual)) {
- return AssertionSuccess();
- }
-
- return EqFailure(expected_expression,
- actual_expression,
- String::ShowCStringQuoted(expected),
- String::ShowCStringQuoted(actual),
- true);
-}
-
-// The helper function for {ASSERT|EXPECT}_STRNE.
-AssertionResult CmpHelperSTRNE(const char* s1_expression,
- const char* s2_expression,
- const char* s1,
- const char* s2) {
- if (!String::CStringEquals(s1, s2)) {
- return AssertionSuccess();
- } else {
- Message msg;
- msg << "Expected: (" << s1_expression << ") != ("
- << s2_expression << "), actual: \""
- << s1 << "\" vs \"" << s2 << "\"";
- return AssertionFailure(msg);
- }
-}
-
-// The helper function for {ASSERT|EXPECT}_STRCASENE.
-AssertionResult CmpHelperSTRCASENE(const char* s1_expression,
- const char* s2_expression,
- const char* s1,
- const char* s2) {
- if (!String::CaseInsensitiveCStringEquals(s1, s2)) {
- return AssertionSuccess();
- } else {
- Message msg;
- msg << "Expected: (" << s1_expression << ") != ("
- << s2_expression << ") (ignoring case), actual: \""
- << s1 << "\" vs \"" << s2 << "\"";
- return AssertionFailure(msg);
- }
-}
-
-} // namespace internal
-
-namespace {
-
-// Helper functions for implementing IsSubString() and IsNotSubstring().
-
-// This group of overloaded functions return true iff needle is a
-// substring of haystack. NULL is considered a substring of itself
-// only.
-
-bool IsSubstringPred(const char* needle, const char* haystack) {
- if (needle == NULL || haystack == NULL)
- return needle == haystack;
-
- return strstr(haystack, needle) != NULL;
-}
-
-bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) {
- if (needle == NULL || haystack == NULL)
- return needle == haystack;
-
- return wcsstr(haystack, needle) != NULL;
-}
-
-// StringType here can be either ::std::string or ::std::wstring.
-template <typename StringType>
-bool IsSubstringPred(const StringType& needle,
- const StringType& haystack) {
- return haystack.find(needle) != StringType::npos;
-}
-
-// This function implements either IsSubstring() or IsNotSubstring(),
-// depending on the value of the expected_to_be_substring parameter.
-// StringType here can be const char*, const wchar_t*, ::std::string,
-// or ::std::wstring.
-template <typename StringType>
-AssertionResult IsSubstringImpl(
- bool expected_to_be_substring,
- const char* needle_expr, const char* haystack_expr,
- const StringType& needle, const StringType& haystack) {
- if (IsSubstringPred(needle, haystack) == expected_to_be_substring)
- return AssertionSuccess();
-
- const bool is_wide_string = sizeof(needle[0]) > 1;
- const char* const begin_string_quote = is_wide_string ? "L\"" : "\"";
- return AssertionFailure(
- Message()
- << "Value of: " << needle_expr << "\n"
- << " Actual: " << begin_string_quote << needle << "\"\n"
- << "Expected: " << (expected_to_be_substring ? "" : "not ")
- << "a substring of " << haystack_expr << "\n"
- << "Which is: " << begin_string_quote << haystack << "\"");
-}
-
-} // namespace
-
-// IsSubstring() and IsNotSubstring() check whether needle is a
-// substring of haystack (NULL is considered a substring of itself
-// only), and return an appropriate error message when they fail.
-
-AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const char* needle, const char* haystack) {
- return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const wchar_t* needle, const wchar_t* haystack) {
- return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const char* needle, const char* haystack) {
- return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const wchar_t* needle, const wchar_t* haystack) {
- return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::string& needle, const ::std::string& haystack) {
- return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::string& needle, const ::std::string& haystack) {
- return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
-}
-
-#if GTEST_HAS_STD_WSTRING
-AssertionResult IsSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::wstring& needle, const ::std::wstring& haystack) {
- return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack);
-}
-
-AssertionResult IsNotSubstring(
- const char* needle_expr, const char* haystack_expr,
- const ::std::wstring& needle, const ::std::wstring& haystack) {
- return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack);
-}
-#endif // GTEST_HAS_STD_WSTRING
-
-namespace internal {
-
-#if GTEST_OS_WINDOWS
-
-namespace {
-
-// Helper function for IsHRESULT{SuccessFailure} predicates
-AssertionResult HRESULTFailureHelper(const char* expr,
- const char* expected,
- long hr) { // NOLINT
-#if GTEST_OS_WINDOWS_MOBILE
- // Windows CE doesn't support FormatMessage.
- const char error_text[] = "";
-#else
- // Looks up the human-readable system message for the HRESULT code
- // and since we're not passing any params to FormatMessage, we don't
- // want inserts expanded.
- const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS;
- const DWORD kBufSize = 4096; // String::Format can't exceed this length.
- // Gets the system's human readable message string for this HRESULT.
- char error_text[kBufSize] = { '\0' };
- DWORD message_length = ::FormatMessageA(kFlags,
- 0, // no source, we're asking system
- hr, // the error
- 0, // no line width restrictions
- error_text, // output buffer
- kBufSize, // buf size
- NULL); // no arguments for inserts
- // Trims tailing white space (FormatMessage leaves a trailing cr-lf)
- for (; message_length && isspace(error_text[message_length - 1]);
- --message_length) {
- error_text[message_length - 1] = '\0';
- }
-#endif // GTEST_OS_WINDOWS_MOBILE
-
- const String error_hex(String::Format("0x%08X ", hr));
- Message msg;
- msg << "Expected: " << expr << " " << expected << ".\n"
- << " Actual: " << error_hex << error_text << "\n";
-
- return ::testing::AssertionFailure(msg);
-}
-
-} // namespace
-
-AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT
- if (SUCCEEDED(hr)) {
- return AssertionSuccess();
- }
- return HRESULTFailureHelper(expr, "succeeds", hr);
-}
-
-AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT
- if (FAILED(hr)) {
- return AssertionSuccess();
- }
- return HRESULTFailureHelper(expr, "fails", hr);
-}
-
-#endif // GTEST_OS_WINDOWS
-
-// Utility functions for encoding Unicode text (wide strings) in
-// UTF-8.
-
-// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8
-// like this:
-//
-// Code-point length Encoding
-// 0 - 7 bits 0xxxxxxx
-// 8 - 11 bits 110xxxxx 10xxxxxx
-// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx
-// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
-
-// The maximum code-point a one-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint1 = (static_cast<UInt32>(1) << 7) - 1;
-
-// The maximum code-point a two-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint2 = (static_cast<UInt32>(1) << (5 + 6)) - 1;
-
-// The maximum code-point a three-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint3 = (static_cast<UInt32>(1) << (4 + 2*6)) - 1;
-
-// The maximum code-point a four-byte UTF-8 sequence can represent.
-const UInt32 kMaxCodePoint4 = (static_cast<UInt32>(1) << (3 + 3*6)) - 1;
-
-// Chops off the n lowest bits from a bit pattern. Returns the n
-// lowest bits. As a side effect, the original bit pattern will be
-// shifted to the right by n bits.
-inline UInt32 ChopLowBits(UInt32* bits, int n) {
- const UInt32 low_bits = *bits & ((static_cast<UInt32>(1) << n) - 1);
- *bits >>= n;
- return low_bits;
-}
-
-// Converts a Unicode code point to a narrow string in UTF-8 encoding.
-// code_point parameter is of type UInt32 because wchar_t may not be
-// wide enough to contain a code point.
-// The output buffer str must containt at least 32 characters.
-// The function returns the address of the output buffer.
-// If the code_point is not a valid Unicode code point
-// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be output
-// as '(Invalid Unicode 0xXXXXXXXX)'.
-char* CodePointToUtf8(UInt32 code_point, char* str) {
- if (code_point <= kMaxCodePoint1) {
- str[1] = '\0';
- str[0] = static_cast<char>(code_point); // 0xxxxxxx
- } else if (code_point <= kMaxCodePoint2) {
- str[2] = '\0';
- str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[0] = static_cast<char>(0xC0 | code_point); // 110xxxxx
- } else if (code_point <= kMaxCodePoint3) {
- str[3] = '\0';
- str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[0] = static_cast<char>(0xE0 | code_point); // 1110xxxx
- } else if (code_point <= kMaxCodePoint4) {
- str[4] = '\0';
- str[3] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[2] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[1] = static_cast<char>(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx
- str[0] = static_cast<char>(0xF0 | code_point); // 11110xxx
- } else {
- // The longest string String::Format can produce when invoked
- // with these parameters is 28 character long (not including
- // the terminating nul character). We are asking for 32 character
- // buffer just in case. This is also enough for strncpy to
- // null-terminate the destination string.
- posix::StrNCpy(
- str, String::Format("(Invalid Unicode 0x%X)", code_point).c_str(), 32);
- str[31] = '\0'; // Makes sure no change in the format to strncpy leaves
- // the result unterminated.
- }
- return str;
-}
-
-// The following two functions only make sense if the the system
-// uses UTF-16 for wide string encoding. All supported systems
-// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16.
-
-// Determines if the arguments constitute UTF-16 surrogate pair
-// and thus should be combined into a single Unicode code point
-// using CreateCodePointFromUtf16SurrogatePair.
-inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) {
- return sizeof(wchar_t) == 2 &&
- (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00;
-}
-
-// Creates a Unicode code point from UTF16 surrogate pair.
-inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first,
- wchar_t second) {
- const UInt32 mask = (1 << 10) - 1;
- return (sizeof(wchar_t) == 2) ?
- (((first & mask) << 10) | (second & mask)) + 0x10000 :
- // This function should not be called when the condition is
- // false, but we provide a sensible default in case it is.
- static_cast<UInt32>(first);
-}
-
-// Converts a wide string to a narrow string in UTF-8 encoding.
-// The wide string is assumed to have the following encoding:
-// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS)
-// UTF-32 if sizeof(wchar_t) == 4 (on Linux)
-// Parameter str points to a null-terminated wide string.
-// Parameter num_chars may additionally limit the number
-// of wchar_t characters processed. -1 is used when the entire string
-// should be processed.
-// If the string contains code points that are not valid Unicode code points
-// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output
-// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding
-// and contains invalid UTF-16 surrogate pairs, values in those pairs
-// will be encoded as individual Unicode characters from Basic Normal Plane.
-String WideStringToUtf8(const wchar_t* str, int num_chars) {
- if (num_chars == -1)
- num_chars = static_cast<int>(wcslen(str));
-
- StrStream stream;
- for (int i = 0; i < num_chars; ++i) {
- UInt32 unicode_code_point;
-
- if (str[i] == L'\0') {
- break;
- } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) {
- unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i],
- str[i + 1]);
- i++;
- } else {
- unicode_code_point = static_cast<UInt32>(str[i]);
- }
-
- char buffer[32]; // CodePointToUtf8 requires a buffer this big.
- stream << CodePointToUtf8(unicode_code_point, buffer);
- }
- return StrStreamToString(&stream);
-}
-
-// Converts a wide C string to a String using the UTF-8 encoding.
-// NULL will be converted to "(null)".
-String String::ShowWideCString(const wchar_t * wide_c_str) {
- if (wide_c_str == NULL) return String("(null)");
-
- return String(internal::WideStringToUtf8(wide_c_str, -1).c_str());
-}
-
-// Similar to ShowWideCString(), except that this function encloses
-// the converted string in double quotes.
-String String::ShowWideCStringQuoted(const wchar_t* wide_c_str) {
- if (wide_c_str == NULL) return String("(null)");
-
- return String::Format("L\"%s\"",
- String::ShowWideCString(wide_c_str).c_str());
-}
-
-// Compares two wide C strings. Returns true iff they have the same
-// content.
-//
-// Unlike wcscmp(), this function can handle NULL argument(s). A NULL
-// C string is considered different to any non-NULL C string,
-// including the empty string.
-bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) {
- if (lhs == NULL) return rhs == NULL;
-
- if (rhs == NULL) return false;
-
- return wcscmp(lhs, rhs) == 0;
-}
-
-// Helper function for *_STREQ on wide strings.
-AssertionResult CmpHelperSTREQ(const char* expected_expression,
- const char* actual_expression,
- const wchar_t* expected,
- const wchar_t* actual) {
- if (String::WideCStringEquals(expected, actual)) {
- return AssertionSuccess();
- }
-
- return EqFailure(expected_expression,
- actual_expression,
- String::ShowWideCStringQuoted(expected),
- String::ShowWideCStringQuoted(actual),
- false);
-}
-
-// Helper function for *_STRNE on wide strings.
-AssertionResult CmpHelperSTRNE(const char* s1_expression,
- const char* s2_expression,
- const wchar_t* s1,
- const wchar_t* s2) {
- if (!String::WideCStringEquals(s1, s2)) {
- return AssertionSuccess();
- }
-
- Message msg;
- msg << "Expected: (" << s1_expression << ") != ("
- << s2_expression << "), actual: "
- << String::ShowWideCStringQuoted(s1)
- << " vs " << String::ShowWideCStringQuoted(s2);
- return AssertionFailure(msg);
-}
-
-// Compares two C strings, ignoring case. Returns true iff they have
-// the same content.
-//
-// Unlike strcasecmp(), this function can handle NULL argument(s). A
-// NULL C string is considered different to any non-NULL C string,
-// including the empty string.
-bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) {
- if (lhs == NULL)
- return rhs == NULL;
- if (rhs == NULL)
- return false;
- return posix::StrCaseCmp(lhs, rhs) == 0;
-}
-
- // Compares two wide C strings, ignoring case. Returns true iff they
- // have the same content.
- //
- // Unlike wcscasecmp(), this function can handle NULL argument(s).
- // A NULL C string is considered different to any non-NULL wide C string,
- // including the empty string.
- // NB: The implementations on different platforms slightly differ.
- // On windows, this method uses _wcsicmp which compares according to LC_CTYPE
- // environment variable. On GNU platform this method uses wcscasecmp
- // which compares according to LC_CTYPE category of the current locale.
- // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
- // current locale.
-bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
- const wchar_t* rhs) {
- if ( lhs == NULL ) return rhs == NULL;
-
- if ( rhs == NULL ) return false;
-
-#if GTEST_OS_WINDOWS
- return _wcsicmp(lhs, rhs) == 0;
-#elif GTEST_OS_LINUX
- return wcscasecmp(lhs, rhs) == 0;
-#else
- // Mac OS X and Cygwin don't define wcscasecmp. Other unknown OSes
- // may not define it either.
- wint_t left, right;
- do {
- left = towlower(*lhs++);
- right = towlower(*rhs++);
- } while (left && left == right);
- return left == right;
-#endif // OS selector
-}
-
-// Compares this with another String.
-// Returns < 0 if this is less than rhs, 0 if this is equal to rhs, or > 0
-// if this is greater than rhs.
-int String::Compare(const String & rhs) const {
- const char* const lhs_c_str = c_str();
- const char* const rhs_c_str = rhs.c_str();
-
- if (lhs_c_str == NULL) {
- return rhs_c_str == NULL ? 0 : -1; // NULL < anything except NULL
- } else if (rhs_c_str == NULL) {
- return 1;
- }
-
- const size_t shorter_str_len =
- length() <= rhs.length() ? length() : rhs.length();
- for (size_t i = 0; i != shorter_str_len; i++) {
- if (lhs_c_str[i] < rhs_c_str[i]) {
- return -1;
- } else if (lhs_c_str[i] > rhs_c_str[i]) {
- return 1;
- }
- }
- return (length() < rhs.length()) ? -1 :
- (length() > rhs.length()) ? 1 : 0;
-}
-
-// Returns true iff this String ends with the given suffix. *Any*
-// String is considered to end with a NULL or empty suffix.
-bool String::EndsWith(const char* suffix) const {
- if (suffix == NULL || CStringEquals(suffix, "")) return true;
-
- if (c_str() == NULL) return false;
-
- const size_t this_len = strlen(c_str());
- const size_t suffix_len = strlen(suffix);
- return (this_len >= suffix_len) &&
- CStringEquals(c_str() + this_len - suffix_len, suffix);
-}
-
-// Returns true iff this String ends with the given suffix, ignoring case.
-// Any String is considered to end with a NULL or empty suffix.
-bool String::EndsWithCaseInsensitive(const char* suffix) const {
- if (suffix == NULL || CStringEquals(suffix, "")) return true;
-
- if (c_str() == NULL) return false;
-
- const size_t this_len = strlen(c_str());
- const size_t suffix_len = strlen(suffix);
- return (this_len >= suffix_len) &&
- CaseInsensitiveCStringEquals(c_str() + this_len - suffix_len, suffix);
-}
-
-// Formats a list of arguments to a String, using the same format
-// spec string as for printf.
-//
-// We do not use the StringPrintf class as it is not universally
-// available.
-//
-// The result is limited to 4096 characters (including the tailing 0).
-// If 4096 characters are not enough to format the input, or if
-// there's an error, "<formatting error or buffer exceeded>" is
-// returned.
-String String::Format(const char * format, ...) {
- va_list args;
- va_start(args, format);
-
- char buffer[4096];
- const int kBufferSize = sizeof(buffer)/sizeof(buffer[0]);
-
- // MSVC 8 deprecates vsnprintf(), so we want to suppress warning
- // 4996 (deprecated function) there.
-#ifdef _MSC_VER // We are using MSVC.
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4996) // Temporarily disables warning 4996.
- const int size = vsnprintf(buffer, kBufferSize, format, args);
-#pragma warning(pop) // Restores the warning state.
-#else // We are not using MSVC.
- const int size = vsnprintf(buffer, kBufferSize, format, args);
-#endif // _MSC_VER
- va_end(args);
-
- // vsnprintf()'s behavior is not portable. When the buffer is not
- // big enough, it returns a negative value in MSVC, and returns the
- // needed buffer size on Linux. When there is an output error, it
- // always returns a negative value. For simplicity, we lump the two
- // error cases together.
- if (size < 0 || size >= kBufferSize) {
- return String("<formatting error or buffer exceeded>");
- } else {
- return String(buffer, size);
- }
-}
-
-// Converts the buffer in a StrStream to a String, converting NUL
-// bytes to "\\0" along the way.
-String StrStreamToString(StrStream* ss) {
- const ::std::string& str = ss->str();
- const char* const start = str.c_str();
- const char* const end = start + str.length();
-
- // We need to use a helper StrStream to do this transformation
- // because String doesn't support push_back().
- StrStream helper;
- for (const char* ch = start; ch != end; ++ch) {
- if (*ch == '\0') {
- helper << "\\0"; // Replaces NUL with "\\0";
- } else {
- helper.put(*ch);
- }
- }
-
- return String(helper.str().c_str());
-}
-
-// Appends the user-supplied message to the Google-Test-generated message.
-String AppendUserMessage(const String& gtest_msg,
- const Message& user_msg) {
- // Appends the user message if it's non-empty.
- const String user_msg_string = user_msg.GetString();
- if (user_msg_string.empty()) {
- return gtest_msg;
- }
-
- Message msg;
- msg << gtest_msg << "\n" << user_msg_string;
-
- return msg.GetString();
-}
-
-} // namespace internal
-
-// class TestResult
-
-// Creates an empty TestResult.
-TestResult::TestResult()
- : death_test_count_(0),
- elapsed_time_(0) {
-}
-
-// D'tor.
-TestResult::~TestResult() {
-}
-
-// Returns the i-th test part result among all the results. i can
-// range from 0 to total_part_count() - 1. If i is not in that range,
-// aborts the program.
-const TestPartResult& TestResult::GetTestPartResult(int i) const {
- if (i < 0 || i >= total_part_count())
- internal::posix::Abort();
- return test_part_results_.at(i);
-}
-
-// Returns the i-th test property. i can range from 0 to
-// test_property_count() - 1. If i is not in that range, aborts the
-// program.
-const TestProperty& TestResult::GetTestProperty(int i) const {
- if (i < 0 || i >= test_property_count())
- internal::posix::Abort();
- return test_properties_.at(i);
-}
-
-// Clears the test part results.
-void TestResult::ClearTestPartResults() {
- test_part_results_.clear();
-}
-
-// Adds a test part result to the list.
-void TestResult::AddTestPartResult(const TestPartResult& test_part_result) {
- test_part_results_.push_back(test_part_result);
-}
-
-// Adds a test property to the list. If a property with the same key as the
-// supplied property is already represented, the value of this test_property
-// replaces the old value for that key.
-void TestResult::RecordProperty(const TestProperty& test_property) {
- if (!ValidateTestProperty(test_property)) {
- return;
- }
- internal::MutexLock lock(&test_properites_mutex_);
- const std::vector<TestProperty>::iterator property_with_matching_key =
- std::find_if(test_properties_.begin(), test_properties_.end(),
- internal::TestPropertyKeyIs(test_property.key()));
- if (property_with_matching_key == test_properties_.end()) {
- test_properties_.push_back(test_property);
- return;
- }
- property_with_matching_key->SetValue(test_property.value());
-}
-
-// Adds a failure if the key is a reserved attribute of Google Test
-// testcase tags. Returns true if the property is valid.
-bool TestResult::ValidateTestProperty(const TestProperty& test_property) {
- internal::String key(test_property.key());
- if (key == "name" || key == "status" || key == "time" || key == "classname") {
- ADD_FAILURE()
- << "Reserved key used in RecordProperty(): "
- << key
- << " ('name', 'status', 'time', and 'classname' are reserved by "
- << GTEST_NAME_ << ")";
- return false;
- }
- return true;
-}
-
-// Clears the object.
-void TestResult::Clear() {
- test_part_results_.clear();
- test_properties_.clear();
- death_test_count_ = 0;
- elapsed_time_ = 0;
-}
-
-// Returns true iff the test failed.
-bool TestResult::Failed() const {
- for (int i = 0; i < total_part_count(); ++i) {
- if (GetTestPartResult(i).failed())
- return true;
- }
- return false;
-}
-
-// Returns true iff the test part fatally failed.
-static bool TestPartFatallyFailed(const TestPartResult& result) {
- return result.fatally_failed();
-}
-
-// Returns true iff the test fatally failed.
-bool TestResult::HasFatalFailure() const {
- return CountIf(test_part_results_, TestPartFatallyFailed) > 0;
-}
-
-// Returns true iff the test part non-fatally failed.
-static bool TestPartNonfatallyFailed(const TestPartResult& result) {
- return result.nonfatally_failed();
-}
-
-// Returns true iff the test has a non-fatal failure.
-bool TestResult::HasNonfatalFailure() const {
- return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0;
-}
-
-// Gets the number of all test parts. This is the sum of the number
-// of successful test parts and the number of failed test parts.
-int TestResult::total_part_count() const {
- return static_cast<int>(test_part_results_.size());
-}
-
-// Returns the number of the test properties.
-int TestResult::test_property_count() const {
- return static_cast<int>(test_properties_.size());
-}
-
-// class Test
-
-// Creates a Test object.
-
-// The c'tor saves the values of all Google Test flags.
-Test::Test()
- : gtest_flag_saver_(new internal::GTestFlagSaver) {
-}
-
-// The d'tor restores the values of all Google Test flags.
-Test::~Test() {
- delete gtest_flag_saver_;
-}
-
-// Sets up the test fixture.
-//
-// A sub-class may override this.
-void Test::SetUp() {
-}
-
-// Tears down the test fixture.
-//
-// A sub-class may override this.
-void Test::TearDown() {
-}
-
-// Allows user supplied key value pairs to be recorded for later output.
-void Test::RecordProperty(const char* key, const char* value) {
- UnitTest::GetInstance()->RecordPropertyForCurrentTest(key, value);
-}
-
-// Allows user supplied key value pairs to be recorded for later output.
-void Test::RecordProperty(const char* key, int value) {
- Message value_message;
- value_message << value;
- RecordProperty(key, value_message.GetString().c_str());
-}
-
-namespace internal {
-
-void ReportFailureInUnknownLocation(TestPartResult::Type result_type,
- const String& message) {
- // This function is a friend of UnitTest and as such has access to
- // AddTestPartResult.
- UnitTest::GetInstance()->AddTestPartResult(
- result_type,
- NULL, // No info about the source file where the exception occurred.
- -1, // We have no info on which line caused the exception.
- message,
- String()); // No stack trace, either.
-}
-
-} // namespace internal
-
-#if GTEST_OS_WINDOWS
-// We are on Windows.
-
-// Adds an "exception thrown" fatal failure to the current test.
-static void AddExceptionThrownFailure(DWORD exception_code,
- const char* location) {
- Message message;
- message << "Exception thrown with code 0x" << std::setbase(16) <<
- exception_code << std::setbase(10) << " in " << location << ".";
-
- internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
- message.GetString());
-}
-
-#endif // GTEST_OS_WINDOWS
-
-// Google Test requires all tests in the same test case to use the same test
-// fixture class. This function checks if the current test has the
-// same fixture class as the first test in the current test case. If
-// yes, it returns true; otherwise it generates a Google Test failure and
-// returns false.
-bool Test::HasSameFixtureClass() {
- internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- const TestCase* const test_case = impl->current_test_case();
-
- // Info about the first test in the current test case.
- const internal::TestInfoImpl* const first_test_info =
- test_case->test_info_list()[0]->impl();
- const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
- const char* const first_test_name = first_test_info->name();
-
- // Info about the current test.
- const internal::TestInfoImpl* const this_test_info =
- impl->current_test_info()->impl();
- const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
- const char* const this_test_name = this_test_info->name();
-
- if (this_fixture_id != first_fixture_id) {
- // Is the first test defined using TEST?
- const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId();
- // Is this test defined using TEST?
- const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId();
-
- if (first_is_TEST || this_is_TEST) {
- // The user mixed TEST and TEST_F in this test case - we'll tell
- // him/her how to fix it.
-
- // Gets the name of the TEST and the name of the TEST_F. Note
- // that first_is_TEST and this_is_TEST cannot both be true, as
- // the fixture IDs are different for the two tests.
- const char* const TEST_name =
- first_is_TEST ? first_test_name : this_test_name;
- const char* const TEST_F_name =
- first_is_TEST ? this_test_name : first_test_name;
-
- ADD_FAILURE()
- << "All tests in the same test case must use the same test fixture\n"
- << "class, so mixing TEST_F and TEST in the same test case is\n"
- << "illegal. In test case " << this_test_info->test_case_name()
- << ",\n"
- << "test " << TEST_F_name << " is defined using TEST_F but\n"
- << "test " << TEST_name << " is defined using TEST. You probably\n"
- << "want to change the TEST to TEST_F or move it to another test\n"
- << "case.";
- } else {
- // The user defined two fixture classes with the same name in
- // two namespaces - we'll tell him/her how to fix it.
- ADD_FAILURE()
- << "All tests in the same test case must use the same test fixture\n"
- << "class. However, in test case "
- << this_test_info->test_case_name() << ",\n"
- << "you defined test " << first_test_name
- << " and test " << this_test_name << "\n"
- << "using two different test fixture classes. This can happen if\n"
- << "the two classes are from different namespaces or translation\n"
- << "units and have the same name. You should probably rename one\n"
- << "of the classes to put the tests into different test cases.";
- }
- return false;
- }
-
- return true;
-}
-
-// Runs the test and updates the test result.
-void Test::Run() {
- if (!HasSameFixtureClass()) return;
-
- internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-#if GTEST_HAS_SEH
- // Catch SEH-style exceptions.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- __try {
- SetUp();
- } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
- GetExceptionCode())) {
- AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
- }
-
- // We will run the test only if SetUp() had no fatal failure.
- if (!HasFatalFailure()) {
- impl->os_stack_trace_getter()->UponLeavingGTest();
- __try {
- TestBody();
- } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
- GetExceptionCode())) {
- AddExceptionThrownFailure(GetExceptionCode(), "the test body");
- }
- }
-
- // However, we want to clean up as much as possible. Hence we will
- // always call TearDown(), even if SetUp() or the test body has
- // failed.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- __try {
- TearDown();
- } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
- GetExceptionCode())) {
- AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
- }
-
-#else // We are on a compiler or platform that doesn't support SEH.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- SetUp();
-
- // We will run the test only if SetUp() was successful.
- if (!HasFatalFailure()) {
- impl->os_stack_trace_getter()->UponLeavingGTest();
- TestBody();
- }
-
- // However, we want to clean up as much as possible. Hence we will
- // always call TearDown(), even if SetUp() or the test body has
- // failed.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- TearDown();
-#endif // GTEST_HAS_SEH
-}
-
-
-// Returns true iff the current test has a fatal failure.
-bool Test::HasFatalFailure() {
- return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
-}
-
-// Returns true iff the current test has a non-fatal failure.
-bool Test::HasNonfatalFailure() {
- return internal::GetUnitTestImpl()->current_test_result()->
- HasNonfatalFailure();
-}
-
-// class TestInfo
-
-// Constructs a TestInfo object. It assumes ownership of the test factory
-// object via impl_.
-TestInfo::TestInfo(const char* a_test_case_name,
- const char* a_name,
- const char* a_test_case_comment,
- const char* a_comment,
- internal::TypeId fixture_class_id,
- internal::TestFactoryBase* factory) {
- impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name,
- a_test_case_comment, a_comment,
- fixture_class_id, factory);
-}
-
-// Destructs a TestInfo object.
-TestInfo::~TestInfo() {
- delete impl_;
-}
-
-namespace internal {
-
-// Creates a new TestInfo object and registers it with Google Test;
-// returns the created object.
-//
-// Arguments:
-//
-// test_case_name: name of the test case
-// name: name of the test
-// test_case_comment: a comment on the test case that will be included in
-// the test output
-// comment: a comment on the test that will be included in the
-// test output
-// fixture_class_id: ID of the test fixture class
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-// factory: pointer to the factory that creates a test object.
-// The newly created TestInfo instance will assume
-// ownership of the factory object.
-TestInfo* MakeAndRegisterTestInfo(
- const char* test_case_name, const char* name,
- const char* test_case_comment, const char* comment,
- TypeId fixture_class_id,
- SetUpTestCaseFunc set_up_tc,
- TearDownTestCaseFunc tear_down_tc,
- TestFactoryBase* factory) {
- TestInfo* const test_info =
- new TestInfo(test_case_name, name, test_case_comment, comment,
- fixture_class_id, factory);
- GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info);
- return test_info;
-}
-
-#if GTEST_HAS_PARAM_TEST
-void ReportInvalidTestCaseType(const char* test_case_name,
- const char* file, int line) {
- Message errors;
- errors
- << "Attempted redefinition of test case " << test_case_name << ".\n"
- << "All tests in the same test case must use the same test fixture\n"
- << "class. However, in test case " << test_case_name << ", you tried\n"
- << "to define a test using a fixture class different from the one\n"
- << "used earlier. This can happen if the two fixture classes are\n"
- << "from different namespaces and have the same name. You should\n"
- << "probably rename one of the classes to put the tests into different\n"
- << "test cases.";
-
- fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
- errors.GetString().c_str());
-}
-#endif // GTEST_HAS_PARAM_TEST
-
-} // namespace internal
-
-// Returns the test case name.
-const char* TestInfo::test_case_name() const {
- return impl_->test_case_name();
-}
-
-// Returns the test name.
-const char* TestInfo::name() const {
- return impl_->name();
-}
-
-// Returns the test case comment.
-const char* TestInfo::test_case_comment() const {
- return impl_->test_case_comment();
-}
-
-// Returns the test comment.
-const char* TestInfo::comment() const {
- return impl_->comment();
-}
-
-// Returns true if this test should run.
-bool TestInfo::should_run() const { return impl_->should_run(); }
-
-// Returns true if this test matches the user-specified filter.
-bool TestInfo::matches_filter() const { return impl_->matches_filter(); }
-
-// Returns the result of the test.
-const TestResult* TestInfo::result() const { return impl_->result(); }
-
-// Increments the number of death tests encountered in this test so
-// far.
-int TestInfo::increment_death_test_count() {
- return impl_->result()->increment_death_test_count();
-}
-
-namespace {
-
-// A predicate that checks the test name of a TestInfo against a known
-// value.
-//
-// This is used for implementation of the TestCase class only. We put
-// it in the anonymous namespace to prevent polluting the outer
-// namespace.
-//
-// TestNameIs is copyable.
-class TestNameIs {
- public:
- // Constructor.
- //
- // TestNameIs has NO default constructor.
- explicit TestNameIs(const char* name)
- : name_(name) {}
-
- // Returns true iff the test name of test_info matches name_.
- bool operator()(const TestInfo * test_info) const {
- return test_info && internal::String(test_info->name()).Compare(name_) == 0;
- }
-
- private:
- internal::String name_;
-};
-
-} // namespace
-
-namespace internal {
-
-// This method expands all parameterized tests registered with macros TEST_P
-// and INSTANTIATE_TEST_CASE_P into regular tests and registers those.
-// This will be done just once during the program runtime.
-void UnitTestImpl::RegisterParameterizedTests() {
-#if GTEST_HAS_PARAM_TEST
- if (!parameterized_tests_registered_) {
- parameterized_test_registry_.RegisterTests();
- parameterized_tests_registered_ = true;
- }
-#endif
-}
-
-// Creates the test object, runs it, records its result, and then
-// deletes it.
-void TestInfoImpl::Run() {
- if (!should_run_) return;
-
- // Tells UnitTest where to store test result.
- UnitTestImpl* const impl = internal::GetUnitTestImpl();
- impl->set_current_test_info(parent_);
-
- TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
-
- // Notifies the unit test event listeners that a test is about to start.
- repeater->OnTestStart(*parent_);
-
- const TimeInMillis start = GetTimeInMillis();
-
- impl->os_stack_trace_getter()->UponLeavingGTest();
-#if GTEST_HAS_SEH
- // Catch SEH-style exceptions.
- Test* test = NULL;
-
- __try {
- // Creates the test object.
- test = factory_->CreateTest();
- } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
- GetExceptionCode())) {
- AddExceptionThrownFailure(GetExceptionCode(),
- "the test fixture's constructor");
- return;
- }
-#else // We are on a compiler or platform that doesn't support SEH.
-
- // TODO(wan): If test->Run() throws, test won't be deleted. This is
- // not a problem now as we don't use exceptions. If we were to
- // enable exceptions, we should revise the following to be
- // exception-safe.
-
- // Creates the test object.
- Test* test = factory_->CreateTest();
-#endif // GTEST_HAS_SEH
-
- // Runs the test only if the constructor of the test fixture didn't
- // generate a fatal failure.
- if (!Test::HasFatalFailure()) {
- test->Run();
- }
-
- // Deletes the test object.
- impl->os_stack_trace_getter()->UponLeavingGTest();
- delete test;
- test = NULL;
-
- result_.set_elapsed_time(GetTimeInMillis() - start);
-
- // Notifies the unit test event listener that a test has just finished.
- repeater->OnTestEnd(*parent_);
-
- // Tells UnitTest to stop associating assertion results to this
- // test.
- impl->set_current_test_info(NULL);
-}
-
-} // namespace internal
-
-// class TestCase
-
-// Gets the number of successful tests in this test case.
-int TestCase::successful_test_count() const {
- return CountIf(test_info_list_, TestPassed);
-}
-
-// Gets the number of failed tests in this test case.
-int TestCase::failed_test_count() const {
- return CountIf(test_info_list_, TestFailed);
-}
-
-int TestCase::disabled_test_count() const {
- return CountIf(test_info_list_, TestDisabled);
-}
-
-// Get the number of tests in this test case that should run.
-int TestCase::test_to_run_count() const {
- return CountIf(test_info_list_, ShouldRunTest);
-}
-
-// Gets the number of all tests.
-int TestCase::total_test_count() const {
- return static_cast<int>(test_info_list_.size());
-}
-
-// Creates a TestCase with the given name.
-//
-// Arguments:
-//
-// name: name of the test case
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-TestCase::TestCase(const char* a_name, const char* a_comment,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc)
- : name_(a_name),
- comment_(a_comment),
- set_up_tc_(set_up_tc),
- tear_down_tc_(tear_down_tc),
- should_run_(false),
- elapsed_time_(0) {
-}
-
-// Destructor of TestCase.
-TestCase::~TestCase() {
- // Deletes every Test in the collection.
- ForEach(test_info_list_, internal::Delete<TestInfo>);
-}
-
-// Returns the i-th test among all the tests. i can range from 0 to
-// total_test_count() - 1. If i is not in that range, returns NULL.
-const TestInfo* TestCase::GetTestInfo(int i) const {
- const int index = GetElementOr(test_indices_, i, -1);
- return index < 0 ? NULL : test_info_list_[index];
-}
-
-// Returns the i-th test among all the tests. i can range from 0 to
-// total_test_count() - 1. If i is not in that range, returns NULL.
-TestInfo* TestCase::GetMutableTestInfo(int i) {
- const int index = GetElementOr(test_indices_, i, -1);
- return index < 0 ? NULL : test_info_list_[index];
-}
-
-// Adds a test to this test case. Will delete the test upon
-// destruction of the TestCase object.
-void TestCase::AddTestInfo(TestInfo * test_info) {
- test_info_list_.push_back(test_info);
- test_indices_.push_back(static_cast<int>(test_indices_.size()));
-}
-
-// Runs every test in this TestCase.
-void TestCase::Run() {
- if (!should_run_) return;
-
- internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
- impl->set_current_test_case(this);
-
- TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
-
- repeater->OnTestCaseStart(*this);
- impl->os_stack_trace_getter()->UponLeavingGTest();
- set_up_tc_();
-
- const internal::TimeInMillis start = internal::GetTimeInMillis();
- for (int i = 0; i < total_test_count(); i++) {
- GetMutableTestInfo(i)->impl()->Run();
- }
- elapsed_time_ = internal::GetTimeInMillis() - start;
-
- impl->os_stack_trace_getter()->UponLeavingGTest();
- tear_down_tc_();
- repeater->OnTestCaseEnd(*this);
- impl->set_current_test_case(NULL);
-}
-
-// Clears the results of all tests in this test case.
-void TestCase::ClearResult() {
- ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult);
-}
-
-// Returns true iff test passed.
-bool TestCase::TestPassed(const TestInfo * test_info) {
- const internal::TestInfoImpl* const impl = test_info->impl();
- return impl->should_run() && impl->result()->Passed();
-}
-
-// Returns true iff test failed.
-bool TestCase::TestFailed(const TestInfo * test_info) {
- const internal::TestInfoImpl* const impl = test_info->impl();
- return impl->should_run() && impl->result()->Failed();
-}
-
-// Returns true iff test is disabled.
-bool TestCase::TestDisabled(const TestInfo * test_info) {
- return test_info->impl()->is_disabled();
-}
-
-// Returns true if the given test should run.
-bool TestCase::ShouldRunTest(const TestInfo *test_info) {
- return test_info->impl()->should_run();
-}
-
-// Shuffles the tests in this test case.
-void TestCase::ShuffleTests(internal::Random* random) {
- Shuffle(random, &test_indices_);
-}
-
-// Restores the test order to before the first shuffle.
-void TestCase::UnshuffleTests() {
- for (size_t i = 0; i < test_indices_.size(); i++) {
- test_indices_[i] = static_cast<int>(i);
- }
-}
-
-// Formats a countable noun. Depending on its quantity, either the
-// singular form or the plural form is used. e.g.
-//
-// FormatCountableNoun(1, "formula", "formuli") returns "1 formula".
-// FormatCountableNoun(5, "book", "books") returns "5 books".
-static internal::String FormatCountableNoun(int count,
- const char * singular_form,
- const char * plural_form) {
- return internal::String::Format("%d %s", count,
- count == 1 ? singular_form : plural_form);
-}
-
-// Formats the count of tests.
-static internal::String FormatTestCount(int test_count) {
- return FormatCountableNoun(test_count, "test", "tests");
-}
-
-// Formats the count of test cases.
-static internal::String FormatTestCaseCount(int test_case_count) {
- return FormatCountableNoun(test_case_count, "test case", "test cases");
-}
-
-// Converts a TestPartResult::Type enum to human-friendly string
-// representation. Both kNonFatalFailure and kFatalFailure are translated
-// to "Failure", as the user usually doesn't care about the difference
-// between the two when viewing the test result.
-static const char * TestPartResultTypeToString(TestPartResult::Type type) {
- switch (type) {
- case TestPartResult::kSuccess:
- return "Success";
-
- case TestPartResult::kNonFatalFailure:
- case TestPartResult::kFatalFailure:
-#ifdef _MSC_VER
- return "error: ";
-#else
- return "Failure\n";
-#endif
- }
-
- return "Unknown result type";
-}
-
-// Prints a TestPartResult to a String.
-static internal::String PrintTestPartResultToString(
- const TestPartResult& test_part_result) {
- return (Message()
- << internal::FormatFileLocation(test_part_result.file_name(),
- test_part_result.line_number())
- << " " << TestPartResultTypeToString(test_part_result.type())
- << test_part_result.message()).GetString();
-}
-
-// Prints a TestPartResult.
-static void PrintTestPartResult(const TestPartResult& test_part_result) {
- const internal::String& result =
- PrintTestPartResultToString(test_part_result);
- printf("%s\n", result.c_str());
- fflush(stdout);
- // If the test program runs in Visual Studio or a debugger, the
- // following statements add the test part result message to the Output
- // window such that the user can double-click on it to jump to the
- // corresponding source code location; otherwise they do nothing.
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
- // We don't call OutputDebugString*() on Windows Mobile, as printing
- // to stdout is done by OutputDebugString() there already - we don't
- // want the same message printed twice.
- ::OutputDebugStringA(result.c_str());
- ::OutputDebugStringA("\n");
-#endif
-}
-
-// class PrettyUnitTestResultPrinter
-
-namespace internal {
-
-enum GTestColor {
- COLOR_DEFAULT,
- COLOR_RED,
- COLOR_GREEN,
- COLOR_YELLOW
-};
-
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
-
-// Returns the character attribute for the given color.
-WORD GetColorAttribute(GTestColor color) {
- switch (color) {
- case COLOR_RED: return FOREGROUND_RED;
- case COLOR_GREEN: return FOREGROUND_GREEN;
- case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
- default: return 0;
- }
-}
-
-#else
-
-// Returns the ANSI color code for the given color. COLOR_DEFAULT is
-// an invalid input.
-const char* GetAnsiColorCode(GTestColor color) {
- switch (color) {
- case COLOR_RED: return "1";
- case COLOR_GREEN: return "2";
- case COLOR_YELLOW: return "3";
- default: return NULL;
- };
-}
-
-#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
-
-// Returns true iff Google Test should use colors in the output.
-bool ShouldUseColor(bool stdout_is_tty) {
- const char* const gtest_color = GTEST_FLAG(color).c_str();
-
- if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) {
-#if GTEST_OS_WINDOWS
- // On Windows the TERM variable is usually not set, but the
- // console there does support colors.
- return stdout_is_tty;
-#else
- // On non-Windows platforms, we rely on the TERM variable.
- const char* const term = posix::GetEnv("TERM");
- const bool term_supports_color =
- String::CStringEquals(term, "xterm") ||
- String::CStringEquals(term, "xterm-color") ||
- String::CStringEquals(term, "xterm-256color") ||
- String::CStringEquals(term, "linux") ||
- String::CStringEquals(term, "cygwin");
- return stdout_is_tty && term_supports_color;
-#endif // GTEST_OS_WINDOWS
- }
-
- return String::CaseInsensitiveCStringEquals(gtest_color, "yes") ||
- String::CaseInsensitiveCStringEquals(gtest_color, "true") ||
- String::CaseInsensitiveCStringEquals(gtest_color, "t") ||
- String::CStringEquals(gtest_color, "1");
- // We take "yes", "true", "t", and "1" as meaning "yes". If the
- // value is neither one of these nor "auto", we treat it as "no" to
- // be conservative.
-}
-
-// Helpers for printing colored strings to stdout. Note that on Windows, we
-// cannot simply emit special characters and have the terminal change colors.
-// This routine must actually emit the characters rather than return a string
-// that would be colored when printed, as can be done on Linux.
-void ColoredPrintf(GTestColor color, const char* fmt, ...) {
- va_list args;
- va_start(args, fmt);
-
-#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
- const bool use_color = false;
-#else
- static const bool in_color_mode =
- ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0);
- const bool use_color = in_color_mode && (color != COLOR_DEFAULT);
-#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS
- // The '!= 0' comparison is necessary to satisfy MSVC 7.1.
-
- if (!use_color) {
- vprintf(fmt, args);
- va_end(args);
- return;
- }
-
-#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
- const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
-
- // Gets the current text color.
- CONSOLE_SCREEN_BUFFER_INFO buffer_info;
- GetConsoleScreenBufferInfo(stdout_handle, &buffer_info);
- const WORD old_color_attrs = buffer_info.wAttributes;
-
- // We need to flush the stream buffers into the console before each
- // SetConsoleTextAttribute call lest it affect the text that is already
- // printed but has not yet reached the console.
- fflush(stdout);
- SetConsoleTextAttribute(stdout_handle,
- GetColorAttribute(color) | FOREGROUND_INTENSITY);
- vprintf(fmt, args);
-
- fflush(stdout);
- // Restores the text color.
- SetConsoleTextAttribute(stdout_handle, old_color_attrs);
-#else
- printf("\033[0;3%sm", GetAnsiColorCode(color));
- vprintf(fmt, args);
- printf("\033[m"); // Resets the terminal to default.
-#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE
- va_end(args);
-}
-
-// This class implements the TestEventListener interface.
-//
-// Class PrettyUnitTestResultPrinter is copyable.
-class PrettyUnitTestResultPrinter : public TestEventListener {
- public:
- PrettyUnitTestResultPrinter() {}
- static void PrintTestName(const char * test_case, const char * test) {
- printf("%s.%s", test_case, test);
- }
-
- // The following methods override what's in the TestEventListener class.
- virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
- virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestCaseStart(const TestCase& test_case);
- virtual void OnTestStart(const TestInfo& test_info);
- virtual void OnTestPartResult(const TestPartResult& result);
- virtual void OnTestEnd(const TestInfo& test_info);
- virtual void OnTestCaseEnd(const TestCase& test_case);
- virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {}
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
- virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {}
-
- private:
- static void PrintFailedTests(const UnitTest& unit_test);
-
- internal::String test_case_name_;
-};
-
- // Fired before each iteration of tests starts.
-void PrettyUnitTestResultPrinter::OnTestIterationStart(
- const UnitTest& unit_test, int iteration) {
- if (GTEST_FLAG(repeat) != 1)
- printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1);
-
- const char* const filter = GTEST_FLAG(filter).c_str();
-
- // Prints the filter if it's not *. This reminds the user that some
- // tests may be skipped.
- if (!internal::String::CStringEquals(filter, kUniversalFilter)) {
- ColoredPrintf(COLOR_YELLOW,
- "Note: %s filter = %s\n", GTEST_NAME_, filter);
- }
-
- if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) {
- ColoredPrintf(COLOR_YELLOW,
- "Note: This is test shard %s of %s.\n",
- internal::posix::GetEnv(kTestShardIndex),
- internal::posix::GetEnv(kTestTotalShards));
- }
-
- if (GTEST_FLAG(shuffle)) {
- ColoredPrintf(COLOR_YELLOW,
- "Note: Randomizing tests' orders with a seed of %d .\n",
- unit_test.random_seed());
- }
-
- ColoredPrintf(COLOR_GREEN, "[==========] ");
- printf("Running %s from %s.\n",
- FormatTestCount(unit_test.test_to_run_count()).c_str(),
- FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart(
- const UnitTest& /*unit_test*/) {
- ColoredPrintf(COLOR_GREEN, "[----------] ");
- printf("Global test environment set-up.\n");
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) {
- test_case_name_ = test_case.name();
- const internal::String counts =
- FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
- ColoredPrintf(COLOR_GREEN, "[----------] ");
- printf("%s from %s", counts.c_str(), test_case_name_.c_str());
- if (test_case.comment()[0] == '\0') {
- printf("\n");
- } else {
- printf(", where %s\n", test_case.comment());
- }
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) {
- ColoredPrintf(COLOR_GREEN, "[ RUN ] ");
- PrintTestName(test_case_name_.c_str(), test_info.name());
- if (test_info.comment()[0] == '\0') {
- printf("\n");
- } else {
- printf(", where %s\n", test_info.comment());
- }
- fflush(stdout);
-}
-
-// Called after an assertion failure.
-void PrettyUnitTestResultPrinter::OnTestPartResult(
- const TestPartResult& result) {
- // If the test part succeeded, we don't need to do anything.
- if (result.type() == TestPartResult::kSuccess)
- return;
-
- // Print failure message from the assertion (e.g. expected this and got that).
- PrintTestPartResult(result);
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) {
- if (test_info.result()->Passed()) {
- ColoredPrintf(COLOR_GREEN, "[ OK ] ");
- } else {
- ColoredPrintf(COLOR_RED, "[ FAILED ] ");
- }
- PrintTestName(test_case_name_.c_str(), test_info.name());
- if (GTEST_FLAG(print_time)) {
- printf(" (%s ms)\n", internal::StreamableToString(
- test_info.result()->elapsed_time()).c_str());
- } else {
- printf("\n");
- }
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) {
- if (!GTEST_FLAG(print_time)) return;
-
- test_case_name_ = test_case.name();
- const internal::String counts =
- FormatCountableNoun(test_case.test_to_run_count(), "test", "tests");
- ColoredPrintf(COLOR_GREEN, "[----------] ");
- printf("%s from %s (%s ms total)\n\n",
- counts.c_str(), test_case_name_.c_str(),
- internal::StreamableToString(test_case.elapsed_time()).c_str());
- fflush(stdout);
-}
-
-void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart(
- const UnitTest& /*unit_test*/) {
- ColoredPrintf(COLOR_GREEN, "[----------] ");
- printf("Global test environment tear-down\n");
- fflush(stdout);
-}
-
-// Internal helper for printing the list of failed tests.
-void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) {
- const int failed_test_count = unit_test.failed_test_count();
- if (failed_test_count == 0) {
- return;
- }
-
- for (int i = 0; i < unit_test.total_test_case_count(); ++i) {
- const TestCase& test_case = *unit_test.GetTestCase(i);
- if (!test_case.should_run() || (test_case.failed_test_count() == 0)) {
- continue;
- }
- for (int j = 0; j < test_case.total_test_count(); ++j) {
- const TestInfo& test_info = *test_case.GetTestInfo(j);
- if (!test_info.should_run() || test_info.result()->Passed()) {
- continue;
- }
- ColoredPrintf(COLOR_RED, "[ FAILED ] ");
- printf("%s.%s", test_case.name(), test_info.name());
- if (test_case.comment()[0] != '\0' ||
- test_info.comment()[0] != '\0') {
- printf(", where %s", test_case.comment());
- if (test_case.comment()[0] != '\0' &&
- test_info.comment()[0] != '\0') {
- printf(" and ");
- }
- }
- printf("%s\n", test_info.comment());
- }
- }
-}
-
- void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
- int /*iteration*/) {
- ColoredPrintf(COLOR_GREEN, "[==========] ");
- printf("%s from %s ran.",
- FormatTestCount(unit_test.test_to_run_count()).c_str(),
- FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str());
- if (GTEST_FLAG(print_time)) {
- printf(" (%s ms total)",
- internal::StreamableToString(unit_test.elapsed_time()).c_str());
- }
- printf("\n");
- ColoredPrintf(COLOR_GREEN, "[ PASSED ] ");
- printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str());
-
- int num_failures = unit_test.failed_test_count();
- if (!unit_test.Passed()) {
- const int failed_test_count = unit_test.failed_test_count();
- ColoredPrintf(COLOR_RED, "[ FAILED ] ");
- printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str());
- PrintFailedTests(unit_test);
- printf("\n%2d FAILED %s\n", num_failures,
- num_failures == 1 ? "TEST" : "TESTS");
- }
-
- int num_disabled = unit_test.disabled_test_count();
- if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) {
- if (!num_failures) {
- printf("\n"); // Add a spacer if no FAILURE banner is displayed.
- }
- ColoredPrintf(COLOR_YELLOW,
- " YOU HAVE %d DISABLED %s\n\n",
- num_disabled,
- num_disabled == 1 ? "TEST" : "TESTS");
- }
- // Ensure that Google Test output is printed before, e.g., heapchecker output.
- fflush(stdout);
-}
-
-// End PrettyUnitTestResultPrinter
-
-// class TestEventRepeater
-//
-// This class forwards events to other event listeners.
-class TestEventRepeater : public TestEventListener {
- public:
- TestEventRepeater() : forwarding_enabled_(true) {}
- virtual ~TestEventRepeater();
- void Append(TestEventListener *listener);
- TestEventListener* Release(TestEventListener* listener);
-
- // Controls whether events will be forwarded to listeners_. Set to false
- // in death test child processes.
- bool forwarding_enabled() const { return forwarding_enabled_; }
- void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; }
-
- virtual void OnTestProgramStart(const UnitTest& unit_test);
- virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration);
- virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test);
- virtual void OnTestCaseStart(const TestCase& test_case);
- virtual void OnTestStart(const TestInfo& test_info);
- virtual void OnTestPartResult(const TestPartResult& result);
- virtual void OnTestEnd(const TestInfo& test_info);
- virtual void OnTestCaseEnd(const TestCase& test_case);
- virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test);
- virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test);
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
- virtual void OnTestProgramEnd(const UnitTest& unit_test);
-
- private:
- // Controls whether events will be forwarded to listeners_. Set to false
- // in death test child processes.
- bool forwarding_enabled_;
- // The list of listeners that receive events.
- std::vector<TestEventListener*> listeners_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater);
-};
-
-TestEventRepeater::~TestEventRepeater() {
- ForEach(listeners_, Delete<TestEventListener>);
-}
-
-void TestEventRepeater::Append(TestEventListener *listener) {
- listeners_.push_back(listener);
-}
-
-// TODO(vladl@google.com): Factor the search functionality into Vector::Find.
-TestEventListener* TestEventRepeater::Release(TestEventListener *listener) {
- for (size_t i = 0; i < listeners_.size(); ++i) {
- if (listeners_[i] == listener) {
- listeners_.erase(listeners_.begin() + i);
- return listener;
- }
- }
-
- return NULL;
-}
-
-// Since most methods are very similar, use macros to reduce boilerplate.
-// This defines a member that forwards the call to all listeners.
-#define GTEST_REPEATER_METHOD_(Name, Type) \
-void TestEventRepeater::Name(const Type& parameter) { \
- if (forwarding_enabled_) { \
- for (size_t i = 0; i < listeners_.size(); i++) { \
- listeners_[i]->Name(parameter); \
- } \
- } \
-}
-// This defines a member that forwards the call to all listeners in reverse
-// order.
-#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \
-void TestEventRepeater::Name(const Type& parameter) { \
- if (forwarding_enabled_) { \
- for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) { \
- listeners_[i]->Name(parameter); \
- } \
- } \
-}
-
-GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest)
-GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest)
-GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase)
-GTEST_REPEATER_METHOD_(OnTestStart, TestInfo)
-GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult)
-GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest)
-GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest)
-GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest)
-GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo)
-GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase)
-GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest)
-
-#undef GTEST_REPEATER_METHOD_
-#undef GTEST_REVERSE_REPEATER_METHOD_
-
-void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test,
- int iteration) {
- if (forwarding_enabled_) {
- for (size_t i = 0; i < listeners_.size(); i++) {
- listeners_[i]->OnTestIterationStart(unit_test, iteration);
- }
- }
-}
-
-void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test,
- int iteration) {
- if (forwarding_enabled_) {
- for (int i = static_cast<int>(listeners_.size()) - 1; i >= 0; i--) {
- listeners_[i]->OnTestIterationEnd(unit_test, iteration);
- }
- }
-}
-
-// End TestEventRepeater
-
-// This class generates an XML output file.
-class XmlUnitTestResultPrinter : public EmptyTestEventListener {
- public:
- explicit XmlUnitTestResultPrinter(const char* output_file);
-
- virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration);
-
- private:
- // Is c a whitespace character that is normalized to a space character
- // when it appears in an XML attribute value?
- static bool IsNormalizableWhitespace(char c) {
- return c == 0x9 || c == 0xA || c == 0xD;
- }
-
- // May c appear in a well-formed XML document?
- static bool IsValidXmlCharacter(char c) {
- return IsNormalizableWhitespace(c) || c >= 0x20;
- }
-
- // Returns an XML-escaped copy of the input string str. If
- // is_attribute is true, the text is meant to appear as an attribute
- // value, and normalizable whitespace is preserved by replacing it
- // with character references.
- static String EscapeXml(const char* str, bool is_attribute);
-
- // Returns the given string with all characters invalid in XML removed.
- static String RemoveInvalidXmlCharacters(const char* str);
-
- // Convenience wrapper around EscapeXml when str is an attribute value.
- static String EscapeXmlAttribute(const char* str) {
- return EscapeXml(str, true);
- }
-
- // Convenience wrapper around EscapeXml when str is not an attribute value.
- static String EscapeXmlText(const char* str) { return EscapeXml(str, false); }
-
- // Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
- static void OutputXmlCDataSection(::std::ostream* stream, const char* data);
-
- // Streams an XML representation of a TestInfo object.
- static void OutputXmlTestInfo(::std::ostream* stream,
- const char* test_case_name,
- const TestInfo& test_info);
-
- // Prints an XML representation of a TestCase object
- static void PrintXmlTestCase(FILE* out, const TestCase& test_case);
-
- // Prints an XML summary of unit_test to output stream out.
- static void PrintXmlUnitTest(FILE* out, const UnitTest& unit_test);
-
- // Produces a string representing the test properties in a result as space
- // delimited XML attributes based on the property key="value" pairs.
- // When the String is not empty, it includes a space at the beginning,
- // to delimit this attribute from prior attributes.
- static String TestPropertiesAsXmlAttributes(const TestResult& result);
-
- // The output file.
- const String output_file_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter);
-};
-
-// Creates a new XmlUnitTestResultPrinter.
-XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file)
- : output_file_(output_file) {
- if (output_file_.c_str() == NULL || output_file_.empty()) {
- fprintf(stderr, "XML output file may not be null\n");
- fflush(stderr);
- exit(EXIT_FAILURE);
- }
-}
-
-// Called after the unit test ends.
-void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test,
- int /*iteration*/) {
- FILE* xmlout = NULL;
- FilePath output_file(output_file_);
- FilePath output_dir(output_file.RemoveFileName());
-
- if (output_dir.CreateDirectoriesRecursively()) {
- xmlout = posix::FOpen(output_file_.c_str(), "w");
- }
- if (xmlout == NULL) {
- // TODO(wan): report the reason of the failure.
- //
- // We don't do it for now as:
- //
- // 1. There is no urgent need for it.
- // 2. It's a bit involved to make the errno variable thread-safe on
- // all three operating systems (Linux, Windows, and Mac OS).
- // 3. To interpret the meaning of errno in a thread-safe way,
- // we need the strerror_r() function, which is not available on
- // Windows.
- fprintf(stderr,
- "Unable to open file \"%s\"\n",
- output_file_.c_str());
- fflush(stderr);
- exit(EXIT_FAILURE);
- }
- PrintXmlUnitTest(xmlout, unit_test);
- fclose(xmlout);
-}
-
-// Returns an XML-escaped copy of the input string str. If is_attribute
-// is true, the text is meant to appear as an attribute value, and
-// normalizable whitespace is preserved by replacing it with character
-// references.
-//
-// Invalid XML characters in str, if any, are stripped from the output.
-// It is expected that most, if not all, of the text processed by this
-// module will consist of ordinary English text.
-// If this module is ever modified to produce version 1.1 XML output,
-// most invalid characters can be retained using character references.
-// TODO(wan): It might be nice to have a minimally invasive, human-readable
-// escaping scheme for invalid characters, rather than dropping them.
-String XmlUnitTestResultPrinter::EscapeXml(const char* str, bool is_attribute) {
- Message m;
-
- if (str != NULL) {
- for (const char* src = str; *src; ++src) {
- switch (*src) {
- case '<':
- m << "<";
- break;
- case '>':
- m << ">";
- break;
- case '&':
- m << "&";
- break;
- case '\'':
- if (is_attribute)
- m << "'";
- else
- m << '\'';
- break;
- case '"':
- if (is_attribute)
- m << """;
- else
- m << '"';
- break;
- default:
- if (IsValidXmlCharacter(*src)) {
- if (is_attribute && IsNormalizableWhitespace(*src))
- m << String::Format("&#x%02X;", unsigned(*src));
- else
- m << *src;
- }
- break;
- }
- }
- }
-
- return m.GetString();
-}
-
-// Returns the given string with all characters invalid in XML removed.
-// Currently invalid characters are dropped from the string. An
-// alternative is to replace them with certain characters such as . or ?.
-String XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters(const char* str) {
- char* const output = new char[strlen(str) + 1];
- char* appender = output;
- for (char ch = *str; ch != '\0'; ch = *++str)
- if (IsValidXmlCharacter(ch))
- *appender++ = ch;
- *appender = '\0';
-
- String ret_value(output);
- delete[] output;
- return ret_value;
-}
-
-// The following routines generate an XML representation of a UnitTest
-// object.
-//
-// This is how Google Test concepts map to the DTD:
-//
-// <testsuites name="AllTests"> <-- corresponds to a UnitTest object
-// <testsuite name="testcase-name"> <-- corresponds to a TestCase object
-// <testcase name="test-name"> <-- corresponds to a TestInfo object
-// <failure message="...">...</failure>
-// <failure message="...">...</failure>
-// <failure message="...">...</failure>
-// <-- individual assertion failures
-// </testcase>
-// </testsuite>
-// </testsuites>
-
-// Formats the given time in milliseconds as seconds.
-std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) {
- ::std::stringstream ss;
- ss << ms/1000.0;
- return ss.str();
-}
-
-// Streams an XML CDATA section, escaping invalid CDATA sequences as needed.
-void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream,
- const char* data) {
- const char* segment = data;
- *stream << "<![CDATA[";
- for (;;) {
- const char* const next_segment = strstr(segment, "]]>");
- if (next_segment != NULL) {
- stream->write(
- segment, static_cast<std::streamsize>(next_segment - segment));
- *stream << "]]>]]><![CDATA[";
- segment = next_segment + strlen("]]>");
- } else {
- *stream << segment;
- break;
- }
- }
- *stream << "]]>";
-}
-
-// Prints an XML representation of a TestInfo object.
-// TODO(wan): There is also value in printing properties with the plain printer.
-void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream,
- const char* test_case_name,
- const TestInfo& test_info) {
- const TestResult& result = *test_info.result();
- *stream << " <testcase name=\""
- << EscapeXmlAttribute(test_info.name()).c_str()
- << "\" status=\""
- << (test_info.should_run() ? "run" : "notrun")
- << "\" time=\""
- << FormatTimeInMillisAsSeconds(result.elapsed_time())
- << "\" classname=\"" << EscapeXmlAttribute(test_case_name).c_str()
- << "\"" << TestPropertiesAsXmlAttributes(result).c_str();
-
- int failures = 0;
- for (int i = 0; i < result.total_part_count(); ++i) {
- const TestPartResult& part = result.GetTestPartResult(i);
- if (part.failed()) {
- if (++failures == 1)
- *stream << ">\n";
- *stream << " <failure message=\""
- << EscapeXmlAttribute(part.summary()).c_str()
- << "\" type=\"\">";
- const String message = RemoveInvalidXmlCharacters(String::Format(
- "%s:%d\n%s",
- part.file_name(), part.line_number(),
- part.message()).c_str());
- OutputXmlCDataSection(stream, message.c_str());
- *stream << "</failure>\n";
- }
- }
-
- if (failures == 0)
- *stream << " />\n";
- else
- *stream << " </testcase>\n";
-}
-
-// Prints an XML representation of a TestCase object
-void XmlUnitTestResultPrinter::PrintXmlTestCase(FILE* out,
- const TestCase& test_case) {
- fprintf(out,
- " <testsuite name=\"%s\" tests=\"%d\" failures=\"%d\" "
- "disabled=\"%d\" ",
- EscapeXmlAttribute(test_case.name()).c_str(),
- test_case.total_test_count(),
- test_case.failed_test_count(),
- test_case.disabled_test_count());
- fprintf(out,
- "errors=\"0\" time=\"%s\">\n",
- FormatTimeInMillisAsSeconds(test_case.elapsed_time()).c_str());
- for (int i = 0; i < test_case.total_test_count(); ++i) {
- StrStream stream;
- OutputXmlTestInfo(&stream, test_case.name(), *test_case.GetTestInfo(i));
- fprintf(out, "%s", StrStreamToString(&stream).c_str());
- }
- fprintf(out, " </testsuite>\n");
-}
-
-// Prints an XML summary of unit_test to output stream out.
-void XmlUnitTestResultPrinter::PrintXmlUnitTest(FILE* out,
- const UnitTest& unit_test) {
- fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- fprintf(out,
- "<testsuites tests=\"%d\" failures=\"%d\" disabled=\"%d\" "
- "errors=\"0\" time=\"%s\" ",
- unit_test.total_test_count(),
- unit_test.failed_test_count(),
- unit_test.disabled_test_count(),
- FormatTimeInMillisAsSeconds(unit_test.elapsed_time()).c_str());
- if (GTEST_FLAG(shuffle)) {
- fprintf(out, "random_seed=\"%d\" ", unit_test.random_seed());
- }
- fprintf(out, "name=\"AllTests\">\n");
- for (int i = 0; i < unit_test.total_test_case_count(); ++i)
- PrintXmlTestCase(out, *unit_test.GetTestCase(i));
- fprintf(out, "</testsuites>\n");
-}
-
-// Produces a string representing the test properties in a result as space
-// delimited XML attributes based on the property key="value" pairs.
-String XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes(
- const TestResult& result) {
- Message attributes;
- for (int i = 0; i < result.test_property_count(); ++i) {
- const TestProperty& property = result.GetTestProperty(i);
- attributes << " " << property.key() << "="
- << "\"" << EscapeXmlAttribute(property.value()) << "\"";
- }
- return attributes.GetString();
-}
-
-// End XmlUnitTestResultPrinter
-
-// Class ScopedTrace
-
-// Pushes the given source file location and message onto a per-thread
-// trace stack maintained by Google Test.
-// L < UnitTest::mutex_
-ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) {
- TraceInfo trace;
- trace.file = file;
- trace.line = line;
- trace.message = message.GetString();
-
- UnitTest::GetInstance()->PushGTestTrace(trace);
-}
-
-// Pops the info pushed by the c'tor.
-// L < UnitTest::mutex_
-ScopedTrace::~ScopedTrace() {
- UnitTest::GetInstance()->PopGTestTrace();
-}
-
-
-// class OsStackTraceGetter
-
-// Returns the current OS stack trace as a String. Parameters:
-//
-// max_depth - the maximum number of stack frames to be included
-// in the trace.
-// skip_count - the number of top frames to be skipped; doesn't count
-// against max_depth.
-//
-// L < mutex_
-// We use "L < mutex_" to denote that the function may acquire mutex_.
-String OsStackTraceGetter::CurrentStackTrace(int, int) {
- return String("");
-}
-
-// L < mutex_
-void OsStackTraceGetter::UponLeavingGTest() {
-}
-
-const char* const
-OsStackTraceGetter::kElidedFramesMarker =
- "... " GTEST_NAME_ " internal frames ...";
-
-} // namespace internal
-
-// class TestEventListeners
-
-TestEventListeners::TestEventListeners()
- : repeater_(new internal::TestEventRepeater()),
- default_result_printer_(NULL),
- default_xml_generator_(NULL) {
-}
-
-TestEventListeners::~TestEventListeners() { delete repeater_; }
-
-// Returns the standard listener responsible for the default console
-// output. Can be removed from the listeners list to shut down default
-// console output. Note that removing this object from the listener list
-// with Release transfers its ownership to the user.
-void TestEventListeners::Append(TestEventListener* listener) {
- repeater_->Append(listener);
-}
-
-// Removes the given event listener from the list and returns it. It then
-// becomes the caller's responsibility to delete the listener. Returns
-// NULL if the listener is not found in the list.
-TestEventListener* TestEventListeners::Release(TestEventListener* listener) {
- if (listener == default_result_printer_)
- default_result_printer_ = NULL;
- else if (listener == default_xml_generator_)
- default_xml_generator_ = NULL;
- return repeater_->Release(listener);
-}
-
-// Returns repeater that broadcasts the TestEventListener events to all
-// subscribers.
-TestEventListener* TestEventListeners::repeater() { return repeater_; }
-
-// Sets the default_result_printer attribute to the provided listener.
-// The listener is also added to the listener list and previous
-// default_result_printer is removed from it and deleted. The listener can
-// also be NULL in which case it will not be added to the list. Does
-// nothing if the previous and the current listener objects are the same.
-void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) {
- if (default_result_printer_ != listener) {
- // It is an error to pass this method a listener that is already in the
- // list.
- delete Release(default_result_printer_);
- default_result_printer_ = listener;
- if (listener != NULL)
- Append(listener);
- }
-}
-
-// Sets the default_xml_generator attribute to the provided listener. The
-// listener is also added to the listener list and previous
-// default_xml_generator is removed from it and deleted. The listener can
-// also be NULL in which case it will not be added to the list. Does
-// nothing if the previous and the current listener objects are the same.
-void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) {
- if (default_xml_generator_ != listener) {
- // It is an error to pass this method a listener that is already in the
- // list.
- delete Release(default_xml_generator_);
- default_xml_generator_ = listener;
- if (listener != NULL)
- Append(listener);
- }
-}
-
-// Controls whether events will be forwarded by the repeater to the
-// listeners in the list.
-bool TestEventListeners::EventForwardingEnabled() const {
- return repeater_->forwarding_enabled();
-}
-
-void TestEventListeners::SuppressEventForwarding() {
- repeater_->set_forwarding_enabled(false);
-}
-
-// class UnitTest
-
-// Gets the singleton UnitTest object. The first time this method is
-// called, a UnitTest object is constructed and returned. Consecutive
-// calls will return the same object.
-//
-// We don't protect this under mutex_ as a user is not supposed to
-// call this before main() starts, from which point on the return
-// value will never change.
-UnitTest * UnitTest::GetInstance() {
- // When compiled with MSVC 7.1 in optimized mode, destroying the
- // UnitTest object upon exiting the program messes up the exit code,
- // causing successful tests to appear failed. We have to use a
- // different implementation in this case to bypass the compiler bug.
- // This implementation makes the compiler happy, at the cost of
- // leaking the UnitTest object.
-
- // CodeGear C++Builder insists on a public destructor for the
- // default implementation. Use this implementation to keep good OO
- // design with private destructor.
-
-#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
- static UnitTest* const instance = new UnitTest;
- return instance;
-#else
- static UnitTest instance;
- return &instance;
-#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__)
-}
-
-// Gets the number of successful test cases.
-int UnitTest::successful_test_case_count() const {
- return impl()->successful_test_case_count();
-}
-
-// Gets the number of failed test cases.
-int UnitTest::failed_test_case_count() const {
- return impl()->failed_test_case_count();
-}
-
-// Gets the number of all test cases.
-int UnitTest::total_test_case_count() const {
- return impl()->total_test_case_count();
-}
-
-// Gets the number of all test cases that contain at least one test
-// that should run.
-int UnitTest::test_case_to_run_count() const {
- return impl()->test_case_to_run_count();
-}
-
-// Gets the number of successful tests.
-int UnitTest::successful_test_count() const {
- return impl()->successful_test_count();
-}
-
-// Gets the number of failed tests.
-int UnitTest::failed_test_count() const { return impl()->failed_test_count(); }
-
-// Gets the number of disabled tests.
-int UnitTest::disabled_test_count() const {
- return impl()->disabled_test_count();
-}
-
-// Gets the number of all tests.
-int UnitTest::total_test_count() const { return impl()->total_test_count(); }
-
-// Gets the number of tests that should run.
-int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); }
-
-// Gets the elapsed time, in milliseconds.
-internal::TimeInMillis UnitTest::elapsed_time() const {
- return impl()->elapsed_time();
-}
-
-// Returns true iff the unit test passed (i.e. all test cases passed).
-bool UnitTest::Passed() const { return impl()->Passed(); }
-
-// Returns true iff the unit test failed (i.e. some test case failed
-// or something outside of all tests failed).
-bool UnitTest::Failed() const { return impl()->Failed(); }
-
-// Gets the i-th test case among all the test cases. i can range from 0 to
-// total_test_case_count() - 1. If i is not in that range, returns NULL.
-const TestCase* UnitTest::GetTestCase(int i) const {
- return impl()->GetTestCase(i);
-}
-
-// Gets the i-th test case among all the test cases. i can range from 0 to
-// total_test_case_count() - 1. If i is not in that range, returns NULL.
-TestCase* UnitTest::GetMutableTestCase(int i) {
- return impl()->GetMutableTestCase(i);
-}
-
-// Returns the list of event listeners that can be used to track events
-// inside Google Test.
-TestEventListeners& UnitTest::listeners() {
- return *impl()->listeners();
-}
-
-// Registers and returns a global test environment. When a test
-// program is run, all global test environments will be set-up in the
-// order they were registered. After all tests in the program have
-// finished, all global test environments will be torn-down in the
-// *reverse* order they were registered.
-//
-// The UnitTest object takes ownership of the given environment.
-//
-// We don't protect this under mutex_, as we only support calling it
-// from the main thread.
-Environment* UnitTest::AddEnvironment(Environment* env) {
- if (env == NULL) {
- return NULL;
- }
-
- impl_->environments().push_back(env);
- return env;
-}
-
-#if GTEST_HAS_EXCEPTIONS
-// A failed Google Test assertion will throw an exception of this type
-// when exceptions are enabled. We derive it from std::runtime_error,
-// which is for errors presumably detectable only at run time. Since
-// std::runtime_error inherits from std::exception, many testing
-// frameworks know how to extract and print the message inside it.
-class GoogleTestFailureException : public ::std::runtime_error {
- public:
- explicit GoogleTestFailureException(const TestPartResult& failure)
- : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
-};
-#endif
-
-// Adds a TestPartResult to the current TestResult object. All Google Test
-// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
-// this to report their results. The user code should use the
-// assertion macros instead of calling this directly.
-// L < mutex_
-void UnitTest::AddTestPartResult(TestPartResult::Type result_type,
- const char* file_name,
- int line_number,
- const internal::String& message,
- const internal::String& os_stack_trace) {
- Message msg;
- msg << message;
-
- internal::MutexLock lock(&mutex_);
- if (impl_->gtest_trace_stack().size() > 0) {
- msg << "\n" << GTEST_NAME_ << " trace:";
-
- for (int i = static_cast<int>(impl_->gtest_trace_stack().size());
- i > 0; --i) {
- const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1];
- msg << "\n" << internal::FormatFileLocation(trace.file, trace.line)
- << " " << trace.message;
- }
- }
-
- if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) {
- msg << internal::kStackTraceMarker << os_stack_trace;
- }
-
- const TestPartResult result =
- TestPartResult(result_type, file_name, line_number,
- msg.GetString().c_str());
- impl_->GetTestPartResultReporterForCurrentThread()->
- ReportTestPartResult(result);
-
- if (result_type != TestPartResult::kSuccess) {
- // gtest_break_on_failure takes precedence over
- // gtest_throw_on_failure. This allows a user to set the latter
- // in the code (perhaps in order to use Google Test assertions
- // with another testing framework) and specify the former on the
- // command line for debugging.
- if (GTEST_FLAG(break_on_failure)) {
-#if GTEST_OS_WINDOWS
- // Using DebugBreak on Windows allows gtest to still break into a debugger
- // when a failure happens and both the --gtest_break_on_failure and
- // the --gtest_catch_exceptions flags are specified.
- DebugBreak();
-#else
- *static_cast<int*>(NULL) = 1;
-#endif // GTEST_OS_WINDOWS
- } else if (GTEST_FLAG(throw_on_failure)) {
-#if GTEST_HAS_EXCEPTIONS
- throw GoogleTestFailureException(result);
-#else
- // We cannot call abort() as it generates a pop-up in debug mode
- // that cannot be suppressed in VC 7.1 or below.
- exit(1);
-#endif
- }
- }
-}
-
-// Creates and adds a property to the current TestResult. If a property matching
-// the supplied value already exists, updates its value instead.
-void UnitTest::RecordPropertyForCurrentTest(const char* key,
- const char* value) {
- const TestProperty test_property(key, value);
- impl_->current_test_result()->RecordProperty(test_property);
-}
-
-// Runs all tests in this UnitTest object and prints the result.
-// Returns 0 if successful, or 1 otherwise.
-//
-// We don't protect this under mutex_, as we only support calling it
-// from the main thread.
-int UnitTest::Run() {
-#if GTEST_HAS_SEH
- // Catch SEH-style exceptions.
-
- const bool in_death_test_child_process =
- internal::GTEST_FLAG(internal_run_death_test).length() > 0;
-
- // Either the user wants Google Test to catch exceptions thrown by the
- // tests or this is executing in the context of death test child
- // process. In either case the user does not want to see pop-up dialogs
- // about crashes - they are expected..
- if (GTEST_FLAG(catch_exceptions) || in_death_test_child_process) {
-#if !GTEST_OS_WINDOWS_MOBILE
- // SetErrorMode doesn't exist on CE.
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT |
- SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
-#endif // !GTEST_OS_WINDOWS_MOBILE
-
-#if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE
- // Death test children can be terminated with _abort(). On Windows,
- // _abort() can show a dialog with a warning message. This forces the
- // abort message to go to stderr instead.
- _set_error_mode(_OUT_TO_STDERR);
-#endif
-
-#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE
- // In the debug version, Visual Studio pops up a separate dialog
- // offering a choice to debug the aborted program. We need to suppress
- // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement
- // executed. Google Test will notify the user of any unexpected
- // failure via stderr.
- //
- // VC++ doesn't define _set_abort_behavior() prior to the version 8.0.
- // Users of prior VC versions shall suffer the agony and pain of
- // clicking through the countless debug dialogs.
- // TODO(vladl@google.com): find a way to suppress the abort dialog() in the
- // debug mode when compiled with VC 7.1 or lower.
- if (!GTEST_FLAG(break_on_failure))
- _set_abort_behavior(
- 0x0, // Clear the following flags:
- _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump.
-#endif
- }
-
- __try {
- return impl_->RunAllTests();
- } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
- GetExceptionCode())) {
- printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
- fflush(stdout);
- return 1;
- }
-
-#else // We are on a compiler or platform that doesn't support SEH.
-
- return impl_->RunAllTests();
-#endif // GTEST_HAS_SEH
-}
-
-// Returns the working directory when the first TEST() or TEST_F() was
-// executed.
-const char* UnitTest::original_working_dir() const {
- return impl_->original_working_dir_.c_str();
-}
-
-// Returns the TestCase object for the test that's currently running,
-// or NULL if no test is running.
-// L < mutex_
-const TestCase* UnitTest::current_test_case() const {
- internal::MutexLock lock(&mutex_);
- return impl_->current_test_case();
-}
-
-// Returns the TestInfo object for the test that's currently running,
-// or NULL if no test is running.
-// L < mutex_
-const TestInfo* UnitTest::current_test_info() const {
- internal::MutexLock lock(&mutex_);
- return impl_->current_test_info();
-}
-
-// Returns the random seed used at the start of the current test run.
-int UnitTest::random_seed() const { return impl_->random_seed(); }
-
-#if GTEST_HAS_PARAM_TEST
-// Returns ParameterizedTestCaseRegistry object used to keep track of
-// value-parameterized tests and instantiate and register them.
-// L < mutex_
-internal::ParameterizedTestCaseRegistry&
- UnitTest::parameterized_test_registry() {
- return impl_->parameterized_test_registry();
-}
-#endif // GTEST_HAS_PARAM_TEST
-
-// Creates an empty UnitTest.
-UnitTest::UnitTest() {
- impl_ = new internal::UnitTestImpl(this);
-}
-
-// Destructor of UnitTest.
-UnitTest::~UnitTest() {
- delete impl_;
-}
-
-// Pushes a trace defined by SCOPED_TRACE() on to the per-thread
-// Google Test trace stack.
-// L < mutex_
-void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) {
- internal::MutexLock lock(&mutex_);
- impl_->gtest_trace_stack().push_back(trace);
-}
-
-// Pops a trace from the per-thread Google Test trace stack.
-// L < mutex_
-void UnitTest::PopGTestTrace() {
- internal::MutexLock lock(&mutex_);
- impl_->gtest_trace_stack().pop_back();
-}
-
-namespace internal {
-
-UnitTestImpl::UnitTestImpl(UnitTest* parent)
- : parent_(parent),
-#ifdef _MSC_VER
-#pragma warning(push) // Saves the current warning state.
-#pragma warning(disable:4355) // Temporarily disables warning 4355
- // (using this in initializer).
- default_global_test_part_result_reporter_(this),
- default_per_thread_test_part_result_reporter_(this),
-#pragma warning(pop) // Restores the warning state again.
-#else
- default_global_test_part_result_reporter_(this),
- default_per_thread_test_part_result_reporter_(this),
-#endif // _MSC_VER
- global_test_part_result_repoter_(
- &default_global_test_part_result_reporter_),
- per_thread_test_part_result_reporter_(
- &default_per_thread_test_part_result_reporter_),
-#if GTEST_HAS_PARAM_TEST
- parameterized_test_registry_(),
- parameterized_tests_registered_(false),
-#endif // GTEST_HAS_PARAM_TEST
- last_death_test_case_(-1),
- current_test_case_(NULL),
- current_test_info_(NULL),
- ad_hoc_test_result_(),
- os_stack_trace_getter_(NULL),
- post_flag_parse_init_performed_(false),
- random_seed_(0), // Will be overridden by the flag before first use.
- random_(0), // Will be reseeded before first use.
-#if GTEST_HAS_DEATH_TEST
- elapsed_time_(0),
- internal_run_death_test_flag_(NULL),
- death_test_factory_(new DefaultDeathTestFactory) {
-#else
- elapsed_time_(0) {
-#endif // GTEST_HAS_DEATH_TEST
- listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter);
-}
-
-UnitTestImpl::~UnitTestImpl() {
- // Deletes every TestCase.
- ForEach(test_cases_, internal::Delete<TestCase>);
-
- // Deletes every Environment.
- ForEach(environments_, internal::Delete<Environment>);
-
- delete os_stack_trace_getter_;
-}
-
-#if GTEST_HAS_DEATH_TEST
-// Disables event forwarding if the control is currently in a death test
-// subprocess. Must not be called before InitGoogleTest.
-void UnitTestImpl::SuppressTestEventsIfInSubprocess() {
- if (internal_run_death_test_flag_.get() != NULL)
- listeners()->SuppressEventForwarding();
-}
-#endif // GTEST_HAS_DEATH_TEST
-
-// Initializes event listeners performing XML output as specified by
-// UnitTestOptions. Must not be called before InitGoogleTest.
-void UnitTestImpl::ConfigureXmlOutput() {
- const String& output_format = UnitTestOptions::GetOutputFormat();
- if (output_format == "xml") {
- listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter(
- UnitTestOptions::GetAbsolutePathToOutputFile().c_str()));
- } else if (output_format != "") {
- printf("WARNING: unrecognized output format \"%s\" ignored.\n",
- output_format.c_str());
- fflush(stdout);
- }
-}
-
-// Performs initialization dependent upon flag values obtained in
-// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to
-// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest
-// this function is also called from RunAllTests. Since this function can be
-// called more than once, it has to be idempotent.
-void UnitTestImpl::PostFlagParsingInit() {
- // Ensures that this function does not execute more than once.
- if (!post_flag_parse_init_performed_) {
- post_flag_parse_init_performed_ = true;
-
-#if GTEST_HAS_DEATH_TEST
- InitDeathTestSubprocessControlInfo();
- SuppressTestEventsIfInSubprocess();
-#endif // GTEST_HAS_DEATH_TEST
-
- // Registers parameterized tests. This makes parameterized tests
- // available to the UnitTest reflection API without running
- // RUN_ALL_TESTS.
- RegisterParameterizedTests();
-
- // Configures listeners for XML output. This makes it possible for users
- // to shut down the default XML output before invoking RUN_ALL_TESTS.
- ConfigureXmlOutput();
- }
-}
-
-// A predicate that checks the name of a TestCase against a known
-// value.
-//
-// This is used for implementation of the UnitTest class only. We put
-// it in the anonymous namespace to prevent polluting the outer
-// namespace.
-//
-// TestCaseNameIs is copyable.
-class TestCaseNameIs {
- public:
- // Constructor.
- explicit TestCaseNameIs(const String& name)
- : name_(name) {}
-
- // Returns true iff the name of test_case matches name_.
- bool operator()(const TestCase* test_case) const {
- return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0;
- }
-
- private:
- String name_;
-};
-
-// Finds and returns a TestCase with the given name. If one doesn't
-// exist, creates one and returns it. It's the CALLER'S
-// RESPONSIBILITY to ensure that this function is only called WHEN THE
-// TESTS ARE NOT SHUFFLED.
-//
-// Arguments:
-//
-// test_case_name: name of the test case
-// set_up_tc: pointer to the function that sets up the test case
-// tear_down_tc: pointer to the function that tears down the test case
-TestCase* UnitTestImpl::GetTestCase(const char* test_case_name,
- const char* comment,
- Test::SetUpTestCaseFunc set_up_tc,
- Test::TearDownTestCaseFunc tear_down_tc) {
- // Can we find a TestCase with the given name?
- const std::vector<TestCase*>::const_iterator test_case =
- std::find_if(test_cases_.begin(), test_cases_.end(),
- TestCaseNameIs(test_case_name));
-
- if (test_case != test_cases_.end())
- return *test_case;
-
- // No. Let's create one.
- TestCase* const new_test_case =
- new TestCase(test_case_name, comment, set_up_tc, tear_down_tc);
-
- // Is this a death test case?
- if (internal::UnitTestOptions::MatchesFilter(String(test_case_name),
- kDeathTestCaseFilter)) {
- // Yes. Inserts the test case after the last death test case
- // defined so far. This only works when the test cases haven't
- // been shuffled. Otherwise we may end up running a death test
- // after a non-death test.
- ++last_death_test_case_;
- test_cases_.insert(test_cases_.begin() + last_death_test_case_,
- new_test_case);
- } else {
- // No. Appends to the end of the list.
- test_cases_.push_back(new_test_case);
- }
-
- test_case_indices_.push_back(static_cast<int>(test_case_indices_.size()));
- return new_test_case;
-}
-
-// Helpers for setting up / tearing down the given environment. They
-// are for use in the ForEach() function.
-static void SetUpEnvironment(Environment* env) { env->SetUp(); }
-static void TearDownEnvironment(Environment* env) { env->TearDown(); }
-
-// Runs all tests in this UnitTest object, prints the result, and
-// returns 0 if all tests are successful, or 1 otherwise. If any
-// exception is thrown during a test on Windows, this test is
-// considered to be failed, but the rest of the tests will still be
-// run. (We disable exceptions on Linux and Mac OS X, so the issue
-// doesn't apply there.)
-// When parameterized tests are enabled, it expands and registers
-// parameterized tests first in RegisterParameterizedTests().
-// All other functions called from RunAllTests() may safely assume that
-// parameterized tests are ready to be counted and run.
-int UnitTestImpl::RunAllTests() {
- // Makes sure InitGoogleTest() was called.
- if (!GTestIsInitialized()) {
- printf("%s",
- "\nThis test program did NOT call ::testing::InitGoogleTest "
- "before calling RUN_ALL_TESTS(). Please fix it.\n");
- return 1;
- }
-
- // Do not run any test if the --help flag was specified.
- if (g_help_flag)
- return 0;
-
- // Repeats the call to the post-flag parsing initialization in case the
- // user didn't call InitGoogleTest.
- PostFlagParsingInit();
-
- // Even if sharding is not on, test runners may want to use the
- // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding
- // protocol.
- internal::WriteToShardStatusFileIfNeeded();
-
- // True iff we are in a subprocess for running a thread-safe-style
- // death test.
- bool in_subprocess_for_death_test = false;
-
-#if GTEST_HAS_DEATH_TEST
- in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL);
-#endif // GTEST_HAS_DEATH_TEST
-
- const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex,
- in_subprocess_for_death_test);
-
- // Compares the full test names with the filter to decide which
- // tests to run.
- const bool has_tests_to_run = FilterTests(should_shard
- ? HONOR_SHARDING_PROTOCOL
- : IGNORE_SHARDING_PROTOCOL) > 0;
-
- // Lists the tests and exits if the --gtest_list_tests flag was specified.
- if (GTEST_FLAG(list_tests)) {
- // This must be called *after* FilterTests() has been called.
- ListTestsMatchingFilter();
- return 0;
- }
-
- random_seed_ = GTEST_FLAG(shuffle) ?
- GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0;
-
- // True iff at least one test has failed.
- bool failed = false;
-
- TestEventListener* repeater = listeners()->repeater();
-
- repeater->OnTestProgramStart(*parent_);
-
- // How many times to repeat the tests? We don't want to repeat them
- // when we are inside the subprocess of a death test.
- const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat);
- // Repeats forever if the repeat count is negative.
- const bool forever = repeat < 0;
- for (int i = 0; forever || i != repeat; i++) {
- ClearResult();
-
- const TimeInMillis start = GetTimeInMillis();
-
- // Shuffles test cases and tests if requested.
- if (has_tests_to_run && GTEST_FLAG(shuffle)) {
- random()->Reseed(random_seed_);
- // This should be done before calling OnTestIterationStart(),
- // such that a test event listener can see the actual test order
- // in the event.
- ShuffleTests();
- }
-
- // Tells the unit test event listeners that the tests are about to start.
- repeater->OnTestIterationStart(*parent_, i);
-
- // Runs each test case if there is at least one test to run.
- if (has_tests_to_run) {
- // Sets up all environments beforehand.
- repeater->OnEnvironmentsSetUpStart(*parent_);
- ForEach(environments_, SetUpEnvironment);
- repeater->OnEnvironmentsSetUpEnd(*parent_);
-
- // Runs the tests only if there was no fatal failure during global
- // set-up.
- if (!Test::HasFatalFailure()) {
- for (int test_index = 0; test_index < total_test_case_count();
- test_index++) {
- GetMutableTestCase(test_index)->Run();
- }
- }
-
- // Tears down all environments in reverse order afterwards.
- repeater->OnEnvironmentsTearDownStart(*parent_);
- std::for_each(environments_.rbegin(), environments_.rend(),
- TearDownEnvironment);
- repeater->OnEnvironmentsTearDownEnd(*parent_);
- }
-
- elapsed_time_ = GetTimeInMillis() - start;
-
- // Tells the unit test event listener that the tests have just finished.
- repeater->OnTestIterationEnd(*parent_, i);
-
- // Gets the result and clears it.
- if (!Passed()) {
- failed = true;
- }
-
- // Restores the original test order after the iteration. This
- // allows the user to quickly repro a failure that happens in the
- // N-th iteration without repeating the first (N - 1) iterations.
- // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in
- // case the user somehow changes the value of the flag somewhere
- // (it's always safe to unshuffle the tests).
- UnshuffleTests();
-
- if (GTEST_FLAG(shuffle)) {
- // Picks a new random seed for each iteration.
- random_seed_ = GetNextRandomSeed(random_seed_);
- }
- }
-
- repeater->OnTestProgramEnd(*parent_);
-
- // Returns 0 if all tests passed, or 1 other wise.
- return failed ? 1 : 0;
-}
-
-// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
-// if the variable is present. If a file already exists at this location, this
-// function will write over it. If the variable is present, but the file cannot
-// be created, prints an error and exits.
-void WriteToShardStatusFileIfNeeded() {
- const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile);
- if (test_shard_file != NULL) {
- FILE* const file = posix::FOpen(test_shard_file, "w");
- if (file == NULL) {
- ColoredPrintf(COLOR_RED,
- "Could not write to the test shard status file \"%s\" "
- "specified by the %s environment variable.\n",
- test_shard_file, kTestShardStatusFile);
- fflush(stdout);
- exit(EXIT_FAILURE);
- }
- fclose(file);
- }
-}
-
-// Checks whether sharding is enabled by examining the relevant
-// environment variable values. If the variables are present,
-// but inconsistent (i.e., shard_index >= total_shards), prints
-// an error and exits. If in_subprocess_for_death_test, sharding is
-// disabled because it must only be applied to the original test
-// process. Otherwise, we could filter out death tests we intended to execute.
-bool ShouldShard(const char* total_shards_env,
- const char* shard_index_env,
- bool in_subprocess_for_death_test) {
- if (in_subprocess_for_death_test) {
- return false;
- }
-
- const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1);
- const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1);
-
- if (total_shards == -1 && shard_index == -1) {
- return false;
- } else if (total_shards == -1 && shard_index != -1) {
- const Message msg = Message()
- << "Invalid environment variables: you have "
- << kTestShardIndex << " = " << shard_index
- << ", but have left " << kTestTotalShards << " unset.\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
- fflush(stdout);
- exit(EXIT_FAILURE);
- } else if (total_shards != -1 && shard_index == -1) {
- const Message msg = Message()
- << "Invalid environment variables: you have "
- << kTestTotalShards << " = " << total_shards
- << ", but have left " << kTestShardIndex << " unset.\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
- fflush(stdout);
- exit(EXIT_FAILURE);
- } else if (shard_index < 0 || shard_index >= total_shards) {
- const Message msg = Message()
- << "Invalid environment variables: we require 0 <= "
- << kTestShardIndex << " < " << kTestTotalShards
- << ", but you have " << kTestShardIndex << "=" << shard_index
- << ", " << kTestTotalShards << "=" << total_shards << ".\n";
- ColoredPrintf(COLOR_RED, msg.GetString().c_str());
- fflush(stdout);
- exit(EXIT_FAILURE);
- }
-
- return total_shards > 1;
-}
-
-// Parses the environment variable var as an Int32. If it is unset,
-// returns default_val. If it is not an Int32, prints an error
-// and aborts.
-Int32 Int32FromEnvOrDie(const char* const var, Int32 default_val) {
- const char* str_val = posix::GetEnv(var);
- if (str_val == NULL) {
- return default_val;
- }
-
- Int32 result;
- if (!ParseInt32(Message() << "The value of environment variable " << var,
- str_val, &result)) {
- exit(EXIT_FAILURE);
- }
- return result;
-}
-
-// Given the total number of shards, the shard index, and the test id,
-// returns true iff the test should be run on this shard. The test id is
-// some arbitrary but unique non-negative integer assigned to each test
-// method. Assumes that 0 <= shard_index < total_shards.
-bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) {
- return (test_id % total_shards) == shard_index;
-}
-
-// Compares the name of each test with the user-specified filter to
-// decide whether the test should be run, then records the result in
-// each TestCase and TestInfo object.
-// If shard_tests == true, further filters tests based on sharding
-// variables in the environment - see
-// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide.
-// Returns the number of tests that should run.
-int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) {
- const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ?
- Int32FromEnvOrDie(kTestTotalShards, -1) : -1;
- const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ?
- Int32FromEnvOrDie(kTestShardIndex, -1) : -1;
-
- // num_runnable_tests are the number of tests that will
- // run across all shards (i.e., match filter and are not disabled).
- // num_selected_tests are the number of tests to be run on
- // this shard.
- int num_runnable_tests = 0;
- int num_selected_tests = 0;
- for (size_t i = 0; i < test_cases_.size(); i++) {
- TestCase* const test_case = test_cases_[i];
- const String &test_case_name = test_case->name();
- test_case->set_should_run(false);
-
- for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
- TestInfo* const test_info = test_case->test_info_list()[j];
- const String test_name(test_info->name());
- // A test is disabled if test case name or test name matches
- // kDisableTestFilter.
- const bool is_disabled =
- internal::UnitTestOptions::MatchesFilter(test_case_name,
- kDisableTestFilter) ||
- internal::UnitTestOptions::MatchesFilter(test_name,
- kDisableTestFilter);
- test_info->impl()->set_is_disabled(is_disabled);
-
- const bool matches_filter =
- internal::UnitTestOptions::FilterMatchesTest(test_case_name,
- test_name);
- test_info->impl()->set_matches_filter(matches_filter);
-
- const bool is_runnable =
- (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
- matches_filter;
-
- const bool is_selected = is_runnable &&
- (shard_tests == IGNORE_SHARDING_PROTOCOL ||
- ShouldRunTestOnShard(total_shards, shard_index,
- num_runnable_tests));
-
- num_runnable_tests += is_runnable;
- num_selected_tests += is_selected;
-
- test_info->impl()->set_should_run(is_selected);
- test_case->set_should_run(test_case->should_run() || is_selected);
- }
- }
- return num_selected_tests;
-}
-
-// Prints the names of the tests matching the user-specified filter flag.
-void UnitTestImpl::ListTestsMatchingFilter() {
- for (size_t i = 0; i < test_cases_.size(); i++) {
- const TestCase* const test_case = test_cases_[i];
- bool printed_test_case_name = false;
-
- for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
- const TestInfo* const test_info =
- test_case->test_info_list()[j];
- if (test_info->matches_filter()) {
- if (!printed_test_case_name) {
- printed_test_case_name = true;
- printf("%s.\n", test_case->name());
- }
- printf(" %s\n", test_info->name());
- }
- }
- }
- fflush(stdout);
-}
-
-// Sets the OS stack trace getter.
-//
-// Does nothing if the input and the current OS stack trace getter are
-// the same; otherwise, deletes the old getter and makes the input the
-// current getter.
-void UnitTestImpl::set_os_stack_trace_getter(
- OsStackTraceGetterInterface* getter) {
- if (os_stack_trace_getter_ != getter) {
- delete os_stack_trace_getter_;
- os_stack_trace_getter_ = getter;
- }
-}
-
-// Returns the current OS stack trace getter if it is not NULL;
-// otherwise, creates an OsStackTraceGetter, makes it the current
-// getter, and returns it.
-OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() {
- if (os_stack_trace_getter_ == NULL) {
- os_stack_trace_getter_ = new OsStackTraceGetter;
- }
-
- return os_stack_trace_getter_;
-}
-
-// Returns the TestResult for the test that's currently running, or
-// the TestResult for the ad hoc test if no test is running.
-TestResult* UnitTestImpl::current_test_result() {
- return current_test_info_ ?
- current_test_info_->impl()->result() : &ad_hoc_test_result_;
-}
-
-// Shuffles all test cases, and the tests within each test case,
-// making sure that death tests are still run first.
-void UnitTestImpl::ShuffleTests() {
- // Shuffles the death test cases.
- ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_);
-
- // Shuffles the non-death test cases.
- ShuffleRange(random(), last_death_test_case_ + 1,
- static_cast<int>(test_cases_.size()), &test_case_indices_);
-
- // Shuffles the tests inside each test case.
- for (size_t i = 0; i < test_cases_.size(); i++) {
- test_cases_[i]->ShuffleTests(random());
- }
-}
-
-// Restores the test cases and tests to their order before the first shuffle.
-void UnitTestImpl::UnshuffleTests() {
- for (size_t i = 0; i < test_cases_.size(); i++) {
- // Unshuffles the tests in each test case.
- test_cases_[i]->UnshuffleTests();
- // Resets the index of each test case.
- test_case_indices_[i] = static_cast<int>(i);
- }
-}
-
-// TestInfoImpl constructor. The new instance assumes ownership of the test
-// factory object.
-TestInfoImpl::TestInfoImpl(TestInfo* parent,
- const char* a_test_case_name,
- const char* a_name,
- const char* a_test_case_comment,
- const char* a_comment,
- TypeId a_fixture_class_id,
- internal::TestFactoryBase* factory) :
- parent_(parent),
- test_case_name_(String(a_test_case_name)),
- name_(String(a_name)),
- test_case_comment_(String(a_test_case_comment)),
- comment_(String(a_comment)),
- fixture_class_id_(a_fixture_class_id),
- should_run_(false),
- is_disabled_(false),
- matches_filter_(false),
- factory_(factory) {
-}
-
-// TestInfoImpl destructor.
-TestInfoImpl::~TestInfoImpl() {
- delete factory_;
-}
-
-// Returns the current OS stack trace as a String.
-//
-// The maximum number of stack frames to be included is specified by
-// the gtest_stack_trace_depth flag. The skip_count parameter
-// specifies the number of top frames to be skipped, which doesn't
-// count against the number of frames to be included.
-//
-// For example, if Foo() calls Bar(), which in turn calls
-// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in
-// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't.
-String GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/,
- int skip_count) {
- // We pass skip_count + 1 to skip this wrapper function in addition
- // to what the user really wants to skip.
- return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
-}
-
-// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable
-// code warnings.
-namespace {
-class ClassUniqueToAlwaysTrue {};
-}
-
-bool IsTrue(bool condition) { return condition; }
-
-bool AlwaysTrue() {
-#if GTEST_HAS_EXCEPTIONS
- // This condition is always false so AlwaysTrue() never actually throws,
- // but it makes the compiler think that it may throw.
- if (IsTrue(false))
- throw ClassUniqueToAlwaysTrue();
-#endif // GTEST_HAS_EXCEPTIONS
- return true;
-}
-
-// If *pstr starts with the given prefix, modifies *pstr to be right
-// past the prefix and returns true; otherwise leaves *pstr unchanged
-// and returns false. None of pstr, *pstr, and prefix can be NULL.
-bool SkipPrefix(const char* prefix, const char** pstr) {
- const size_t prefix_len = strlen(prefix);
- if (strncmp(*pstr, prefix, prefix_len) == 0) {
- *pstr += prefix_len;
- return true;
- }
- return false;
-}
-
-// Parses a string as a command line flag. The string should have
-// the format "--flag=value". When def_optional is true, the "=value"
-// part can be omitted.
-//
-// Returns the value of the flag, or NULL if the parsing failed.
-const char* ParseFlagValue(const char* str,
- const char* flag,
- bool def_optional) {
- // str and flag must not be NULL.
- if (str == NULL || flag == NULL) return NULL;
-
- // The flag must start with "--" followed by GTEST_FLAG_PREFIX_.
- const String flag_str = String::Format("--%s%s", GTEST_FLAG_PREFIX_, flag);
- const size_t flag_len = flag_str.length();
- if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL;
-
- // Skips the flag name.
- const char* flag_end = str + flag_len;
-
- // When def_optional is true, it's OK to not have a "=value" part.
- if (def_optional && (flag_end[0] == '\0')) {
- return flag_end;
- }
-
- // If def_optional is true and there are more characters after the
- // flag name, or if def_optional is false, there must be a '=' after
- // the flag name.
- if (flag_end[0] != '=') return NULL;
-
- // Returns the string after "=".
- return flag_end + 1;
-}
-
-// Parses a string for a bool flag, in the form of either
-// "--flag=value" or "--flag".
-//
-// In the former case, the value is taken as true as long as it does
-// not start with '0', 'f', or 'F'.
-//
-// In the latter case, the value is taken as true.
-//
-// On success, stores the value of the flag in *value, and returns
-// true. On failure, returns false without changing *value.
-bool ParseBoolFlag(const char* str, const char* flag, bool* value) {
- // Gets the value of the flag as a string.
- const char* const value_str = ParseFlagValue(str, flag, true);
-
- // Aborts if the parsing failed.
- if (value_str == NULL) return false;
-
- // Converts the string value to a bool.
- *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F');
- return true;
-}
-
-// Parses a string for an Int32 flag, in the form of
-// "--flag=value".
-//
-// On success, stores the value of the flag in *value, and returns
-// true. On failure, returns false without changing *value.
-bool ParseInt32Flag(const char* str, const char* flag, Int32* value) {
- // Gets the value of the flag as a string.
- const char* const value_str = ParseFlagValue(str, flag, false);
-
- // Aborts if the parsing failed.
- if (value_str == NULL) return false;
-
- // Sets *value to the value of the flag.
- return ParseInt32(Message() << "The value of flag --" << flag,
- value_str, value);
-}
-
-// Parses a string for a string flag, in the form of
-// "--flag=value".
-//
-// On success, stores the value of the flag in *value, and returns
-// true. On failure, returns false without changing *value.
-bool ParseStringFlag(const char* str, const char* flag, String* value) {
- // Gets the value of the flag as a string.
- const char* const value_str = ParseFlagValue(str, flag, false);
-
- // Aborts if the parsing failed.
- if (value_str == NULL) return false;
-
- // Sets *value to the value of the flag.
- *value = value_str;
- return true;
-}
-
-// Determines whether a string has a prefix that Google Test uses for its
-// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_.
-// If Google Test detects that a command line flag has its prefix but is not
-// recognized, it will print its help message. Flags starting with
-// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test
-// internal flags and do not trigger the help message.
-static bool HasGoogleTestFlagPrefix(const char* str) {
- return (SkipPrefix("--", &str) ||
- SkipPrefix("-", &str) ||
- SkipPrefix("/", &str)) &&
- !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) &&
- (SkipPrefix(GTEST_FLAG_PREFIX_, &str) ||
- SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str));
-}
-
-// Prints a string containing code-encoded text. The following escape
-// sequences can be used in the string to control the text color:
-//
-// @@ prints a single '@' character.
-// @R changes the color to red.
-// @G changes the color to green.
-// @Y changes the color to yellow.
-// @D changes to the default terminal text color.
-//
-// TODO(wan@google.com): Write tests for this once we add stdout
-// capturing to Google Test.
-static void PrintColorEncoded(const char* str) {
- GTestColor color = COLOR_DEFAULT; // The current color.
-
- // Conceptually, we split the string into segments divided by escape
- // sequences. Then we print one segment at a time. At the end of
- // each iteration, the str pointer advances to the beginning of the
- // next segment.
- for (;;) {
- const char* p = strchr(str, '@');
- if (p == NULL) {
- ColoredPrintf(color, "%s", str);
- return;
- }
-
- ColoredPrintf(color, "%s", String(str, p - str).c_str());
-
- const char ch = p[1];
- str = p + 2;
- if (ch == '@') {
- ColoredPrintf(color, "@");
- } else if (ch == 'D') {
- color = COLOR_DEFAULT;
- } else if (ch == 'R') {
- color = COLOR_RED;
- } else if (ch == 'G') {
- color = COLOR_GREEN;
- } else if (ch == 'Y') {
- color = COLOR_YELLOW;
- } else {
- --str;
- }
- }
-}
-
-static const char kColorEncodedHelpMessage[] =
-"This program contains tests written using " GTEST_NAME_ ". You can use the\n"
-"following command line flags to control its behavior:\n"
-"\n"
-"Test Selection:\n"
-" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n"
-" List the names of all tests instead of running them. The name of\n"
-" TEST(Foo, Bar) is \"Foo.Bar\".\n"
-" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS"
- "[@G-@YNEGATIVE_PATTERNS]@D\n"
-" Run only the tests whose name matches one of the positive patterns but\n"
-" none of the negative patterns. '?' matches any single character; '*'\n"
-" matches any substring; ':' separates two patterns.\n"
-" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n"
-" Run all disabled tests too.\n"
-"\n"
-"Test Execution:\n"
-" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n"
-" Run the tests repeatedly; use a negative count to repeat forever.\n"
-" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n"
-" Randomize tests' orders on every iteration.\n"
-" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n"
-" Random number seed to use for shuffling test orders (between 1 and\n"
-" 99999, or 0 to use a seed based on the current time).\n"
-"\n"
-"Test Output:\n"
-" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n"
-" Enable/disable colored output. The default is @Gauto@D.\n"
-" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n"
-" Don't print the elapsed time of each test.\n"
-" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G"
- GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n"
-" Generate an XML report in the given directory or with the given file\n"
-" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n"
-"\n"
-"Assertion Behavior:\n"
-#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
-" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n"
-" Set the default death test style.\n"
-#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS
-" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n"
-" Turn assertion failures into debugger break-points.\n"
-" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n"
-" Turn assertion failures into C++ exceptions.\n"
-#if GTEST_OS_WINDOWS
-" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions@D\n"
-" Suppress pop-ups caused by exceptions.\n"
-#endif // GTEST_OS_WINDOWS
-"\n"
-"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set "
- "the corresponding\n"
-"environment variable of a flag (all letters in upper-case). For example, to\n"
-"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_
- "color=no@D or set\n"
-"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n"
-"\n"
-"For more information, please read the " GTEST_NAME_ " documentation at\n"
-"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n"
-"(not one in your own code or tests), please report it to\n"
-"@G<" GTEST_DEV_EMAIL_ ">@D.\n";
-
-// Parses the command line for Google Test flags, without initializing
-// other parts of Google Test. The type parameter CharType can be
-// instantiated to either char or wchar_t.
-template <typename CharType>
-void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) {
- for (int i = 1; i < *argc; i++) {
- const String arg_string = StreamableToString(argv[i]);
- const char* const arg = arg_string.c_str();
-
- using internal::ParseBoolFlag;
- using internal::ParseInt32Flag;
- using internal::ParseStringFlag;
-
- // Do we see a Google Test flag?
- if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag,
- >EST_FLAG(also_run_disabled_tests)) ||
- ParseBoolFlag(arg, kBreakOnFailureFlag,
- >EST_FLAG(break_on_failure)) ||
- ParseBoolFlag(arg, kCatchExceptionsFlag,
- >EST_FLAG(catch_exceptions)) ||
- ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) ||
- ParseStringFlag(arg, kDeathTestStyleFlag,
- >EST_FLAG(death_test_style)) ||
- ParseBoolFlag(arg, kDeathTestUseFork,
- >EST_FLAG(death_test_use_fork)) ||
- ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) ||
- ParseStringFlag(arg, kInternalRunDeathTestFlag,
- >EST_FLAG(internal_run_death_test)) ||
- ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) ||
- ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) ||
- ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) ||
- ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) ||
- ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) ||
- ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) ||
- ParseInt32Flag(arg, kStackTraceDepthFlag,
- >EST_FLAG(stack_trace_depth)) ||
- ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure))
- ) {
- // Yes. Shift the remainder of the argv list left by one. Note
- // that argv has (*argc + 1) elements, the last one always being
- // NULL. The following loop moves the trailing NULL element as
- // well.
- for (int j = i; j != *argc; j++) {
- argv[j] = argv[j + 1];
- }
-
- // Decrements the argument count.
- (*argc)--;
-
- // We also need to decrement the iterator as we just removed
- // an element.
- i--;
- } else if (arg_string == "--help" || arg_string == "-h" ||
- arg_string == "-?" || arg_string == "/?" ||
- HasGoogleTestFlagPrefix(arg)) {
- // Both help flag and unrecognized Google Test flags (excluding
- // internal ones) trigger help display.
- g_help_flag = true;
- }
- }
-
- if (g_help_flag) {
- // We print the help here instead of in RUN_ALL_TESTS(), as the
- // latter may not be called at all if the user is using Google
- // Test with another testing framework.
- PrintColorEncoded(kColorEncodedHelpMessage);
- }
-}
-
-// Parses the command line for Google Test flags, without initializing
-// other parts of Google Test.
-void ParseGoogleTestFlagsOnly(int* argc, char** argv) {
- ParseGoogleTestFlagsOnlyImpl(argc, argv);
-}
-void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) {
- ParseGoogleTestFlagsOnlyImpl(argc, argv);
-}
-
-// The internal implementation of InitGoogleTest().
-//
-// The type parameter CharType can be instantiated to either char or
-// wchar_t.
-template <typename CharType>
-void InitGoogleTestImpl(int* argc, CharType** argv) {
- g_init_gtest_count++;
-
- // We don't want to run the initialization code twice.
- if (g_init_gtest_count != 1) return;
-
- if (*argc <= 0) return;
-
- internal::g_executable_path = internal::StreamableToString(argv[0]);
-
-#if GTEST_HAS_DEATH_TEST
- g_argvs.clear();
- for (int i = 0; i != *argc; i++) {
- g_argvs.push_back(StreamableToString(argv[i]));
- }
-#endif // GTEST_HAS_DEATH_TEST
-
- ParseGoogleTestFlagsOnly(argc, argv);
- GetUnitTestImpl()->PostFlagParsingInit();
-}
-
-} // namespace internal
-
-// Initializes Google Test. This must be called before calling
-// RUN_ALL_TESTS(). In particular, it parses a command line for the
-// flags that Google Test recognizes. Whenever a Google Test flag is
-// seen, it is removed from argv, and *argc is decremented.
-//
-// No value is returned. Instead, the Google Test flag variables are
-// updated.
-//
-// Calling the function for the second time has no user-visible effect.
-void InitGoogleTest(int* argc, char** argv) {
- internal::InitGoogleTestImpl(argc, argv);
-}
-
-// This overloaded version can be used in Windows programs compiled in
-// UNICODE mode.
-void InitGoogleTest(int* argc, wchar_t** argv) {
- internal::InitGoogleTestImpl(argc, argv);
-}
-
-} // namespace testing
-// Copyright 2005, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev)
-//
-// This file implements death tests.
-
-
-#if GTEST_HAS_DEATH_TEST
-
-#if GTEST_OS_MAC
-#include <crt_externs.h>
-#endif // GTEST_OS_MAC
-
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <stdarg.h>
-
-#if GTEST_OS_WINDOWS
-#include <windows.h>
-#else
-#include <sys/mman.h>
-#include <sys/wait.h>
-#endif // GTEST_OS_WINDOWS
-
-#endif // GTEST_HAS_DEATH_TEST
-
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
-#define GTEST_IMPLEMENTATION_ 1
-#undef GTEST_IMPLEMENTATION_
-
-namespace testing {
-
-// Constants.
-
-// The default death test style.
-static const char kDefaultDeathTestStyle[] = "fast";
-
-GTEST_DEFINE_string_(
- death_test_style,
- internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle),
- "Indicates how to run a death test in a forked child process: "
- "\"threadsafe\" (child process re-executes the test binary "
- "from the beginning, running only the specific death test) or "
- "\"fast\" (child process runs the death test immediately "
- "after forking).");
-
-GTEST_DEFINE_bool_(
- death_test_use_fork,
- internal::BoolFromGTestEnv("death_test_use_fork", false),
- "Instructs to use fork()/_exit() instead of clone() in death tests. "
- "Ignored and always uses fork() on POSIX systems where clone() is not "
- "implemented. Useful when running under valgrind or similar tools if "
- "those do not support clone(). Valgrind 3.3.1 will just fail if "
- "it sees an unsupported combination of clone() flags. "
- "It is not recommended to use this flag w/o valgrind though it will "
- "work in 99% of the cases. Once valgrind is fixed, this flag will "
- "most likely be removed.");
-
-namespace internal {
-GTEST_DEFINE_string_(
- internal_run_death_test, "",
- "Indicates the file, line number, temporal index of "
- "the single death test to run, and a file descriptor to "
- "which a success code may be sent, all separated by "
- "colons. This flag is specified if and only if the current "
- "process is a sub-process launched for running a thread-safe "
- "death test. FOR INTERNAL USE ONLY.");
-} // namespace internal
-
-#if GTEST_HAS_DEATH_TEST
-
-// ExitedWithCode constructor.
-ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) {
-}
-
-// ExitedWithCode function-call operator.
-bool ExitedWithCode::operator()(int exit_status) const {
-#if GTEST_OS_WINDOWS
- return exit_status == exit_code_;
-#else
- return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_;
-#endif // GTEST_OS_WINDOWS
-}
-
-#if !GTEST_OS_WINDOWS
-// KilledBySignal constructor.
-KilledBySignal::KilledBySignal(int signum) : signum_(signum) {
-}
-
-// KilledBySignal function-call operator.
-bool KilledBySignal::operator()(int exit_status) const {
- return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_;
-}
-#endif // !GTEST_OS_WINDOWS
-
-namespace internal {
-
-// Utilities needed for death tests.
-
-// Generates a textual description of a given exit code, in the format
-// specified by wait(2).
-static String ExitSummary(int exit_code) {
- Message m;
-#if GTEST_OS_WINDOWS
- m << "Exited with exit status " << exit_code;
-#else
- if (WIFEXITED(exit_code)) {
- m << "Exited with exit status " << WEXITSTATUS(exit_code);
- } else if (WIFSIGNALED(exit_code)) {
- m << "Terminated by signal " << WTERMSIG(exit_code);
- }
-#ifdef WCOREDUMP
- if (WCOREDUMP(exit_code)) {
- m << " (core dumped)";
- }
-#endif
-#endif // GTEST_OS_WINDOWS
- return m.GetString();
-}
-
-// Returns true if exit_status describes a process that was terminated
-// by a signal, or exited normally with a nonzero exit code.
-bool ExitedUnsuccessfully(int exit_status) {
- return !ExitedWithCode(0)(exit_status);
-}
-
-#if !GTEST_OS_WINDOWS
-// Generates a textual failure message when a death test finds more than
-// one thread running, or cannot determine the number of threads, prior
-// to executing the given statement. It is the responsibility of the
-// caller not to pass a thread_count of 1.
-static String DeathTestThreadWarning(size_t thread_count) {
- Message msg;
- msg << "Death tests use fork(), which is unsafe particularly"
- << " in a threaded context. For this test, " << GTEST_NAME_ << " ";
- if (thread_count == 0)
- msg << "couldn't detect the number of threads.";
- else
- msg << "detected " << thread_count << " threads.";
- return msg.GetString();
-}
-#endif // !GTEST_OS_WINDOWS
-
-// Flag characters for reporting a death test that did not die.
-static const char kDeathTestLived = 'L';
-static const char kDeathTestReturned = 'R';
-static const char kDeathTestInternalError = 'I';
-
-// An enumeration describing all of the possible ways that a death test
-// can conclude. DIED means that the process died while executing the
-// test code; LIVED means that process lived beyond the end of the test
-// code; and RETURNED means that the test statement attempted a "return,"
-// which is not allowed. IN_PROGRESS means the test has not yet
-// concluded.
-enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED };
-
-// Routine for aborting the program which is safe to call from an
-// exec-style death test child process, in which case the error
-// message is propagated back to the parent process. Otherwise, the
-// message is simply printed to stderr. In either case, the program
-// then exits with status 1.
-void DeathTestAbort(const String& message) {
- // On a POSIX system, this function may be called from a threadsafe-style
- // death test child process, which operates on a very small stack. Use
- // the heap for any additional non-minuscule memory requirements.
- const InternalRunDeathTestFlag* const flag =
- GetUnitTestImpl()->internal_run_death_test_flag();
- if (flag != NULL) {
- FILE* parent = posix::FDOpen(flag->write_fd(), "w");
- fputc(kDeathTestInternalError, parent);
- fprintf(parent, "%s", message.c_str());
- fflush(parent);
- _exit(1);
- } else {
- fprintf(stderr, "%s", message.c_str());
- fflush(stderr);
- abort();
- }
-}
-
-// A replacement for CHECK that calls DeathTestAbort if the assertion
-// fails.
-#define GTEST_DEATH_TEST_CHECK_(expression) \
- do { \
- if (!::testing::internal::IsTrue(expression)) { \
- DeathTestAbort(::testing::internal::String::Format( \
- "CHECK failed: File %s, line %d: %s", \
- __FILE__, __LINE__, #expression)); \
- } \
- } while (::testing::internal::AlwaysFalse())
-
-// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for
-// evaluating any system call that fulfills two conditions: it must return
-// -1 on failure, and set errno to EINTR when it is interrupted and
-// should be tried again. The macro expands to a loop that repeatedly
-// evaluates the expression as long as it evaluates to -1 and sets
-// errno to EINTR. If the expression evaluates to -1 but errno is
-// something other than EINTR, DeathTestAbort is called.
-#define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \
- do { \
- int gtest_retval; \
- do { \
- gtest_retval = (expression); \
- } while (gtest_retval == -1 && errno == EINTR); \
- if (gtest_retval == -1) { \
- DeathTestAbort(::testing::internal::String::Format( \
- "CHECK failed: File %s, line %d: %s != -1", \
- __FILE__, __LINE__, #expression)); \
- } \
- } while (::testing::internal::AlwaysFalse())
-
-// Returns the message describing the last system error in errno.
-String GetLastErrnoDescription() {
- return String(errno == 0 ? "" : posix::StrError(errno));
-}
-
-// This is called from a death test parent process to read a failure
-// message from the death test child process and log it with the FATAL
-// severity. On Windows, the message is read from a pipe handle. On other
-// platforms, it is read from a file descriptor.
-static void FailFromInternalError(int fd) {
- Message error;
- char buffer[256];
- int num_read;
-
- do {
- while ((num_read = posix::Read(fd, buffer, 255)) > 0) {
- buffer[num_read] = '\0';
- error << buffer;
- }
- } while (num_read == -1 && errno == EINTR);
-
- if (num_read == 0) {
- GTEST_LOG_(FATAL) << error.GetString();
- } else {
- const int last_error = errno;
- GTEST_LOG_(FATAL) << "Error while reading death test internal: "
- << GetLastErrnoDescription() << " [" << last_error << "]";
- }
-}
-
-// Death test constructor. Increments the running death test count
-// for the current test.
-DeathTest::DeathTest() {
- TestInfo* const info = GetUnitTestImpl()->current_test_info();
- if (info == NULL) {
- DeathTestAbort("Cannot run a death test outside of a TEST or "
- "TEST_F construct");
- }
-}
-
-// Creates and returns a death test by dispatching to the current
-// death test factory.
-bool DeathTest::Create(const char* statement, const RE* regex,
- const char* file, int line, DeathTest** test) {
- return GetUnitTestImpl()->death_test_factory()->Create(
- statement, regex, file, line, test);
-}
-
-const char* DeathTest::LastMessage() {
- return last_death_test_message_.c_str();
-}
-
-void DeathTest::set_last_death_test_message(const String& message) {
- last_death_test_message_ = message;
-}
-
-String DeathTest::last_death_test_message_;
-
-// Provides cross platform implementation for some death functionality.
-class DeathTestImpl : public DeathTest {
- protected:
- DeathTestImpl(const char* a_statement, const RE* a_regex)
- : statement_(a_statement),
- regex_(a_regex),
- spawned_(false),
- status_(-1),
- outcome_(IN_PROGRESS),
- read_fd_(-1),
- write_fd_(-1) {}
-
- // read_fd_ is expected to be closed and cleared by a derived class.
- ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); }
-
- void Abort(AbortReason reason);
- virtual bool Passed(bool status_ok);
-
- const char* statement() const { return statement_; }
- const RE* regex() const { return regex_; }
- bool spawned() const { return spawned_; }
- void set_spawned(bool is_spawned) { spawned_ = is_spawned; }
- int status() const { return status_; }
- void set_status(int a_status) { status_ = a_status; }
- DeathTestOutcome outcome() const { return outcome_; }
- void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; }
- int read_fd() const { return read_fd_; }
- void set_read_fd(int fd) { read_fd_ = fd; }
- int write_fd() const { return write_fd_; }
- void set_write_fd(int fd) { write_fd_ = fd; }
-
- // Called in the parent process only. Reads the result code of the death
- // test child process via a pipe, interprets it to set the outcome_
- // member, and closes read_fd_. Outputs diagnostics and terminates in
- // case of unexpected codes.
- void ReadAndInterpretStatusByte();
-
- private:
- // The textual content of the code this object is testing. This class
- // doesn't own this string and should not attempt to delete it.
- const char* const statement_;
- // The regular expression which test output must match. DeathTestImpl
- // doesn't own this object and should not attempt to delete it.
- const RE* const regex_;
- // True if the death test child process has been successfully spawned.
- bool spawned_;
- // The exit status of the child process.
- int status_;
- // How the death test concluded.
- DeathTestOutcome outcome_;
- // Descriptor to the read end of the pipe to the child process. It is
- // always -1 in the child process. The child keeps its write end of the
- // pipe in write_fd_.
- int read_fd_;
- // Descriptor to the child's write end of the pipe to the parent process.
- // It is always -1 in the parent process. The parent keeps its end of the
- // pipe in read_fd_.
- int write_fd_;
-};
-
-// Called in the parent process only. Reads the result code of the death
-// test child process via a pipe, interprets it to set the outcome_
-// member, and closes read_fd_. Outputs diagnostics and terminates in
-// case of unexpected codes.
-void DeathTestImpl::ReadAndInterpretStatusByte() {
- char flag;
- int bytes_read;
-
- // The read() here blocks until data is available (signifying the
- // failure of the death test) or until the pipe is closed (signifying
- // its success), so it's okay to call this in the parent before
- // the child process has exited.
- do {
- bytes_read = posix::Read(read_fd(), &flag, 1);
- } while (bytes_read == -1 && errno == EINTR);
-
- if (bytes_read == 0) {
- set_outcome(DIED);
- } else if (bytes_read == 1) {
- switch (flag) {
- case kDeathTestReturned:
- set_outcome(RETURNED);
- break;
- case kDeathTestLived:
- set_outcome(LIVED);
- break;
- case kDeathTestInternalError:
- FailFromInternalError(read_fd()); // Does not return.
- break;
- default:
- GTEST_LOG_(FATAL) << "Death test child process reported "
- << "unexpected status byte ("
- << static_cast<unsigned int>(flag) << ")";
- }
- } else {
- GTEST_LOG_(FATAL) << "Read from death test child process failed: "
- << GetLastErrnoDescription();
- }
- GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd()));
- set_read_fd(-1);
-}
-
-// Signals that the death test code which should have exited, didn't.
-// Should be called only in a death test child process.
-// Writes a status byte to the child's status file descriptor, then
-// calls _exit(1).
-void DeathTestImpl::Abort(AbortReason reason) {
- // The parent process considers the death test to be a failure if
- // it finds any data in our pipe. So, here we write a single flag byte
- // to the pipe, then exit.
- const char status_ch =
- reason == TEST_DID_NOT_DIE ? kDeathTestLived : kDeathTestReturned;
- GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1));
- GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(write_fd()));
- _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash)
-}
-
-// Assesses the success or failure of a death test, using both private
-// members which have previously been set, and one argument:
-//
-// Private data members:
-// outcome: An enumeration describing how the death test
-// concluded: DIED, LIVED, or RETURNED. The death test fails
-// in the latter two cases.
-// status: The exit status of the child process. On *nix, it is in the
-// in the format specified by wait(2). On Windows, this is the
-// value supplied to the ExitProcess() API or a numeric code
-// of the exception that terminated the program.
-// regex: A regular expression object to be applied to
-// the test's captured standard error output; the death test
-// fails if it does not match.
-//
-// Argument:
-// status_ok: true if exit_status is acceptable in the context of
-// this particular death test, which fails if it is false
-//
-// Returns true iff all of the above conditions are met. Otherwise, the
-// first failing condition, in the order given above, is the one that is
-// reported. Also sets the last death test message string.
-bool DeathTestImpl::Passed(bool status_ok) {
- if (!spawned())
- return false;
-
- const String error_message = GetCapturedStderr();
-
- bool success = false;
- Message buffer;
-
- buffer << "Death test: " << statement() << "\n";
- switch (outcome()) {
- case LIVED:
- buffer << " Result: failed to die.\n"
- << " Error msg: " << error_message;
- break;
- case RETURNED:
- buffer << " Result: illegal return in test statement.\n"
- << " Error msg: " << error_message;
- break;
- case DIED:
- if (status_ok) {
- const bool matched = RE::PartialMatch(error_message.c_str(), *regex());
- if (matched) {
- success = true;
- } else {
- buffer << " Result: died but not with expected error.\n"
- << " Expected: " << regex()->pattern() << "\n"
- << "Actual msg: " << error_message;
- }
- } else {
- buffer << " Result: died but not with expected exit code:\n"
- << " " << ExitSummary(status()) << "\n";
- }
- break;
- case IN_PROGRESS:
- default:
- GTEST_LOG_(FATAL)
- << "DeathTest::Passed somehow called before conclusion of test";
- }
-
- DeathTest::set_last_death_test_message(buffer.GetString());
- return success;
-}
-
-#if GTEST_OS_WINDOWS
-// WindowsDeathTest implements death tests on Windows. Due to the
-// specifics of starting new processes on Windows, death tests there are
-// always threadsafe, and Google Test considers the
-// --gtest_death_test_style=fast setting to be equivalent to
-// --gtest_death_test_style=threadsafe there.
-//
-// A few implementation notes: Like the Linux version, the Windows
-// implementation uses pipes for child-to-parent communication. But due to
-// the specifics of pipes on Windows, some extra steps are required:
-//
-// 1. The parent creates a communication pipe and stores handles to both
-// ends of it.
-// 2. The parent starts the child and provides it with the information
-// necessary to acquire the handle to the write end of the pipe.
-// 3. The child acquires the write end of the pipe and signals the parent
-// using a Windows event.
-// 4. Now the parent can release the write end of the pipe on its side. If
-// this is done before step 3, the object's reference count goes down to
-// 0 and it is destroyed, preventing the child from acquiring it. The
-// parent now has to release it, or read operations on the read end of
-// the pipe will not return when the child terminates.
-// 5. The parent reads child's output through the pipe (outcome code and
-// any possible error messages) from the pipe, and its stderr and then
-// determines whether to fail the test.
-//
-// Note: to distinguish Win32 API calls from the local method and function
-// calls, the former are explicitly resolved in the global namespace.
-//
-class WindowsDeathTest : public DeathTestImpl {
- public:
- WindowsDeathTest(const char* statement,
- const RE* regex,
- const char* file,
- int line)
- : DeathTestImpl(statement, regex), file_(file), line_(line) {}
-
- // All of these virtual functions are inherited from DeathTest.
- virtual int Wait();
- virtual TestRole AssumeRole();
-
- private:
- // The name of the file in which the death test is located.
- const char* const file_;
- // The line number on which the death test is located.
- const int line_;
- // Handle to the write end of the pipe to the child process.
- AutoHandle write_handle_;
- // Child process handle.
- AutoHandle child_handle_;
- // Event the child process uses to signal the parent that it has
- // acquired the handle to the write end of the pipe. After seeing this
- // event the parent can release its own handles to make sure its
- // ReadFile() calls return when the child terminates.
- AutoHandle event_handle_;
-};
-
-// Waits for the child in a death test to exit, returning its exit
-// status, or 0 if no child process exists. As a side effect, sets the
-// outcome data member.
-int WindowsDeathTest::Wait() {
- if (!spawned())
- return 0;
-
- // Wait until the child either signals that it has acquired the write end
- // of the pipe or it dies.
- const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() };
- switch (::WaitForMultipleObjects(2,
- wait_handles,
- FALSE, // Waits for any of the handles.
- INFINITE)) {
- case WAIT_OBJECT_0:
- case WAIT_OBJECT_0 + 1:
- break;
- default:
- GTEST_DEATH_TEST_CHECK_(false); // Should not get here.
- }
-
- // The child has acquired the write end of the pipe or exited.
- // We release the handle on our side and continue.
- write_handle_.Reset();
- event_handle_.Reset();
-
- ReadAndInterpretStatusByte();
-
- // Waits for the child process to exit if it haven't already. This
- // returns immediately if the child has already exited, regardless of
- // whether previous calls to WaitForMultipleObjects synchronized on this
- // handle or not.
- GTEST_DEATH_TEST_CHECK_(
- WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(),
- INFINITE));
- DWORD status;
- GTEST_DEATH_TEST_CHECK_(::GetExitCodeProcess(child_handle_.Get(), &status)
- != FALSE);
- child_handle_.Reset();
- set_status(static_cast<int>(status));
- return this->status();
-}
-
-// The AssumeRole process for a Windows death test. It creates a child
-// process with the same executable as the current process to run the
-// death test. The child process is given the --gtest_filter and
-// --gtest_internal_run_death_test flags such that it knows to run the
-// current death test only.
-DeathTest::TestRole WindowsDeathTest::AssumeRole() {
- const UnitTestImpl* const impl = GetUnitTestImpl();
- const InternalRunDeathTestFlag* const flag =
- impl->internal_run_death_test_flag();
- const TestInfo* const info = impl->current_test_info();
- const int death_test_index = info->result()->death_test_count();
-
- if (flag != NULL) {
- // ParseInternalRunDeathTestFlag() has performed all the necessary
- // processing.
- set_write_fd(flag->write_fd());
- return EXECUTE_TEST;
- }
-
- // WindowsDeathTest uses an anonymous pipe to communicate results of
- // a death test.
- SECURITY_ATTRIBUTES handles_are_inheritable = {
- sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
- HANDLE read_handle, write_handle;
- GTEST_DEATH_TEST_CHECK_(
- ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable,
- 0) // Default buffer size.
- != FALSE);
- set_read_fd(::_open_osfhandle(reinterpret_cast<intptr_t>(read_handle),
- O_RDONLY));
- write_handle_.Reset(write_handle);
- event_handle_.Reset(::CreateEvent(
- &handles_are_inheritable,
- TRUE, // The event will automatically reset to non-signaled state.
- FALSE, // The initial state is non-signalled.
- NULL)); // The even is unnamed.
- GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL);
- const String filter_flag = String::Format("--%s%s=%s.%s",
- GTEST_FLAG_PREFIX_, kFilterFlag,
- info->test_case_name(),
- info->name());
- const String internal_flag = String::Format(
- "--%s%s=%s|%d|%d|%u|%Iu|%Iu",
- GTEST_FLAG_PREFIX_,
- kInternalRunDeathTestFlag,
- file_, line_,
- death_test_index,
- static_cast<unsigned int>(::GetCurrentProcessId()),
- // size_t has the same with as pointers on both 32-bit and 64-bit
- // Windows platforms.
- // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx.
- reinterpret_cast<size_t>(write_handle),
- reinterpret_cast<size_t>(event_handle_.Get()));
-
- char executable_path[_MAX_PATH + 1]; // NOLINT
- GTEST_DEATH_TEST_CHECK_(
- _MAX_PATH + 1 != ::GetModuleFileNameA(NULL,
- executable_path,
- _MAX_PATH));
-
- String command_line = String::Format("%s %s \"%s\"",
- ::GetCommandLineA(),
- filter_flag.c_str(),
- internal_flag.c_str());
-
- DeathTest::set_last_death_test_message("");
-
- CaptureStderr();
- // Flush the log buffers since the log streams are shared with the child.
- FlushInfoLog();
-
- // The child process will share the standard handles with the parent.
- STARTUPINFOA startup_info;
- memset(&startup_info, 0, sizeof(STARTUPINFO));
- startup_info.dwFlags = STARTF_USESTDHANDLES;
- startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE);
- startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE);
- startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE);
-
- PROCESS_INFORMATION process_info;
- GTEST_DEATH_TEST_CHECK_(::CreateProcessA(
- executable_path,
- const_cast<char*>(command_line.c_str()),
- NULL, // Retuned process handle is not inheritable.
- NULL, // Retuned thread handle is not inheritable.
- TRUE, // Child inherits all inheritable handles (for write_handle_).
- 0x0, // Default creation flags.
- NULL, // Inherit the parent's environment.
- UnitTest::GetInstance()->original_working_dir(),
- &startup_info,
- &process_info) != FALSE);
- child_handle_.Reset(process_info.hProcess);
- ::CloseHandle(process_info.hThread);
- set_spawned(true);
- return OVERSEE_TEST;
-}
-#else // We are not on Windows.
-
-// ForkingDeathTest provides implementations for most of the abstract
-// methods of the DeathTest interface. Only the AssumeRole method is
-// left undefined.
-class ForkingDeathTest : public DeathTestImpl {
- public:
- ForkingDeathTest(const char* statement, const RE* regex);
-
- // All of these virtual functions are inherited from DeathTest.
- virtual int Wait();
-
- protected:
- void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; }
-
- private:
- // PID of child process during death test; 0 in the child process itself.
- pid_t child_pid_;
-};
-
-// Constructs a ForkingDeathTest.
-ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex)
- : DeathTestImpl(a_statement, a_regex),
- child_pid_(-1) {}
-
-// Waits for the child in a death test to exit, returning its exit
-// status, or 0 if no child process exists. As a side effect, sets the
-// outcome data member.
-int ForkingDeathTest::Wait() {
- if (!spawned())
- return 0;
-
- ReadAndInterpretStatusByte();
-
- int status_value;
- GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0));
- set_status(status_value);
- return status_value;
-}
-
-// A concrete death test class that forks, then immediately runs the test
-// in the child process.
-class NoExecDeathTest : public ForkingDeathTest {
- public:
- NoExecDeathTest(const char* a_statement, const RE* a_regex) :
- ForkingDeathTest(a_statement, a_regex) { }
- virtual TestRole AssumeRole();
-};
-
-// The AssumeRole process for a fork-and-run death test. It implements a
-// straightforward fork, with a simple pipe to transmit the status byte.
-DeathTest::TestRole NoExecDeathTest::AssumeRole() {
- const size_t thread_count = GetThreadCount();
- if (thread_count != 1) {
- GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count);
- }
-
- int pipe_fd[2];
- GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
-
- DeathTest::set_last_death_test_message("");
- CaptureStderr();
- // When we fork the process below, the log file buffers are copied, but the
- // file descriptors are shared. We flush all log files here so that closing
- // the file descriptors in the child process doesn't throw off the
- // synchronization between descriptors and buffers in the parent process.
- // This is as close to the fork as possible to avoid a race condition in case
- // there are multiple threads running before the death test, and another
- // thread writes to the log file.
- FlushInfoLog();
-
- const pid_t child_pid = fork();
- GTEST_DEATH_TEST_CHECK_(child_pid != -1);
- set_child_pid(child_pid);
- if (child_pid == 0) {
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0]));
- set_write_fd(pipe_fd[1]);
- // Redirects all logging to stderr in the child process to prevent
- // concurrent writes to the log files. We capture stderr in the parent
- // process and append the child process' output to a log.
- LogToStderr();
- // Event forwarding to the listeners of event listener API mush be shut
- // down in death test subprocesses.
- GetUnitTestImpl()->listeners()->SuppressEventForwarding();
- return EXECUTE_TEST;
- } else {
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
- set_read_fd(pipe_fd[0]);
- set_spawned(true);
- return OVERSEE_TEST;
- }
-}
-
-// A concrete death test class that forks and re-executes the main
-// program from the beginning, with command-line flags set that cause
-// only this specific death test to be run.
-class ExecDeathTest : public ForkingDeathTest {
- public:
- ExecDeathTest(const char* a_statement, const RE* a_regex,
- const char* file, int line) :
- ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { }
- virtual TestRole AssumeRole();
- private:
- // The name of the file in which the death test is located.
- const char* const file_;
- // The line number on which the death test is located.
- const int line_;
-};
-
-// Utility class for accumulating command-line arguments.
-class Arguments {
- public:
- Arguments() {
- args_.push_back(NULL);
- }
-
- ~Arguments() {
- for (std::vector<char*>::iterator i = args_.begin(); i != args_.end();
- ++i) {
- free(*i);
- }
- }
- void AddArgument(const char* argument) {
- args_.insert(args_.end() - 1, posix::StrDup(argument));
- }
-
- template <typename Str>
- void AddArguments(const ::std::vector<Str>& arguments) {
- for (typename ::std::vector<Str>::const_iterator i = arguments.begin();
- i != arguments.end();
- ++i) {
- args_.insert(args_.end() - 1, posix::StrDup(i->c_str()));
- }
- }
- char* const* Argv() {
- return &args_[0];
- }
- private:
- std::vector<char*> args_;
-};
-
-// A struct that encompasses the arguments to the child process of a
-// threadsafe-style death test process.
-struct ExecDeathTestArgs {
- char* const* argv; // Command-line arguments for the child's call to exec
- int close_fd; // File descriptor to close; the read end of a pipe
-};
-
-#if GTEST_OS_MAC
-inline char** GetEnviron() {
- // When Google Test is built as a framework on MacOS X, the environ variable
- // is unavailable. Apple's documentation (man environ) recommends using
- // _NSGetEnviron() instead.
- return *_NSGetEnviron();
-}
-#else
-// Some POSIX platforms expect you to declare environ. extern "C" makes
-// it reside in the global namespace.
-extern "C" char** environ;
-inline char** GetEnviron() { return environ; }
-#endif // GTEST_OS_MAC
-
-// The main function for a threadsafe-style death test child process.
-// This function is called in a clone()-ed process and thus must avoid
-// any potentially unsafe operations like malloc or libc functions.
-static int ExecDeathTestChildMain(void* child_arg) {
- ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
-
- // We need to execute the test program in the same environment where
- // it was originally invoked. Therefore we change to the original
- // working directory first.
- const char* const original_dir =
- UnitTest::GetInstance()->original_working_dir();
- // We can safely call chdir() as it's a direct system call.
- if (chdir(original_dir) != 0) {
- DeathTestAbort(String::Format("chdir(\"%s\") failed: %s",
- original_dir,
- GetLastErrnoDescription().c_str()));
- return EXIT_FAILURE;
- }
-
- // We can safely call execve() as it's a direct system call. We
- // cannot use execvp() as it's a libc function and thus potentially
- // unsafe. Since execve() doesn't search the PATH, the user must
- // invoke the test program via a valid path that contains at least
- // one path separator.
- execve(args->argv[0], args->argv, GetEnviron());
- DeathTestAbort(String::Format("execve(%s, ...) in %s failed: %s",
- args->argv[0],
- original_dir,
- GetLastErrnoDescription().c_str()));
- return EXIT_FAILURE;
-}
-
-// Two utility routines that together determine the direction the stack
-// grows.
-// This could be accomplished more elegantly by a single recursive
-// function, but we want to guard against the unlikely possibility of
-// a smart compiler optimizing the recursion away.
-bool StackLowerThanAddress(const void* ptr) {
- int dummy;
- return &dummy < ptr;
-}
-
-bool StackGrowsDown() {
- int dummy;
- return StackLowerThanAddress(&dummy);
-}
-
-// A threadsafe implementation of fork(2) for threadsafe-style death tests
-// that uses clone(2). It dies with an error message if anything goes
-// wrong.
-static pid_t ExecDeathTestFork(char* const* argv, int close_fd) {
- ExecDeathTestArgs args = { argv, close_fd };
- pid_t child_pid = -1;
-
-#if GTEST_HAS_CLONE
- const bool use_fork = GTEST_FLAG(death_test_use_fork);
-
- if (!use_fork) {
- static const bool stack_grows_down = StackGrowsDown();
- const size_t stack_size = getpagesize();
- // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead.
- void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, -1, 0);
- GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED);
- void* const stack_top =
- static_cast<char*>(stack) + (stack_grows_down ? stack_size : 0);
-
- child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args);
-
- GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1);
- }
-#else
- const bool use_fork = true;
-#endif // GTEST_HAS_CLONE
-
- if (use_fork && (child_pid = fork()) == 0) {
- ExecDeathTestChildMain(&args);
- _exit(0);
- }
-
- GTEST_DEATH_TEST_CHECK_(child_pid != -1);
- return child_pid;
-}
-
-// The AssumeRole process for a fork-and-exec death test. It re-executes the
-// main program from the beginning, setting the --gtest_filter
-// and --gtest_internal_run_death_test flags to cause only the current
-// death test to be re-run.
-DeathTest::TestRole ExecDeathTest::AssumeRole() {
- const UnitTestImpl* const impl = GetUnitTestImpl();
- const InternalRunDeathTestFlag* const flag =
- impl->internal_run_death_test_flag();
- const TestInfo* const info = impl->current_test_info();
- const int death_test_index = info->result()->death_test_count();
-
- if (flag != NULL) {
- set_write_fd(flag->write_fd());
- return EXECUTE_TEST;
- }
-
- int pipe_fd[2];
- GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1);
- // Clear the close-on-exec flag on the write end of the pipe, lest
- // it be closed when the child process does an exec:
- GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1);
-
- const String filter_flag =
- String::Format("--%s%s=%s.%s",
- GTEST_FLAG_PREFIX_, kFilterFlag,
- info->test_case_name(), info->name());
- const String internal_flag =
- String::Format("--%s%s=%s|%d|%d|%d",
- GTEST_FLAG_PREFIX_, kInternalRunDeathTestFlag,
- file_, line_, death_test_index, pipe_fd[1]);
- Arguments args;
- args.AddArguments(GetArgvs());
- args.AddArgument(filter_flag.c_str());
- args.AddArgument(internal_flag.c_str());
-
- DeathTest::set_last_death_test_message("");
-
- CaptureStderr();
- // See the comment in NoExecDeathTest::AssumeRole for why the next line
- // is necessary.
- FlushInfoLog();
-
- const pid_t child_pid = ExecDeathTestFork(args.Argv(), pipe_fd[0]);
- GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1]));
- set_child_pid(child_pid);
- set_read_fd(pipe_fd[0]);
- set_spawned(true);
- return OVERSEE_TEST;
-}
-
-#endif // !GTEST_OS_WINDOWS
-
-// Creates a concrete DeathTest-derived class that depends on the
-// --gtest_death_test_style flag, and sets the pointer pointed to
-// by the "test" argument to its address. If the test should be
-// skipped, sets that pointer to NULL. Returns true, unless the
-// flag is set to an invalid value.
-bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex,
- const char* file, int line,
- DeathTest** test) {
- UnitTestImpl* const impl = GetUnitTestImpl();
- const InternalRunDeathTestFlag* const flag =
- impl->internal_run_death_test_flag();
- const int death_test_index = impl->current_test_info()
- ->increment_death_test_count();
-
- if (flag != NULL) {
- if (death_test_index > flag->index()) {
- DeathTest::set_last_death_test_message(String::Format(
- "Death test count (%d) somehow exceeded expected maximum (%d)",
- death_test_index, flag->index()));
- return false;
- }
-
- if (!(flag->file() == file && flag->line() == line &&
- flag->index() == death_test_index)) {
- *test = NULL;
- return true;
- }
- }
-
-#if GTEST_OS_WINDOWS
- if (GTEST_FLAG(death_test_style) == "threadsafe" ||
- GTEST_FLAG(death_test_style) == "fast") {
- *test = new WindowsDeathTest(statement, regex, file, line);
- }
-#else
- if (GTEST_FLAG(death_test_style) == "threadsafe") {
- *test = new ExecDeathTest(statement, regex, file, line);
- } else if (GTEST_FLAG(death_test_style) == "fast") {
- *test = new NoExecDeathTest(statement, regex);
- }
-#endif // GTEST_OS_WINDOWS
- else { // NOLINT - this is more readable than unbalanced brackets inside #if.
- DeathTest::set_last_death_test_message(String::Format(
- "Unknown death test style \"%s\" encountered",
- GTEST_FLAG(death_test_style).c_str()));
- return false;
- }
-
- return true;
-}
-
-// Splits a given string on a given delimiter, populating a given
-// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have
-// ::std::string, so we can use it here.
-static void SplitString(const ::std::string& str, char delimiter,
- ::std::vector< ::std::string>* dest) {
- ::std::vector< ::std::string> parsed;
- ::std::string::size_type pos = 0;
- while (::testing::internal::AlwaysTrue()) {
- const ::std::string::size_type colon = str.find(delimiter, pos);
- if (colon == ::std::string::npos) {
- parsed.push_back(str.substr(pos));
- break;
- } else {
- parsed.push_back(str.substr(pos, colon - pos));
- pos = colon + 1;
- }
- }
- dest->swap(parsed);
-}
-
-#if GTEST_OS_WINDOWS
-// Recreates the pipe and event handles from the provided parameters,
-// signals the event, and returns a file descriptor wrapped around the pipe
-// handle. This function is called in the child process only.
-int GetStatusFileDescriptor(unsigned int parent_process_id,
- size_t write_handle_as_size_t,
- size_t event_handle_as_size_t) {
- AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE,
- FALSE, // Non-inheritable.
- parent_process_id));
- if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) {
- DeathTestAbort(String::Format("Unable to open parent process %u",
- parent_process_id));
- }
-
- // TODO(vladl@google.com): Replace the following check with a
- // compile-time assertion when available.
- GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t));
-
- const HANDLE write_handle =
- reinterpret_cast<HANDLE>(write_handle_as_size_t);
- HANDLE dup_write_handle;
-
- // The newly initialized handle is accessible only in in the parent
- // process. To obtain one accessible within the child, we need to use
- // DuplicateHandle.
- if (!::DuplicateHandle(parent_process_handle.Get(), write_handle,
- ::GetCurrentProcess(), &dup_write_handle,
- 0x0, // Requested privileges ignored since
- // DUPLICATE_SAME_ACCESS is used.
- FALSE, // Request non-inheritable handler.
- DUPLICATE_SAME_ACCESS)) {
- DeathTestAbort(String::Format(
- "Unable to duplicate the pipe handle %Iu from the parent process %u",
- write_handle_as_size_t, parent_process_id));
- }
-
- const HANDLE event_handle = reinterpret_cast<HANDLE>(event_handle_as_size_t);
- HANDLE dup_event_handle;
-
- if (!::DuplicateHandle(parent_process_handle.Get(), event_handle,
- ::GetCurrentProcess(), &dup_event_handle,
- 0x0,
- FALSE,
- DUPLICATE_SAME_ACCESS)) {
- DeathTestAbort(String::Format(
- "Unable to duplicate the event handle %Iu from the parent process %u",
- event_handle_as_size_t, parent_process_id));
- }
-
- const int write_fd =
- ::_open_osfhandle(reinterpret_cast<intptr_t>(dup_write_handle), O_APPEND);
- if (write_fd == -1) {
- DeathTestAbort(String::Format(
- "Unable to convert pipe handle %Iu to a file descriptor",
- write_handle_as_size_t));
- }
-
- // Signals the parent that the write end of the pipe has been acquired
- // so the parent can release its own write end.
- ::SetEvent(dup_event_handle);
-
- return write_fd;
-}
-#endif // GTEST_OS_WINDOWS
-
-// Returns a newly created InternalRunDeathTestFlag object with fields
-// initialized from the GTEST_FLAG(internal_run_death_test) flag if
-// the flag is specified; otherwise returns NULL.
-InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() {
- if (GTEST_FLAG(internal_run_death_test) == "") return NULL;
-
- // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we
- // can use it here.
- int line = -1;
- int index = -1;
- ::std::vector< ::std::string> fields;
- SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields);
- int write_fd = -1;
-
-#if GTEST_OS_WINDOWS
- unsigned int parent_process_id = 0;
- size_t write_handle_as_size_t = 0;
- size_t event_handle_as_size_t = 0;
-
- if (fields.size() != 6
- || !ParseNaturalNumber(fields[1], &line)
- || !ParseNaturalNumber(fields[2], &index)
- || !ParseNaturalNumber(fields[3], &parent_process_id)
- || !ParseNaturalNumber(fields[4], &write_handle_as_size_t)
- || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) {
- DeathTestAbort(String::Format(
- "Bad --gtest_internal_run_death_test flag: %s",
- GTEST_FLAG(internal_run_death_test).c_str()));
- }
- write_fd = GetStatusFileDescriptor(parent_process_id,
- write_handle_as_size_t,
- event_handle_as_size_t);
-#else
- if (fields.size() != 4
- || !ParseNaturalNumber(fields[1], &line)
- || !ParseNaturalNumber(fields[2], &index)
- || !ParseNaturalNumber(fields[3], &write_fd)) {
- DeathTestAbort(String::Format(
- "Bad --gtest_internal_run_death_test flag: %s",
- GTEST_FLAG(internal_run_death_test).c_str()));
- }
-#endif // GTEST_OS_WINDOWS
- return new InternalRunDeathTestFlag(fields[0], line, index, write_fd);
-}
-
-} // namespace internal
-
-#endif // GTEST_HAS_DEATH_TEST
-
-} // namespace testing
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Authors: keith.ray@gmail.com (Keith Ray)
-
-
-#include <stdlib.h>
-
-#if GTEST_OS_WINDOWS_MOBILE
-#include <windows.h>
-#elif GTEST_OS_WINDOWS
-#include <direct.h>
-#include <io.h>
-#elif GTEST_OS_SYMBIAN
-// Symbian OpenC has PATH_MAX in sys/syslimits.h
-#include <sys/syslimits.h>
-#else
-#include <limits.h>
-#include <climits> // Some Linux distributions define PATH_MAX here.
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-#if GTEST_OS_WINDOWS
-#define GTEST_PATH_MAX_ _MAX_PATH
-#elif defined(PATH_MAX)
-#define GTEST_PATH_MAX_ PATH_MAX
-#elif defined(_XOPEN_PATH_MAX)
-#define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
-#else
-#define GTEST_PATH_MAX_ _POSIX_PATH_MAX
-#endif // GTEST_OS_WINDOWS
-
-
-namespace testing {
-namespace internal {
-
-#if GTEST_OS_WINDOWS
-// On Windows, '\\' is the standard path separator, but many tools and the
-// Windows API also accept '/' as an alternate path separator. Unless otherwise
-// noted, a file path can contain either kind of path separators, or a mixture
-// of them.
-const char kPathSeparator = '\\';
-const char kAlternatePathSeparator = '/';
-const char kPathSeparatorString[] = "\\";
-const char kAlternatePathSeparatorString[] = "/";
-#if GTEST_OS_WINDOWS_MOBILE
-// Windows CE doesn't have a current directory. You should not use
-// the current directory in tests on Windows CE, but this at least
-// provides a reasonable fallback.
-const char kCurrentDirectoryString[] = "\\";
-// Windows CE doesn't define INVALID_FILE_ATTRIBUTES
-const DWORD kInvalidFileAttributes = 0xffffffff;
-#else
-const char kCurrentDirectoryString[] = ".\\";
-#endif // GTEST_OS_WINDOWS_MOBILE
-#else
-const char kPathSeparator = '/';
-const char kPathSeparatorString[] = "/";
-const char kCurrentDirectoryString[] = "./";
-#endif // GTEST_OS_WINDOWS
-
-// Returns whether the given character is a valid path separator.
-static bool IsPathSeparator(char c) {
-#if GTEST_HAS_ALT_PATH_SEP_
- return (c == kPathSeparator) || (c == kAlternatePathSeparator);
-#else
- return c == kPathSeparator;
-#endif
-}
-
-// Returns the current working directory, or "" if unsuccessful.
-FilePath FilePath::GetCurrentDir() {
-#if GTEST_OS_WINDOWS_MOBILE
- // Windows CE doesn't have a current directory, so we just return
- // something reasonable.
- return FilePath(kCurrentDirectoryString);
-#elif GTEST_OS_WINDOWS
- char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
- return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
-#else
- char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
- return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
-#endif // GTEST_OS_WINDOWS_MOBILE
-}
-
-// Returns a copy of the FilePath with the case-insensitive extension removed.
-// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
-// FilePath("dir/file"). If a case-insensitive extension is not
-// found, returns a copy of the original FilePath.
-FilePath FilePath::RemoveExtension(const char* extension) const {
- String dot_extension(String::Format(".%s", extension));
- if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
- return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
- }
- return *this;
-}
-
-// Returns a pointer to the last occurence of a valid path separator in
-// the FilePath. On Windows, for example, both '/' and '\' are valid path
-// separators. Returns NULL if no path separator was found.
-const char* FilePath::FindLastPathSeparator() const {
- const char* const last_sep = strrchr(c_str(), kPathSeparator);
-#if GTEST_HAS_ALT_PATH_SEP_
- const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
- // Comparing two pointers of which only one is NULL is undefined.
- if (last_alt_sep != NULL &&
- (last_sep == NULL || last_alt_sep > last_sep)) {
- return last_alt_sep;
- }
-#endif
- return last_sep;
-}
-
-// Returns a copy of the FilePath with the directory part removed.
-// Example: FilePath("path/to/file").RemoveDirectoryName() returns
-// FilePath("file"). If there is no directory part ("just_a_file"), it returns
-// the FilePath unmodified. If there is no file part ("just_a_dir/") it
-// returns an empty FilePath ("").
-// On Windows platform, '\' is the path separator, otherwise it is '/'.
-FilePath FilePath::RemoveDirectoryName() const {
- const char* const last_sep = FindLastPathSeparator();
- return last_sep ? FilePath(String(last_sep + 1)) : *this;
-}
-
-// RemoveFileName returns the directory path with the filename removed.
-// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
-// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
-// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
-// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
-// On Windows platform, '\' is the path separator, otherwise it is '/'.
-FilePath FilePath::RemoveFileName() const {
- const char* const last_sep = FindLastPathSeparator();
- String dir;
- if (last_sep) {
- dir = String(c_str(), last_sep + 1 - c_str());
- } else {
- dir = kCurrentDirectoryString;
- }
- return FilePath(dir);
-}
-
-// Helper functions for naming files in a directory for xml output.
-
-// Given directory = "dir", base_name = "test", number = 0,
-// extension = "xml", returns "dir/test.xml". If number is greater
-// than zero (e.g., 12), returns "dir/test_12.xml".
-// On Windows platform, uses \ as the separator rather than /.
-FilePath FilePath::MakeFileName(const FilePath& directory,
- const FilePath& base_name,
- int number,
- const char* extension) {
- String file;
- if (number == 0) {
- file = String::Format("%s.%s", base_name.c_str(), extension);
- } else {
- file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
- }
- return ConcatPaths(directory, FilePath(file));
-}
-
-// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
-// On Windows, uses \ as the separator rather than /.
-FilePath FilePath::ConcatPaths(const FilePath& directory,
- const FilePath& relative_path) {
- if (directory.IsEmpty())
- return relative_path;
- const FilePath dir(directory.RemoveTrailingPathSeparator());
- return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
- relative_path.c_str()));
-}
-
-// Returns true if pathname describes something findable in the file-system,
-// either a file, directory, or whatever.
-bool FilePath::FileOrDirectoryExists() const {
-#if GTEST_OS_WINDOWS_MOBILE
- LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
- const DWORD attributes = GetFileAttributes(unicode);
- delete [] unicode;
- return attributes != kInvalidFileAttributes;
-#else
- posix::StatStruct file_stat;
- return posix::Stat(pathname_.c_str(), &file_stat) == 0;
-#endif // GTEST_OS_WINDOWS_MOBILE
-}
-
-// Returns true if pathname describes a directory in the file-system
-// that exists.
-bool FilePath::DirectoryExists() const {
- bool result = false;
-#if GTEST_OS_WINDOWS
- // Don't strip off trailing separator if path is a root directory on
- // Windows (like "C:\\").
- const FilePath& path(IsRootDirectory() ? *this :
- RemoveTrailingPathSeparator());
-#else
- const FilePath& path(*this);
-#endif
-
-#if GTEST_OS_WINDOWS_MOBILE
- LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
- const DWORD attributes = GetFileAttributes(unicode);
- delete [] unicode;
- if ((attributes != kInvalidFileAttributes) &&
- (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
- result = true;
- }
-#else
- posix::StatStruct file_stat;
- result = posix::Stat(path.c_str(), &file_stat) == 0 &&
- posix::IsDir(file_stat);
-#endif // GTEST_OS_WINDOWS_MOBILE
-
- return result;
-}
-
-// Returns true if pathname describes a root directory. (Windows has one
-// root directory per disk drive.)
-bool FilePath::IsRootDirectory() const {
-#if GTEST_OS_WINDOWS
- // TODO(wan@google.com): on Windows a network share like
- // \\server\share can be a root directory, although it cannot be the
- // current directory. Handle this properly.
- return pathname_.length() == 3 && IsAbsolutePath();
-#else
- return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
-#endif
-}
-
-// Returns true if pathname describes an absolute path.
-bool FilePath::IsAbsolutePath() const {
- const char* const name = pathname_.c_str();
-#if GTEST_OS_WINDOWS
- return pathname_.length() >= 3 &&
- ((name[0] >= 'a' && name[0] <= 'z') ||
- (name[0] >= 'A' && name[0] <= 'Z')) &&
- name[1] == ':' &&
- IsPathSeparator(name[2]);
-#else
- return IsPathSeparator(name[0]);
-#endif
-}
-
-// Returns a pathname for a file that does not currently exist. The pathname
-// will be directory/base_name.extension or
-// directory/base_name_<number>.extension if directory/base_name.extension
-// already exists. The number will be incremented until a pathname is found
-// that does not already exist.
-// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
-// There could be a race condition if two or more processes are calling this
-// function at the same time -- they could both pick the same filename.
-FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
- const FilePath& base_name,
- const char* extension) {
- FilePath full_pathname;
- int number = 0;
- do {
- full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
- } while (full_pathname.FileOrDirectoryExists());
- return full_pathname;
-}
-
-// Returns true if FilePath ends with a path separator, which indicates that
-// it is intended to represent a directory. Returns false otherwise.
-// This does NOT check that a directory (or file) actually exists.
-bool FilePath::IsDirectory() const {
- return !pathname_.empty() &&
- IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
-}
-
-// Create directories so that path exists. Returns true if successful or if
-// the directories already exist; returns false if unable to create directories
-// for any reason.
-bool FilePath::CreateDirectoriesRecursively() const {
- if (!this->IsDirectory()) {
- return false;
- }
-
- if (pathname_.length() == 0 || this->DirectoryExists()) {
- return true;
- }
-
- const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
- return parent.CreateDirectoriesRecursively() && this->CreateFolder();
-}
-
-// Create the directory so that path exists. Returns true if successful or
-// if the directory already exists; returns false if unable to create the
-// directory for any reason, including if the parent directory does not
-// exist. Not named "CreateDirectory" because that's a macro on Windows.
-bool FilePath::CreateFolder() const {
-#if GTEST_OS_WINDOWS_MOBILE
- FilePath removed_sep(this->RemoveTrailingPathSeparator());
- LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
- int result = CreateDirectory(unicode, NULL) ? 0 : -1;
- delete [] unicode;
-#elif GTEST_OS_WINDOWS
- int result = _mkdir(pathname_.c_str());
-#else
- int result = mkdir(pathname_.c_str(), 0777);
-#endif // GTEST_OS_WINDOWS_MOBILE
-
- if (result == -1) {
- return this->DirectoryExists(); // An error is OK if the directory exists.
- }
- return true; // No error.
-}
-
-// If input name has a trailing separator character, remove it and return the
-// name, otherwise return the name string unmodified.
-// On Windows platform, uses \ as the separator, other platforms use /.
-FilePath FilePath::RemoveTrailingPathSeparator() const {
- return IsDirectory()
- ? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
- : *this;
-}
-
-// Removes any redundant separators that might be in the pathname.
-// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
-// redundancies that might be in a pathname involving "." or "..".
-// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
-void FilePath::Normalize() {
- if (pathname_.c_str() == NULL) {
- pathname_ = "";
- return;
- }
- const char* src = pathname_.c_str();
- char* const dest = new char[pathname_.length() + 1];
- char* dest_ptr = dest;
- memset(dest_ptr, 0, pathname_.length() + 1);
-
- while (*src != '\0') {
- *dest_ptr = *src;
- if (!IsPathSeparator(*src)) {
- src++;
- } else {
-#if GTEST_HAS_ALT_PATH_SEP_
- if (*dest_ptr == kAlternatePathSeparator) {
- *dest_ptr = kPathSeparator;
- }
-#endif
- while (IsPathSeparator(*src))
- src++;
- }
- dest_ptr++;
- }
- *dest_ptr = '\0';
- pathname_ = dest;
- delete[] dest;
-}
-
-} // namespace internal
-} // namespace testing
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-
-#include <limits.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#if GTEST_OS_WINDOWS_MOBILE
-#include <windows.h> // For TerminateProcess()
-#elif GTEST_OS_WINDOWS
-#include <io.h>
-#include <sys/stat.h>
-#else
-#include <unistd.h>
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-#if GTEST_OS_MAC
-#include <mach/mach_init.h>
-#include <mach/task.h>
-#include <mach/vm_map.h>
-#endif // GTEST_OS_MAC
-
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
-#define GTEST_IMPLEMENTATION_ 1
-#undef GTEST_IMPLEMENTATION_
-
-namespace testing {
-namespace internal {
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
-const int kStdOutFileno = 1;
-const int kStdErrFileno = 2;
-#else
-const int kStdOutFileno = STDOUT_FILENO;
-const int kStdErrFileno = STDERR_FILENO;
-#endif // _MSC_VER
-
-#if GTEST_OS_MAC
-
-// Returns the number of threads running in the process, or 0 to indicate that
-// we cannot detect it.
-size_t GetThreadCount() {
- const task_t task = mach_task_self();
- mach_msg_type_number_t thread_count;
- thread_act_array_t thread_list;
- const kern_return_t status = task_threads(task, &thread_list, &thread_count);
- if (status == KERN_SUCCESS) {
- // task_threads allocates resources in thread_list and we need to free them
- // to avoid leaks.
- vm_deallocate(task,
- reinterpret_cast<vm_address_t>(thread_list),
- sizeof(thread_t) * thread_count);
- return static_cast<size_t>(thread_count);
- } else {
- return 0;
- }
-}
-
-#else
-
-size_t GetThreadCount() {
- // There's no portable way to detect the number of threads, so we just
- // return 0 to indicate that we cannot detect it.
- return 0;
-}
-
-#endif // GTEST_OS_MAC
-
-#if GTEST_USES_POSIX_RE
-
-// Implements RE. Currently only needed for death tests.
-
-RE::~RE() {
- if (is_valid_) {
- // regfree'ing an invalid regex might crash because the content
- // of the regex is undefined. Since the regex's are essentially
- // the same, one cannot be valid (or invalid) without the other
- // being so too.
- regfree(&partial_regex_);
- regfree(&full_regex_);
- }
- free(const_cast<char*>(pattern_));
-}
-
-// Returns true iff regular expression re matches the entire str.
-bool RE::FullMatch(const char* str, const RE& re) {
- if (!re.is_valid_) return false;
-
- regmatch_t match;
- return regexec(&re.full_regex_, str, 1, &match, 0) == 0;
-}
-
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
-bool RE::PartialMatch(const char* str, const RE& re) {
- if (!re.is_valid_) return false;
-
- regmatch_t match;
- return regexec(&re.partial_regex_, str, 1, &match, 0) == 0;
-}
-
-// Initializes an RE from its string representation.
-void RE::Init(const char* regex) {
- pattern_ = posix::StrDup(regex);
-
- // Reserves enough bytes to hold the regular expression used for a
- // full match.
- const size_t full_regex_len = strlen(regex) + 10;
- char* const full_pattern = new char[full_regex_len];
-
- snprintf(full_pattern, full_regex_len, "^(%s)$", regex);
- is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0;
- // We want to call regcomp(&partial_regex_, ...) even if the
- // previous expression returns false. Otherwise partial_regex_ may
- // not be properly initialized can may cause trouble when it's
- // freed.
- //
- // Some implementation of POSIX regex (e.g. on at least some
- // versions of Cygwin) doesn't accept the empty string as a valid
- // regex. We change it to an equivalent form "()" to be safe.
- if (is_valid_) {
- const char* const partial_regex = (*regex == '\0') ? "()" : regex;
- is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0;
- }
- EXPECT_TRUE(is_valid_)
- << "Regular expression \"" << regex
- << "\" is not a valid POSIX Extended regular expression.";
-
- delete[] full_pattern;
-}
-
-#elif GTEST_USES_SIMPLE_RE
-
-// Returns true iff ch appears anywhere in str (excluding the
-// terminating '\0' character).
-bool IsInSet(char ch, const char* str) {
- return ch != '\0' && strchr(str, ch) != NULL;
-}
-
-// Returns true iff ch belongs to the given classification. Unlike
-// similar functions in <ctype.h>, these aren't affected by the
-// current locale.
-bool IsDigit(char ch) { return '0' <= ch && ch <= '9'; }
-bool IsPunct(char ch) {
- return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
-}
-bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
-bool IsWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
-bool IsWordChar(char ch) {
- return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') ||
- ('0' <= ch && ch <= '9') || ch == '_';
-}
-
-// Returns true iff "\\c" is a supported escape sequence.
-bool IsValidEscape(char c) {
- return (IsPunct(c) || IsInSet(c, "dDfnrsStvwW"));
-}
-
-// Returns true iff the given atom (specified by escaped and pattern)
-// matches ch. The result is undefined if the atom is invalid.
-bool AtomMatchesChar(bool escaped, char pattern_char, char ch) {
- if (escaped) { // "\\p" where p is pattern_char.
- switch (pattern_char) {
- case 'd': return IsDigit(ch);
- case 'D': return !IsDigit(ch);
- case 'f': return ch == '\f';
- case 'n': return ch == '\n';
- case 'r': return ch == '\r';
- case 's': return IsWhiteSpace(ch);
- case 'S': return !IsWhiteSpace(ch);
- case 't': return ch == '\t';
- case 'v': return ch == '\v';
- case 'w': return IsWordChar(ch);
- case 'W': return !IsWordChar(ch);
- }
- return IsPunct(pattern_char) && pattern_char == ch;
- }
-
- return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
-}
-
-// Helper function used by ValidateRegex() to format error messages.
-String FormatRegexSyntaxError(const char* regex, int index) {
- return (Message() << "Syntax error at index " << index
- << " in simple regular expression \"" << regex << "\": ").GetString();
-}
-
-// Generates non-fatal failures and returns false if regex is invalid;
-// otherwise returns true.
-bool ValidateRegex(const char* regex) {
- if (regex == NULL) {
- // TODO(wan@google.com): fix the source file location in the
- // assertion failures to match where the regex is used in user
- // code.
- ADD_FAILURE() << "NULL is not a valid simple regular expression.";
- return false;
- }
-
- bool is_valid = true;
-
- // True iff ?, *, or + can follow the previous atom.
- bool prev_repeatable = false;
- for (int i = 0; regex[i]; i++) {
- if (regex[i] == '\\') { // An escape sequence
- i++;
- if (regex[i] == '\0') {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
- << "'\\' cannot appear at the end.";
- return false;
- }
-
- if (!IsValidEscape(regex[i])) {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1)
- << "invalid escape sequence \"\\" << regex[i] << "\".";
- is_valid = false;
- }
- prev_repeatable = true;
- } else { // Not an escape sequence.
- const char ch = regex[i];
-
- if (ch == '^' && i > 0) {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
- << "'^' can only appear at the beginning.";
- is_valid = false;
- } else if (ch == '$' && regex[i + 1] != '\0') {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
- << "'$' can only appear at the end.";
- is_valid = false;
- } else if (IsInSet(ch, "()[]{}|")) {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
- << "'" << ch << "' is unsupported.";
- is_valid = false;
- } else if (IsRepeat(ch) && !prev_repeatable) {
- ADD_FAILURE() << FormatRegexSyntaxError(regex, i)
- << "'" << ch << "' can only follow a repeatable token.";
- is_valid = false;
- }
-
- prev_repeatable = !IsInSet(ch, "^$?*+");
- }
- }
-
- return is_valid;
-}
-
-// Matches a repeated regex atom followed by a valid simple regular
-// expression. The regex atom is defined as c if escaped is false,
-// or \c otherwise. repeat is the repetition meta character (?, *,
-// or +). The behavior is undefined if str contains too many
-// characters to be indexable by size_t, in which case the test will
-// probably time out anyway. We are fine with this limitation as
-// std::string has it too.
-bool MatchRepetitionAndRegexAtHead(
- bool escaped, char c, char repeat, const char* regex,
- const char* str) {
- const size_t min_count = (repeat == '+') ? 1 : 0;
- const size_t max_count = (repeat == '?') ? 1 :
- static_cast<size_t>(-1) - 1;
- // We cannot call numeric_limits::max() as it conflicts with the
- // max() macro on Windows.
-
- for (size_t i = 0; i <= max_count; ++i) {
- // We know that the atom matches each of the first i characters in str.
- if (i >= min_count && MatchRegexAtHead(regex, str + i)) {
- // We have enough matches at the head, and the tail matches too.
- // Since we only care about *whether* the pattern matches str
- // (as opposed to *how* it matches), there is no need to find a
- // greedy match.
- return true;
- }
- if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i]))
- return false;
- }
- return false;
-}
-
-// Returns true iff regex matches a prefix of str. regex must be a
-// valid simple regular expression and not start with "^", or the
-// result is undefined.
-bool MatchRegexAtHead(const char* regex, const char* str) {
- if (*regex == '\0') // An empty regex matches a prefix of anything.
- return true;
-
- // "$" only matches the end of a string. Note that regex being
- // valid guarantees that there's nothing after "$" in it.
- if (*regex == '$')
- return *str == '\0';
-
- // Is the first thing in regex an escape sequence?
- const bool escaped = *regex == '\\';
- if (escaped)
- ++regex;
- if (IsRepeat(regex[1])) {
- // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so
- // here's an indirect recursion. It terminates as the regex gets
- // shorter in each recursion.
- return MatchRepetitionAndRegexAtHead(
- escaped, regex[0], regex[1], regex + 2, str);
- } else {
- // regex isn't empty, isn't "$", and doesn't start with a
- // repetition. We match the first atom of regex with the first
- // character of str and recurse.
- return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) &&
- MatchRegexAtHead(regex + 1, str + 1);
- }
-}
-
-// Returns true iff regex matches any substring of str. regex must be
-// a valid simple regular expression, or the result is undefined.
-//
-// The algorithm is recursive, but the recursion depth doesn't exceed
-// the regex length, so we won't need to worry about running out of
-// stack space normally. In rare cases the time complexity can be
-// exponential with respect to the regex length + the string length,
-// but usually it's must faster (often close to linear).
-bool MatchRegexAnywhere(const char* regex, const char* str) {
- if (regex == NULL || str == NULL)
- return false;
-
- if (*regex == '^')
- return MatchRegexAtHead(regex + 1, str);
-
- // A successful match can be anywhere in str.
- do {
- if (MatchRegexAtHead(regex, str))
- return true;
- } while (*str++ != '\0');
- return false;
-}
-
-// Implements the RE class.
-
-RE::~RE() {
- free(const_cast<char*>(pattern_));
- free(const_cast<char*>(full_pattern_));
-}
-
-// Returns true iff regular expression re matches the entire str.
-bool RE::FullMatch(const char* str, const RE& re) {
- return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str);
-}
-
-// Returns true iff regular expression re matches a substring of str
-// (including str itself).
-bool RE::PartialMatch(const char* str, const RE& re) {
- return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str);
-}
-
-// Initializes an RE from its string representation.
-void RE::Init(const char* regex) {
- pattern_ = full_pattern_ = NULL;
- if (regex != NULL) {
- pattern_ = posix::StrDup(regex);
- }
-
- is_valid_ = ValidateRegex(regex);
- if (!is_valid_) {
- // No need to calculate the full pattern when the regex is invalid.
- return;
- }
-
- const size_t len = strlen(regex);
- // Reserves enough bytes to hold the regular expression used for a
- // full match: we need space to prepend a '^', append a '$', and
- // terminate the string with '\0'.
- char* buffer = static_cast<char*>(malloc(len + 3));
- full_pattern_ = buffer;
-
- if (*regex != '^')
- *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'.
-
- // We don't use snprintf or strncpy, as they trigger a warning when
- // compiled with VC++ 8.0.
- memcpy(buffer, regex, len);
- buffer += len;
-
- if (len == 0 || regex[len - 1] != '$')
- *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'.
-
- *buffer = '\0';
-}
-
-#endif // GTEST_USES_POSIX_RE
-
-
-GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line)
- : severity_(severity) {
- const char* const marker =
- severity == GTEST_INFO ? "[ INFO ]" :
- severity == GTEST_WARNING ? "[WARNING]" :
- severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]";
- GetStream() << ::std::endl << marker << " "
- << FormatFileLocation(file, line).c_str() << ": ";
-}
-
-// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program.
-GTestLog::~GTestLog() {
- GetStream() << ::std::endl;
- if (severity_ == GTEST_FATAL) {
- fflush(stderr);
- posix::Abort();
- }
-}
-// Disable Microsoft deprecation warnings for POSIX functions called from
-// this class (creat, dup, dup2, and close)
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable: 4996)
-#endif // _MSC_VER
-
-#if GTEST_HAS_STREAM_REDIRECTION_
-
-// Object that captures an output stream (stdout/stderr).
-class CapturedStream {
- public:
- // The ctor redirects the stream to a temporary file.
- CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) {
-#if GTEST_OS_WINDOWS
- char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT
- char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT
-
- ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
- const UINT success = ::GetTempFileNameA(temp_dir_path,
- "gtest_redir",
- 0, // Generate unique file name.
- temp_file_path);
- GTEST_CHECK_(success != 0)
- << "Unable to create a temporary file in " << temp_dir_path;
- const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
- GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file "
- << temp_file_path;
- filename_ = temp_file_path;
-#else
- // There's no guarantee that a test has write access to the
- // current directory, so we create the temporary file in the /tmp
- // directory instead.
- char name_template[] = "/tmp/captured_stream.XXXXXX";
- const int captured_fd = mkstemp(name_template);
- filename_ = name_template;
-#endif // GTEST_OS_WINDOWS
- fflush(NULL);
- dup2(captured_fd, fd_);
- close(captured_fd);
- }
-
- ~CapturedStream() {
- remove(filename_.c_str());
- }
-
- String GetCapturedString() {
- if (uncaptured_fd_ != -1) {
- // Restores the original stream.
- fflush(NULL);
- dup2(uncaptured_fd_, fd_);
- close(uncaptured_fd_);
- uncaptured_fd_ = -1;
- }
-
- FILE* const file = posix::FOpen(filename_.c_str(), "r");
- const String content = ReadEntireFile(file);
- posix::FClose(file);
- return content;
- }
-
- private:
- // Reads the entire content of a file as a String.
- static String ReadEntireFile(FILE* file);
-
- // Returns the size (in bytes) of a file.
- static size_t GetFileSize(FILE* file);
-
- const int fd_; // A stream to capture.
- int uncaptured_fd_;
- // Name of the temporary file holding the stderr output.
- ::std::string filename_;
-
- GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream);
-};
-
-// Returns the size (in bytes) of a file.
-size_t CapturedStream::GetFileSize(FILE* file) {
- fseek(file, 0, SEEK_END);
- return static_cast<size_t>(ftell(file));
-}
-
-// Reads the entire content of a file as a string.
-String CapturedStream::ReadEntireFile(FILE* file) {
- const size_t file_size = GetFileSize(file);
- char* const buffer = new char[file_size];
-
- size_t bytes_last_read = 0; // # of bytes read in the last fread()
- size_t bytes_read = 0; // # of bytes read so far
-
- fseek(file, 0, SEEK_SET);
-
- // Keeps reading the file until we cannot read further or the
- // pre-determined file size is reached.
- do {
- bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
- bytes_read += bytes_last_read;
- } while (bytes_last_read > 0 && bytes_read < file_size);
-
- const String content(buffer, bytes_read);
- delete[] buffer;
-
- return content;
-}
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER
-
-static CapturedStream* g_captured_stderr = NULL;
-static CapturedStream* g_captured_stdout = NULL;
-
-// Starts capturing an output stream (stdout/stderr).
-void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) {
- if (*stream != NULL) {
- GTEST_LOG_(FATAL) << "Only one " << stream_name
- << " capturer can exist at a time.";
- }
- *stream = new CapturedStream(fd);
-}
-
-// Stops capturing the output stream and returns the captured string.
-String GetCapturedStream(CapturedStream** captured_stream) {
- const String content = (*captured_stream)->GetCapturedString();
-
- delete *captured_stream;
- *captured_stream = NULL;
-
- return content;
-}
-
-// Starts capturing stdout.
-void CaptureStdout() {
- CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout);
-}
-
-// Starts capturing stderr.
-void CaptureStderr() {
- CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr);
-}
-
-// Stops capturing stdout and returns the captured string.
-String GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
-
-// Stops capturing stderr and returns the captured string.
-String GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
-
-#endif // GTEST_HAS_STREAM_REDIRECTION_
-
-#if GTEST_HAS_DEATH_TEST
-
-// A copy of all command line arguments. Set by InitGoogleTest().
-::std::vector<String> g_argvs;
-
-// Returns the command line as a vector of strings.
-const ::std::vector<String>& GetArgvs() { return g_argvs; }
-
-#endif // GTEST_HAS_DEATH_TEST
-
-#if GTEST_OS_WINDOWS_MOBILE
-namespace posix {
-void Abort() {
- DebugBreak();
- TerminateProcess(GetCurrentProcess(), 1);
-}
-} // namespace posix
-#endif // GTEST_OS_WINDOWS_MOBILE
-
-// Returns the name of the environment variable corresponding to the
-// given flag. For example, FlagToEnvVar("foo") will return
-// "GTEST_FOO" in the open-source version.
-static String FlagToEnvVar(const char* flag) {
- const String full_flag =
- (Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
-
- Message env_var;
- for (size_t i = 0; i != full_flag.length(); i++) {
- env_var << static_cast<char>(toupper(full_flag.c_str()[i]));
- }
-
- return env_var.GetString();
-}
-
-// Parses 'str' for a 32-bit signed integer. If successful, writes
-// the result to *value and returns true; otherwise leaves *value
-// unchanged and returns false.
-bool ParseInt32(const Message& src_text, const char* str, Int32* value) {
- // Parses the environment variable as a decimal integer.
- char* end = NULL;
- const long long_value = strtol(str, &end, 10); // NOLINT
-
- // Has strtol() consumed all characters in the string?
- if (*end != '\0') {
- // No - an invalid character was encountered.
- Message msg;
- msg << "WARNING: " << src_text
- << " is expected to be a 32-bit integer, but actually"
- << " has value \"" << str << "\".\n";
- printf("%s", msg.GetString().c_str());
- fflush(stdout);
- return false;
- }
-
- // Is the parsed value in the range of an Int32?
- const Int32 result = static_cast<Int32>(long_value);
- if (long_value == LONG_MAX || long_value == LONG_MIN ||
- // The parsed value overflows as a long. (strtol() returns
- // LONG_MAX or LONG_MIN when the input overflows.)
- result != long_value
- // The parsed value overflows as an Int32.
- ) {
- Message msg;
- msg << "WARNING: " << src_text
- << " is expected to be a 32-bit integer, but actually"
- << " has value " << str << ", which overflows.\n";
- printf("%s", msg.GetString().c_str());
- fflush(stdout);
- return false;
- }
-
- *value = result;
- return true;
-}
-
-// Reads and returns the Boolean environment variable corresponding to
-// the given flag; if it's not set, returns default_value.
-//
-// The value is considered true iff it's not "0".
-bool BoolFromGTestEnv(const char* flag, bool default_value) {
- const String env_var = FlagToEnvVar(flag);
- const char* const string_value = posix::GetEnv(env_var.c_str());
- return string_value == NULL ?
- default_value : strcmp(string_value, "0") != 0;
-}
-
-// Reads and returns a 32-bit integer stored in the environment
-// variable corresponding to the given flag; if it isn't set or
-// doesn't represent a valid 32-bit integer, returns default_value.
-Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) {
- const String env_var = FlagToEnvVar(flag);
- const char* const string_value = posix::GetEnv(env_var.c_str());
- if (string_value == NULL) {
- // The environment variable is not set.
- return default_value;
- }
-
- Int32 result = default_value;
- if (!ParseInt32(Message() << "Environment variable " << env_var,
- string_value, &result)) {
- printf("The default value %s is used.\n",
- (Message() << default_value).GetString().c_str());
- fflush(stdout);
- return default_value;
- }
-
- return result;
-}
-
-// Reads and returns the string environment variable corresponding to
-// the given flag; if it's not set, returns default_value.
-const char* StringFromGTestEnv(const char* flag, const char* default_value) {
- const String env_var = FlagToEnvVar(flag);
- const char* const value = posix::GetEnv(env_var.c_str());
- return value == NULL ? default_value : value;
-}
-
-} // namespace internal
-} // namespace testing
-// Copyright 2008, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: mheule@google.com (Markus Heule)
-//
-// The Google C++ Testing Framework (Google Test)
-
-
-// Indicates that this translation unit is part of Google Test's
-// implementation. It must come before gtest-internal-inl.h is
-// included, or there will be a compiler error. This trick is to
-// prevent a user from accidentally including gtest-internal-inl.h in
-// his code.
-#define GTEST_IMPLEMENTATION_ 1
-#undef GTEST_IMPLEMENTATION_
-
-namespace testing {
-
-using internal::GetUnitTestImpl;
-
-// Gets the summary of the failure message by omitting the stack trace
-// in it.
-internal::String TestPartResult::ExtractSummary(const char* message) {
- const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
- return stack_trace == NULL ? internal::String(message) :
- internal::String(message, stack_trace - message);
-}
-
-// Prints a TestPartResult object.
-std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {
- return os
- << result.file_name() << ":" << result.line_number() << ": "
- << (result.type() == TestPartResult::kSuccess ? "Success" :
- result.type() == TestPartResult::kFatalFailure ? "Fatal failure" :
- "Non-fatal failure") << ":\n"
- << result.message() << std::endl;
-}
-
-// Appends a TestPartResult to the array.
-void TestPartResultArray::Append(const TestPartResult& result) {
- array_.push_back(result);
-}
-
-// Returns the TestPartResult at the given index (0-based).
-const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {
- if (index < 0 || index >= size()) {
- printf("\nInvalid index (%d) into TestPartResultArray.\n", index);
- internal::posix::Abort();
- }
-
- return array_[index];
-}
-
-// Returns the number of TestPartResult objects in the array.
-int TestPartResultArray::size() const {
- return static_cast<int>(array_.size());
-}
-
-namespace internal {
-
-HasNewFatalFailureHelper::HasNewFatalFailureHelper()
- : has_new_fatal_failure_(false),
- original_reporter_(GetUnitTestImpl()->
- GetTestPartResultReporterForCurrentThread()) {
- GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this);
-}
-
-HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {
- GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(
- original_reporter_);
-}
-
-void HasNewFatalFailureHelper::ReportTestPartResult(
- const TestPartResult& result) {
- if (result.fatally_failed())
- has_new_fatal_failure_ = true;
- original_reporter_->ReportTestPartResult(result);
-}
-
-} // namespace internal
-
-} // namespace testing
-// Copyright 2008 Google Inc.
-// All Rights Reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Author: wan@google.com (Zhanyong Wan)
-
-
-namespace testing {
-namespace internal {
-
-#if GTEST_HAS_TYPED_TEST_P
-
-// Skips to the first non-space char in str. Returns an empty string if str
-// contains only whitespace characters.
-static const char* SkipSpaces(const char* str) {
- while (isspace(*str))
- str++;
- return str;
-}
-
-// Verifies that registered_tests match the test names in
-// defined_test_names_; returns registered_tests if successful, or
-// aborts the program otherwise.
-const char* TypedTestCasePState::VerifyRegisteredTestNames(
- const char* file, int line, const char* registered_tests) {
- typedef ::std::set<const char*>::const_iterator DefinedTestIter;
- registered_ = true;
-
- // Skip initial whitespace in registered_tests since some
- // preprocessors prefix stringizied literals with whitespace.
- registered_tests = SkipSpaces(registered_tests);
-
- Message errors;
- ::std::set<String> tests;
- for (const char* names = registered_tests; names != NULL;
- names = SkipComma(names)) {
- const String name = GetPrefixUntilComma(names);
- if (tests.count(name) != 0) {
- errors << "Test " << name << " is listed more than once.\n";
- continue;
- }
-
- bool found = false;
- for (DefinedTestIter it = defined_test_names_.begin();
- it != defined_test_names_.end();
- ++it) {
- if (name == *it) {
- found = true;
- break;
- }
- }
-
- if (found) {
- tests.insert(name);
- } else {
- errors << "No test named " << name
- << " can be found in this test case.\n";
- }
- }
-
- for (DefinedTestIter it = defined_test_names_.begin();
- it != defined_test_names_.end();
- ++it) {
- if (tests.count(*it) == 0) {
- errors << "You forgot to list test " << *it << ".\n";
- }
- }
-
- const String& errors_str = errors.GetString();
- if (errors_str != "") {
- fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(),
- errors_str.c_str());
- fflush(stderr);
- posix::Abort();
- }
-
- return registered_tests;
-}
-
-#endif // GTEST_HAS_TYPED_TEST_P
-
-} // namespace internal
-} // namespace testing
+++ /dev/null
-#include "precomp.hpp"
-#include <float.h>
-#include <limits.h>
-
-using namespace cv;
-
-namespace cvtest
-{
-
-Size randomSize(RNG& rng, double maxSizeLog)
-{
- double width_log = rng.uniform(0., maxSizeLog);
- double height_log = rng.uniform(0., maxSizeLog - width_log);
- if( (unsigned)rng % 2 != 0 )
- std::swap(width_log, height_log);
- Size sz;
- sz.width = cvRound(exp(width_log));
- sz.height = cvRound(exp(height_log));
- return sz;
-}
-
-void randomSize(RNG& rng, int minDims, int maxDims, double maxSizeLog, vector<int>& sz)
-{
- int i, dims = rng.uniform(minDims, maxDims+1);
- sz.resize(dims);
- for( i = 0; i < dims; i++ )
- {
- double v = rng.uniform(0., maxSizeLog);
- maxSizeLog -= v;
- sz[i] = cvRound(exp(v));
- }
- for( i = 0; i < dims; i++ )
- {
- int j = rng.uniform(0, dims);
- int k = rng.uniform(0, dims);
- std::swap(sz[j], sz[k]);
- }
-}
-
-int randomType(RNG& rng, int typeMask, int minChannels, int maxChannels)
-{
- int channels = rng.uniform(minChannels, maxChannels+1);
- int depth = 0;
- CV_Assert((typeMask & TYPE_MASK_ALL) != 0);
- for(;;)
- {
- depth = rng.uniform(CV_8U, CV_64F+1);
- if( ((1 << depth) & typeMask) != 0 )
- break;
- }
- return CV_MAKETYPE(depth, channels);
-}
-
-double getMinVal(int depth)
-{
- double val = depth == CV_8U ? 0 : depth == CV_8S ? SCHAR_MIN : depth == CV_16U ? 0 :
- depth == CV_16S ? SHRT_MIN : depth == CV_32S ? INT_MIN :
- depth == CV_32F ? -FLT_MAX : depth == CV_64F ? -DBL_MAX : -1;
- CV_Assert(val != -1);
- return val;
-}
-
-double getMaxVal(int depth)
-{
- double val = depth == CV_8U ? UCHAR_MAX : depth == CV_8S ? SCHAR_MAX : depth == CV_16U ? USHRT_MAX :
- depth == CV_16S ? SHRT_MAX : depth == CV_32S ? INT_MAX :
- depth == CV_32F ? FLT_MAX : depth == CV_64F ? DBL_MAX : -1;
- CV_Assert(val != -1);
- return val;
-}
-
-Mat randomMat(RNG& rng, Size size, int type, double minVal, double maxVal, bool useRoi)
-{
- Size size0 = size;
- if( useRoi )
- {
- size0.width += std::max(rng.uniform(0, 10) - 5, 0);
- size0.height += std::max(rng.uniform(0, 10) - 5, 0);
- }
-
- Mat m(size0, type);
-
- rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal));
- if( size0 == size )
- return m;
- return m(Rect((size0.width-size.width)/2, (size0.height-size.height)/2, size.width, size.height));
-}
-
-Mat randomMat(RNG& rng, const vector<int>& size, int type, double minVal, double maxVal, bool useRoi)
-{
- int i, dims = (int)size.size();
- vector<int> size0(dims);
- vector<Range> r(dims);
- bool eqsize = true;
- for( i = 0; i < dims; i++ )
- {
- size0[i] = size[i];
- r[i] = Range::all();
- if( useRoi )
- {
- size0[i] += std::max(rng.uniform(0, 5) - 2, 0);
- r[i] = Range((size0[i] - size[i])/2, (size0[i] - size[i])/2 + size[i]);
- }
- eqsize = eqsize && size[i] == size0[i];
- }
-
- Mat m(dims, &size0[0], type);
-
- rng.fill(m, RNG::UNIFORM, Scalar::all(minVal), Scalar::all(maxVal));
- if( eqsize )
- return m;
- return m(&r[0]);
-}
-
-void add(const Mat& _a, double alpha, const Mat& _b, double beta,
- Scalar gamma, Mat& c, int ctype, bool calcAbs)
-{
- Mat a = _a, b = _b;
- if( a.empty() || alpha == 0 )
- {
- // both alpha and beta can be 0, but at least one of a and b must be non-empty array,
- // otherwise we do not know the size of the output (and may be type of the output, when ctype<0)
- CV_Assert( !a.empty() || !b.empty() );
- if( !b.empty() )
- {
- a = b;
- alpha = beta;
- b = Mat();
- beta = 0;
- }
- }
- if( b.empty() || beta == 0 )
- {
- b = Mat();
- beta = 0;
- }
- else
- CV_Assert(a.size == b.size);
-
- if( ctype < 0 )
- ctype = a.depth();
- ctype = CV_MAKETYPE(CV_MAT_DEPTH(ctype), a.channels());
- c.create(a.dims, &a.size[0], ctype);
- const Mat *arrays[3];
- Mat planes[3], buf[3];
- arrays[0] = &a;
- arrays[1] = b.empty() ? 0 : &b;
- arrays[2] = &c;
-
- NAryMatIterator it(arrays, planes, 3);
- int i, nplanes = it.nplanes, cn=a.channels();
- size_t total = planes[0].total(), maxsize = std::min((size_t)12*12*std::max(12/cn, 1), total);
-
- CV_Assert(planes[0].rows == 1);
- buf[0].create(1, (int)maxsize, CV_64FC(cn));
- if(!b.empty())
- buf[1].create(1, maxsize, CV_64FC(cn));
- buf[2].create(1, maxsize, CV_64FC(cn));
- scalarToRawData(gamma, buf[2].data, CV_64FC(cn), (int)(maxsize*cn));
-
- for( i = 0; i < nplanes; i++, ++it)
- {
- for( size_t j = 0; j < total; j += maxsize )
- {
- size_t j2 = min(j + maxsize, total);
- Mat apart0 = planes[0].colRange((int)j, (int)j2);
- Mat cpart0 = planes[2].colRange((int)j, (int)j2);
- Mat apart = buf[0].colRange(0, (int)(j2 - j));
-
- apart0.convertTo(apart, apart.type(), alpha);
- size_t k, n = (j2 - j)*cn;
- double* aptr = (double*)apart.data;
- const double* gptr = (const double*)buf[2].data;
-
- if( b.empty() )
- {
- for( k = 0; k < n; k++ )
- aptr[k] += gptr[k];
- }
- else
- {
- Mat bpart0 = planes[1].colRange((int)j, (int)j2);
- Mat bpart = buf[1].colRange(0, (int)(j2 - j));
- bpart0.convertTo(bpart, bpart.type(), beta);
- const double* bptr = (const double*)bpart.data;
-
- for( k = 0; k < n; k++ )
- aptr[k] += bptr[k] + gptr[k];
- }
- if( calcAbs )
- for( k = 0; k < n; k++ )
- aptr[k] = fabs(aptr[k]);
- apart.convertTo(cpart0, cpart0.type(), 1, 0);
- }
- }
-}
-
-
-template<typename _Tp1, typename _Tp2> inline void
-convert_(const _Tp1* src, _Tp2* dst, size_t total, double alpha, double beta)
-{
- size_t i;
- if( alpha == 1 && beta == 0 )
- for( i = 0; i < total; i++ )
- dst[i] = saturate_cast<_Tp2>(src[i]);
- else if( beta == 0 )
- for( i = 0; i < total; i++ )
- dst[i] = saturate_cast<_Tp2>(src[i]*alpha);
- else
- for( i = 0; i < total; i++ )
- dst[i] = saturate_cast<_Tp2>(src[i]*alpha + beta);
-}
-
-template<typename _Tp> inline void
-convertTo(const _Tp* src, void* dst, int dtype, size_t total, double alpha, double beta)
-{
- switch( CV_MAT_DEPTH(dtype) )
- {
- case CV_8U:
- convert_(src, (uchar*)dst, total, alpha, beta);
- break;
- case CV_8S:
- convert_(src, (schar*)dst, total, alpha, beta);
- break;
- case CV_16U:
- convert_(src, (ushort*)dst, total, alpha, beta);
- break;
- case CV_16S:
- convert_(src, (short*)dst, total, alpha, beta);
- break;
- case CV_32S:
- convert_(src, (int*)dst, total, alpha, beta);
- break;
- case CV_32F:
- convert_(src, (float*)dst, total, alpha, beta);
- break;
- case CV_64F:
- convert_(src, (double*)dst, total, alpha, beta);
- break;
- default:
- CV_Assert(0);
- }
-}
-
-void convert(const Mat& src, Mat& dst, int dtype, double alpha, double beta)
-{
- dtype = CV_MAKETYPE(CV_MAT_DEPTH(dtype), src.channels());
- dst.create(src.dims, &src.size[0], dtype);
- if( alpha == 0 )
- {
- set( dst, Scalar::all(beta) );
- return;
- }
- if( dtype == src.type() && alpha == 1 && beta == 0 )
- {
- copy( src, dst );
- return;
- }
-
- const Mat *arrays[]={&src, &dst};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t total = planes[0].total()*planes[0].channels();
- int i, nplanes = it.nplanes;
-
- for( i = 0; i < nplanes; i++, ++it)
- {
- const uchar* sptr = planes[0].data;
- uchar* dptr = planes[1].data;
-
- switch( src.depth() )
- {
- case CV_8U:
- convertTo((const uchar*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_8S:
- convertTo((const schar*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_16U:
- convertTo((const ushort*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_16S:
- convertTo((const short*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_32S:
- convertTo((const int*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_32F:
- convertTo((const float*)sptr, dptr, dtype, total, alpha, beta);
- break;
- case CV_64F:
- convertTo((const double*)sptr, dptr, dtype, total, alpha, beta);
- break;
- }
- }
-}
-
-
-void copy(const Mat& src, Mat& dst, const Mat& mask, bool invertMask)
-{
- dst.create(src.dims, &src.size[0], src.type());
-
- if(mask.empty())
- {
- const Mat* arrays[] = {&src, &dst};
- Mat planes[2];
- NAryMatIterator it(arrays, planes, 2);
- int i, nplanes = it.nplanes;
- size_t planeSize = planes[0].total()*src.elemSize();
-
- for( i = 0; i < nplanes; i++, ++it )
- memcpy(planes[1].data, planes[0].data, planeSize);
-
- return;
- }
-
- CV_Assert( src.size == mask.size && mask.type() == CV_8U );
-
- const Mat *arrays[3]={&src, &dst, &mask};
- Mat planes[3];
-
- NAryMatIterator it(arrays, planes, 3);
- size_t j, k, elemSize = src.elemSize(), total = planes[0].total();
- int i, nplanes = it.nplanes;
-
- for( i = 0; i < nplanes; i++, ++it)
- {
- const uchar* sptr = planes[0].data;
- uchar* dptr = planes[1].data;
- const uchar* mptr = planes[2].data;
-
- for( j = 0; j < total; j++, sptr += elemSize, dptr += elemSize )
- {
- if( (mptr[j] != 0) ^ invertMask )
- for( k = 0; k < elemSize; k++ )
- dptr[k] = sptr[k];
- }
- }
-}
-
-
-void set(Mat& dst, const Scalar& gamma, const Mat& mask)
-{
- double buf[12];
- scalarToRawData(gamma, &buf, dst.type(), dst.channels());
- const uchar* gptr = (const uchar*)&buf[0];
-
- if(mask.empty())
- {
- const Mat* arrays[] = {&dst};
- Mat plane;
- NAryMatIterator it(arrays, &plane, 1);
- int i, nplanes = it.nplanes;
- size_t j, k, elemSize = dst.elemSize(), planeSize = plane.total()*elemSize;
-
- for( k = 1; k < elemSize; k++ )
- if( gptr[k] != gptr[0] )
- break;
- bool uniform = k >= elemSize;
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- uchar* dptr = plane.data;
- if( uniform )
- memset( dptr, gptr[0], planeSize );
- else if( i == 0 )
- {
- for( j = 0; j < planeSize; j += elemSize, dptr += elemSize )
- for( k = 0; k < elemSize; k++ )
- dptr[k] = gptr[k];
- }
- else
- memcpy(dptr, dst.data, planeSize);
- }
- return;
- }
-
- CV_Assert( dst.size == mask.size && mask.type() == CV_8U );
-
- const Mat *arrays[2]={&dst, &mask};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t j, k, elemSize = dst.elemSize(), total = planes[0].total();
- int i, nplanes = it.nplanes;
-
- for( i = 0; i < nplanes; i++, ++it)
- {
- uchar* dptr = planes[0].data;
- const uchar* mptr = planes[1].data;
-
- for( j = 0; j < total; j++, dptr += elemSize )
- {
- if( mptr[j] )
- for( k = 0; k < elemSize; k++ )
- dptr[k] = gptr[k];
- }
- }
-}
-
-
-template<typename _Tp> static void
-erode_(const Mat& src, Mat& dst, const vector<int>& ofsvec)
-{
- int width = src.cols*src.channels(), n = (int)ofsvec.size();
- const int* ofs = &ofsvec[0];
-
- for( int y = 0; y < dst.rows; y++ )
- {
- const _Tp* sptr = src.ptr<_Tp>(y);
- _Tp* dptr = dst.ptr<_Tp>(y);
-
- for( int x = 0; x < width; x++ )
- {
- _Tp result = sptr[x + ofs[0]];
- for( int i = 1; i < n; i++ )
- result = std::min(result, sptr[x + ofs[i]]);
- dptr[x] = result;
- }
- }
-}
-
-
-template<typename _Tp> static void
-dilate_(const Mat& src, Mat& dst, const vector<int>& ofsvec)
-{
- int width = src.cols*src.channels(), n = (int)ofsvec.size();
- const int* ofs = &ofsvec[0];
-
- for( int y = 0; y < dst.rows; y++ )
- {
- const _Tp* sptr = src.ptr<_Tp>(y);
- _Tp* dptr = dst.ptr<_Tp>(y);
-
- for( int x = 0; x < width; x++ )
- {
- _Tp result = sptr[x + ofs[0]];
- for( int i = 1; i < n; i++ )
- result = std::max(result, sptr[x + ofs[i]]);
- dptr[x] = result;
- }
- }
-}
-
-
-void erode(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor,
- int borderType, const Scalar& _borderValue)
-{
- Mat kernel = _kernel, src;
- Scalar borderValue = _borderValue;
- if( kernel.empty() )
- kernel = Mat::ones(3, 3, CV_8U);
- else
- {
- CV_Assert( kernel.type() == CV_8U );
- }
- if( anchor == Point(-1,-1) )
- anchor = Point(kernel.cols/2, kernel.rows/2);
- if( borderType == IPL_BORDER_CONSTANT )
- borderValue = getMaxVal(src.depth());
- copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
- anchor.x, kernel.cols - anchor.y - 1,
- borderType, borderValue);
- dst.create( _src.size(), src.type() );
-
- vector<int> ofs;
- int step = (int)(src.step/src.elemSize1()), cn = src.channels();
- for( int i = 0; i < kernel.rows; i++ )
- for( int j = 0; j < kernel.cols; j++ )
- if( kernel.at<uchar>(i, j) != 0 )
- ofs.push_back(i*step + j*cn);
- if( ofs.empty() )
- ofs.push_back(anchor.y*step + anchor.x*cn);
-
- switch( src.depth() )
- {
- case CV_8U:
- erode_<uchar>(src, dst, ofs);
- break;
- case CV_8S:
- erode_<schar>(src, dst, ofs);
- break;
- case CV_16U:
- erode_<ushort>(src, dst, ofs);
- break;
- case CV_16S:
- erode_<short>(src, dst, ofs);
- break;
- case CV_32S:
- erode_<int>(src, dst, ofs);
- break;
- case CV_32F:
- erode_<float>(src, dst, ofs);
- break;
- case CV_64F:
- erode_<double>(src, dst, ofs);
- break;
- default:
- CV_Assert(0);
- }
-}
-
-void dilate(const Mat& _src, Mat& dst, const Mat& _kernel, Point anchor,
- int borderType, const Scalar& _borderValue)
-{
- Mat kernel = _kernel, src;
- Scalar borderValue = _borderValue;
- if( kernel.empty() )
- kernel = Mat::ones(3, 3, CV_8U);
- else
- {
- CV_Assert( kernel.type() == CV_8U );
- }
- if( anchor == Point(-1,-1) )
- anchor = Point(kernel.cols/2, kernel.rows/2);
- if( borderType == IPL_BORDER_CONSTANT )
- borderValue = getMinVal(src.depth());
- copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
- anchor.x, kernel.cols - anchor.y - 1,
- borderType, borderValue);
- dst.create( _src.size(), src.type() );
-
- vector<int> ofs;
- int step = (int)(src.step/src.elemSize1()), cn = src.channels();
- for( int i = 0; i < kernel.rows; i++ )
- for( int j = 0; j < kernel.cols; j++ )
- if( kernel.at<uchar>(i, j) != 0 )
- ofs.push_back(i*step + j*cn);
- if( ofs.empty() )
- ofs.push_back(anchor.y*step + anchor.x*cn);
-
- switch( src.depth() )
- {
- case CV_8U:
- dilate_<uchar>(src, dst, ofs);
- break;
- case CV_8S:
- dilate_<schar>(src, dst, ofs);
- break;
- case CV_16U:
- dilate_<ushort>(src, dst, ofs);
- break;
- case CV_16S:
- dilate_<short>(src, dst, ofs);
- break;
- case CV_32S:
- dilate_<int>(src, dst, ofs);
- break;
- case CV_32F:
- dilate_<float>(src, dst, ofs);
- break;
- case CV_64F:
- dilate_<double>(src, dst, ofs);
- break;
- default:
- CV_Assert(0);
- }
-}
-
-
-template<typename _Tp> static void
-filter2D_(const Mat& src, Mat& dst, const vector<int>& ofsvec, const vector<double>& coeffvec)
-{
- const int* ofs = &ofsvec[0];
- const double* coeff = &coeffvec[0];
- int width = dst.cols*dst.channels(), ncoeffs = (int)ofsvec.size();
-
- for( int y = 0; y < dst.rows; y++ )
- {
- const _Tp* sptr = src.ptr<_Tp>(y);
- double* dptr = dst.ptr<double>(y);
-
- for( int x = 0; x < width; x++ )
- {
- double s = 0;
- for( int i = 0; i < ncoeffs; i++ )
- s += sptr[ofs[i]]*coeff[i];
- dptr[x] = s;
- }
- }
-}
-
-
-void filter2D(const Mat& _src, Mat& dst, int ddepth, const Mat& _kernel,
- Point anchor, double delta, int borderType, const Scalar& _borderValue)
-{
- Mat kernel = _kernel, src, _dst;
- Scalar borderValue = _borderValue;
- CV_Assert( kernel.type() == CV_32F || kernel.type() == CV_64F );
- if( anchor == Point(-1,-1) )
- anchor = Point(kernel.cols/2, kernel.rows/2);
- if( borderType == IPL_BORDER_CONSTANT )
- borderValue = getMinVal(src.depth());
- copyMakeBorder(_src, src, anchor.y, kernel.rows - anchor.y - 1,
- anchor.x, kernel.cols - anchor.y - 1,
- borderType, borderValue);
- _dst.create( _src.size(), CV_MAKETYPE(CV_64F, src.channels()) );
-
- vector<int> ofs;
- vector<double> coeff(kernel.rows*kernel.cols);
- Mat cmat(kernel.rows, kernel.cols, CV_64F, &coeff[0]);
- convert(kernel, cmat, cmat.type());
-
- int step = (int)(src.step/src.elemSize1()), cn = src.channels();
- for( int i = 0; i < kernel.rows; i++ )
- for( int j = 0; j < kernel.cols; j++ )
- ofs.push_back(i*step + j*cn);
-
- switch( src.depth() )
- {
- case CV_8U:
- filter2D_<uchar>(src, _dst, ofs, coeff);
- break;
- case CV_8S:
- filter2D_<schar>(src, _dst, ofs, coeff);
- break;
- case CV_16U:
- filter2D_<ushort>(src, _dst, ofs, coeff);
- break;
- case CV_16S:
- filter2D_<short>(src, _dst, ofs, coeff);
- break;
- case CV_32S:
- filter2D_<int>(src, _dst, ofs, coeff);
- break;
- case CV_32F:
- filter2D_<float>(src, _dst, ofs, coeff);
- break;
- case CV_64F:
- filter2D_<double>(src, _dst, ofs, coeff);
- break;
- default:
- CV_Assert(0);
- }
-
- convert(_dst, dst, ddepth, 1, delta);
-}
-
-
-static int borderInterpolate( int p, int len, int borderType )
-{
- if( (unsigned)p < (unsigned)len )
- ;
- else if( borderType == IPL_BORDER_REPLICATE )
- p = p < 0 ? 0 : len - 1;
- else if( borderType == IPL_BORDER_REFLECT || borderType == IPL_BORDER_REFLECT_101 )
- {
- int delta = borderType == IPL_BORDER_REFLECT_101;
- if( len == 1 )
- return 0;
- do
- {
- if( p < 0 )
- p = -p - 1 + delta;
- else
- p = len - 1 - (p - len) - delta;
- }
- while( (unsigned)p >= (unsigned)len );
- }
- else if( borderType == IPL_BORDER_WRAP )
- {
- if( p < 0 )
- p -= ((p-len+1)/len)*len;
- if( p >= len )
- p %= len;
- }
- else if( borderType == IPL_BORDER_CONSTANT )
- p = -1;
- else
- CV_Error( CV_StsBadArg, "Unknown/unsupported border type" );
- return p;
-}
-
-
-void copyMakeBorder(const Mat& src, Mat& dst, int top, int bottom, int left, int right,
- int borderType, const Scalar& borderValue)
-{
- dst.create(src.rows + top + bottom, src.cols + left + right, src.type());
- int i, j, k, esz = (int)src.elemSize();
- int width = src.cols*esz, width1 = dst.cols*esz;
-
- if( borderType == IPL_BORDER_CONSTANT )
- {
- vector<uchar> valvec((src.cols + left + right)*esz);
- uchar* val = &valvec[0];
- scalarToRawData(borderValue, val, src.type(), (src.cols + left + right)*src.channels());
-
- left *= esz;
- right *= esz;
- for( i = 0; i < src.rows; i++ )
- {
- const uchar* sptr = src.ptr(i);
- uchar* dptr = dst.ptr(i + top) + left;
- for( j = 0; j < left; j++ )
- dptr[j - left] = val[j];
- if( dptr != sptr )
- for( j = 0; j < width; j++ )
- dptr[j] = sptr[j];
- for( j = 0; j < right; j++ )
- dptr[j + width] = val[j];
- }
-
- for( i = 0; i < top; i++ )
- {
- uchar* dptr = dst.ptr(i);
- for( j = 0; j < width1; j++ )
- dptr[j] = val[j];
- }
-
- for( i = 0; i < bottom; i++ )
- {
- uchar* dptr = dst.ptr(i + top + src.rows);
- for( j = 0; j < width1; j++ )
- dptr[j] = val[j];
- }
- }
- else
- {
- vector<int> tabvec((left + right)*esz);
- int* ltab = &tabvec[0];
- int* rtab = &tabvec[left*esz];
- for( i = 0; i < left; i++ )
- {
- j = borderInterpolate(i - left, src.cols, borderType)*esz;
- for( k = 0; k < esz; k++ )
- ltab[i*esz + k] = j + k;
- }
- for( i = 0; i < right; i++ )
- {
- j = borderInterpolate(src.cols + i, src.cols, borderType)*esz;
- for( k = 0; k < esz; k++ )
- rtab[i*esz + k] = j + k;
- }
-
- left *= esz;
- right *= esz;
- for( i = 0; i < src.rows; i++ )
- {
- const uchar* sptr = src.ptr(i);
- uchar* dptr = dst.ptr(i + top);
-
- for( j = 0; j < left; j++ )
- dptr[j] = sptr[ltab[j]];
- if( dptr + left != sptr )
- {
- for( j = 0; j < width; j++ )
- dptr[j + left] = sptr[j];
- }
- for( j = 0; j < right; j++ )
- dptr[j + left + width] = sptr[rtab[j]];
- }
-
- for( i = 0; i < top; i++ )
- {
- j = borderInterpolate(i - top, src.rows, borderType);
- const uchar* sptr = dst.ptr(j + top);
- uchar* dptr = dst.ptr(i);
-
- for( k = 0; k < width1; k++ )
- dptr[k] = sptr[k];
- }
-
- for( i = 0; i < bottom; i++ )
- {
- j = borderInterpolate(i + src.rows, src.rows, borderType);
- const uchar* sptr = dst.ptr(j + top);
- uchar* dptr = dst.ptr(i + top + src.rows);
-
- for( k = 0; k < width1; k++ )
- dptr[k] = sptr[k];
- }
- }
-}
-
-
-template<typename _Tp> static void
-minMaxLoc_(const _Tp* src, size_t total, size_t startidx,
- double* _maxval, double* _minval,
- size_t* _minpos, size_t* _maxpos,
- const uchar* mask)
-{
- _Tp maxval = saturate_cast<_Tp>(*_maxval), minval = saturate_cast<_Tp>(*_minval);
- size_t minpos = *_minpos, maxpos = *_maxpos;
-
- if( !mask )
- {
- for( size_t i = 0; i < total; i++ )
- {
- _Tp val = src[i];
- if( minval > val )
- {
- minval = val;
- minpos = startidx + i;
- }
- if( maxval < val )
- {
- maxval = val;
- maxpos = startidx + i;
- }
- }
- }
- else
- {
- for( size_t i = 0; i < total; i++ )
- {
- _Tp val = src[i];
- if( minval > val && mask[i] )
- {
- minval = val;
- minpos = startidx + i;
- }
- if( maxval < val && mask[i] )
- {
- maxval = val;
- maxpos = startidx + i;
- }
- }
- }
-
- *_maxval = maxval;
- *_minval = minval;
- *_maxpos = maxpos;
- *_minpos = minpos;
-}
-
-
-static void setpos( const Mat& mtx, vector<int>& pos, size_t idx )
-{
- pos.resize(mtx.dims);
- for( int i = mtx.dims-1; i >= 0; i-- )
- {
- int sz = mtx.size[i]*(i == mtx.dims-1 ? mtx.channels() : 1);
- pos[i] = idx % sz;
- idx /= sz;
- }
-}
-
-void minMaxLoc(const Mat& src, double* _maxval, double* _minval,
- vector<int>* _maxloc, vector<int>* _minloc,
- const Mat& mask)
-{
- CV_Assert( src.channels() == 1 );
- const Mat *arrays[2]={&src, &mask};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t startidx = 1, total = planes[0].total();
- int i, nplanes = it.nplanes, depth = src.depth();
- double maxval = depth < CV_32F ? INT_MIN : depth == CV_32F ? -FLT_MAX : -DBL_MAX;
- double minval = depth < CV_32F ? INT_MAX : depth == CV_32F ? FLT_MAX : DBL_MAX;
- size_t maxidx = 0, minidx = 0;
-
- for( i = 0; i < nplanes; i++, ++it, startidx += total )
- {
- const uchar* sptr = planes[0].data;
- const uchar* mptr = planes[1].data;
-
- switch( depth )
- {
- case CV_8U:
- minMaxLoc_((const uchar*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_8S:
- minMaxLoc_((const schar*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_16U:
- minMaxLoc_((const ushort*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_16S:
- minMaxLoc_((const short*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_32S:
- minMaxLoc_((const int*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_32F:
- minMaxLoc_((const float*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- case CV_64F:
- minMaxLoc_((const double*)sptr, total, startidx,
- &maxval, &minval, &maxidx, &minidx, mptr);
- break;
- default:
- CV_Assert(0);
- }
- }
-
- if( _maxval )
- *_maxval = maxval;
- if( _minval )
- *_minval = minval;
- if( _maxloc )
- setpos( src, *_maxloc, maxidx );
- if( _minloc )
- setpos( src, *_minloc, minidx );
-}
-
-
-template<typename _Tp> static double
-norm_(const _Tp* src, size_t total, int normType, double startval, const uchar* mask)
-{
- size_t i;
- double result = startval;
-
- if( normType == NORM_INF )
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- result = std::max(result, (double)std::abs(src[i]));
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- result = std::max(result, (double)std::abs(src[i]));
- }
- else if( normType == NORM_L1 )
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- result += std::abs(src[i]);
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- result += std::abs(src[i]);
- }
- else
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- {
- double v = src[i];
- result += v*v;
- }
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- {
- double v = src[i];
- result += v*v;
- }
- }
- return result;
-}
-
-
-template<typename _Tp> static double
-norm_(const _Tp* src1, const _Tp* src2, size_t total, int normType, double startval, const uchar* mask)
-{
- size_t i;
- double result = startval;
-
- if( normType == NORM_INF )
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- result = std::max(result, (double)std::abs(src1[i] - src2[i]));
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- result = std::max(result, (double)std::abs(src1[i] - src2[i]));
- }
- else if( normType == NORM_L1 )
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- result += std::abs(src1[i] - src2[i]);
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- result += std::abs(src1[i] - src2[i]);
- }
- else
- {
- if( !mask )
- for( i = 0; i < total; i++ )
- {
- double v = src1[i] - src2[i];
- result += v*v;
- }
- else
- for( i = 0; i < total; i++ )
- if( mask[i] )
- {
- double v = src1[i] - src2[i];
- result += v*v;
- }
- }
- return result;
-}
-
-
-double norm(const Mat& src, int normType, const Mat& mask)
-{
- CV_Assert( mask.empty() || (src.size == mask.size && mask.type() == CV_8U) );
- CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
- const Mat *arrays[2]={&src, &mask};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t total = planes[0].total()*planes[0].channels();
- int i, nplanes = it.nplanes, depth = src.depth();
- double result = 0;
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr = planes[0].data;
- const uchar* mptr = planes[1].data;
-
- switch( depth )
- {
- case CV_8U:
- result = norm_((const uchar*)sptr, total, normType, result, mptr);
- break;
- case CV_8S:
- result = norm_((const schar*)sptr, total, normType, result, mptr);
- break;
- case CV_16U:
- result = norm_((const ushort*)sptr, total, normType, result, mptr);
- break;
- case CV_16S:
- result = norm_((const short*)sptr, total, normType, result, mptr);
- break;
- case CV_32S:
- result = norm_((const int*)sptr, total, normType, result, mptr);
- break;
- case CV_32F:
- result = norm_((const float*)sptr, total, normType, result, mptr);
- break;
- case CV_64F:
- result = norm_((const double*)sptr, total, normType, result, mptr);
- break;
- default:
- CV_Error(CV_StsUnsupportedFormat, "");
- };
- }
- if( normType == NORM_L2 )
- result = sqrt(result);
- return result;
-}
-
-double norm(const Mat& src1, const Mat& src2, int normType, const Mat& mask)
-{
- CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
- CV_Assert( mask.empty() || (src1.size == mask.size && mask.type() == CV_8U) );
- CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 );
- const Mat *arrays[3]={&src1, &src2, &mask};
- Mat planes[3];
-
- NAryMatIterator it(arrays, planes, 3);
- size_t total = planes[0].total()*planes[0].channels();
- int i, nplanes = it.nplanes, depth = src1.depth();
- double result = 0;
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr1 = planes[0].data;
- const uchar* sptr2 = planes[1].data;
- const uchar* mptr = planes[2].data;
-
- switch( depth )
- {
- case CV_8U:
- result = norm_((const uchar*)sptr1, (const uchar*)sptr2, total, normType, result, mptr);
- break;
- case CV_8S:
- result = norm_((const schar*)sptr1, (const schar*)sptr2, total, normType, result, mptr);
- break;
- case CV_16U:
- result = norm_((const ushort*)sptr1, (const ushort*)sptr2, total, normType, result, mptr);
- break;
- case CV_16S:
- result = norm_((const short*)sptr1, (const short*)sptr2, total, normType, result, mptr);
- break;
- case CV_32S:
- result = norm_((const int*)sptr1, (const int*)sptr2, total, normType, result, mptr);
- break;
- case CV_32F:
- result = norm_((const float*)sptr1, (const float*)sptr2, total, normType, result, mptr);
- break;
- case CV_64F:
- result = norm_((const double*)sptr1, (const double*)sptr2, total, normType, result, mptr);
- break;
- default:
- CV_Error(CV_StsUnsupportedFormat, "");
- };
- }
- if( normType == NORM_L2 )
- result = sqrt(result);
- return result;
-}
-
-bool cmpEps(const Mat& src1, const Mat& src2, int int_maxdiff, int flt_maxulp, vector<int>* loc);
-
-static void
-logicOp_(const uchar* src1, const uchar* src2, uchar* dst, size_t total, char c)
-{
- size_t i;
- if( c == '&' )
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] & src2[i];
- else if( c == '|' )
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] | src2[i];
- else
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] ^ src2[i];
-}
-
-static void
-logicOpS_(const uchar* src, const uchar* scalar, uchar* dst, size_t total, char c)
-{
- const size_t blockSize = 96;
- size_t i, j;
- if( c == '&' )
- for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
- {
- size_t sz = std::min(total - i, blockSize);
- for( j = 0; j < sz; j++ )
- dst[j] = src[j] & scalar[j];
- }
- else if( c == '|' )
- for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
- {
- size_t sz = std::min(total - i, blockSize);
- for( j = 0; j < sz; j++ )
- dst[j] = src[j] | scalar[j];
- }
- else if( c == '^' )
- {
- for( i = 0; i < total; i += blockSize, dst += blockSize, src += blockSize )
- {
- size_t sz = std::min(total - i, blockSize);
- for( j = 0; j < sz; j++ )
- dst[j] = src[j] ^ scalar[j];
- }
- }
- else
- for( i = 0; i < total; i++ )
- dst[i] = ~src[i];
-}
-
-void logicOp( const Mat& src1, const Mat& src2, Mat& dst, char op )
-{
- CV_Assert( op == '&' || op == '|' || op == '^' );
- CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
- dst.create( src1.dims, &src1.size[0], src1.type() );
- const Mat *arrays[3]={&src1, &src2, &dst};
- Mat planes[3];
-
- NAryMatIterator it(arrays, planes, 3);
- size_t total = planes[0].total()*planes[0].elemSize();
- int i, nplanes = it.nplanes;
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr1 = planes[0].data;
- const uchar* sptr2 = planes[1].data;
- uchar* dptr = planes[2].data;
-
- logicOp_(sptr1, sptr2, dptr, total, op);
- }
-}
-
-
-void logicOp(const Mat& src, const Scalar& s, Mat& dst, char op)
-{
- CV_Assert( op == '&' || op == '|' || op == '^' );
- dst.create( src.dims, &src.size[0], src.type() );
- const Mat *arrays[2]={&src, &dst};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t total = planes[0].total()*planes[0].elemSize();
- int i, nplanes = it.nplanes;
- double buf[12];
- scalarToRawData(s, buf, src.type(), 12);
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr = planes[0].data;
- uchar* dptr = planes[1].data;
-
- logicOpS_(sptr, (uchar*)&buf[0], dptr, total, op);
- }
-}
-
-
-template<typename _Tp> static void
-compare_(const _Tp* src1, const _Tp* src2, uchar* dst, size_t total, int cmpop)
-{
- size_t i;
- switch( cmpop )
- {
- case CMP_LT:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] < src2[i] ? 255 : 0;
- break;
- case CMP_LE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] <= src2[i] ? 255 : 0;
- break;
- case CMP_EQ:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] == src2[i] ? 255 : 0;
- break;
- case CMP_NE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] != src2[i] ? 255 : 0;
- break;
- case CMP_GE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] >= src2[i] ? 255 : 0;
- break;
- case CMP_GT:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] > src2[i] ? 255 : 0;
- break;
- default:
- CV_Error(CV_StsBadArg, "Unknown comparison operation");
- }
-}
-
-
-template<typename _Tp, typename _WTp> static void
-compareS_(const _Tp* src1, _WTp value, uchar* dst, size_t total, int cmpop)
-{
- size_t i;
- switch( cmpop )
- {
- case CMP_LT:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] < value ? 255 : 0;
- break;
- case CMP_LE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] <= value ? 255 : 0;
- break;
- case CMP_EQ:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] == value ? 255 : 0;
- break;
- case CMP_NE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] != value ? 255 : 0;
- break;
- case CMP_GE:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] >= value ? 255 : 0;
- break;
- case CMP_GT:
- for( i = 0; i < total; i++ )
- dst[i] = src1[i] > value ? 255 : 0;
- break;
- default:
- CV_Error(CV_StsBadArg, "Unknown comparison operation");
- }
-}
-
-
-void compare(const Mat& src1, const Mat& src2, Mat& dst, int cmpop)
-{
- CV_Assert( src1.type() == src2.type() && src1.channels() == 1 && src1.size == src2.size );
- dst.create( src1.dims, &src1.size[0], CV_8U );
- const Mat *arrays[3]={&src1, &src2, &dst};
- Mat planes[3];
-
- NAryMatIterator it(arrays, planes, 3);
- size_t total = planes[0].total()*planes[0].elemSize();
- int i, nplanes = it.nplanes, depth = src1.depth();
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr1 = planes[0].data;
- const uchar* sptr2 = planes[1].data;
- uchar* dptr = planes[2].data;
-
- switch( depth )
- {
- case CV_8U:
- compare_((const uchar*)sptr1, (const uchar*)sptr2, dptr, total, cmpop);
- break;
- case CV_8S:
- compare_((const schar*)sptr1, (const schar*)sptr2, dptr, total, cmpop);
- break;
- case CV_16U:
- compare_((const ushort*)sptr1, (const ushort*)sptr2, dptr, total, cmpop);
- break;
- case CV_16S:
- compare_((const short*)sptr1, (const short*)sptr2, dptr, total, cmpop);
- break;
- case CV_32S:
- compare_((const int*)sptr1, (const int*)sptr2, dptr, total, cmpop);
- break;
- case CV_32F:
- compare_((const float*)sptr1, (const float*)sptr2, dptr, total, cmpop);
- break;
- case CV_64F:
- compare_((const double*)sptr1, (const double*)sptr2, dptr, total, cmpop);
- break;
- default:
- CV_Error(CV_StsUnsupportedFormat, "");
- }
- }
-}
-
-void compare(const Mat& src, double value, Mat& dst, int cmpop)
-{
- CV_Assert( src.channels() == 1 );
- dst.create( src.dims, &src.size[0], CV_8U );
- const Mat *arrays[2]={&src, &dst};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t total = planes[0].total()*planes[0].elemSize();
- int i, nplanes = it.nplanes, depth = src.depth();
- int ivalue = saturate_cast<int>(value);
-
- for( i = 0; i < nplanes; i++, ++it )
- {
- const uchar* sptr = planes[0].data;
- uchar* dptr = planes[1].data;
-
- switch( depth )
- {
- case CV_8U:
- compareS_((const uchar*)sptr, ivalue, dptr, total, cmpop);
- break;
- case CV_8S:
- compareS_((const schar*)sptr, ivalue, dptr, total, cmpop);
- break;
- case CV_16U:
- compareS_((const ushort*)sptr, ivalue, dptr, total, cmpop);
- break;
- case CV_16S:
- compareS_((const short*)sptr, ivalue, dptr, total, cmpop);
- break;
- case CV_32S:
- compareS_((const int*)sptr, ivalue, dptr, total, cmpop);
- break;
- case CV_32F:
- compareS_((const float*)sptr, value, dptr, total, cmpop);
- break;
- case CV_64F:
- compareS_((const double*)sptr, value, dptr, total, cmpop);
- break;
- default:
- CV_Error(CV_StsUnsupportedFormat, "");
- }
- }
-}
-
-
-template<typename _Tp> static bool
-cmpEpsInt_(const _Tp* src1, const _Tp* src2, int imaxdiff, size_t total, size_t startidx, size_t& idx)
-{
- size_t i;
- for( i = 0; i < total; i++ )
- if( std::abs(src1[i] - src2[i]) > imaxdiff )
- {
- idx = i + startidx;
- return false;
- }
- return true;
-}
-
-
-template<typename _Tp> static bool
-cmpEpsFlt_(const _Tp* src1, const _Tp* src2, size_t total, int imaxdiff, size_t startidx, size_t& idx)
-{
- const _Tp C = ((_Tp)1 << (sizeof(_Tp)*8-1)) - 1;
- size_t i;
- for( i = 0; i < total; i++ )
- {
- _Tp a = src1[i], b = src2[i];
- if( a < 0 ) a ^= C; if( b < 0 ) b ^= C;
- _Tp d = std::abs(double(a - b));
- if( d > imaxdiff )
- {
- idx = i + startidx;
- return false;
- }
- }
- return true;
-}
-
-
-bool cmpEps(const Mat& src1, const Mat& src2, int imaxDiff, vector<int>* loc)
-{
- CV_Assert( src1.type() == src2.type() && src1.size == src2.size );
- const Mat *arrays[2]={&src1, &src2};
- Mat planes[2];
-
- NAryMatIterator it(arrays, planes, 2);
- size_t total = planes[0].total()*planes[0].channels();
- int i, nplanes = it.nplanes, depth = src1.depth();
- size_t startidx = 0, idx = -1;
- bool ok = true;
-
- for( i = 0; i < nplanes; i++, ++it, startidx += total )
- {
- const uchar* sptr1 = planes[0].data;
- const uchar* sptr2 = planes[1].data;
-
- switch( depth )
- {
- case CV_8U:
- ok = cmpEpsInt_((const uchar*)sptr1, (const uchar*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_8S:
- ok = cmpEpsInt_((const schar*)sptr1, (const schar*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_16U:
- ok = cmpEpsInt_((const ushort*)sptr1, (const ushort*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_16S:
- ok = cmpEpsInt_((const short*)sptr1, (const short*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_32S:
- ok = cmpEpsInt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_32F:
- ok = cmpEpsFlt_((const int*)sptr1, (const int*)sptr2, total, imaxDiff, startidx, idx);
- break;
- case CV_64F:
- ok = cmpEpsFlt_((const int64*)sptr1, (const int64*)sptr2, total, imaxDiff, startidx, idx);
- break;
- default:
- CV_Error(CV_StsUnsupportedFormat, "");
- }
- if(!ok)
- break;
- }
- if(!ok && loc)
- setpos(src1, *loc, idx);
- return ok;
-}
-
-}
+++ /dev/null
-#include "precomp.hpp"
+++ /dev/null
-#include "opencv2/gtest/gtestcv.hpp"
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+
+//#define DRAW_TEST_IMAGE
+
+class CV_DrawingTest : public CvTest
+{
+public:
+ CV_DrawingTest( const char* testName ) : CvTest( testName, "drawing funcs" ) {}
+protected:
+ void run( int );
+ virtual void draw( Mat& img ) = 0;
+ virtual int checkLineIterator( Mat& img) = 0;
+};
+
+void CV_DrawingTest::run( int )
+{
+ int code = CvTS::OK;
+ Mat testImg, valImg;
+ const string name = "drawing/image.jpg";
+ string path = ts->get_data_path(), filename;
+ filename = path + name;
+
+ draw( testImg );
+
+#ifdef DRAW_TEST_IMAGE
+ imwrite( filename, testImg );
+#else
+ valImg = imread( filename );
+ if( valImg.empty() )
+ {
+ ts->printf( CvTS::LOG, "test image can not be read");
+ code = CvTS::FAIL_INVALID_TEST_DATA;
+ }
+ else
+ {
+ float err = (float)norm( testImg, valImg, CV_RELATIVE_L1 );
+ float Eps = 0.9f;
+ if( err > Eps)
+ {
+ ts->printf( CvTS::LOG, "CV_RELATIVE_L1 between testImg and valImg is equal %f (larger than %f)\n", err, Eps );
+ code = CvTS::FAIL_BAD_ACCURACY;
+ }
+ else
+ {
+ code = checkLineIterator( testImg );
+ }
+ }
+#endif
+ ts->set_failed_test_info( code );
+}
+
+class CV_DrawingTest_CPP : public CV_DrawingTest
+{
+public:
+ CV_DrawingTest_CPP() : CV_DrawingTest( "drawing_cpp" ) {}
+protected:
+ virtual void draw( Mat& img );
+ virtual int checkLineIterator( Mat& img);
+};
+
+void CV_DrawingTest_CPP::draw( Mat& img )
+{
+ Size imgSize( 600, 400 );
+ img.create( imgSize, CV_8UC3 );
+
+ vector<Point> polyline(4);
+ polyline[0] = Point(0, 0);
+ polyline[1] = Point(imgSize.width, 0);
+ polyline[2] = Point(imgSize.width, imgSize.height);
+ polyline[3] = Point(0, imgSize.height);
+ const Point* pts = &polyline[0];
+ int n = (int)polyline.size();
+ fillPoly( img, &pts, &n, 1, Scalar::all(255) );
+
+ Point p1(1,1), p2(3,3);
+ if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+ circle( img, Point(300,100), 40, Scalar(0,0,255), 3 ); // draw
+
+ p2 = Point(3,imgSize.height+1000);
+ if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+ circle( img, Point(500,300), 50, cvColorToScalar(255,CV_8UC3), 5, 8, 1 ); // draw
+
+ p1 = Point(imgSize.width,1), p2 = Point(imgSize.width,3);
+ if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+ circle( img, Point(390,100), 10, Scalar(0,0,255), 3 ); // not draw
+
+ p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
+ if( clipLine(Rect(0,0,imgSize.width,imgSize.height), p1, p2) && clipLine(imgSize, p1, p2) )
+ ellipse( img, Point(390,100), Size(20,30), 60, 0, 220.0, Scalar(0,200,0), 4 ); //draw
+
+ ellipse( img, RotatedRect(Point(100,200),Size(200,100),160), Scalar(200,200,255), 5 );
+
+ polyline.clear();
+ ellipse2Poly( Point(430,180), Size(100,150), 30, 0, 150, 20, polyline );
+ pts = &polyline[0];
+ n = (int)polyline.size();
+ polylines( img, &pts, &n, 1, false, Scalar(0,0,150), 4, CV_AA );
+ n = 0;
+ for( vector<Point>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
+ {
+ line( img, *it, *(it+1), Scalar(50,250,100));
+ }
+
+ polyline.clear();
+ ellipse2Poly( Point(500,300), Size(50,80), 0, 0, 180, 10, polyline );
+ pts = &polyline[0];
+ n = (int)polyline.size();
+ polylines( img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
+ fillConvexPoly( img, pts, n, Scalar(0, 80, 0) );
+
+ polyline.resize(8);
+ // external rectengular
+ polyline[0] = Point(0, 0);
+ polyline[1] = Point(80, 0);
+ polyline[2] = Point(80, 80);
+ polyline[3] = Point(0, 80);
+ // internal rectangular
+ polyline[4] = Point(20, 20);
+ polyline[5] = Point(60, 20);
+ polyline[6] = Point(60, 60);
+ polyline[7] = Point(20, 60);
+ const Point* ppts[] = {&polyline[0], &polyline[0]+4};
+ int pn[] = {4, 4};
+ fillPoly( img, ppts, pn, 2, Scalar(100, 100, 0), 8, 0, Point(500, 20) );
+
+ rectangle( img, Point(0, 300), Point(50, 398), Scalar(0,0,255) );
+
+ string text1 = "OpenCV";
+ int baseline = 0, thickness = 3, fontFace = FONT_HERSHEY_SCRIPT_SIMPLEX;
+ float fontScale = 2;
+ Size textSize = getTextSize( text1, fontFace, fontScale, thickness, &baseline);
+ baseline += thickness;
+ Point textOrg((img.cols - textSize.width)/2, (img.rows + textSize.height)/2);
+ rectangle(img, textOrg + Point(0, baseline), textOrg + Point(textSize.width, -textSize.height), Scalar(0,0,255));
+ line(img, textOrg + Point(0, thickness), textOrg + Point(textSize.width, thickness), Scalar(0, 0, 255));
+ putText(img, text1, textOrg, fontFace, fontScale, Scalar(150,0,150), thickness, 8);
+
+ string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
+ Scalar color(200,0,0);
+ fontScale = 0.5, thickness = 1;
+ int dist = 5;
+
+ textSize = getTextSize( text2, FONT_HERSHEY_SIMPLEX, fontScale, thickness, &baseline);
+ textOrg = Point(5,5)+Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+ fontScale = 1;
+ textSize = getTextSize( text2, FONT_HERSHEY_PLAIN, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_PLAIN, fontScale, color, thickness, CV_AA);
+
+ fontScale = 0.5;
+ textSize = getTextSize( text2, FONT_HERSHEY_DUPLEX, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_DUPLEX, fontScale, color, thickness, CV_AA);
+
+ textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX, fontScale, color, thickness, CV_AA);
+
+ textSize = getTextSize( text2, FONT_HERSHEY_TRIPLEX, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_TRIPLEX, fontScale, color, thickness, CV_AA);
+
+ fontScale = 1;
+ textSize = getTextSize( text2, FONT_HERSHEY_COMPLEX_SMALL, fontScale, thickness, &baseline);
+ textOrg += Point(0,180) + Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_COMPLEX_SMALL, fontScale, color, thickness, CV_AA);
+
+ textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_SIMPLEX, fontScale, color, thickness, CV_AA);
+
+ textSize = getTextSize( text2, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_HERSHEY_SCRIPT_COMPLEX, fontScale, color, thickness, CV_AA);
+
+ dist = 15, fontScale = 0.5;
+ textSize = getTextSize( text2, FONT_ITALIC, fontScale, thickness, &baseline);
+ textOrg += Point(0,textSize.height+dist);
+ putText(img, text2, textOrg, FONT_ITALIC, fontScale, color, thickness, CV_AA);
+}
+
+int CV_DrawingTest_CPP::checkLineIterator( Mat& img )
+{
+ LineIterator it( img, Point(0,300), Point(1000, 300) );
+ for(int i = 0; i < it.count; ++it, i++ )
+ {
+ Vec3b v = (Vec3b)(*(*it)) - img.at<Vec3b>(300,i);
+ float err = (float)norm( v );
+ if( err != 0 )
+ {
+ ts->printf( CvTS::LOG, "LineIterator works incorrect" );
+ return CvTS::FAIL_INVALID_OUTPUT;
+ }
+ }
+ return CvTS::OK;
+}
+
+class CV_DrawingTest_C : public CV_DrawingTest
+{
+public:
+ CV_DrawingTest_C() : CV_DrawingTest( "drawing_c" ) {}
+protected:
+ virtual void draw( Mat& img );
+ virtual int checkLineIterator( Mat& img);
+};
+
+void CV_DrawingTest_C::draw( Mat& _img )
+{
+ CvSize imgSize = cvSize(600, 400);
+ _img.create( imgSize, CV_8UC3 );
+ CvMat img = _img;
+
+ vector<CvPoint> polyline(4);
+ polyline[0] = cvPoint(0, 0);
+ polyline[1] = cvPoint(imgSize.width, 0);
+ polyline[2] = cvPoint(imgSize.width, imgSize.height);
+ polyline[3] = cvPoint(0, imgSize.height);
+ CvPoint* pts = &polyline[0];
+ int n = (int)polyline.size();
+ cvFillPoly( &img, &pts, &n, 1, cvScalar(255,255,255) );
+
+ CvPoint p1 = cvPoint(1,1), p2 = cvPoint(3,3);
+ if( cvClipLine(imgSize, &p1, &p2) )
+ cvCircle( &img, cvPoint(300,100), 40, cvScalar(0,0,255), 3 ); // draw
+
+ p1 = cvPoint(1,1), p2 = cvPoint(3,imgSize.height+1000);
+ if( cvClipLine(imgSize, &p1, &p2) )
+ cvCircle( &img, cvPoint(500,300), 50, cvScalar(255,0,0), 5, 8, 1 ); // draw
+
+ p1 = cvPoint(imgSize.width,1), p2 = cvPoint(imgSize.width,3);
+ if( cvClipLine(imgSize, &p1, &p2) )
+ cvCircle( &img, cvPoint(390,100), 10, cvScalar(0,0,255), 3 ); // not draw
+
+ p1 = Point(imgSize.width-1,1), p2 = Point(imgSize.width,3);
+ if( cvClipLine(imgSize, &p1, &p2) )
+ cvEllipse( &img, cvPoint(390,100), cvSize(20,30), 60, 0, 220.0, cvScalar(0,200,0), 4 ); //draw
+
+ CvBox2D box;
+ box.center.x = 100;
+ box.center.y = 200;
+ box.size.width = 200;
+ box.size.height = 100;
+ box.angle = 160;
+ cvEllipseBox( &img, box, Scalar(200,200,255), 5 );
+
+ polyline.resize(9);
+ pts = &polyline[0];
+ n = (int)polyline.size();
+ assert( cvEllipse2Poly( cvPoint(430,180), cvSize(100,150), 30, 0, 150, &polyline[0], 20 ) == n );
+ cvPolyLine( &img, &pts, &n, 1, false, cvScalar(0,0,150), 4, CV_AA );
+ n = 0;
+ for( vector<CvPoint>::const_iterator it = polyline.begin(); n < (int)polyline.size()-1; ++it, n++ )
+ {
+ cvLine( &img, *it, *(it+1), cvScalar(50,250,100) );
+ }
+
+ polyline.resize(19);
+ pts = &polyline[0];
+ n = (int)polyline.size();
+ assert( cvEllipse2Poly( cvPoint(500,300), cvSize(50,80), 0, 0, 180, &polyline[0], 10 ) == n );
+ cvPolyLine( &img, &pts, &n, 1, true, Scalar(100,200,100), 20 );
+ cvFillConvexPoly( &img, pts, n, cvScalar(0, 80, 0) );
+
+ polyline.resize(8);
+ // external rectengular
+ polyline[0] = cvPoint(500, 20);
+ polyline[1] = cvPoint(580, 20);
+ polyline[2] = cvPoint(580, 100);
+ polyline[3] = cvPoint(500, 100);
+ // internal rectangular
+ polyline[4] = cvPoint(520, 40);
+ polyline[5] = cvPoint(560, 40);
+ polyline[6] = cvPoint(560, 80);
+ polyline[7] = cvPoint(520, 80);
+ CvPoint* ppts[] = {&polyline[0], &polyline[0]+4};
+ int pn[] = {4, 4};
+ cvFillPoly( &img, ppts, pn, 2, cvScalar(100, 100, 0), 8, 0 );
+
+ cvRectangle( &img, cvPoint(0, 300), cvPoint(50, 398), cvScalar(0,0,255) );
+
+ string text1 = "OpenCV";
+ CvFont font;
+ cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 2, 2, 0, 3 );
+ int baseline = 0;
+ CvSize textSize;
+ cvGetTextSize( text1.c_str(), &font, &textSize, &baseline );
+ baseline += font.thickness;
+ CvPoint textOrg = cvPoint((imgSize.width - textSize.width)/2, (imgSize.height + textSize.height)/2);
+ cvRectangle( &img, cvPoint( textOrg.x, textOrg.y + baseline),
+ cvPoint(textOrg.x + textSize.width, textOrg.y - textSize.height), cvScalar(0,0,255));
+ cvLine( &img, cvPoint(textOrg.x, textOrg.y + font.thickness),
+ cvPoint(textOrg.x + textSize.width, textOrg.y + font.thickness), cvScalar(0, 0, 255));
+ cvPutText( &img, text1.c_str(), textOrg, &font, cvScalar(150,0,150) );
+
+ int dist = 5;
+ string text2 = "abcdefghijklmnopqrstuvwxyz1234567890";
+ CvScalar color = cvScalar(200,0,0);
+ cvInitFont( &font, FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(5, 5+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_PLAIN, 1, 1, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_DUPLEX, 0.5, 0.5, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_COMPLEX, 0.5, 0.5, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_TRIPLEX, 0.5, 0.5, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_COMPLEX_SMALL, 1, 1, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist + 180);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_SCRIPT_SIMPLEX, 1, 1, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ cvInitFont( &font, FONT_HERSHEY_SCRIPT_COMPLEX, 1, 1, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+
+ dist = 15;
+ cvInitFont( &font, FONT_ITALIC, 0.5, 0.5, 0, 1, CV_AA );
+ cvGetTextSize( text2.c_str(), &font, &textSize, &baseline );
+ textOrg = cvPoint(textOrg.x,textOrg.y+textSize.height+dist);
+ cvPutText(&img, text2.c_str(), textOrg, &font, color );
+}
+
+int CV_DrawingTest_C::checkLineIterator( Mat& _img )
+{
+ CvLineIterator it;
+ CvMat img = _img;
+ int count = cvInitLineIterator( &img, cvPoint(0,300), cvPoint(1000, 300), &it );
+ for(int i = 0; i < count; i++ )
+ {
+ Vec3b v = (Vec3b)(*(it.ptr)) - _img.at<Vec3b>(300,i);
+ float err = (float)norm( v );
+ if( err != 0 )
+ {
+ ts->printf( CvTS::LOG, "CvLineIterator works incorrect" );
+ return CvTS::FAIL_INVALID_OUTPUT;
+ }
+ CV_NEXT_LINE_POINT(it);
+ }
+ return CvTS::OK;
+}
+
+CV_DrawingTest_CPP drawing_test_cpp;
+CV_DrawingTest_C drawing_test_c;
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "cvtest.h"
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <iostream>
+#include "cvaux.h"
+
+using namespace cv;
+using namespace std;
+
+//#if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64
+#define MARKERS
+
+#ifdef MARKERS
+ #define marker(x) cout << (x) << endl
+#else
+ #define marker(x)
+#endif
+
+
+class CV_HighGuiOnlyGuiTest : public CvTest
+{
+public:
+ CV_HighGuiOnlyGuiTest();
+ ~CV_HighGuiOnlyGuiTest();
+protected:
+ void run(int);
+};
+
+CV_HighGuiOnlyGuiTest::CV_HighGuiOnlyGuiTest(): CvTest( "z-highgui-gui-only", "?" )
+{
+ support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
+}
+CV_HighGuiOnlyGuiTest::~CV_HighGuiOnlyGuiTest() {}
+
+void Foo(int /*k*/, void* /*z*/) {}
+
+void CV_HighGuiOnlyGuiTest::run( int /*start_from */)
+{
+ cout << "GUI 1" << endl;
+ namedWindow("Win");
+ cout << "GUI 2" << endl;
+ Mat m(30, 30, CV_8U);
+ m = Scalar(128);
+ cout << "GUI 3" << endl;
+ imshow("Win", m);
+ cout << "GUI 4" << endl;
+ int value = 50;
+ cout << "GUI 5" << endl;
+ createTrackbar( "trackbar", "Win", &value, 100, Foo, &value);
+ cout << "GUI 6" << endl;
+ getTrackbarPos( "trackbar", "Win" );
+ cout << "GUI 7" << endl;
+ waitKey(500);
+ cout << "GUI 8" << endl;
+ cvDestroyAllWindows();
+ cout << "GUI 9" << endl;
+
+ ts->set_failed_test_info(CvTS::OK);
+}
+
+CV_HighGuiOnlyGuiTest highGuiOnlyGui_test;
+
+
--- /dev/null
+#include "test_precomp.hpp"
+#include "opencv2/ts/ts_main.hpp"
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/core/imgproc_c.h"
+#include <iostream>
+
+#endif
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+
+using namespace cv;
+using namespace std;
+
+#if defined WIN32 || defined _WIN32
+//#if 0
+
+#else
+
+#define MARKERS1
+
+#ifdef MARKERS
+ #define marker(x) cout << (x) << endl
+#else
+ #define marker(x)
+#endif
+
+struct TempDirHolder
+{
+ string temp_folder;
+ TempDirHolder()
+ {
+ char* p = tmpnam(0);
+ if(p[0] == '\\') p++;
+ temp_folder = string(p);
+ exec_cmd("mkdir " + temp_folder);
+ }
+ ~TempDirHolder() { exec_cmd("rm -rf " + temp_folder); }
+ static void exec_cmd(const string& cmd) { marker(cmd); int res = system( cmd.c_str() ); (void)res; }
+
+ TempDirHolder& operator=(const TempDirHolder&);
+};
+
+
+class CV_HighGuiTest : public CvTest
+{
+public:
+ CV_HighGuiTest();
+ ~CV_HighGuiTest();
+protected:
+ void run(int);
+
+ bool ImagesTest(const string& dir, const string& tmp);
+ bool VideoTest(const string& dir, const string& tmp, int fourcc);
+
+ bool GuiTest(const string& dir, const string& tmp);
+};
+
+CV_HighGuiTest::CV_HighGuiTest(): CvTest( "z-highgui", "?" )
+{
+ support_testing_modes = CvTS::CORRECTNESS_CHECK_MODE;
+}
+CV_HighGuiTest::~CV_HighGuiTest() {}
+
+double PSNR(const Mat& m1, const Mat& m2)
+{
+ Mat tmp;
+ absdiff( m1.reshape(1), m2.reshape(1), tmp);
+ multiply(tmp, tmp, tmp);
+
+ double MSE = 1.0/(tmp.cols * tmp.rows) * sum(tmp)[0];
+
+ return 20 * log10(255.0 / sqrt(MSE));
+}
+
+bool CV_HighGuiTest::ImagesTest(const string& dir, const string& tmp)
+{
+ int code = CvTS::OK;
+ Mat image = imread(dir + "shared/baboon.jpg");
+
+ if (image.empty())
+ {
+ ts->set_failed_test_info(CvTS::FAIL_MISSING_TEST_DATA);
+ return false;
+ }
+
+ const string exts[] = {"png", "bmp", "tiff", "jpg", "jp2", "ppm", "ras"};
+ const size_t ext_num = sizeof(exts)/sizeof(exts[0]);
+
+ for(size_t i = 0; i < ext_num; ++i)
+ {
+ ts->printf(CvTS::LOG, "ext=%s\n", exts[i].c_str());
+ string ext = exts[i];
+ string full_name = tmp + "/img." + ext;
+ marker(exts[i]);
+
+ imwrite(full_name, image);
+ Mat loaded = imread(full_name);
+ if (loaded.empty())
+ {
+ ts->printf(CvTS::LOG, "Reading failed at fmt=%s\n", ext.c_str());
+ code = CvTS::FAIL_MISMATCH;
+ continue;
+ }
+
+ const double thresDbell = 20;
+ double psnr = PSNR(loaded, image);
+ if (psnr < thresDbell)
+ {
+ ts->printf(CvTS::LOG, "Reading image from file: too big difference (=%g) with fmt=%s\n", psnr, ext.c_str());
+ code = CvTS::FAIL_BAD_ACCURACY;
+ continue;
+ }
+
+ FILE *f = fopen(full_name.c_str(), "rb");
+ fseek(f, 0, SEEK_END);
+ size_t len = ftell(f);
+ vector<uchar> from_file(len);
+ fseek(f, 0, SEEK_SET);
+ size_t read = fread(&from_file[0], len, sizeof(vector<uchar>::value_type), f); (void)read;
+ fclose(f);
+
+
+ vector<uchar> buf;
+ imencode("." + exts[i], image, buf);
+
+ if (buf != from_file)
+ {
+ ts->printf(CvTS::LOG, "Encoding failed with fmt=%s\n", ext.c_str());
+ code = CvTS::FAIL_MISMATCH;
+ continue;
+ }
+
+ Mat buf_loaded = imdecode(Mat(buf), 1);
+ if (buf_loaded.empty())
+ {
+ ts->printf(CvTS::LOG, "Decoding failed with fmt=%s\n", ext.c_str());
+ code = CvTS::FAIL_MISMATCH;
+ continue;
+ }
+
+
+ psnr = PSNR(buf_loaded, image);
+ if (psnr < thresDbell)
+ {
+ ts->printf(CvTS::LOG, "Decoding image from memory: too small PSNR (=%gdb) with fmt=%s\n", psnr, ext.c_str());
+ code = CvTS::FAIL_MISMATCH;
+ continue;
+ }
+ }
+ ts->set_failed_test_info(code);
+ return code == CvTS::OK;
+}
+
+bool CV_HighGuiTest::VideoTest(const string& dir, const string& tmp, int fourcc)
+{
+ string src_file = dir + "shared/video_for_test.avi";
+ string tmp_name = tmp + "/video.avi";
+
+ CvCapture* cap = cvCaptureFromFile(src_file.c_str());
+
+ if (!cap)
+ {
+ ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
+ return false;
+ }
+
+ CvVideoWriter* writer = 0;
+
+ int counter = 0;
+ for(;;)
+ {
+ IplImage* img = cvQueryFrame( cap );
+
+ if (!img)
+ break;
+
+ if (writer == 0)
+ {
+ writer = cvCreateVideoWriter(tmp_name.c_str(), fourcc, 24, cvGetSize(img));
+ if (writer == 0)
+ {
+ marker("can't craete writer");
+ cvReleaseCapture( &cap );
+ ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
+ return false;
+ }
+ }
+
+ cvWriteFrame(writer, img);
+ }
+
+
+ cvReleaseVideoWriter( &writer );
+ cvReleaseCapture( &cap );
+
+ marker("mid++");
+
+ cap = cvCaptureFromFile(src_file.c_str());
+ marker("mid1");
+ CvCapture *saved = cvCaptureFromFile(tmp_name.c_str());
+ if (!saved)
+ {
+ ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
+ return false;
+ }
+
+
+ const double thresDbell = 20;
+
+ bool error = false;
+ counter = 0;
+ for(;;)
+ {
+
+ IplImage* ipl = cvQueryFrame( cap );
+ IplImage* ipl1 = cvQueryFrame( saved );
+
+
+ if (!ipl || !ipl1)
+ break;
+
+ Mat img(ipl);
+ Mat img1(ipl1);
+
+ if (PSNR(img1, img) < thresDbell)
+ {
+ error = true;
+ break;
+ }
+ }
+
+ cvReleaseCapture( &cap );
+ cvReleaseCapture( &saved );
+
+ if (error)
+ {
+ ts->set_failed_test_info(CvTS::FAIL_MISMATCH);
+ return false;
+ }
+
+ return true;
+}
+
+
+void CV_HighGuiTest::run( int /*start_from */)
+{
+ TempDirHolder th;
+
+ if (!ImagesTest(ts->get_data_path(), th.temp_folder))
+ return;
+
+#if defined WIN32 || defined __linux__
+
+#if !defined HAVE_GSTREAMER || defined HAVE_GSTREAMER_APP
+ if (!VideoTest(ts->get_data_path(), th.temp_folder, CV_FOURCC_DEFAULT))
+ return;
+
+
+ if (!VideoTest(ts->get_data_path(), th.temp_folder, CV_FOURCC('M', 'J', 'P', 'G')))
+ return;
+
+
+ if (!VideoTest(ts->get_data_path(), th.temp_folder, CV_FOURCC('M', 'P', 'G', '2')))
+ return;
+
+#endif
+ //if (!VideoTest(ts->get_data_path(), th.temp_folder, CV_FOURCC('D', 'X', '5', '0'))) return;
+#endif
+ ts->set_failed_test_info(CvTS::OK);
+}
+CV_HighGuiTest HighGui_test;
+
+
+#endif
+
//! normalizes the grayscale image brightness and contrast by normalizing its histogram
CV_EXPORTS_W void equalizeHist( const Mat& src, CV_OUT Mat& dst );
+
+CV_EXPORTS float EMD( const Mat& signature1, const Mat& signature2,
+ int distType, const Mat& cost=Mat(),
+ float* lowerBound=0, Mat* flow=0 );
//! segments the image using watershed algorithm
CV_EXPORTS_W void watershed( const Mat& image, Mat& markers );
return (float)s;
}
-/* End of file. */
+namespace cv
+{
+
+float EMD( const Mat& signature1, const Mat& signature2,
+ int distType, const Mat& cost, float* lowerBound, Mat* flow )
+{
+ CvMat _signature1 = signature1;
+ CvMat _signature2 = signature2;
+ CvMat _cost = cost, _flow;
+ if( flow )
+ _flow = *flow;
+
+ return cvCalcEMD2( &_signature1, &_signature2, distType, 0, cost.empty() ? 0 : &_cost,
+ flow ? &_flow : 0, lowerBound, 0 );
+}
+
+}
+
+/* End of file. */
dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Ptr<FilterEngine> f = createSeparableLinearFilter(src.type(),
- dst.type(), kernelX, kernelY, anchor, delta, borderType );
- f->apply(src, dst);
+ dst.type(), kernelX, kernelY, anchor, delta, borderType & ~BORDER_ISOLATED );
+ f->apply(src, dst, Rect(0,0,-1,-1), Point(), (borderType & BORDER_ISOLATED) != 0 );
}
}
namespace cv
{
-//#undef CV_SSE2
-
template<typename T, int shift> struct FixPtCast
{
typedef int type1;
const Mat& cameraMatrix, const Mat& distCoeffs,
const Mat& R, const Mat& P )
{
- CV_Assert( src.isContinuous() && src.depth() == CV_32F &&
+ CV_Assert( src.isContinuous() && (src.depth() == CV_32F || src.depth() == CV_64F) &&
((src.rows == 1 && src.channels() == 2) || src.cols*src.channels() == 2));
dst.create(src.size(), src.type());
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <limits.h>
+
+using namespace cv;
+using namespace std;
+
+//
+// TODO!!!:
+// check_slice (and/or check) seem(s) to be broken, or this is a bug in function
+// (or its inability to handle possible self-intersections in the generated contours).
+//
+// At least, if // return TotalErrors;
+// is uncommented in check_slice, the test fails easily.
+// So, now (and it looks like since 0.9.6)
+// we only check that the set of vertices of the approximated polygon is
+// a subset of vertices of the original contour.
+//
+
+class CV_ApproxPolyTest : public cvtest::BaseTest
+{
+public:
+ CV_ApproxPolyTest();
+ ~CV_ApproxPolyTest();
+ void clear();
+ //int write_default_params(CvFileStorage* fs);
+
+protected:
+ //int read_params( CvFileStorage* fs );
+
+ int check_slice( CvPoint StartPt, CvPoint EndPt,
+ CvSeqReader* SrcReader, float Eps,
+ int* j, int Count );
+ int check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps );
+
+ bool get_contour( int /*type*/, CvSeq** Seq, int* d,
+ CvMemStorage* storage );
+
+ void run(int);
+};
+
+
+CV_ApproxPolyTest::CV_ApproxPolyTest()
+{
+}
+
+
+CV_ApproxPolyTest::~CV_ApproxPolyTest()
+{
+ clear();
+}
+
+
+void CV_ApproxPolyTest::clear()
+{
+ cvtest::BaseTest::clear();
+}
+
+
+/*int CV_ApproxPolyTest::write_default_params( CvFileStorage* fs )
+{
+ cvtest::BaseTest::write_default_params( fs );
+ if( ts->get_testing_mode() != cvtest::TS::TIMING_MODE )
+ {
+ write_param( fs, "test_case_count", test_case_count );
+ }
+ return 0;
+}
+
+
+int CV_ApproxPolyTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
+ min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
+ return 0;
+}*/
+
+
+bool CV_ApproxPolyTest::get_contour( int /*type*/, CvSeq** Seq, int* d,
+ CvMemStorage* storage )
+{
+ RNG& rng = ts->get_rng();
+ int max_x = INT_MIN, max_y = INT_MIN, min_x = INT_MAX, min_y = INT_MAX;
+ int i;
+ CvSeq* seq;
+ int total = cvtest::randInt(rng) % 1000 + 1;
+ CvPoint center;
+ int radius, angle;
+ double deg_to_rad = CV_PI/180.;
+ CvPoint pt;
+
+ center.x = cvtest::randInt( rng ) % 1000;
+ center.y = cvtest::randInt( rng ) % 1000;
+ radius = cvtest::randInt( rng ) % 1000;
+ angle = cvtest::randInt( rng ) % 360;
+
+ seq = cvCreateSeq( CV_SEQ_POLYGON, sizeof(CvContour), sizeof(CvPoint), storage );
+
+ for( i = 0; i < total; i++ )
+ {
+ int d_radius = cvtest::randInt( rng ) % 10 - 5;
+ int d_angle = 360/total;//cvtest::randInt( rng ) % 10 - 5;
+ pt.x = cvRound( center.x + radius*cos(angle*deg_to_rad));
+ pt.y = cvRound( center.x - radius*sin(angle*deg_to_rad));
+ radius += d_radius;
+ angle += d_angle;
+ cvSeqPush( seq, &pt );
+
+ max_x = MAX( max_x, pt.x );
+ max_y = MAX( max_y, pt.y );
+
+ min_x = MIN( min_x, pt.x );
+ min_y = MIN( min_y, pt.y );
+ }
+
+ *d = (max_x - min_x)*(max_x - min_x) + (max_y - min_y)*(max_y - min_y);
+ *Seq = seq;
+ return true;
+}
+
+
+int CV_ApproxPolyTest::check_slice( CvPoint StartPt, CvPoint EndPt,
+ CvSeqReader* SrcReader, float Eps,
+ int* _j, int Count )
+{
+ ///////////
+ CvPoint Pt;
+ ///////////
+ bool flag;
+ double dy,dx;
+ double A,B,C;
+ double Sq;
+ double sin_a = 0;
+ double cos_a = 0;
+ double d = 0;
+ double dist;
+ ///////////
+ int j, TotalErrors = 0;
+
+ ////////////////////////////////
+ if( SrcReader == NULL )
+ {
+ assert( false );
+ return 0;
+ }
+
+ ///////// init line ////////////
+ flag = true;
+
+ dx = (double)StartPt.x - (double)EndPt.x;
+ dy = (double)StartPt.y - (double)EndPt.y;
+
+ if( ( dx == 0 ) && ( dy == 0 ) ) flag = false;
+ else
+ {
+ A = -dy;
+ B = dx;
+ C = dy * (double)StartPt.x - dx * (double)StartPt.y;
+ Sq = sqrt( A*A + B*B );
+
+ sin_a = B/Sq;
+ cos_a = A/Sq;
+ d = C/Sq;
+ }
+
+ /////// find start point and check distance ////////
+ for( j = *_j; j < Count; j++ )
+ {
+ CV_READ_SEQ_ELEM( Pt, *SrcReader );
+ if( StartPt.x == Pt.x && StartPt.y == Pt.y ) break;
+ else
+ {
+ if( flag ) dist = sin_a * Pt.y + cos_a * Pt.x - d;
+ else dist = sqrt( (double)(EndPt.y - Pt.y)*(EndPt.y - Pt.y) + (EndPt.x - Pt.x)*(EndPt.x - Pt.x) );
+ if( dist > Eps ) TotalErrors++;
+ }
+ }
+
+ *_j = j;
+
+ //return TotalErrors;
+ return 0;
+}
+
+
+int CV_ApproxPolyTest::check( CvSeq* SrcSeq, CvSeq* DstSeq, float Eps )
+{
+ //////////
+ CvSeqReader DstReader;
+ CvSeqReader SrcReader;
+ CvPoint StartPt, EndPt;
+ ///////////
+ int TotalErrors = 0;
+ ///////////
+ int Count;
+ int i,j;
+
+ assert( SrcSeq && DstSeq );
+
+ ////////// init ////////////////////
+ Count = SrcSeq->total;
+
+ cvStartReadSeq( DstSeq, &DstReader, 0 );
+ cvStartReadSeq( SrcSeq, &SrcReader, 0 );
+
+ CV_READ_SEQ_ELEM( StartPt, DstReader );
+ for( i = 0 ; i < Count ; )
+ {
+ CV_READ_SEQ_ELEM( EndPt, SrcReader );
+ i++;
+ if( StartPt.x == EndPt.x && StartPt.y == EndPt.y ) break;
+ }
+
+ ///////// start ////////////////
+ for( i = 1, j = 0 ; i <= DstSeq->total ; )
+ {
+ ///////// read slice ////////////
+ EndPt.x = StartPt.x;
+ EndPt.y = StartPt.y;
+ CV_READ_SEQ_ELEM( StartPt, DstReader );
+ i++;
+
+ TotalErrors += check_slice( StartPt, EndPt, &SrcReader, Eps, &j, Count );
+
+ if( j > Count )
+ {
+ TotalErrors++;
+ return TotalErrors;
+ } //if( !flag )
+
+ } // for( int i = 0 ; i < DstSeq->total ; i++ )
+
+ return TotalErrors;
+}
+
+
+//extern CvTestContourGenerator cvTsTestContours[];
+
+void CV_ApproxPolyTest::run( int /*start_from*/ )
+{
+ int code = cvtest::TS::OK;
+ CvMemStorage* storage = 0;
+ ////////////// Variables ////////////////
+ int IntervalsCount = 10;
+ ///////////
+ //CvTestContourGenerator Cont;
+ CvSeq* SrcSeq = NULL;
+ CvSeq* DstSeq;
+ int iDiam;
+ float dDiam, Eps, EpsStep;
+
+ for( int i = 0; i < 30; i++ )
+ {
+ CvMemStoragePos pos;
+
+ ts->update_context( this, i, false );
+
+ ///////////////////// init contour /////////
+ dDiam = 0;
+ while( sqrt(dDiam) / IntervalsCount == 0 )
+ {
+ if( storage != 0 )
+ cvReleaseMemStorage(&storage);
+
+ storage = cvCreateMemStorage( 0 );
+ if( get_contour( 0, &SrcSeq, &iDiam, storage ) )
+ dDiam = (float)iDiam;
+ }
+ dDiam = (float)sqrt( dDiam );
+
+ storage = SrcSeq->storage;
+
+ ////////////////// test /////////////
+ EpsStep = dDiam / IntervalsCount ;
+ for( Eps = EpsStep ; Eps < dDiam ; Eps += EpsStep )
+ {
+ cvSaveMemStoragePos( storage, &pos );
+
+ ////////// call function ////////////
+ DstSeq = cvApproxPoly( SrcSeq, SrcSeq->header_size, storage,
+ CV_POLY_APPROX_DP, Eps );
+
+ if( DstSeq == NULL )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "cvApproxPoly returned NULL for contour #%d, espilon = %g\n", i, Eps );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ } // if( DstSeq == NULL )
+
+ code = check( SrcSeq, DstSeq, Eps );
+ if( code != 0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Incorrect result for the contour #%d approximated with epsilon=%g\n", i, Eps );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ cvRestoreMemStoragePos( storage, &pos );
+ } // for( Eps = EpsStep ; Eps <= Diam ; Eps += EpsStep )
+
+ ///////////// free memory ///////////////////
+ cvReleaseMemStorage(&storage);
+ } // for( int i = 0; NULL != ( Cont = Contours[i] ) ; i++ )
+
+_exit_:
+ cvReleaseMemStorage(&storage);
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Imgproc_ApproxPoly, accuracy) { CV_ApproxPolyTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_CannyTest : public cvtest::ArrayTest
+{
+public:
+ CV_CannyTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int prepare_test_case( int test_case_idx );
+ void run_func();
+ void prepare_to_validation( int );
+ int validate_test_results( int /*test_case_idx*/ );
+
+ int aperture_size;
+ bool use_true_gradient;
+ double threshold1, threshold2;
+ bool test_cpp;
+};
+
+
+CV_CannyTest::CV_CannyTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = true;
+ aperture_size = 0;
+ use_true_gradient = false;
+ threshold1 = threshold2 = 0;
+
+ test_cpp = false;
+}
+
+
+void CV_CannyTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ double thresh_range;
+
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8U;
+
+ aperture_size = cvtest::randInt(rng) % 2 ? 5 : 3;
+ thresh_range = aperture_size == 3 ? 300 : 1000;
+
+ threshold1 = cvtest::randReal(rng)*thresh_range;
+ threshold2 = cvtest::randReal(rng)*thresh_range*0.3;
+
+ if( cvtest::randInt(rng) % 2 )
+ CV_SWAP( threshold1, threshold2, thresh_range );
+
+ use_true_gradient = cvtest::randInt(rng) % 2 != 0;
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+int CV_CannyTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ Mat& src = test_mat[INPUT][0];
+ GaussianBlur(src, src, Size(11, 11), 5, 5);
+ }
+
+ return code;
+}
+
+
+double CV_CannyTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 0;
+}
+
+
+void CV_CannyTest::run_func()
+{
+ if(!test_cpp)
+ cvCanny( test_array[INPUT][0], test_array[OUTPUT][0], threshold1, threshold2,
+ aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0));
+ else
+ {
+ cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
+ cv::Canny(cv::cvarrToMat(test_array[INPUT][0]), _out, threshold1, threshold2,
+ aperture_size + (use_true_gradient ? CV_CANNY_L2_GRADIENT : 0));
+ }
+}
+
+
+static void
+cannyFollow( int x, int y, float lowThreshold, const Mat& mag, Mat& dst )
+{
+ static const int ofs[][2] = {{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1},{0,1},{1,1}};
+ int i;
+
+ dst.at<uchar>(y, x) = (uchar)255;
+
+ for( i = 0; i < 8; i++ )
+ {
+ int x1 = x + ofs[i][0];
+ int y1 = y + ofs[i][1];
+ if( (unsigned)x1 < (unsigned)mag.cols &&
+ (unsigned)y1 < (unsigned)mag.rows &&
+ mag.at<float>(y1, x1) > lowThreshold &&
+ !dst.at<uchar>(y1, x1) )
+ cannyFollow( x1, y1, lowThreshold, mag, dst );
+ }
+}
+
+
+static void
+test_Canny( const Mat& src, Mat& dst,
+ double threshold1, double threshold2,
+ int aperture_size, bool use_true_gradient )
+{
+ int m = aperture_size;
+ Point anchor(m/2, m/2);
+ const double tan_pi_8 = tan(CV_PI/8.);
+ const double tan_3pi_8 = tan(CV_PI*3/8);
+ float lowThreshold = (float)MIN(threshold1, threshold2);
+ float highThreshold = (float)MAX(threshold1, threshold2);
+
+ int x, y, width = src.cols, height = src.rows;
+
+ Mat dxkernel = cvtest::calcSobelKernel2D( 1, 0, m, 0 );
+ Mat dykernel = cvtest::calcSobelKernel2D( 0, 1, m, 0 );
+ Mat dx, dy, mag(height, width, CV_32F);
+ cvtest::filter2D(src, dx, CV_16S, dxkernel, anchor, 0, BORDER_REPLICATE);
+ cvtest::filter2D(src, dy, CV_16S, dykernel, anchor, 0, BORDER_REPLICATE);
+
+ // calc gradient magnitude
+ for( y = 0; y < height; y++ )
+ {
+ for( x = 0; x < width; x++ )
+ {
+ int dxval = dx.at<short>(y, x), dyval = dy.at<short>(y, x);
+ mag.at<float>(y, x) = use_true_gradient ?
+ (float)sqrt((double)(dxval*dxval + dyval*dyval)) :
+ (float)(fabs(dxval) + fabs(dyval));
+ }
+ }
+
+ // calc gradient direction, do nonmaxima suppression
+ for( y = 0; y < height; y++ )
+ {
+ for( x = 0; x < width; x++ )
+ {
+
+ float a = mag.at<float>(y, x), b = 0, c = 0;
+ int y1 = 0, y2 = 0, x1 = 0, x2 = 0;
+
+ if( a <= lowThreshold )
+ continue;
+
+ int dxval = dx.at<short>(y, x);
+ int dyval = dy.at<short>(y, x);
+
+ double tg = dxval ? (double)dyval/dxval : DBL_MAX*CV_SIGN(dyval);
+
+ if( fabs(tg) < tan_pi_8 )
+ {
+ y1 = y2 = y; x1 = x + 1; x2 = x - 1;
+ }
+ else if( tan_pi_8 <= tg && tg <= tan_3pi_8 )
+ {
+ y1 = y + 1; y2 = y - 1; x1 = x + 1; x2 = x - 1;
+ }
+ else if( -tan_3pi_8 <= tg && tg <= -tan_pi_8 )
+ {
+ y1 = y - 1; y2 = y + 1; x1 = x + 1; x2 = x - 1;
+ }
+ else
+ {
+ assert( fabs(tg) > tan_3pi_8 );
+ x1 = x2 = x; y1 = y + 1; y2 = y - 1;
+ }
+
+ if( (unsigned)y1 < (unsigned)height && (unsigned)x1 < (unsigned)width )
+ b = (float)fabs(mag.at<float>(y1, x1));
+
+ if( (unsigned)y2 < (unsigned)height && (unsigned)x2 < (unsigned)width )
+ c = (float)fabs(mag.at<float>(y2, x2));
+
+ if( (a > b || (a == b && ((x1 == x+1 && y1 == y) || (x1 == x && y1 == y+1)))) && a > c )
+ ;
+ else
+ mag.at<float>(y, x) = -a;
+ }
+ }
+
+ dst = Scalar::all(0);
+
+ // hysteresis threshold
+ for( y = 0; y < height; y++ )
+ {
+ for( x = 0; x < width; x++ )
+ if( mag.at<float>(y, x) > highThreshold && !dst.at<uchar>(y, x) )
+ cannyFollow( x, y, lowThreshold, mag, dst );
+ }
+}
+
+
+void CV_CannyTest::prepare_to_validation( int )
+{
+ Mat src = test_mat[INPUT][0], dst = test_mat[REF_OUTPUT][0];
+ test_Canny( src, dst, threshold1, threshold2, aperture_size, use_true_gradient );
+}
+
+
+int CV_CannyTest::validate_test_results( int test_case_idx )
+{
+ int code = cvtest::TS::OK, nz0;
+ prepare_to_validation(test_case_idx);
+
+ double err = cvtest::norm(test_mat[OUTPUT][0], test_mat[REF_OUTPUT][0], CV_L1);
+ if( err == 0 )
+ return code;
+
+ if( err != cvRound(err) || cvRound(err)%255 != 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Some of the pixels, produced by Canny, are not 0's or 255's; the difference is %g\n", err );
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
+ return code;
+ }
+
+ nz0 = cvRound(cvtest::norm(test_mat[REF_OUTPUT][0], CV_L1)/255);
+ err = (err/255/MAX(nz0,100))*100;
+ if( err > 1 )
+ {
+ ts->printf( cvtest::TS::LOG, "Too high percentage of non-matching edge pixels = %g%%\n", err);
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ }
+
+ return code;
+}
+
+TEST(Imgproc_Canny, accuracy) { CV_CannyTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+/////////////////////////// base test class for color transformations /////////////////////////
+
+class CV_ColorCvtBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_ColorCvtBaseTest( bool custom_inv_transform, bool allow_32f, bool allow_16u );
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+
+ // input --- fwd_transform -> ref_output[0]
+ virtual void convert_forward( const Mat& src, Mat& dst );
+ // ref_output[0] --- inv_transform ---> ref_output[1] (or input -- copy --> ref_output[1])
+ virtual void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 );
+
+ // called from default implementation of convert_forward
+ virtual void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+
+ // called from default implementation of convert_backward
+ virtual void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+
+ const char* fwd_code_str;
+ const char* inv_code_str;
+
+ void run_func();
+ bool allow_16u, allow_32f;
+ int blue_idx;
+ bool inplace;
+ bool custom_inv_transform;
+ int fwd_code, inv_code;
+ bool test_cpp;
+ bool hue_channel;
+};
+
+
+CV_ColorCvtBaseTest::CV_ColorCvtBaseTest( bool _custom_inv_transform, bool _allow_32f, bool _allow_16u )
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ allow_16u = _allow_16u;
+ allow_32f = _allow_32f;
+ custom_inv_transform = _custom_inv_transform;
+ fwd_code = inv_code = -1;
+ element_wise_relative_error = false;
+
+ fwd_code_str = inv_code_str = 0;
+
+ test_cpp = false;
+ hue_channel = false;
+}
+
+
+void CV_ColorCvtBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT )
+ {
+ int depth = CV_MAT_DEPTH(type);
+ low = Scalar::all(0.);
+ high = Scalar::all( depth == CV_8U ? 256 : depth == CV_16U ? 65536 : 1. );
+ }
+}
+
+
+void CV_ColorCvtBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth, cn;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( allow_16u && allow_32f )
+ {
+ depth = cvtest::randInt(rng) % 3;
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
+ }
+ else if( allow_16u || allow_32f )
+ {
+ depth = cvtest::randInt(rng) % 2;
+ depth = depth == 0 ? CV_8U : allow_16u ? CV_16U : CV_32F;
+ }
+ else
+ depth = CV_8U;
+
+ cn = (cvtest::randInt(rng) & 1) + 3;
+ blue_idx = cvtest::randInt(rng) & 1 ? 2 : 0;
+
+ types[INPUT][0] = CV_MAKETYPE(depth, cn);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, 3);
+ if( test_array[OUTPUT].size() > 1 )
+ types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(depth, cn);
+
+ inplace = cn == 3 && cvtest::randInt(rng) % 2 != 0;
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+int CV_ColorCvtBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 && inplace )
+ cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] );
+ return code;
+}
+
+void CV_ColorCvtBaseTest::run_func()
+{
+ CvArr* out0 = test_array[OUTPUT][0];
+ cv::Mat _out0 = cv::cvarrToMat(out0), _out1 = cv::cvarrToMat(test_array[OUTPUT][1]);
+
+ if(!test_cpp)
+ cvCvtColor( inplace ? out0 : test_array[INPUT][0], out0, fwd_code );
+ else
+ cv::cvtColor( cv::cvarrToMat(inplace ? out0 : test_array[INPUT][0]), _out0, fwd_code, _out0.channels());
+
+ if( inplace )
+ {
+ cvCopy( out0, test_array[OUTPUT][1] );
+ out0 = test_array[OUTPUT][1];
+ }
+ if(!test_cpp)
+ cvCvtColor( out0, test_array[OUTPUT][1], inv_code );
+ else
+ cv::cvtColor(cv::cvarrToMat(out0), _out1, inv_code, _out1.channels());
+}
+
+
+void CV_ColorCvtBaseTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ convert_forward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0] );
+ convert_backward( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ test_mat[REF_OUTPUT][1] );
+ int depth = test_mat[REF_OUTPUT][0].depth();
+ if( depth == CV_8U && hue_channel )
+ {
+ for( int y = 0; y < test_mat[REF_OUTPUT][0].rows; y++ )
+ {
+ const uchar* h0 = test_mat[REF_OUTPUT][0].ptr(y);
+ uchar* h = test_mat[OUTPUT][0].ptr(y);
+
+ for( int x = 0; x < test_mat[REF_OUTPUT][0].cols; x++, h0 += 3, h += 3 )
+ {
+ if( abs(*h - *h0) == 180 && *h == 0 )
+ *h = 180;
+ }
+ }
+ }
+}
+
+
+void CV_ColorCvtBaseTest::convert_forward( const Mat& src, Mat& dst )
+{
+ const float c8u = 0.0039215686274509803f; // 1./255
+ const float c16u = 1.5259021896696422e-005f; // 1./65535
+ int depth = src.depth();
+ int cn = src.channels(), dst_cn = dst.channels();
+ int cols = src.cols, dst_cols_n = dst.cols*dst_cn;
+ vector<float> _src_buf(src.cols*3);
+ vector<float> _dst_buf(dst.cols*3);
+ float* src_buf = &_src_buf[0];
+ float* dst_buf = &_dst_buf[0];
+ int i, j;
+
+ assert( (cn == 3 || cn == 4) && (dst_cn == 3 || dst_cn == 1) );
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ switch( depth )
+ {
+ case CV_8U:
+ {
+ const uchar* src_row = src.ptr(i);
+ uchar* dst_row = dst.ptr(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ src_buf[j*3] = src_row[j*cn + blue_idx]*c8u;
+ src_buf[j*3+1] = src_row[j*cn + 1]*c8u;
+ src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c8u;
+ }
+
+ convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols );
+
+ for( j = 0; j < dst_cols_n; j++ )
+ {
+ int t = cvRound( dst_buf[j] );
+ dst_row[j] = saturate_cast<uchar>(t);
+ }
+ }
+ break;
+ case CV_16U:
+ {
+ const ushort* src_row = src.ptr<ushort>(i);
+ ushort* dst_row = dst.ptr<ushort>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ src_buf[j*3] = src_row[j*cn + blue_idx]*c16u;
+ src_buf[j*3+1] = src_row[j*cn + 1]*c16u;
+ src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)]*c16u;
+ }
+
+ convert_row_bgr2abc_32f_c3( src_buf, dst_buf, cols );
+
+ for( j = 0; j < dst_cols_n; j++ )
+ {
+ int t = cvRound( dst_buf[j] );
+ dst_row[j] = saturate_cast<ushort>(t);
+ }
+ }
+ break;
+ case CV_32F:
+ {
+ const float* src_row = src.ptr<float>(i);
+ float* dst_row = dst.ptr<float>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ src_buf[j*3] = src_row[j*cn + blue_idx];
+ src_buf[j*3+1] = src_row[j*cn + 1];
+ src_buf[j*3+2] = src_row[j*cn + (blue_idx^2)];
+ }
+
+ convert_row_bgr2abc_32f_c3( src_buf, dst_row, cols );
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+void CV_ColorCvtBaseTest::convert_row_bgr2abc_32f_c3( const float* /*src_row*/,
+ float* /*dst_row*/, int /*n*/ )
+{
+}
+
+
+void CV_ColorCvtBaseTest::convert_row_abc2bgr_32f_c3( const float* /*src_row*/,
+ float* /*dst_row*/, int /*n*/ )
+{
+}
+
+
+void CV_ColorCvtBaseTest::convert_backward( const Mat& src, const Mat& dst, Mat& dst2 )
+{
+ if( custom_inv_transform )
+ {
+ int depth = src.depth();
+ int src_cn = dst.channels(), cn = dst2.channels();
+ int cols_n = src.cols*src_cn, dst_cols = dst.cols;
+ vector<float> _src_buf(src.cols*3);
+ vector<float> _dst_buf(dst.cols*3);
+ float* src_buf = &_src_buf[0];
+ float* dst_buf = &_dst_buf[0];
+ int i, j;
+
+ assert( cn == 3 || cn == 4 );
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ switch( depth )
+ {
+ case CV_8U:
+ {
+ const uchar* src_row = dst.ptr(i);
+ uchar* dst_row = dst2.ptr(i);
+
+ for( j = 0; j < cols_n; j++ )
+ src_buf[j] = src_row[j];
+
+ convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols );
+
+ for( j = 0; j < dst_cols; j++ )
+ {
+ int b = cvRound( dst_buf[j*3]*255. );
+ int g = cvRound( dst_buf[j*3+1]*255. );
+ int r = cvRound( dst_buf[j*3+2]*255. );
+ dst_row[j*cn + blue_idx] = saturate_cast<uchar>(b);
+ dst_row[j*cn + 1] = saturate_cast<uchar>(g);
+ dst_row[j*cn + (blue_idx^2)] = saturate_cast<uchar>(r);
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 255;
+ }
+ }
+ break;
+ case CV_16U:
+ {
+ const ushort* src_row = dst.ptr<ushort>(i);
+ ushort* dst_row = dst2.ptr<ushort>(i);
+
+ for( j = 0; j < cols_n; j++ )
+ src_buf[j] = src_row[j];
+
+ convert_row_abc2bgr_32f_c3( src_buf, dst_buf, dst_cols );
+
+ for( j = 0; j < dst_cols; j++ )
+ {
+ int b = cvRound( dst_buf[j*3]*65535. );
+ int g = cvRound( dst_buf[j*3+1]*65535. );
+ int r = cvRound( dst_buf[j*3+2]*65535. );
+ dst_row[j*cn + blue_idx] = saturate_cast<ushort>(b);
+ dst_row[j*cn + 1] = saturate_cast<ushort>(g);
+ dst_row[j*cn + (blue_idx^2)] = saturate_cast<ushort>(r);
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 65535;
+ }
+ }
+ break;
+ case CV_32F:
+ {
+ const float* src_row = dst.ptr<float>(i);
+ float* dst_row = dst2.ptr<float>(i);
+
+ convert_row_abc2bgr_32f_c3( src_row, dst_buf, dst_cols );
+
+ for( j = 0; j < dst_cols; j++ )
+ {
+ float b = dst_buf[j*3];
+ float g = dst_buf[j*3+1];
+ float r = dst_buf[j*3+2];
+ dst_row[j*cn + blue_idx] = b;
+ dst_row[j*cn + 1] = g;
+ dst_row[j*cn + (blue_idx^2)] = r;
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 1.f;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+ else
+ {
+ int i, j, k;
+ int elem_size = src.elemSize(), elem_size1 = src.elemSize1();
+ int width_n = src.cols*elem_size;
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ memcpy( dst2.ptr(i), src.ptr(i), width_n );
+ if( src.channels() == 4 )
+ {
+ // clear the alpha channel
+ uchar* ptr = dst2.ptr(i) + elem_size1*3;
+ for( j = 0; j < width_n; j += elem_size )
+ {
+ for( k = 0; k < elem_size1; k++ )
+ ptr[j + k] = 0;
+ }
+ }
+ }
+ }
+}
+
+
+#undef INIT_FWD_INV_CODES
+#define INIT_FWD_INV_CODES( fwd, inv ) \
+ fwd_code = CV_##fwd; inv_code = CV_##inv; \
+ fwd_code_str = #fwd; inv_code_str = #inv
+
+//// rgb <=> gray
+class CV_ColorGrayTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorGrayTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_ColorGrayTest::CV_ColorGrayTest() : CV_ColorCvtBaseTest( true, true, true )
+{
+ INIT_FWD_INV_CODES( BGR2GRAY, GRAY2BGR );
+}
+
+
+void CV_ColorGrayTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int cn = CV_MAT_CN(types[INPUT][0]);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = types[INPUT][0] & CV_MAT_DEPTH_MASK;
+ inplace = false;
+
+ if( cn == 3 )
+ {
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2GRAY, inv_code = CV_GRAY2BGR;
+ else
+ fwd_code = CV_RGB2GRAY, inv_code = CV_GRAY2RGB;
+ }
+ else
+ {
+ if( blue_idx == 0 )
+ fwd_code = CV_BGRA2GRAY, inv_code = CV_GRAY2BGRA;
+ else
+ fwd_code = CV_RGBA2GRAY, inv_code = CV_GRAY2RGBA;
+ }
+}
+
+
+double CV_ColorGrayTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? 2 : depth == CV_16U ? 16 : 1e-5;
+}
+
+
+void CV_ColorGrayTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1;
+ double cr = 0.299*scale;
+ double cg = 0.587*scale;
+ double cb = 0.114*scale;
+ int j;
+
+ for( j = 0; j < n; j++ )
+ dst_row[j] = (float)(src_row[j*3]*cb + src_row[j*3+1]*cg + src_row[j*3+2]*cr);
+}
+
+
+void CV_ColorGrayTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int j, depth = test_mat[INPUT][0].depth();
+ float scale = depth == CV_8U ? (1.f/255) : depth == CV_16U ? 1.f/65535 : 1.f;
+ for( j = 0; j < n; j++ )
+ dst_row[j*3] = dst_row[j*3+1] = dst_row[j*3+2] = src_row[j]*scale;
+}
+
+
+//// rgb <=> ycrcb
+class CV_ColorYCrCbTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorYCrCbTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorYCrCbTest::CV_ColorYCrCbTest() : CV_ColorCvtBaseTest( true, true, true )
+{
+ INIT_FWD_INV_CODES( BGR2YCrCb, YCrCb2BGR );
+}
+
+
+void CV_ColorYCrCbTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2YCrCb, inv_code = CV_YCrCb2BGR;
+ else
+ fwd_code = CV_RGB2YCrCb, inv_code = CV_YCrCb2RGB;
+}
+
+
+double CV_ColorYCrCbTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? 2 : depth == CV_16U ? 32 : 1e-3;
+}
+
+
+void CV_ColorYCrCbTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1;
+ double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5;
+
+ double M[] = { 0.299, 0.587, 0.114,
+ 0.49981, -0.41853, -0.08128,
+ -0.16864, -0.33107, 0.49970 };
+ int j;
+ for( j = 0; j < 9; j++ )
+ M[j] *= scale;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ double r = src_row[j+2];
+ double g = src_row[j+1];
+ double b = src_row[j];
+ double y = M[0]*r + M[1]*g + M[2]*b;
+ double cr = M[3]*r + M[4]*g + M[5]*b + bias;
+ double cb = M[6]*r + M[7]*g + M[8]*b + bias;
+ dst_row[j] = (float)y;
+ dst_row[j+1] = (float)cr;
+ dst_row[j+2] = (float)cb;
+ }
+}
+
+
+void CV_ColorYCrCbTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ double bias = depth == CV_8U ? 128 : depth == CV_16U ? 32768 : 0.5;
+ double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1;
+ double M[] = { 1, 1.40252, 0,
+ 1, -0.71440, -0.34434,
+ 1, 0, 1.77305 };
+ int j;
+ for( j = 0; j < 9; j++ )
+ M[j] *= scale;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ double y = src_row[j];
+ double cr = src_row[j+1] - bias;
+ double cb = src_row[j+2] - bias;
+ double r = M[0]*y + M[1]*cr + M[2]*cb;
+ double g = M[3]*y + M[4]*cr + M[5]*cb;
+ double b = M[6]*y + M[7]*cr + M[8]*cb;
+ dst_row[j] = (float)b;
+ dst_row[j+1] = (float)g;
+ dst_row[j+2] = (float)r;
+ }
+}
+
+
+//// rgb <=> hsv
+class CV_ColorHSVTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorHSVTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorHSVTest::CV_ColorHSVTest() : CV_ColorCvtBaseTest( true, true, false )
+{
+ INIT_FWD_INV_CODES( BGR2HSV, HSV2BGR );
+ hue_channel = true;
+}
+
+
+void CV_ColorHSVTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2HSV, inv_code = CV_HSV2BGR;
+ else
+ fwd_code = CV_RGB2HSV, inv_code = CV_HSV2RGB;
+}
+
+
+double CV_ColorHSVTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-3;
+}
+
+
+void CV_ColorHSVTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float h_scale = depth == CV_8U ? 30.f : 60.f;
+ float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f;
+ int j;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float r = src_row[j+2];
+ float g = src_row[j+1];
+ float b = src_row[j];
+ float vmin = MIN(r,g);
+ float v = MAX(r,g);
+ float s, h, diff;
+ vmin = MIN(vmin,b);
+ v = MAX(v,b);
+ diff = v - vmin;
+ if( diff == 0 )
+ s = h = 0;
+ else
+ {
+ s = diff/(v + FLT_EPSILON);
+ diff = 1.f/diff;
+
+ h = r == v ? (g - b)*diff :
+ g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff;
+
+ if( h < 0 )
+ h += 6;
+ }
+
+ dst_row[j] = h*h_scale;
+ dst_row[j+1] = s*scale;
+ dst_row[j+2] = v*scale;
+ }
+}
+
+// taken from http://www.cs.rit.edu/~ncs/color/t_convert.html
+void CV_ColorHSVTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float h_scale = depth == CV_8U ? 1.f/30 : 1.f/60;
+ float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1;
+ int j;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float h = src_row[j]*h_scale;
+ float s = src_row[j+1]*scale;
+ float v = src_row[j+2]*scale;
+ float r = v, g = v, b = v;
+
+ if( h < 0 )
+ h += 6;
+ else if( h >= 6 )
+ h -= 6;
+
+ if( s != 0 )
+ {
+ int i = cvFloor(h);
+ float f = h - i;
+ float p = v*(1 - s);
+ float q = v*(1 - s*f);
+ float t = v*(1 - s*(1 - f));
+
+ if( i == 0 )
+ r = v, g = t, b = p;
+ else if( i == 1 )
+ r = q, g = v, b = p;
+ else if( i == 2 )
+ r = p, g = v, b = t;
+ else if( i == 3 )
+ r = p, g = q, b = v;
+ else if( i == 4 )
+ r = t, g = p, b = v;
+ else
+ r = v, g = p, b = q;
+ }
+
+ dst_row[j] = b;
+ dst_row[j+1] = g;
+ dst_row[j+2] = r;
+ }
+}
+
+
+//// rgb <=> hls
+class CV_ColorHLSTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorHLSTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorHLSTest::CV_ColorHLSTest() : CV_ColorCvtBaseTest( true, true, false )
+{
+ INIT_FWD_INV_CODES( BGR2HLS, HLS2BGR );
+ hue_channel = true;
+}
+
+
+void CV_ColorHLSTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2HLS, inv_code = CV_HLS2BGR;
+ else
+ fwd_code = CV_RGB2HLS, inv_code = CV_HLS2RGB;
+}
+
+
+double CV_ColorHLSTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? (j == 0 ? 4 : 16) : depth == CV_16U ? 32 : 1e-4;
+}
+
+
+void CV_ColorHLSTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float h_scale = depth == CV_8U ? 30.f : 60.f;
+ float scale = depth == CV_8U ? 255.f : depth == CV_16U ? 65535.f : 1.f;
+ int j;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float r = src_row[j+2];
+ float g = src_row[j+1];
+ float b = src_row[j];
+ float vmin = MIN(r,g);
+ float v = MAX(r,g);
+ float s, h, l, diff;
+ vmin = MIN(vmin,b);
+ v = MAX(v,b);
+ diff = v - vmin;
+
+ if( diff == 0 )
+ s = h = 0, l = v;
+ else
+ {
+ l = (v + vmin)*0.5f;
+ s = l <= 0.5f ? diff / (v + vmin) : diff / (2 - v - vmin);
+ diff = 1.f/diff;
+
+ h = r == v ? (g - b)*diff :
+ g == v ? 2 + (b - r)*diff : 4 + (r - g)*diff;
+
+ if( h < 0 )
+ h += 6;
+ }
+
+ dst_row[j] = h*h_scale;
+ dst_row[j+1] = l*scale;
+ dst_row[j+2] = s*scale;
+ }
+}
+
+
+void CV_ColorHLSTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float h_scale = depth == CV_8U ? 1.f/30 : 1.f/60;
+ float scale = depth == CV_8U ? 1.f/255 : depth == CV_16U ? 1.f/65535 : 1;
+ int j;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float h = src_row[j]*h_scale;
+ float l = src_row[j+1]*scale;
+ float s = src_row[j+2]*scale;
+ float r = l, g = l, b = l;
+
+ if( h < 0 )
+ h += 6;
+ else if( h >= 6 )
+ h -= 6;
+
+ if( s != 0 )
+ {
+ float m2 = l <= 0.5f ? l*(1.f + s) : l + s - l*s;
+ float m1 = 2*l - m2;
+ float h1 = h + 2;
+
+ if( h1 >= 6 )
+ h1 -= 6;
+ if( h1 < 1 )
+ r = m1 + (m2 - m1)*h1;
+ else if( h1 < 3 )
+ r = m2;
+ else if( h1 < 4 )
+ r = m1 + (m2 - m1)*(4 - h1);
+ else
+ r = m1;
+
+ h1 = h;
+
+ if( h1 < 1 )
+ g = m1 + (m2 - m1)*h1;
+ else if( h1 < 3 )
+ g = m2;
+ else if( h1 < 4 )
+ g = m1 + (m2 - m1)*(4 - h1);
+ else
+ g = m1;
+
+ h1 = h - 2;
+ if( h1 < 0 )
+ h1 += 6;
+
+ if( h1 < 1 )
+ b = m1 + (m2 - m1)*h1;
+ else if( h1 < 3 )
+ b = m2;
+ else if( h1 < 4 )
+ b = m1 + (m2 - m1)*(4 - h1);
+ else
+ b = m1;
+ }
+
+ dst_row[j] = b;
+ dst_row[j+1] = g;
+ dst_row[j+2] = r;
+ }
+}
+
+
+static const double RGB2XYZ[] =
+{
+ 0.412453, 0.357580, 0.180423,
+ 0.212671, 0.715160, 0.072169,
+ 0.019334, 0.119193, 0.950227
+};
+
+
+static const double XYZ2RGB[] =
+{
+ 3.240479, -1.53715, -0.498535,
+ -0.969256, 1.875991, 0.041556,
+ 0.055648, -0.204043, 1.057311
+};
+
+static const float Xn = 0.950456f;
+static const float Zn = 1.088754f;
+
+
+//// rgb <=> xyz
+class CV_ColorXYZTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorXYZTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorXYZTest::CV_ColorXYZTest() : CV_ColorCvtBaseTest( true, true, true )
+{
+ INIT_FWD_INV_CODES( BGR2XYZ, XYZ2BGR );
+}
+
+
+void CV_ColorXYZTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2XYZ, inv_code = CV_XYZ2BGR;
+ else
+ fwd_code = CV_RGB2XYZ, inv_code = CV_XYZ2RGB;
+}
+
+
+double CV_ColorXYZTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? (j == 0 ? 2 : 8) : depth == CV_16U ? (j == 0 ? 64 : 128) : 1e-1;
+}
+
+
+void CV_ColorXYZTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ double scale = depth == CV_8U ? 255 : depth == CV_16U ? 65535 : 1;
+
+ double M[9];
+ int j;
+ for( j = 0; j < 9; j++ )
+ M[j] = RGB2XYZ[j]*scale;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ double r = src_row[j+2];
+ double g = src_row[j+1];
+ double b = src_row[j];
+ double x = M[0]*r + M[1]*g + M[2]*b;
+ double y = M[3]*r + M[4]*g + M[5]*b;
+ double z = M[6]*r + M[7]*g + M[8]*b;
+ dst_row[j] = (float)x;
+ dst_row[j+1] = (float)y;
+ dst_row[j+2] = (float)z;
+ }
+}
+
+
+void CV_ColorXYZTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ double scale = depth == CV_8U ? 1./255 : depth == CV_16U ? 1./65535 : 1;
+
+ double M[9];
+ int j;
+ for( j = 0; j < 9; j++ )
+ M[j] = XYZ2RGB[j]*scale;
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ double x = src_row[j];
+ double y = src_row[j+1];
+ double z = src_row[j+2];
+ double r = M[0]*x + M[1]*y + M[2]*z;
+ double g = M[3]*x + M[4]*y + M[5]*z;
+ double b = M[6]*x + M[7]*y + M[8]*z;
+ dst_row[j] = (float)b;
+ dst_row[j+1] = (float)g;
+ dst_row[j+2] = (float)r;
+ }
+}
+
+
+//// rgb <=> L*a*b*
+class CV_ColorLabTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorLabTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorLabTest::CV_ColorLabTest() : CV_ColorCvtBaseTest( true, true, false )
+{
+ INIT_FWD_INV_CODES( BGR2Lab, Lab2BGR );
+}
+
+
+void CV_ColorLabTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_LBGR2Lab, inv_code = CV_Lab2LBGR;
+ else
+ fwd_code = CV_LRGB2Lab, inv_code = CV_Lab2LRGB;
+}
+
+
+double CV_ColorLabTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 32 : 1e-3;
+}
+
+
+static const double _1_3 = 0.333333333333;
+
+void CV_ColorLabTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f;
+ float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f;
+ int j;
+ float M[9];
+
+ for( j = 0; j < 9; j++ )
+ M[j] = (float)RGB2XYZ[j];
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float r = src_row[j+2];
+ float g = src_row[j+1];
+ float b = src_row[j];
+
+ float X = (r*M[0] + g*M[1] + b*M[2])*(1.f/Xn);
+ float Y = r*M[3] + g*M[4] + b*M[5];
+ float Z = (r*M[6] + g*M[7] + b*M[8])*(1.f/Zn);
+ float fX, fY, fZ;
+
+ float L, a;
+
+ if( Y > 0.008856 )
+ {
+ fY = (float)pow((double)Y,_1_3);
+ L = 116.f*fY - 16.f;
+ }
+ else
+ {
+ fY = 7.787f*Y + 16.f/116.f;
+ L = 903.3f*Y;
+ }
+
+ if( X > 0.008856 )
+ fX = (float)pow((double)X,_1_3);
+ else
+ fX = 7.787f*X + 16.f/116.f;
+
+ if( Z > 0.008856 )
+ fZ = (float)pow((double)Z,_1_3);
+ else
+ fZ = 7.787f*Z + 16.f/116.f;
+
+ a = 500.f*(fX - fY);
+ b = 200.f*(fY - fZ);
+
+ dst_row[j] = L*Lscale;
+ dst_row[j+1] = a + ab_bias;
+ dst_row[j+2] = b + ab_bias;
+ }
+}
+
+
+void CV_ColorLabTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f;
+ float ab_bias = depth == CV_8U ? 128.f : depth == CV_16U ? 32768.f : 0.f;
+ int j;
+ float M[9];
+
+ for( j = 0; j < 9; j++ )
+ M[j] = (float)XYZ2RGB[j];
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float L = src_row[j]*Lscale;
+ float a = src_row[j+1] - ab_bias;
+ float b = src_row[j+2] - ab_bias;
+
+ float P = (L + 16.f)*(1.f/116.f);
+ float X = (P + a*0.002f);
+ float Z = (P - b*0.005f);
+ float Y = P*P*P;
+ X = Xn*X*X*X;
+ Z = Zn*Z*Z*Z;
+
+ float r = M[0]*X + M[1]*Y + M[2]*Z;
+ float g = M[3]*X + M[4]*Y + M[5]*Z;
+ b = M[6]*X + M[7]*Y + M[8]*Z;
+
+ dst_row[j] = b;
+ dst_row[j+1] = g;
+ dst_row[j+2] = r;
+ }
+}
+
+
+//// rgb <=> L*u*v*
+class CV_ColorLuvTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorLuvTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n );
+ void convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n );
+};
+
+
+CV_ColorLuvTest::CV_ColorLuvTest() : CV_ColorCvtBaseTest( true, true, false )
+{
+ INIT_FWD_INV_CODES( BGR2Luv, Luv2BGR );
+}
+
+
+void CV_ColorLuvTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ if( blue_idx == 0 )
+ fwd_code = CV_LBGR2Luv, inv_code = CV_Luv2LBGR;
+ else
+ fwd_code = CV_LRGB2Luv, inv_code = CV_Luv2LRGB;
+}
+
+
+double CV_ColorLuvTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_8U ? 48 : depth == CV_16U ? 32 : 5e-2;
+}
+
+
+void CV_ColorLuvTest::convert_row_bgr2abc_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float Lscale = depth == CV_8U ? 255.f/100.f : depth == CV_16U ? 65535.f/100.f : 1.f;
+ int j;
+
+ float M[9];
+ float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn);
+ float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn);
+ float u_scale = 1.f, u_bias = 0.f;
+ float v_scale = 1.f, v_bias = 0.f;
+
+ for( j = 0; j < 9; j++ )
+ M[j] = (float)RGB2XYZ[j];
+
+ if( depth == CV_8U )
+ {
+ u_scale = 0.720338983f;
+ u_bias = 96.5254237f;
+ v_scale = 0.99609375f;
+ v_bias = 139.453125f;
+ }
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float r = src_row[j+2];
+ float g = src_row[j+1];
+ float b = src_row[j];
+
+ float X = r*M[0] + g*M[1] + b*M[2];
+ float Y = r*M[3] + g*M[4] + b*M[5];
+ float Z = r*M[6] + g*M[7] + b*M[8];
+ float d = X + 15*Y + 3*Z, L, u, v;
+
+ if( d == 0 )
+ L = u = v = 0;
+ else
+ {
+ if( Y > 0.008856f )
+ L = (float)(116.*pow((double)Y,_1_3) - 16.);
+ else
+ L = 903.3f * Y;
+
+ d = 1.f/d;
+ u = 13*L*(4*X*d - un);
+ v = 13*L*(9*Y*d - vn);
+ }
+ dst_row[j] = L*Lscale;
+ dst_row[j+1] = u*u_scale + u_bias;
+ dst_row[j+2] = v*v_scale + v_bias;
+ }
+}
+
+
+void CV_ColorLuvTest::convert_row_abc2bgr_32f_c3( const float* src_row, float* dst_row, int n )
+{
+ int depth = test_mat[INPUT][0].depth();
+ float Lscale = depth == CV_8U ? 100.f/255.f : depth == CV_16U ? 100.f/65535.f : 1.f;
+ int j;
+ float M[9];
+ float un = 4.f*Xn/(Xn + 15.f*1.f + 3*Zn);
+ float vn = 9.f*1.f/(Xn + 15.f*1.f + 3*Zn);
+ float u_scale = 1.f, u_bias = 0.f;
+ float v_scale = 1.f, v_bias = 0.f;
+
+ for( j = 0; j < 9; j++ )
+ M[j] = (float)XYZ2RGB[j];
+
+ if( depth == CV_8U )
+ {
+ u_scale = 1.f/0.720338983f;
+ u_bias = 96.5254237f;
+ v_scale = 1.f/0.99609375f;
+ v_bias = 139.453125f;
+ }
+
+ for( j = 0; j < n*3; j += 3 )
+ {
+ float L = src_row[j]*Lscale;
+ float u = (src_row[j+1] - u_bias)*u_scale;
+ float v = (src_row[j+2] - v_bias)*v_scale;
+ float X, Y, Z;
+
+ if( L >= 8 )
+ {
+ Y = (L + 16.f)*(1.f/116.f);
+ Y = Y*Y*Y;
+ }
+ else
+ {
+ Y = L * (1.f/903.3f);
+ if( L == 0 )
+ L = 0.001f;
+ }
+
+ u = u/(13*L) + un;
+ v = v/(13*L) + vn;
+
+ X = -9*Y*u/((u - 4)*v - u*v);
+ Z = (9*Y - 15*v*Y - v*X)/(3*v);
+
+ float r = M[0]*X + M[1]*Y + M[2]*Z;
+ float g = M[3]*X + M[4]*Y + M[5]*Z;
+ float b = M[6]*X + M[7]*Y + M[8]*Z;
+
+ dst_row[j] = b;
+ dst_row[j+1] = g;
+ dst_row[j+2] = r;
+ }
+}
+
+
+//// rgb <=> another rgb
+class CV_ColorRGBTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorRGBTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void convert_forward( const Mat& src, Mat& dst );
+ void convert_backward( const Mat& src, const Mat& dst, Mat& dst2 );
+ int dst_bits;
+};
+
+
+CV_ColorRGBTest::CV_ColorRGBTest() : CV_ColorCvtBaseTest( true, true, true )
+{
+ dst_bits = 0;
+}
+
+
+void CV_ColorRGBTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int cn = CV_MAT_CN(types[INPUT][0]);
+
+ dst_bits = 24;
+
+ if( cvtest::randInt(rng) % 3 == 0 )
+ {
+ types[INPUT][0] = types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_8U,cn);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(CV_8U,2);
+ if( cvtest::randInt(rng) & 1 )
+ {
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2BGR565, inv_code = CV_BGR5652BGR;
+ else
+ fwd_code = CV_RGB2BGR565, inv_code = CV_BGR5652RGB;
+ dst_bits = 16;
+ }
+ else
+ {
+ if( blue_idx == 0 )
+ fwd_code = CV_BGR2BGR555, inv_code = CV_BGR5552BGR;
+ else
+ fwd_code = CV_RGB2BGR555, inv_code = CV_BGR5552RGB;
+ dst_bits = 15;
+ }
+ }
+ else
+ {
+ if( cn == 3 )
+ {
+ fwd_code = CV_RGB2BGR, inv_code = CV_BGR2RGB;
+ blue_idx = 2;
+ }
+ else if( blue_idx == 0 )
+ fwd_code = CV_BGRA2BGR, inv_code = CV_BGR2BGRA;
+ else
+ fwd_code = CV_RGBA2BGR, inv_code = CV_BGR2RGBA;
+ }
+
+ if( CV_MAT_CN(types[INPUT][0]) != CV_MAT_CN(types[OUTPUT][0]) )
+ inplace = false;
+}
+
+
+double CV_ColorRGBTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 0;
+}
+
+
+void CV_ColorRGBTest::convert_forward( const Mat& src, Mat& dst )
+{
+ int depth = src.depth(), cn = src.channels();
+/*#if defined _DEBUG || defined DEBUG
+ int dst_cn = CV_MAT_CN(dst->type);
+#endif*/
+ int i, j, cols = src.cols;
+ int g_rshift = dst_bits == 16 ? 2 : 3;
+ int r_lshift = dst_bits == 16 ? 11 : 10;
+
+ //assert( (cn == 3 || cn == 4) && (dst_cn == 3 || (dst_cn == 2 && depth == CV_8U)) );
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ switch( depth )
+ {
+ case CV_8U:
+ {
+ const uchar* src_row = src.ptr(i);
+ uchar* dst_row = dst.ptr(i);
+
+ if( dst_bits == 24 )
+ {
+ for( j = 0; j < cols; j++ )
+ {
+ uchar b = src_row[j*cn + blue_idx];
+ uchar g = src_row[j*cn + 1];
+ uchar r = src_row[j*cn + (blue_idx^2)];
+ dst_row[j*3] = b;
+ dst_row[j*3+1] = g;
+ dst_row[j*3+2] = r;
+ }
+ }
+ else
+ {
+ for( j = 0; j < cols; j++ )
+ {
+ int b = src_row[j*cn + blue_idx] >> 3;
+ int g = src_row[j*cn + 1] >> g_rshift;
+ int r = src_row[j*cn + (blue_idx^2)] >> 3;
+ ((ushort*)dst_row)[j] = (ushort)(b | (g << 5) | (r << r_lshift));
+ if( cn == 4 && src_row[j*4+3] )
+ ((ushort*)dst_row)[j] |= 1 << (r_lshift+5);
+ }
+ }
+ }
+ break;
+ case CV_16U:
+ {
+ const ushort* src_row = src.ptr<ushort>(i);
+ ushort* dst_row = dst.ptr<ushort>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ ushort b = src_row[j*cn + blue_idx];
+ ushort g = src_row[j*cn + 1];
+ ushort r = src_row[j*cn + (blue_idx^2)];
+ dst_row[j*3] = b;
+ dst_row[j*3+1] = g;
+ dst_row[j*3+2] = r;
+ }
+ }
+ break;
+ case CV_32F:
+ {
+ const float* src_row = src.ptr<float>(i);
+ float* dst_row = dst.ptr<float>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ float b = src_row[j*cn + blue_idx];
+ float g = src_row[j*cn + 1];
+ float r = src_row[j*cn + (blue_idx^2)];
+ dst_row[j*3] = b;
+ dst_row[j*3+1] = g;
+ dst_row[j*3+2] = r;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+void CV_ColorRGBTest::convert_backward( const Mat& /*src*/, const Mat& src, Mat& dst )
+{
+ int depth = src.depth(), cn = dst.channels();
+/*#if defined _DEBUG || defined DEBUG
+ int src_cn = CV_MAT_CN(src->type);
+#endif*/
+ int i, j, cols = src.cols;
+ int g_lshift = dst_bits == 16 ? 2 : 3;
+ int r_rshift = dst_bits == 16 ? 11 : 10;
+
+ //assert( (cn == 3 || cn == 4) && (src_cn == 3 || (src_cn == 2 && depth == CV_8U)) );
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ switch( depth )
+ {
+ case CV_8U:
+ {
+ const uchar* src_row = src.ptr(i);
+ uchar* dst_row = dst.ptr(i);
+
+ if( dst_bits == 24 )
+ {
+ for( j = 0; j < cols; j++ )
+ {
+ uchar b = src_row[j*3];
+ uchar g = src_row[j*3 + 1];
+ uchar r = src_row[j*3 + 2];
+
+ dst_row[j*cn + blue_idx] = b;
+ dst_row[j*cn + 1] = g;
+ dst_row[j*cn + (blue_idx^2)] = r;
+
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 255;
+ }
+ }
+ else
+ {
+ for( j = 0; j < cols; j++ )
+ {
+ ushort val = ((ushort*)src_row)[j];
+ uchar b = (uchar)(val << 3);
+ uchar g = (uchar)((val >> 5) << g_lshift);
+ uchar r = (uchar)((val >> r_rshift) << 3);
+
+ dst_row[j*cn + blue_idx] = b;
+ dst_row[j*cn + 1] = g;
+ dst_row[j*cn + (blue_idx^2)] = r;
+
+ if( cn == 4 )
+ {
+ uchar alpha = r_rshift == 11 || (val & 0x8000) != 0 ? 255 : 0;
+ dst_row[j*cn + 3] = alpha;
+ }
+ }
+ }
+ }
+ break;
+ case CV_16U:
+ {
+ const ushort* src_row = src.ptr<ushort>(i);
+ ushort* dst_row = dst.ptr<ushort>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ ushort b = src_row[j*3];
+ ushort g = src_row[j*3 + 1];
+ ushort r = src_row[j*3 + 2];
+
+ dst_row[j*cn + blue_idx] = b;
+ dst_row[j*cn + 1] = g;
+ dst_row[j*cn + (blue_idx^2)] = r;
+
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 65535;
+ }
+ }
+ break;
+ case CV_32F:
+ {
+ const float* src_row = src.ptr<float>(i);
+ float* dst_row = dst.ptr<float>(i);
+
+ for( j = 0; j < cols; j++ )
+ {
+ float b = src_row[j*3];
+ float g = src_row[j*3 + 1];
+ float r = src_row[j*3 + 2];
+
+ dst_row[j*cn + blue_idx] = b;
+ dst_row[j*cn + 1] = g;
+ dst_row[j*cn + (blue_idx^2)] = r;
+
+ if( cn == 4 )
+ dst_row[j*cn + 3] = 1.f;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+}
+
+
+//// rgb <=> bayer
+
+class CV_ColorBayerTest : public CV_ColorCvtBaseTest
+{
+public:
+ CV_ColorBayerTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int test_case_idx );
+};
+
+
+CV_ColorBayerTest::CV_ColorBayerTest() : CV_ColorCvtBaseTest( false, false, false )
+{
+ test_array[OUTPUT].pop_back();
+ test_array[REF_OUTPUT].pop_back();
+
+ fwd_code_str = "BayerBG2BGR";
+ inv_code_str = "";
+ fwd_code = CV_BayerBG2BGR;
+ inv_code = -1;
+}
+
+
+void CV_ColorBayerTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_ColorCvtBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ types[INPUT][0] = CV_8UC1;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC3;
+ inplace = false;
+
+ fwd_code = cvtest::randInt(rng)%4 + CV_BayerBG2BGR;
+}
+
+
+double CV_ColorBayerTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 1;
+}
+
+
+void CV_ColorBayerTest::run_func()
+{
+ if(!test_cpp)
+ cvCvtColor( test_array[INPUT][0], test_array[OUTPUT][0], fwd_code );
+ else
+ {
+ cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
+ cv::cvtColor(cv::cvarrToMat(test_array[INPUT][0]), _out, fwd_code, _out.channels());
+ }
+}
+
+
+void CV_ColorBayerTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_OUTPUT][0];
+ int i, j, cols = src.cols - 2;
+ int code = fwd_code;
+ int bi = 0;
+ int step = src.step;
+
+ if( fwd_code == CV_BayerRG2BGR || fwd_code == CV_BayerGR2BGR )
+ bi ^= 2;
+
+ for( i = 1; i < src.rows - 1; i++ )
+ {
+ const uchar* ptr = src.ptr(i) + 1;
+ uchar* dst_row = dst.ptr(i) + 3;
+ int save_code = code;
+ if( cols <= 0 )
+ {
+ dst_row[-3] = dst_row[-2] = dst_row[-1] = 0;
+ dst_row[cols*3] = dst_row[cols*3+1] = dst_row[cols*3+2] = 0;
+ continue;
+ }
+
+ for( j = 0; j < cols; j++ )
+ {
+ int b, g, r;
+ if( !(code & 1) )
+ {
+ b = ptr[j];
+ g = (ptr[j-1] + ptr[j+1] + ptr[j-step] + ptr[j+step])>>2;
+ r = (ptr[j-step-1] + ptr[j-step+1] + ptr[j+step-1] + ptr[j+step+1]) >> 2;
+ }
+ else
+ {
+ b = (ptr[j-1] + ptr[j+1]) >> 1;
+ g = ptr[j];
+ r = (ptr[j-step] + ptr[j+step]) >> 1;
+ }
+ code ^= 1;
+ dst_row[j*3 + bi] = (uchar)b;
+ dst_row[j*3 + 1] = (uchar)g;
+ dst_row[j*3 + (bi^2)] = (uchar)r;
+ }
+
+ dst_row[-3] = dst_row[0];
+ dst_row[-2] = dst_row[1];
+ dst_row[-1] = dst_row[2];
+ dst_row[cols*3] = dst_row[cols*3-3];
+ dst_row[cols*3+1] = dst_row[cols*3-2];
+ dst_row[cols*3+2] = dst_row[cols*3-1];
+
+ code = save_code ^ 1;
+ bi ^= 2;
+ }
+
+ if( src.rows <= 2 )
+ {
+ memset( dst.ptr(), 0, (cols+2)*3 );
+ memset( dst.ptr(dst.rows-1), 0, (cols+2)*3 );
+ }
+ else
+ {
+ uchar* top_row = dst.ptr();
+ uchar* bottom_row = dst.ptr(dst.rows-1);
+ int dstep = dst.step;
+
+ for( j = 0; j < (cols+2)*3; j++ )
+ {
+ top_row[j] = top_row[j + dstep];
+ bottom_row[j] = bottom_row[j - dstep];
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST(Imgcore_ColorGray, accuracy) { CV_ColorGrayTest test; test.safe_run(); }
+TEST(Imgcore_ColorYCrCb, accuracy) { CV_ColorYCrCbTest test; test.safe_run(); }
+TEST(Imgcore_ColorHSV, accuracy) { CV_ColorHSVTest test; test.safe_run(); }
+TEST(Imgcore_ColorHLS, accuracy) { CV_ColorHLSTest test; test.safe_run(); }
+TEST(Imgcore_ColorXYZ, accuracy) { CV_ColorXYZTest test; test.safe_run(); }
+TEST(Imgcore_ColorLab, accuracy) { CV_ColorLabTest test; test.safe_run(); }
+TEST(Imgcore_ColorLuv, accuracy) { CV_ColorLuvTest test; test.safe_run(); }
+TEST(Imgcore_ColorRGB, accuracy) { CV_ColorRGBTest test; test.safe_run(); }
+TEST(Imgcore_ColorBayer, accuracy) { CV_ColorBayerTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_FindContourTest : public cvtest::BaseTest
+{
+public:
+ enum { NUM_IMG = 4 };
+
+ CV_FindContourTest();
+ ~CV_FindContourTest();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void run_func();
+
+ int min_blob_size, max_blob_size;
+ int blob_count, max_log_blob_count;
+ int retr_mode, approx_method;
+
+ int min_log_img_size, max_log_img_size;
+ CvSize img_size;
+ int count, count2;
+
+ IplImage* img[NUM_IMG];
+ CvMemStorage* storage;
+ CvSeq *contours, *contours2, *chain;
+};
+
+
+CV_FindContourTest::CV_FindContourTest()
+{
+ int i;
+
+ test_case_count = 300;
+ min_blob_size = 1;
+ max_blob_size = 50;
+ max_log_blob_count = 10;
+
+ min_log_img_size = 3;
+ max_log_img_size = 10;
+
+ for( i = 0; i < NUM_IMG; i++ )
+ img[i] = 0;
+
+ storage = 0;
+}
+
+
+CV_FindContourTest::~CV_FindContourTest()
+{
+ clear();
+}
+
+
+void CV_FindContourTest::clear()
+{
+ int i;
+
+ cvtest::BaseTest::clear();
+
+ for( i = 0; i < NUM_IMG; i++ )
+ cvReleaseImage( &img[i] );
+
+ cvReleaseMemStorage( &storage );
+}
+
+
+int CV_FindContourTest::read_params( CvFileStorage* fs )
+{
+ int t;
+ int code = cvtest::BaseTest::read_params( fs );
+
+ if( code < 0 )
+ return code;
+
+ min_blob_size = cvReadInt( find_param( fs, "min_blob_size" ), min_blob_size );
+ max_blob_size = cvReadInt( find_param( fs, "max_blob_size" ), max_blob_size );
+ max_log_blob_count = cvReadInt( find_param( fs, "max_log_blob_count" ), max_log_blob_count );
+ min_log_img_size = cvReadInt( find_param( fs, "min_log_img_size" ), min_log_img_size );
+ max_log_img_size = cvReadInt( find_param( fs, "max_log_img_size" ), max_log_img_size );
+
+ min_blob_size = cvtest::clipInt( min_blob_size, 1, 100 );
+ max_blob_size = cvtest::clipInt( max_blob_size, 1, 100 );
+
+ if( min_blob_size > max_blob_size )
+ CV_SWAP( min_blob_size, max_blob_size, t );
+
+ max_log_blob_count = cvtest::clipInt( max_log_blob_count, 1, 10 );
+
+ min_log_img_size = cvtest::clipInt( min_log_img_size, 1, 10 );
+ max_log_img_size = cvtest::clipInt( max_log_img_size, 1, 10 );
+
+ if( min_log_img_size > max_log_img_size )
+ CV_SWAP( min_log_img_size, max_log_img_size, t );
+
+ return 0;
+}
+
+
+static void
+cvTsGenerateBlobImage( IplImage* img, int min_blob_size, int max_blob_size,
+ int blob_count, int min_brightness, int max_brightness,
+ RNG& rng )
+{
+ int i;
+ CvSize size;
+
+ assert( img->depth == IPL_DEPTH_8U && img->nChannels == 1 );
+
+ cvZero( img );
+
+ // keep the border clear
+ cvSetImageROI( img, cvRect(1,1,img->width-2,img->height-2) );
+ size = cvGetSize( img );
+
+ for( i = 0; i < blob_count; i++ )
+ {
+ CvPoint center;
+ CvSize axes;
+ int angle = cvtest::randInt(rng) % 180;
+ int brightness = cvtest::randInt(rng) %
+ (max_brightness - min_brightness) + min_brightness;
+ center.x = cvtest::randInt(rng) % size.width;
+ center.y = cvtest::randInt(rng) % size.height;
+
+ axes.width = (cvtest::randInt(rng) %
+ (max_blob_size - min_blob_size) + min_blob_size + 1)/2;
+ axes.height = (cvtest::randInt(rng) %
+ (max_blob_size - min_blob_size) + min_blob_size + 1)/2;
+
+ cvEllipse( img, center, axes, angle, 0, 360, cvScalar(brightness), CV_FILLED );
+ }
+
+ cvResetImageROI( img );
+}
+
+
+static void
+cvTsMarkContours( IplImage* img, int val )
+{
+ int i, j;
+ int step = img->widthStep;
+
+ assert( img->depth == IPL_DEPTH_8U && img->nChannels == 1 && (val&1) != 0);
+
+ for( i = 1; i < img->height - 1; i++ )
+ for( j = 1; j < img->width - 1; j++ )
+ {
+ uchar* t = (uchar*)(img->imageData + img->widthStep*i + j);
+ if( *t == 1 && (t[-step] == 0 || t[-1] == 0 || t[1] == 0 || t[step] == 0))
+ *t = (uchar)val;
+ }
+
+ cvThreshold( img, img, val - 2, val, CV_THRESH_BINARY );
+}
+
+
+int CV_FindContourTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ const int min_brightness = 0, max_brightness = 2;
+ int i, code = cvtest::BaseTest::prepare_test_case( test_case_idx );
+
+ if( code < 0 )
+ return code;
+
+ clear();
+
+ blob_count = cvRound(exp(cvtest::randReal(rng)*max_log_blob_count*CV_LOG2));
+
+ img_size.width = cvRound(exp((cvtest::randReal(rng)*
+ (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+ img_size.height = cvRound(exp((cvtest::randReal(rng)*
+ (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+
+ approx_method = cvtest::randInt( rng ) % 4 + 1;
+ retr_mode = cvtest::randInt( rng ) % 4;
+
+ storage = cvCreateMemStorage( 1 << 10 );
+
+ for( i = 0; i < NUM_IMG; i++ )
+ img[i] = cvCreateImage( img_size, 8, 1 );
+
+ cvTsGenerateBlobImage( img[0], min_blob_size, max_blob_size,
+ blob_count, min_brightness, max_brightness, rng );
+
+ cvCopy( img[0], img[1] );
+ cvCopy( img[0], img[2] );
+
+ cvTsMarkContours( img[1], 255 );
+
+ return 1;
+}
+
+
+void CV_FindContourTest::run_func()
+{
+ contours = contours2 = chain = 0;
+ count = cvFindContours( img[2], storage, &contours, sizeof(CvContour), retr_mode, approx_method );
+
+ cvZero( img[3] );
+
+ if( contours && retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 )
+ cvDrawContours( img[3], contours, cvScalar(255), cvScalar(255), INT_MAX, -1 );
+
+ cvCopy( img[0], img[2] );
+
+ count2 = cvFindContours( img[2], storage, &chain, sizeof(CvChain), retr_mode, CV_CHAIN_CODE );
+
+ if( chain )
+ contours2 = cvApproxChains( chain, storage, approx_method, 0, 0, 1 );
+
+ cvZero( img[2] );
+
+ if( contours && retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 )
+ cvDrawContours( img[2], contours2, cvScalar(255), cvScalar(255), INT_MAX );
+}
+
+
+// the whole testing is done here, run_func() is not utilized in this test
+int CV_FindContourTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int i, code = cvtest::TS::OK;
+
+ cvCmpS( img[0], 0, img[0], CV_CMP_GT );
+
+ if( count != count2 )
+ {
+ ts->printf( cvtest::TS::LOG, "The number of contours retrieved with different "
+ "approximation methods is not the same\n"
+ "(%d contour(s) for method %d vs %d contour(s) for method %d)\n",
+ count, approx_method, count2, CV_CHAIN_CODE );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+
+ if( retr_mode != CV_RETR_EXTERNAL && approx_method < CV_CHAIN_APPROX_TC89_L1 )
+ {
+ Mat _img[4];
+ for( int i = 0; i < 4; i++ )
+ _img[i] = cvarrToMat(img[i]);
+
+ code = cvtest::cmpEps2(ts, _img[0], _img[3], 0, true, "Comparing original image with the map of filled contours" );
+
+ if( code < 0 )
+ goto _exit_;
+
+ code = cvtest::cmpEps2( ts, _img[1], _img[2], 0, true,
+ "Comparing contour outline vs manually produced edge map" );
+
+ if( code < 0 )
+ goto _exit_;
+ }
+
+ if( contours )
+ {
+ CvTreeNodeIterator iterator1;
+ CvTreeNodeIterator iterator2;
+ int count3;
+
+ for( i = 0; i < 2; i++ )
+ {
+ CvTreeNodeIterator iterator;
+ cvInitTreeNodeIterator( &iterator, i == 0 ? contours : contours2, INT_MAX );
+
+ for( count3 = 0; cvNextTreeNode( &iterator ) != 0; count3++ )
+ ;
+
+ if( count3 != count )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The returned number of retrieved contours (using the approx_method = %d) does not match\n"
+ "to the actual number of contours in the tree/list (returned %d, actual %d)\n",
+ i == 0 ? approx_method : 0, count, count3 );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ }
+
+ cvInitTreeNodeIterator( &iterator1, contours, INT_MAX );
+ cvInitTreeNodeIterator( &iterator2, contours2, INT_MAX );
+
+ for( count3 = 0; count3 < count; count3++ )
+ {
+ CvSeq* seq1 = (CvSeq*)cvNextTreeNode( &iterator1 );
+ CvSeq* seq2 = (CvSeq*)cvNextTreeNode( &iterator2 );
+ CvSeqReader reader1;
+ CvSeqReader reader2;
+
+ if( !seq1 || !seq2 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "There are NULL pointers in the original contour tree or the "
+ "tree produced by cvApproxChains\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ cvStartReadSeq( seq1, &reader1 );
+ cvStartReadSeq( seq2, &reader2 );
+
+ if( seq1->total != seq2->total )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The original contour #%d has %d points, while the corresponding contour has %d point\n",
+ count3, seq1->total, seq2->total );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ for( i = 0; i < seq1->total; i++ )
+ {
+ CvPoint pt1;
+ CvPoint pt2;
+
+ CV_READ_SEQ_ELEM( pt1, reader1 );
+ CV_READ_SEQ_ELEM( pt2, reader2 );
+
+ if( pt1.x != pt2.x || pt1.y != pt2.y )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The point #%d in the contour #%d is different from the corresponding point "
+ "in the approximated chain ((%d,%d) vs (%d,%d)", count3, i, pt1.x, pt1.y, pt2.x, pt2.y );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ }
+ }
+ }
+
+_exit_:
+ if( code < 0 )
+ {
+#if 0
+ cvNamedWindow( "test", 0 );
+ cvShowImage( "test", img[0] );
+ cvWaitKey();
+#endif
+ ts->set_failed_test_info( code );
+ }
+
+ return code;
+}
+
+
+TEST(Imgproc_FindContours, accuracy) { CV_FindContourTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+/*static int
+cvTsPointConvexPolygon( CvPoint2D32f pt, CvPoint2D32f* v, int n )
+{
+ CvPoint2D32f v0 = v[n-1];
+ int i, sign = 0;
+
+ for( i = 0; i < n; i++ )
+ {
+ CvPoint2D32f v1 = v[i];
+ float dx = pt.x - v0.x, dy = pt.y - v0.y;
+ float dx1 = v1.x - v0.x, dy1 = v1.y - v0.y;
+ double t = (double)dx*dy1 - (double)dx1*dy;
+ if( fabs(t) > DBL_EPSILON )
+ {
+ if( t*sign < 0 )
+ break;
+ if( sign == 0 )
+ sign = t < 0 ? -1 : 1;
+ }
+ else if( fabs(dx) + fabs(dy) < DBL_EPSILON )
+ return i+1;
+ v0 = v1;
+ }
+
+ return i < n ? -1 : 0;
+}*/
+
+CV_INLINE double
+cvTsDist( CvPoint2D32f a, CvPoint2D32f b )
+{
+ double dx = a.x - b.x;
+ double dy = a.y - b.y;
+ return sqrt(dx*dx + dy*dy);
+}
+
+CV_INLINE double
+cvTsPtLineDist( CvPoint2D32f pt, CvPoint2D32f a, CvPoint2D32f b )
+{
+ double d0 = cvTsDist( pt, a ), d1;
+ double dd = cvTsDist( a, b );
+ if( dd < FLT_EPSILON )
+ return d0;
+ d1 = cvTsDist( pt, b );
+ dd = fabs((double)(pt.x - a.x)*(b.y - a.y) - (double)(pt.y - a.y)*(b.x - a.x))/dd;
+ d0 = MIN( d0, d1 );
+ return MIN( d0, dd );
+}
+
+static double
+cvTsPointPolygonTest( CvPoint2D32f pt, const CvPoint2D32f* vv, int n, int* _idx=0, int* _on_edge=0 )
+{
+ int i;
+ CvPoint2D32f v = vv[n-1], v0;
+ double min_dist_num = FLT_MAX, min_dist_denom = 1;
+ int min_dist_idx = -1, min_on_edge = 0;
+ int counter = 0;
+ double result;
+
+ for( i = 0; i < n; i++ )
+ {
+ double dx, dy, dx1, dy1, dx2, dy2, dist_num, dist_denom = 1;
+ int on_edge = 0, idx = i;
+
+ v0 = v; v = vv[i];
+ dx = v.x - v0.x; dy = v.y - v0.y;
+ dx1 = pt.x - v0.x; dy1 = pt.y - v0.y;
+ dx2 = pt.x - v.x; dy2 = pt.y - v.y;
+
+ if( dx2*dx + dy2*dy >= 0 )
+ dist_num = dx2*dx2 + dy2*dy2;
+ else if( dx1*dx + dy1*dy <= 0 )
+ {
+ dist_num = dx1*dx1 + dy1*dy1;
+ idx = i - 1;
+ if( idx < 0 ) idx = n-1;
+ }
+ else
+ {
+ dist_num = (dy1*dx - dx1*dy);
+ dist_num *= dist_num;
+ dist_denom = dx*dx + dy*dy;
+ on_edge = 1;
+ }
+
+ if( dist_num*min_dist_denom < min_dist_num*dist_denom )
+ {
+ min_dist_num = dist_num;
+ min_dist_denom = dist_denom;
+ min_dist_idx = idx;
+ min_on_edge = on_edge;
+ if( min_dist_num == 0 )
+ break;
+ }
+
+ if( (v0.y <= pt.y && v.y <= pt.y) ||
+ (v0.y > pt.y && v.y > pt.y) ||
+ (v0.x < pt.x && v.x < pt.x) )
+ continue;
+
+ dist_num = dy1*dx - dx1*dy;
+ if( dy < 0 )
+ dist_num = -dist_num;
+ counter += dist_num > 0;
+ }
+
+ result = sqrt(min_dist_num/min_dist_denom);
+ if( counter % 2 == 0 )
+ result = -result;
+
+ if( _idx )
+ *_idx = min_dist_idx;
+ if( _on_edge )
+ *_on_edge = min_on_edge;
+
+ return result;
+}
+
+
+/****************************************************************************************\
+* Base class for shape descriptor tests *
+\****************************************************************************************/
+
+class CV_BaseShapeDescrTest : public cvtest::BaseTest
+{
+public:
+ CV_BaseShapeDescrTest();
+ virtual ~CV_BaseShapeDescrTest();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ virtual void generate_point_set( void* points );
+ virtual void extract_points();
+
+ int min_log_size;
+ int max_log_size;
+ int dims;
+ bool enable_flt_points;
+
+ CvMemStorage* storage;
+ CvSeq* points1;
+ CvMat* points2;
+ void* points;
+ void* result;
+ double low_high_range;
+ CvScalar low, high;
+
+ bool test_cpp;
+};
+
+
+CV_BaseShapeDescrTest::CV_BaseShapeDescrTest()
+{
+ points1 = 0;
+ points2 = 0;
+ points = 0;
+ storage = 0;
+ test_case_count = 500;
+ min_log_size = 0;
+ max_log_size = 10;
+ low = high = cvScalarAll(0);
+ low_high_range = 50;
+ dims = 2;
+ enable_flt_points = true;
+
+ test_cpp = false;
+}
+
+
+CV_BaseShapeDescrTest::~CV_BaseShapeDescrTest()
+{
+ clear();
+}
+
+
+void CV_BaseShapeDescrTest::clear()
+{
+ cvtest::BaseTest::clear();
+ cvReleaseMemStorage( &storage );
+ cvReleaseMat( &points2 );
+ points1 = 0;
+ points = 0;
+}
+
+
+int CV_BaseShapeDescrTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count );
+ min_log_size = cvReadInt( find_param( fs, "min_log_size" ), min_log_size );
+ max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
+
+ min_log_size = cvtest::clipInt( min_log_size, 0, 8 );
+ max_log_size = cvtest::clipInt( max_log_size, 0, 10 );
+ if( min_log_size > max_log_size )
+ {
+ int t;
+ CV_SWAP( min_log_size, max_log_size, t );
+ }
+
+ return 0;
+}
+
+
+void CV_BaseShapeDescrTest::generate_point_set( void* points )
+{
+ RNG& rng = ts->get_rng();
+ int i, k, n, total, point_type;
+ CvSeqReader reader;
+ uchar* data = 0;
+ double a[4], b[4];
+
+ for( k = 0; k < 4; k++ )
+ {
+ a[k] = high.val[k] - low.val[k];
+ b[k] = low.val[k];
+ }
+ memset( &reader, 0, sizeof(reader) );
+
+ if( CV_IS_SEQ(points) )
+ {
+ CvSeq* ptseq = (CvSeq*)points;
+ total = ptseq->total;
+ point_type = CV_SEQ_ELTYPE(ptseq);
+ cvStartReadSeq( ptseq, &reader );
+ }
+ else
+ {
+ CvMat* ptm = (CvMat*)points;
+ assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
+ total = ptm->rows + ptm->cols - 1;
+ point_type = CV_MAT_TYPE(ptm->type);
+ data = ptm->data.ptr;
+ }
+
+ n = CV_MAT_CN(point_type);
+ point_type = CV_MAT_DEPTH(point_type);
+
+ assert( (point_type == CV_32S || point_type == CV_32F) && n <= 4 );
+
+ for( i = 0; i < total; i++ )
+ {
+ int* pi;
+ float* pf;
+ if( reader.ptr )
+ {
+ pi = (int*)reader.ptr;
+ pf = (float*)reader.ptr;
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+ else
+ {
+ pi = (int*)data + i*n;
+ pf = (float*)data + i*n;
+ }
+ if( point_type == CV_32S )
+ for( k = 0; k < n; k++ )
+ pi[k] = cvRound(cvtest::randReal(rng)*a[k] + b[k]);
+ else
+ for( k = 0; k < n; k++ )
+ pf[k] = (float)(cvtest::randReal(rng)*a[k] + b[k]);
+ }
+}
+
+
+int CV_BaseShapeDescrTest::prepare_test_case( int test_case_idx )
+{
+ int size;
+ int use_storage = 0;
+ int point_type;
+ int i;
+ RNG& rng = ts->get_rng();
+
+ cvtest::BaseTest::prepare_test_case( test_case_idx );
+
+ clear();
+ size = cvRound( exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2) );
+ use_storage = cvtest::randInt(rng) % 2;
+ point_type = CV_MAKETYPE(cvtest::randInt(rng) %
+ (enable_flt_points ? 2 : 1) ? CV_32F : CV_32S, dims);
+
+ if( use_storage )
+ {
+ storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 );
+ points1 = cvCreateSeq( point_type, sizeof(CvSeq), CV_ELEM_SIZE(point_type), storage );
+ cvSeqPushMulti( points1, 0, size );
+ points = points1;
+ }
+ else
+ {
+ int rows = 1, cols = size;
+ if( cvtest::randInt(rng) % 2 )
+ rows = size, cols = 1;
+
+ points2 = cvCreateMat( rows, cols, point_type );
+ points = points2;
+ }
+
+ for( i = 0; i < 4; i++ )
+ {
+ low.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2;
+ high.val[i] = (cvtest::randReal(rng)-0.5)*low_high_range*2;
+ if( low.val[i] > high.val[i] )
+ {
+ double t;
+ CV_SWAP( low.val[i], high.val[i], t );
+ }
+ if( high.val[i] < low.val[i] + 1 )
+ high.val[i] += 1;
+ }
+
+ generate_point_set( points );
+
+ test_cpp = (cvtest::randInt(rng) & 16) == 0;
+ return 1;
+}
+
+
+void CV_BaseShapeDescrTest::extract_points()
+{
+ if( points1 )
+ {
+ points2 = cvCreateMat( 1, points1->total, CV_SEQ_ELTYPE(points1) );
+ cvCvtSeqToArray( points1, points2->data.ptr );
+ }
+
+ if( CV_MAT_DEPTH(points2->type) != CV_32F && enable_flt_points )
+ {
+ CvMat tmp = cvMat( points2->rows, points2->cols,
+ (points2->type & ~CV_MAT_DEPTH_MASK) | CV_32F, points2->data.ptr );
+ cvConvert( points2, &tmp );
+ }
+}
+
+
+void CV_BaseShapeDescrTest::run_func(void)
+{
+}
+
+
+int CV_BaseShapeDescrTest::validate_test_results( int /*test_case_idx*/ )
+{
+ extract_points();
+ return 0;
+}
+
+
+/****************************************************************************************\
+* Convex Hull Test *
+\****************************************************************************************/
+
+class CV_ConvHullTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_ConvHullTest();
+ virtual ~CV_ConvHullTest();
+ void clear();
+
+protected:
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+
+ CvSeq* hull1;
+ CvMat* hull2;
+ void* hull_storage;
+ int orientation;
+ int return_points;
+};
+
+
+CV_ConvHullTest::CV_ConvHullTest()
+{
+ hull1 = 0;
+ hull2 = 0;
+ hull_storage = 0;
+ orientation = return_points = 0;
+}
+
+
+CV_ConvHullTest::~CV_ConvHullTest()
+{
+ clear();
+}
+
+
+void CV_ConvHullTest::clear()
+{
+ CV_BaseShapeDescrTest::clear();
+ cvReleaseMat( &hull2 );
+ hull1 = 0;
+ hull_storage = 0;
+}
+
+
+int CV_ConvHullTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
+ int use_storage_for_hull = 0;
+ RNG& rng = ts->get_rng();
+
+ if( code <= 0 )
+ return code;
+
+ orientation = cvtest::randInt(rng) % 2 ? CV_CLOCKWISE : CV_COUNTER_CLOCKWISE;
+ return_points = cvtest::randInt(rng) % 2;
+
+ use_storage_for_hull = (cvtest::randInt(rng) % 2) && !test_cpp;
+ if( use_storage_for_hull )
+ {
+ if( !storage )
+ storage = cvCreateMemStorage( (cvtest::randInt(rng)%10 + 1)*1024 );
+ hull_storage = storage;
+ }
+ else
+ {
+ int rows, cols;
+ int sz = points1 ? points1->total : points2->cols + points2->rows - 1;
+ int point_type = points1 ? CV_SEQ_ELTYPE(points1) : CV_MAT_TYPE(points2->type);
+
+ if( cvtest::randInt(rng) % 2 )
+ rows = sz, cols = 1;
+ else
+ rows = 1, cols = sz;
+
+ hull2 = cvCreateMat( rows, cols, return_points ? point_type : CV_32SC1 );
+ hull_storage = hull2;
+ }
+
+ return code;
+}
+
+
+void CV_ConvHullTest::run_func()
+{
+ if(!test_cpp)
+ hull1 = cvConvexHull2( points, hull_storage, orientation, return_points );
+ else
+ {
+ cv::Mat _points = cv::cvarrToMat(points);
+ bool clockwise = orientation == CV_CLOCKWISE;
+ size_t n = 0;
+ if( !return_points )
+ {
+ std::vector<int> _hull;
+ cv::convexHull(_points, _hull, clockwise);
+ n = _hull.size();
+ memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
+ }
+ else if(_points.type() == CV_32SC2)
+ {
+ std::vector<cv::Point> _hull;
+ cv::convexHull(_points, _hull, clockwise);
+ n = _hull.size();
+ memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
+ }
+ else if(_points.type() == CV_32FC2)
+ {
+ std::vector<cv::Point2f> _hull;
+ cv::convexHull(_points, _hull, clockwise);
+ n = _hull.size();
+ memcpy(hull2->data.ptr, &_hull[0], n*sizeof(_hull[0]));
+ }
+ if(hull2->rows > hull2->cols)
+ hull2->rows = (int)n;
+ else
+ hull2->cols = (int)n;
+ }
+}
+
+
+int CV_ConvHullTest::validate_test_results( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ CvMat* hull = 0;
+ CvMat* mask = 0;
+ int i, point_count, hull_count;
+ CvPoint2D32f *p, *h;
+ CvSeq header, hheader, *ptseq, *hseq;
+ CvSeqBlock block, hblock;
+
+ if( points1 )
+ ptseq = points1;
+ else
+ ptseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(points2->type),
+ sizeof(CvSeq), CV_ELEM_SIZE(points2->type), points2->data.ptr,
+ points2->rows + points2->cols - 1, &header, &block );
+ point_count = ptseq->total;
+ p = (CvPoint2D32f*)(points2->data.ptr);
+
+ if( hull1 )
+ hseq = hull1;
+ else
+ hseq = cvMakeSeqHeaderForArray( CV_MAT_TYPE(hull2->type),
+ sizeof(CvSeq), CV_ELEM_SIZE(hull2->type), hull2->data.ptr,
+ hull2->rows + hull2->cols - 1, &hheader, &hblock );
+ hull_count = hseq->total;
+ hull = cvCreateMat( 1, hull_count, CV_32FC2 );
+ mask = cvCreateMat( 1, hull_count, CV_8UC1 );
+ cvZero( mask );
+ h = (CvPoint2D32f*)(hull->data.ptr);
+
+ // extract convex hull points
+ if( return_points )
+ {
+ cvCvtSeqToArray( hseq, hull->data.ptr );
+ if( CV_SEQ_ELTYPE(hseq) != CV_32FC2 )
+ {
+ CvMat tmp = cvMat( hull->rows, hull->cols, CV_32SC2, hull->data.ptr );
+ cvConvert( &tmp, hull );
+ }
+ }
+ else
+ {
+ CvSeqReader reader;
+ cvStartReadSeq( hseq, &reader );
+
+ for( i = 0; i < hull_count; i++ )
+ {
+ schar* ptr = reader.ptr;
+ int idx;
+ CV_NEXT_SEQ_ELEM( hseq->elem_size, reader );
+
+ if( hull1 )
+ idx = cvSeqElemIdx( ptseq, *(uchar**)ptr );
+ else
+ idx = *(int*)ptr;
+
+ if( idx < 0 || idx >= point_count )
+ {
+ ts->printf( cvtest::TS::LOG, "Invalid convex hull point #%d\n", i );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ h[i] = p[idx];
+ }
+ }
+
+ // check that the convex hull is a convex polygon
+ if( hull_count >= 3 )
+ {
+ CvPoint2D32f pt0 = h[hull_count-1];
+ for( i = 0; i < hull_count; i++ )
+ {
+ int j = i+1;
+ CvPoint2D32f pt1 = h[i], pt2 = h[j < hull_count ? j : 0];
+ float dx0 = pt1.x - pt0.x, dy0 = pt1.y - pt0.y;
+ float dx1 = pt2.x - pt1.x, dy1 = pt2.y - pt1.y;
+ double t = (double)dx0*dy1 - (double)dx1*dy0;
+ if( (t < 0) ^ (orientation != CV_COUNTER_CLOCKWISE) )
+ {
+ ts->printf( cvtest::TS::LOG, "The convex hull is not convex or has a wrong orientation (vtx %d)\n", i );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ pt0 = pt1;
+ }
+ }
+
+ // check that all the points are inside the hull or on the hull edge
+ // and at least hull_point points are at the hull vertices
+ for( i = 0; i < point_count; i++ )
+ {
+ int idx = 0, on_edge = 0;
+ double result = cvTsPointPolygonTest( p[i], h, hull_count, &idx, &on_edge );
+
+ if( result < 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "The point #%d is outside of the convex hull\n", i );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( result < FLT_EPSILON && !on_edge )
+ mask->data.ptr[idx] = (uchar)1;
+ }
+
+ if( cvNorm( mask, 0, CV_L1 ) != hull_count )
+ {
+ ts->printf( cvtest::TS::LOG, "Not every convex hull vertex coincides with some input point\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ cvReleaseMat( &hull );
+ cvReleaseMat( &mask );
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+/****************************************************************************************\
+* MinAreaRect Test *
+\****************************************************************************************/
+
+class CV_MinAreaRectTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_MinAreaRectTest();
+
+protected:
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+
+ CvBox2D box;
+ CvPoint2D32f box_pt[4];
+};
+
+
+CV_MinAreaRectTest::CV_MinAreaRectTest()
+{
+}
+
+
+void CV_MinAreaRectTest::run_func()
+{
+ if(!test_cpp)
+ {
+ box = cvMinAreaRect2( points, storage );
+ cvBoxPoints( box, box_pt );
+ }
+ else
+ {
+ cv::RotatedRect r = cv::minAreaRect(cv::cvarrToMat(points));
+ box = (CvBox2D)r;
+ r.points((cv::Point2f*)box_pt);
+ }
+}
+
+
+int CV_MinAreaRectTest::validate_test_results( int test_case_idx )
+{
+ double eps = 1e-1;
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ int i, j, point_count = points2->rows + points2->cols - 1;
+ CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr);
+ int mask[] = {0,0,0,0};
+
+ // check that the bounding box is a rotated rectangle:
+ // 1. diagonals should be equal
+ // 2. they must intersect in their middle points
+ {
+ double d0 = cvTsDist( box_pt[0], box_pt[2] );
+ double d1 = cvTsDist( box_pt[1], box_pt[3] );
+
+ double x0 = (box_pt[0].x + box_pt[2].x)*0.5;
+ double y0 = (box_pt[0].y + box_pt[2].y)*0.5;
+ double x1 = (box_pt[1].x + box_pt[3].x)*0.5;
+ double y1 = (box_pt[1].y + box_pt[3].y)*0.5;
+
+ if( fabs(d0 - d1) + fabs(x0 - x1) + fabs(y0 - y1) > eps*MAX(d0,d1) )
+ {
+ ts->printf( cvtest::TS::LOG, "The bounding box is not a rectangle\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ }
+
+#if 0
+ {
+ int n = 4;
+ double a = 8, c = 8, b = 100, d = 150;
+ CvPoint bp[4], *bpp = bp;
+ cvNamedWindow( "test", 1 );
+ IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
+ cvZero(img);
+ for( i = 0; i < point_count; i++ )
+ cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*c+d)), 3, CV_RGB(0,255,0), -1 );
+ for( i = 0; i < n; i++ )
+ bp[i] = cvPoint(cvRound(box_pt[i].x*a+b),cvRound(box_pt[i].y*c+d));
+ cvPolyLine( img, &bpp, &n, 1, 1, CV_RGB(255,255,0), 1, CV_AA, 0 );
+ cvShowImage( "test", img );
+ cvWaitKey();
+ cvReleaseImage(&img);
+ }
+#endif
+
+ // check that the box includes all the points
+ // and there is at least one point at (or very close to) every box side
+ for( i = 0; i < point_count; i++ )
+ {
+ int idx = 0, on_edge = 0;
+ double result = cvTsPointPolygonTest( p[i], box_pt, 4, &idx, &on_edge );
+ if( result < -eps )
+ {
+ ts->printf( cvtest::TS::LOG, "The point #%d is outside of the box\n", i );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( result < eps )
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ double d = cvTsPtLineDist( p[i], box_pt[(j-1)&3], box_pt[j] );
+ if( d < eps )
+ mask[j] = (uchar)1;
+ }
+ }
+ }
+
+ if( mask[0] + mask[1] + mask[2] + mask[3] != 4 )
+ {
+ ts->printf( cvtest::TS::LOG, "Not every box side has a point nearby\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+/****************************************************************************************\
+* MinEnclosingCircle Test *
+\****************************************************************************************/
+
+class CV_MinCircleTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_MinCircleTest();
+
+protected:
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+
+ CvPoint2D32f center;
+ float radius;
+};
+
+
+CV_MinCircleTest::CV_MinCircleTest()
+{
+}
+
+
+void CV_MinCircleTest::run_func()
+{
+ if(!test_cpp)
+ cvMinEnclosingCircle( points, ¢er, &radius );
+ else
+ cv::minEnclosingCircle(cv::cvarrToMat(points), (cv::Point2f&)center, radius);
+}
+
+
+int CV_MinCircleTest::validate_test_results( int test_case_idx )
+{
+ double eps = 1.03;
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ int i, j = 0, point_count = points2->rows + points2->cols - 1;
+ CvPoint2D32f *p = (CvPoint2D32f*)(points2->data.ptr);
+ CvPoint2D32f v[3];
+
+#if 0
+ {
+ double a = 2, b = 200, d = 400;
+ cvNamedWindow( "test", 1 );
+ IplImage* img = cvCreateImage( cvSize(500,500), 8, 3 );
+ cvZero(img);
+ for( i = 0; i < point_count; i++ )
+ cvCircle(img,cvPoint(cvRound(p[i].x*a+b),cvRound(p[i].y*a+d)), 3, CV_RGB(0,255,0), -1 );
+ cvCircle( img, cvPoint(cvRound(center.x*a+b),cvRound(center.y*a+d)),
+ cvRound(radius*a), CV_RGB(255,255,0), 1 );
+ cvShowImage( "test", img );
+ cvWaitKey();
+ cvReleaseImage(&img);
+ }
+#endif
+
+ // check that the circle contains all the points inside and
+ // remember at most 3 points that are close to the boundary
+ for( i = 0; i < point_count; i++ )
+ {
+ double d = cvTsDist( p[i], center );
+ if( d > radius )
+ {
+ ts->printf( cvtest::TS::LOG, "The point #%d is outside of the circle\n", i );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( radius - d < eps*radius && j < 3 )
+ v[j++] = p[i];
+ }
+
+ if( point_count >= 2 && (j < 2 || (j == 2 && cvTsDist(v[0],v[1]) < (radius-1)*2/eps)) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "There should be at at least 3 points near the circle boundary or 2 points on the diameter\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+/****************************************************************************************\
+* Perimeter Test *
+\****************************************************************************************/
+
+class CV_PerimeterTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_PerimeterTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ CvSlice slice;
+ int is_closed;
+ double result;
+};
+
+
+CV_PerimeterTest::CV_PerimeterTest()
+{
+}
+
+
+int CV_PerimeterTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
+ RNG& rng = ts->get_rng();
+ int total;
+
+ if( code < 0 )
+ return code;
+
+ is_closed = cvtest::randInt(rng) % 2;
+
+ if( points1 )
+ {
+ points1->flags |= CV_SEQ_KIND_CURVE;
+ if( is_closed )
+ points1->flags |= CV_SEQ_FLAG_CLOSED;
+ total = points1->total;
+ }
+ else
+ total = points2->cols + points2->rows - 1;
+
+ if( (cvtest::randInt(rng) % 3) && !test_cpp )
+ {
+ slice.start_index = cvtest::randInt(rng) % total;
+ slice.end_index = cvtest::randInt(rng) % total;
+ }
+ else
+ slice = CV_WHOLE_SEQ;
+
+ return 1;
+}
+
+
+void CV_PerimeterTest::run_func()
+{
+ if(!test_cpp)
+ result = cvArcLength( points, slice, points1 ? -1 : is_closed );
+ else
+ result = cv::arcLength(cv::cvarrToMat(points),
+ !points1 ? is_closed != 0 : (points1->flags & CV_SEQ_FLAG_CLOSED) != 0);
+}
+
+
+int CV_PerimeterTest::validate_test_results( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ int i, len = slice.end_index - slice.start_index, total = points2->cols + points2->rows - 1;
+ double result0 = 0;
+ CvPoint2D32f prev_pt, pt, *ptr;
+
+ if( len < 0 )
+ len += total;
+
+ len = MIN( len, total );
+ len -= !is_closed && len == total;
+
+ ptr = (CvPoint2D32f*)points2->data.fl;
+ prev_pt = ptr[slice.start_index % total];
+
+ for( i = 1; i <= len; i++ )
+ {
+ pt = ptr[(i + slice.start_index) % total];
+ double dx = pt.x - prev_pt.x, dy = pt.y - prev_pt.y;
+ result0 += sqrt(dx*dx + dy*dy);
+ prev_pt = pt;
+ }
+
+ if( cvIsNaN(result) || cvIsInf(result) )
+ {
+ ts->printf( cvtest::TS::LOG, "cvArcLength() returned invalid value (%g)\n", result );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ else if( fabs(result - result0) > FLT_EPSILON*100*result0 )
+ {
+ ts->printf( cvtest::TS::LOG, "The function returned %g, while the correct result is %g\n", result, result0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+/****************************************************************************************\
+* FitEllipse Test *
+\****************************************************************************************/
+
+class CV_FitEllipseTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_FitEllipseTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void generate_point_set( void* points );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ CvBox2D box0, box;
+ double min_ellipse_size, max_noise;
+};
+
+
+CV_FitEllipseTest::CV_FitEllipseTest()
+{
+ min_log_size = 5; // for robust ellipse fitting a dozen of points is needed at least
+ max_log_size = 10;
+ min_ellipse_size = 10;
+ max_noise = 0.05;
+}
+
+
+void CV_FitEllipseTest::generate_point_set( void* points )
+{
+ RNG& rng = ts->get_rng();
+ int i, total, point_type;
+ CvSeqReader reader;
+ uchar* data = 0;
+ double a, b;
+
+ box0.center.x = (float)((low.val[0] + high.val[0])*0.5);
+ box0.center.y = (float)((low.val[1] + high.val[1])*0.5);
+ box0.size.width = (float)(MAX(high.val[0] - low.val[0], min_ellipse_size)*2);
+ box0.size.height = (float)(MAX(high.val[1] - low.val[1], min_ellipse_size)*2);
+ box0.angle = (float)(cvtest::randReal(rng)*180);
+ a = cos(box0.angle*CV_PI/180.);
+ b = sin(box0.angle*CV_PI/180.);
+
+ if( box0.size.width > box0.size.height )
+ {
+ float t;
+ CV_SWAP( box0.size.width, box0.size.height, t );
+ }
+ memset( &reader, 0, sizeof(reader) );
+
+ if( CV_IS_SEQ(points) )
+ {
+ CvSeq* ptseq = (CvSeq*)points;
+ total = ptseq->total;
+ point_type = CV_SEQ_ELTYPE(ptseq);
+ cvStartReadSeq( ptseq, &reader );
+ }
+ else
+ {
+ CvMat* ptm = (CvMat*)points;
+ assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
+ total = ptm->rows + ptm->cols - 1;
+ point_type = CV_MAT_TYPE(ptm->type);
+ data = ptm->data.ptr;
+ }
+
+ assert( point_type == CV_32SC2 || point_type == CV_32FC2 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvPoint* pp;
+ CvPoint2D32f p;
+ double angle = cvtest::randReal(rng)*CV_PI*2;
+ double x = box0.size.height*0.5*(cos(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise);
+ double y = box0.size.width*0.5*(sin(angle) + (cvtest::randReal(rng)-0.5)*2*max_noise);
+ p.x = (float)(box0.center.x + a*x + b*y);
+ p.y = (float)(box0.center.y - b*x + a*y);
+
+ if( reader.ptr )
+ {
+ pp = (CvPoint*)reader.ptr;
+ CV_NEXT_SEQ_ELEM( sizeof(*pp), reader );
+ }
+ else
+ pp = ((CvPoint*)data) + i;
+ if( point_type == CV_32SC2 )
+ {
+ pp->x = cvRound(p.x);
+ pp->y = cvRound(p.y);
+ }
+ else
+ *(CvPoint2D32f*)pp = p;
+ }
+}
+
+
+int CV_FitEllipseTest::prepare_test_case( int test_case_idx )
+{
+ min_log_size = MAX(min_log_size,4);
+ max_log_size = MAX(min_log_size,max_log_size);
+ return CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
+}
+
+
+void CV_FitEllipseTest::run_func()
+{
+ if(!test_cpp)
+ box = cvFitEllipse2( points );
+ else
+ box = (CvBox2D)cv::fitEllipse(cv::cvarrToMat(points));
+}
+
+
+int CV_FitEllipseTest::validate_test_results( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ double diff_angle;
+
+ if( cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
+ cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
+ cvIsNaN(box.size.width) || cvIsInf(box.size.width) ||
+ cvIsNaN(box.size.height) || cvIsInf(box.size.height) ||
+ cvIsNaN(box.angle) || cvIsInf(box.angle) )
+ {
+ ts->printf( cvtest::TS::LOG, "Some of the computed ellipse parameters are invalid (x=%g,y=%g,w=%g,h=%g,angle=%g)\n",
+ box.center.x, box.center.y, box.size.width, box.size.height, box.angle );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ box.angle = (float)(90-box.angle);
+ if( box.angle < 0 )
+ box.angle += 360;
+ if( box.angle > 360 )
+ box.angle -= 360;
+
+ if( fabs(box.center.x - box0.center.x) > 3 ||
+ fabs(box.center.y - box0.center.y) > 3 ||
+ fabs(box.size.width - box0.size.width) > 0.1*fabs(box0.size.width) ||
+ fabs(box.size.height - box0.size.height) > 0.1*fabs(box0.size.height) )
+ {
+ ts->printf( cvtest::TS::LOG, "The computed ellipse center and/or size are incorrect:\n\t"
+ "(x=%.1f,y=%.1f,w=%.1f,h=%.1f), while it should be (x=%.1f,y=%.1f,w=%.1f,h=%.1f)\n",
+ box.center.x, box.center.y, box.size.width, box.size.height,
+ box0.center.x, box0.center.y, box0.size.width, box0.size.height );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ diff_angle = fabs(box0.angle - box.angle);
+ diff_angle = MIN( diff_angle, fabs(diff_angle - 360));
+ diff_angle = MIN( diff_angle, fabs(diff_angle - 180));
+
+ if( box0.size.height >= 1.3*box0.size.width && diff_angle > 30 )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect ellipse angle (=%1.f, should be %1.f)\n",
+ box.angle, box0.angle );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+#if 0
+ cvNamedWindow( "test", 0 );
+ IplImage* img = cvCreateImage( cvSize(cvRound(low_high_range*4),
+ cvRound(low_high_range*4)), 8, 3 );
+ cvZero( img );
+
+ box.center.x += (float)low_high_range*2;
+ box.center.y += (float)low_high_range*2;
+ cvEllipseBox( img, box, CV_RGB(255,0,0), 3, 8 );
+
+ for( int i = 0; i < points2->rows + points2->cols - 1; i++ )
+ {
+ CvPoint pt;
+ pt.x = cvRound(points2->data.fl[i*2] + low_high_range*2);
+ pt.y = cvRound(points2->data.fl[i*2+1] + low_high_range*2);
+ cvCircle( img, pt, 1, CV_RGB(255,255,255), -1, 8 );
+ }
+
+ cvShowImage( "test", img );
+ cvReleaseImage( &img );
+ cvWaitKey(0);
+#endif
+
+ if( code < 0 )
+ {
+ ts->set_failed_test_info( code );
+ }
+ return code;
+}
+
+
+/****************************************************************************************\
+* FitLine Test *
+\****************************************************************************************/
+
+class CV_FitLineTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_FitLineTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void generate_point_set( void* points );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ double max_noise;
+ float line[6], line0[6];
+ int dist_type;
+ double reps, aeps;
+};
+
+
+CV_FitLineTest::CV_FitLineTest()
+{
+ min_log_size = 5; // for robust ellipse fitting a dozen of points is needed at least
+ max_log_size = 10;
+ max_noise = 0.05;
+}
+
+
+void CV_FitLineTest::generate_point_set( void* points )
+{
+ RNG& rng = ts->get_rng();
+ int i, k, n, total, point_type;
+ CvSeqReader reader;
+ uchar* data = 0;
+ double s = 0;
+
+ n = dims;
+ for( k = 0; k < n; k++ )
+ {
+ line0[k+n] = (float)((low.val[k] + high.val[k])*0.5);
+ line0[k] = (float)(high.val[k] - low.val[k]);
+ if( cvtest::randInt(rng) % 2 )
+ line0[k] = -line0[k];
+ s += (double)line0[k]*line0[k];
+ }
+
+ s = 1./sqrt(s);
+ for( k = 0; k < n; k++ )
+ line0[k] = (float)(line0[k]*s);
+
+ memset( &reader, 0, sizeof(reader) );
+
+ if( CV_IS_SEQ(points) )
+ {
+ CvSeq* ptseq = (CvSeq*)points;
+ total = ptseq->total;
+ point_type = CV_MAT_DEPTH(CV_SEQ_ELTYPE(ptseq));
+ cvStartReadSeq( ptseq, &reader );
+ }
+ else
+ {
+ CvMat* ptm = (CvMat*)points;
+ assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
+ total = ptm->rows + ptm->cols - 1;
+ point_type = CV_MAT_DEPTH(CV_MAT_TYPE(ptm->type));
+ data = ptm->data.ptr;
+ }
+
+ for( i = 0; i < total; i++ )
+ {
+ int* pi;
+ float* pf;
+ float p[4], t;
+ if( reader.ptr )
+ {
+ pi = (int*)reader.ptr;
+ pf = (float*)reader.ptr;
+ CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
+ }
+ else
+ {
+ pi = (int*)data + i*n;
+ pf = (float*)data + i*n;
+ }
+
+ t = (float)((cvtest::randReal(rng)-0.5)*low_high_range*2);
+
+ for( k = 0; k < n; k++ )
+ p[k] = (float)((cvtest::randReal(rng)-0.5)*max_noise*2 + t*line0[k] + line0[k+n]);
+
+ if( point_type == CV_32S )
+ for( k = 0; k < n; k++ )
+ pi[k] = cvRound(p[k]);
+ else
+ for( k = 0; k < n; k++ )
+ pf[k] = p[k];
+ }
+}
+
+
+int CV_FitLineTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ dims = cvtest::randInt(rng) % 2 + 2;
+ min_log_size = MAX(min_log_size,5);
+ max_log_size = MAX(min_log_size,max_log_size);
+ int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
+ dist_type = cvtest::randInt(rng) % 6 + 1;
+ dist_type += dist_type == CV_DIST_C;
+ reps = 0.1; aeps = 0.01;
+ return code;
+}
+
+
+void CV_FitLineTest::run_func()
+{
+ if(!test_cpp)
+ cvFitLine( points, dist_type, 0, reps, aeps, line );
+ else if(dims == 2)
+ cv::fitLine(cv::cvarrToMat(points), (cv::Vec4f&)line[0], dist_type, 0, reps, aeps);
+ else
+ cv::fitLine(cv::cvarrToMat(points), (cv::Vec6f&)line[0], dist_type, 0, reps, aeps);
+}
+
+
+int CV_FitLineTest::validate_test_results( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ int k, max_k = 0;
+ double vec_diff = 0, t;
+
+ for( k = 0; k < dims*2; k++ )
+ {
+ if( cvIsNaN(line[k]) || cvIsInf(line[k]) )
+ {
+ ts->printf( cvtest::TS::LOG, "Some of the computed line parameters are invalid (line[%d]=%g)\n",
+ k, line[k] );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ }
+
+ if( fabs(line0[1]) > fabs(line0[0]) )
+ max_k = 1;
+ if( fabs(line0[dims-1]) > fabs(line0[max_k]) )
+ max_k = dims-1;
+ if( line0[max_k] < 0 )
+ for( k = 0; k < dims; k++ )
+ line0[k] = -line0[k];
+ if( line[max_k] < 0 )
+ for( k = 0; k < dims; k++ )
+ line[k] = -line[k];
+
+ for( k = 0; k < dims; k++ )
+ {
+ double dt = line[k] - line0[k];
+ vec_diff += dt*dt;
+ }
+
+ if( sqrt(vec_diff) > 0.05 )
+ {
+ if( dims == 2 )
+ ts->printf( cvtest::TS::LOG,
+ "The computed line vector (%.2f,%.2f) is different from the actual (%.2f,%.2f)\n",
+ line[0], line[1], line0[0], line0[1] );
+ else
+ ts->printf( cvtest::TS::LOG,
+ "The computed line vector (%.2f,%.2f,%.2f) is different from the actual (%.2f,%.2f,%.2f)\n",
+ line[0], line[1], line[2], line0[0], line0[1], line0[2] );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ t = (line[max_k+dims] - line0[max_k+dims])/line0[max_k];
+ for( k = 0; k < dims; k++ )
+ {
+ double p = line0[k+dims] + t*line0[k] - line[k+dims];
+ vec_diff += p*p;
+ }
+
+ if( sqrt(vec_diff) > 1*MAX(fabs(t),1) )
+ {
+ if( dims == 2 )
+ ts->printf( cvtest::TS::LOG,
+ "The computed line point (%.2f,%.2f) is too far from the actual line\n",
+ line[2]+line0[2], line[3]+line0[3] );
+ else
+ ts->printf( cvtest::TS::LOG,
+ "The computed line point (%.2f,%.2f,%.2f) is too far from the actual line\n",
+ line[3]+line0[3], line[4]+line0[4], line[5]+line0[5] );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ if( code < 0 )
+ {
+ ts->set_failed_test_info( code );
+ }
+ return code;
+}
+
+
+/****************************************************************************************\
+* ContourMoments Test *
+\****************************************************************************************/
+
+
+static void
+cvTsGenerateTousledBlob( CvPoint2D32f center, CvSize2D32f axes,
+ double max_r_scale, double angle, CvArr* points, RNG& rng )
+{
+ int i, total, point_type;
+ uchar* data = 0;
+ CvSeqReader reader;
+ memset( &reader, 0, sizeof(reader) );
+
+ if( CV_IS_SEQ(points) )
+ {
+ CvSeq* ptseq = (CvSeq*)points;
+ total = ptseq->total;
+ point_type = CV_SEQ_ELTYPE(ptseq);
+ cvStartReadSeq( ptseq, &reader );
+ }
+ else
+ {
+ CvMat* ptm = (CvMat*)points;
+ assert( CV_IS_MAT(ptm) && CV_IS_MAT_CONT(ptm->type) );
+ total = ptm->rows + ptm->cols - 1;
+ point_type = CV_MAT_TYPE(ptm->type);
+ data = ptm->data.ptr;
+ }
+
+ assert( point_type == CV_32SC2 || point_type == CV_32FC2 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvPoint* pp;
+ CvPoint2D32f p;
+
+ double phi0 = 2*CV_PI*i/total;
+ double phi = CV_PI*angle/180.;
+ double t = cvtest::randReal(rng)*max_r_scale + (1 - max_r_scale);
+ double ta = axes.height*t;
+ double tb = axes.width*t;
+ double c0 = cos(phi0)*ta, s0 = sin(phi0)*tb;
+ double c = cos(phi), s = sin(phi);
+ p.x = (float)(c0*c - s0*s + center.x);
+ p.y = (float)(c0*s + s0*c + center.y);
+
+ if( reader.ptr )
+ {
+ pp = (CvPoint*)reader.ptr;
+ CV_NEXT_SEQ_ELEM( sizeof(*pp), reader );
+ }
+ else
+ pp = ((CvPoint*)data) + i;
+
+ if( point_type == CV_32SC2 )
+ {
+ pp->x = cvRound(p.x);
+ pp->y = cvRound(p.y);
+ }
+ else
+ *(CvPoint2D32f*)pp = p;
+ }
+}
+
+
+class CV_ContourMomentsTest : public CV_BaseShapeDescrTest
+{
+public:
+ CV_ContourMomentsTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void generate_point_set( void* points );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ CvMoments moments0, moments;
+ double area0, area;
+ CvSize2D32f axes;
+ CvPoint2D32f center;
+ int max_max_r_scale;
+ double max_r_scale, angle;
+ CvSize img_size;
+};
+
+
+CV_ContourMomentsTest::CV_ContourMomentsTest()
+{
+ min_log_size = 3;
+ max_log_size = 8;
+ max_max_r_scale = 15;
+ low_high_range = 200;
+ enable_flt_points = false;
+}
+
+
+void CV_ContourMomentsTest::generate_point_set( void* points )
+{
+ RNG& rng = ts->get_rng();
+ float max_sz;
+
+ axes.width = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range);
+ axes.height = (float)((cvtest::randReal(rng)*0.9 + 0.1)*low_high_range);
+ max_sz = MAX(axes.width, axes.height);
+
+ img_size.width = img_size.height = cvRound(low_high_range*2.2);
+
+ center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - max_sz*2)*0.8);
+ center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - max_sz*2)*0.8);
+
+ assert( 0 < center.x - max_sz && center.x + max_sz < img_size.width &&
+ 0 < center.y - max_sz && center.y + max_sz < img_size.height );
+
+ max_r_scale = cvtest::randReal(rng)*max_max_r_scale*0.01;
+ angle = cvtest::randReal(rng)*360;
+
+ cvTsGenerateTousledBlob( center, axes, max_r_scale, angle, points, rng );
+
+ if( points1 )
+ points1->flags = CV_SEQ_MAGIC_VAL + CV_SEQ_POLYGON;
+}
+
+
+int CV_ContourMomentsTest::prepare_test_case( int test_case_idx )
+{
+ min_log_size = MAX(min_log_size,3);
+ max_log_size = MIN(max_log_size,8);
+ max_log_size = MAX(min_log_size,max_log_size);
+ int code = CV_BaseShapeDescrTest::prepare_test_case( test_case_idx );
+ return code;
+}
+
+
+void CV_ContourMomentsTest::run_func()
+{
+ if(!test_cpp)
+ {
+ cvMoments( points, &moments );
+ area = cvContourArea( points );
+ }
+ else
+ {
+ moments = (CvMoments)cv::moments(cv::cvarrToMat(points));
+ area = cv::contourArea(cv::cvarrToMat(points));
+ }
+}
+
+
+int CV_ContourMomentsTest::validate_test_results( int test_case_idx )
+{
+ int code = CV_BaseShapeDescrTest::validate_test_results( test_case_idx );
+ int i, n = (int)(sizeof(moments)/sizeof(moments.inv_sqrt_m00));
+ CvMat* img = cvCreateMat( img_size.height, img_size.width, CV_8UC1 );
+ CvPoint* pt = (CvPoint*)points2->data.i;
+ int count = points2->cols + points2->rows - 1;
+ double max_v0 = 0;
+
+ cvZero(img);
+ cvFillPoly( img, &pt, &count, 1, cvScalarAll(1));
+ cvMoments( img, &moments0 );
+
+ for( i = 0; i < n; i++ )
+ {
+ double t = fabs((&moments0.m00)[i]);
+ max_v0 = MAX(max_v0, t);
+ }
+
+ for( i = 0; i <= n; i++ )
+ {
+ double v = i < n ? (&moments.m00)[i] : area;
+ double v0 = i < n ? (&moments0.m00)[i] : moments0.m00;
+
+ if( cvIsNaN(v) || cvIsInf(v) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The contour %s is invalid (=%g)\n", i < n ? "moment" : "area", v );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+
+ if( fabs(v - v0) > 0.1*max_v0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The computed contour %s is %g, while it should be %g\n",
+ i < n ? "moment" : "area", v, v0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ break;
+ }
+ }
+
+ if( code < 0 )
+ {
+#if 0
+ cvCmpS( img, 0, img, CV_CMP_GT );
+ cvNamedWindow( "test", 1 );
+ cvShowImage( "test", img );
+ cvWaitKey();
+#endif
+ ts->set_failed_test_info( code );
+ }
+
+ cvReleaseMat( &img );
+ return code;
+}
+
+
+TEST(Imgproc_ConvexHull, accuracy) { CV_ConvHullTest test; test.safe_run(); }
+TEST(Imgproc_MinAreaRect, accuracy) { CV_MinAreaRectTest test; test.safe_run(); }
+TEST(Imgproc_MinCircle, accuracy) { CV_MinCircleTest test; test.safe_run(); }
+TEST(Imgproc_ContourPerimeter, accuracy) { CV_PerimeterTest test; test.safe_run(); }
+TEST(Imgproc_FitEllipse, accuracy) { CV_FitEllipseTest test; test.safe_run(); }
+TEST(Imgproc_FitLine, accuracy) { CV_FitLineTest test; test.safe_run(); }
+TEST(Imgproc_ContourMoments, accuracy) { CV_ContourMomentsTest test; test.safe_run(); }
+
+/* End of file. */
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_DisTransTest : public cvtest::ArrayTest
+{
+public:
+ CV_DisTransTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+
+ int mask_size;
+ int dist_type;
+ int fill_labels;
+ float mask[3];
+};
+
+
+CV_DisTransTest::CV_DisTransTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ optional_mask = false;
+ element_wise_relative_error = true;
+}
+
+
+void CV_DisTransTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ types[INPUT][0] = CV_8UC1;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
+ types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32SC1;
+
+ if( cvtest::randInt(rng) & 1 )
+ {
+ mask_size = 3;
+ dist_type = cvtest::randInt(rng) % 4;
+ dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 :
+ dist_type == 2 ? CV_DIST_L2 : CV_DIST_USER;
+ }
+ else
+ {
+ mask_size = 5;
+ dist_type = cvtest::randInt(rng) % 10;
+ dist_type = dist_type == 0 ? CV_DIST_C : dist_type == 1 ? CV_DIST_L1 :
+ dist_type < 6 ? CV_DIST_L2 : CV_DIST_USER;
+ }
+
+ // for now, check only the "labeled" distance transform mode
+ fill_labels = 0;
+
+ if( !fill_labels )
+ sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = cvSize(0,0);
+
+ if( dist_type == CV_DIST_USER )
+ {
+ mask[0] = (float)(1.1 - cvtest::randReal(rng)*0.2);
+ mask[1] = (float)(1.9 - cvtest::randReal(rng)*0.8);
+ mask[2] = (float)(3. - cvtest::randReal(rng));
+ }
+}
+
+
+double CV_DisTransTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ Size sz = test_mat[INPUT][0].size();
+ return dist_type == CV_DIST_C || dist_type == CV_DIST_L1 ? 0 : 0.01*MAX(sz.width, sz.height);
+}
+
+
+void CV_DisTransTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )
+ {
+ low = Scalar::all(0);
+ high = Scalar::all(10);
+ }
+}
+
+int CV_DisTransTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ // the function's response to an "all-nonzeros" image is not determined,
+ // so put at least one zero point
+ Mat& mat = test_mat[INPUT][0];
+ RNG& rng = ts->get_rng();
+ int i = cvtest::randInt(rng) % mat.rows;
+ int j = cvtest::randInt(rng) % mat.cols;
+ mat.at<uchar>(i,j) = 0;
+ }
+
+ return code;
+}
+
+
+void CV_DisTransTest::run_func()
+{
+ cvDistTransform( test_array[INPUT][0], test_array[OUTPUT][0], dist_type, mask_size,
+ dist_type == CV_DIST_USER ? mask : 0, test_array[OUTPUT][1] );
+}
+
+
+static void
+cvTsDistTransform( const CvMat* _src, CvMat* _dst, int dist_type,
+ int mask_size, float* _mask, CvMat* /*_labels*/ )
+{
+ int i, j, k;
+ int width = _src->cols, height = _src->rows;
+ const float init_val = 1e6;
+ float mask[3];
+ CvMat* temp;
+ int ofs[16];
+ float delta[16];
+ int tstep, count;
+
+ assert( mask_size == 3 || mask_size == 5 );
+
+ if( dist_type == CV_DIST_USER )
+ memcpy( mask, _mask, sizeof(mask) );
+ else if( dist_type == CV_DIST_C )
+ {
+ mask_size = 3;
+ mask[0] = mask[1] = 1.f;
+ }
+ else if( dist_type == CV_DIST_L1 )
+ {
+ mask_size = 3;
+ mask[0] = 1.f;
+ mask[1] = 2.f;
+ }
+ else if( mask_size == 3 )
+ {
+ mask[0] = 0.955f;
+ mask[1] = 1.3693f;
+ }
+ else
+ {
+ mask[0] = 1.0f;
+ mask[1] = 1.4f;
+ mask[2] = 2.1969f;
+ }
+
+ temp = cvCreateMat( height + mask_size-1, width + mask_size-1, CV_32F );
+ tstep = temp->step / sizeof(float);
+
+ if( mask_size == 3 )
+ {
+ count = 4;
+ ofs[0] = -1; delta[0] = mask[0];
+ ofs[1] = -tstep-1; delta[1] = mask[1];
+ ofs[2] = -tstep; delta[2] = mask[0];
+ ofs[3] = -tstep+1; delta[3] = mask[1];
+ }
+ else
+ {
+ count = 8;
+ ofs[0] = -1; delta[0] = mask[0];
+ ofs[1] = -tstep-2; delta[1] = mask[2];
+ ofs[2] = -tstep-1; delta[2] = mask[1];
+ ofs[3] = -tstep; delta[3] = mask[0];
+ ofs[4] = -tstep+1; delta[4] = mask[1];
+ ofs[5] = -tstep+2; delta[5] = mask[2];
+ ofs[6] = -tstep*2-1; delta[6] = mask[2];
+ ofs[7] = -tstep*2+1; delta[7] = mask[2];
+ }
+
+ for( i = 0; i < mask_size/2; i++ )
+ {
+ float* t0 = (float*)(temp->data.ptr + i*temp->step);
+ float* t1 = (float*)(temp->data.ptr + (temp->rows - i - 1)*temp->step);
+
+ for( j = 0; j < width + mask_size - 1; j++ )
+ t0[j] = t1[j] = init_val;
+ }
+
+ for( i = 0; i < height; i++ )
+ {
+ uchar* s = _src->data.ptr + i*_src->step;
+ float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);
+
+ for( j = 0; j < mask_size/2; j++ )
+ tmp[-j-1] = tmp[j + width] = init_val;
+
+ for( j = 0; j < width; j++ )
+ {
+ if( s[j] == 0 )
+ tmp[j] = 0;
+ else
+ {
+ float min_dist = init_val;
+ for( k = 0; k < count; k++ )
+ {
+ float t = tmp[j+ofs[k]] + delta[k];
+ if( min_dist > t )
+ min_dist = t;
+ }
+ tmp[j] = min_dist;
+ }
+ }
+ }
+
+ for( i = height - 1; i >= 0; i-- )
+ {
+ float* d = (float*)(_dst->data.ptr + i*_dst->step);
+ float* tmp = (float*)(temp->data.ptr + temp->step*(i + (mask_size/2))) + (mask_size/2);
+
+ for( j = width - 1; j >= 0; j-- )
+ {
+ float min_dist = tmp[j];
+ if( min_dist > mask[0] )
+ {
+ for( k = 0; k < count; k++ )
+ {
+ float t = tmp[j-ofs[k]] + delta[k];
+ if( min_dist > t )
+ min_dist = t;
+ }
+ tmp[j] = min_dist;
+ }
+ d[j] = min_dist;
+ }
+ }
+
+ cvReleaseMat( &temp );
+}
+
+
+void CV_DisTransTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ CvMat _input = test_mat[INPUT][0], _output = test_mat[REF_OUTPUT][0];
+
+ cvTsDistTransform( &_input, &_output, dist_type, mask_size, mask, 0 );
+}
+
+
+TEST(Imgproc_DistanceTransform, accuracy) { CV_DisTransTest test; test.safe_run(); }
+
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+/*////////////////////// emd_test /////////////////////////*/
+
+class CV_EMDTest : public cvtest::BaseTest
+{
+public:
+ CV_EMDTest();
+protected:
+ void run(int);
+};
+
+
+CV_EMDTest::CV_EMDTest()
+{
+}
+
+void CV_EMDTest::run( int )
+{
+ int code = cvtest::TS::OK;
+ const double success_error_level = 1e-6;
+ #define M 10000
+ double emd0 = 2460./210;
+ static float cost[] =
+ {
+ 16, 16, 13, 22, 17,
+ 14, 14, 13, 19, 15,
+ 19, 19, 20, 23, M,
+ M , 0, M, 0, 0
+ };
+ static float w1[] = { 50, 60, 50, 50 },
+ w2[] = { 30, 20, 70, 30, 60 };
+ Mat _w1(4, 1, CV_32F, w1);
+ Mat _w2(5, 1, CV_32F, w2);
+ Mat _cost(_w1.rows, _w2.rows, CV_32F, cost);
+
+ float emd = EMD( _w1, _w2, -1, _cost );
+ if( fabs( emd - emd0 ) > success_error_level*emd0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The computed distance is %.2f, while it should be %.2f\n", emd, emd0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Imgproc_EMD, regression) { CV_EMDTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_FilterBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_FilterBaseTest( bool _fp_kernel );
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ int read_params( CvFileStorage* fs );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ CvSize aperture_size;
+ CvPoint anchor;
+ int max_aperture_size;
+ bool fp_kernel;
+ bool inplace;
+ int border;
+};
+
+
+CV_FilterBaseTest::CV_FilterBaseTest( bool _fp_kernel ) : fp_kernel(_fp_kernel)
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ max_aperture_size = 13;
+ inplace = false;
+ aperture_size = cvSize(0,0);
+ anchor = cvPoint(0,0);
+ element_wise_relative_error = false;
+}
+
+
+int CV_FilterBaseTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
+ max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 100 );
+
+ return code;
+}
+
+
+void CV_FilterBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT )
+ {
+ if( j == 1 )
+ {
+ if( fp_kernel )
+ {
+ RNG& rng = ts->get_rng();
+ double val = exp( cvtest::randReal(rng)*10 - 4 );
+ low = Scalar::all(-val);
+ high = Scalar::all(val);
+ }
+ else
+ {
+ low = Scalar::all(0);
+ high = Scalar::all(2);
+ }
+ }
+ else if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ low = Scalar::all(-10.);
+ high = Scalar::all(10.);
+ }
+ }
+}
+
+
+void CV_FilterBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % CV_32F;
+ int cn = cvtest::randInt(rng) % 3 + 1;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth += depth == CV_8S;
+ cn += cn == 2;
+
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+
+ aperture_size.width = cvtest::randInt(rng) % max_aperture_size + 1;
+ aperture_size.height = cvtest::randInt(rng) % max_aperture_size + 1;
+ anchor.x = cvtest::randInt(rng) % aperture_size.width;
+ anchor.y = cvtest::randInt(rng) % aperture_size.height;
+
+ types[INPUT][1] = fp_kernel ? CV_32FC1 : CV_8UC1;
+ sizes[INPUT][1] = aperture_size;
+
+ inplace = cvtest::randInt(rng) % 2 != 0;
+ border = BORDER_REPLICATE;
+}
+
+
+int CV_FilterBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ if( inplace && test_mat[INPUT][0].type() == test_mat[OUTPUT][0].type())
+ cvtest::copy( test_mat[INPUT][0], test_mat[OUTPUT][0] );
+ else
+ inplace = false;
+ }
+ return code;
+}
+
+
+/////////////////////////
+
+class CV_MorphologyBaseTest : public CV_FilterBaseTest
+{
+public:
+ CV_MorphologyBaseTest();
+
+protected:
+ void prepare_to_validation( int test_case_idx );
+ int prepare_test_case( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int optype, optype_min, optype_max;
+ int shape;
+ IplConvKernel* element;
+};
+
+
+CV_MorphologyBaseTest::CV_MorphologyBaseTest() : CV_FilterBaseTest( false )
+{
+ shape = -1;
+ element = 0;
+ optype = optype_min = optype_max = -1;
+}
+
+
+void CV_MorphologyBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = cvtest::randInt(rng) % 4;
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F;
+ int cn = CV_MAT_CN(types[INPUT][0]);
+
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+ shape = cvtest::randInt(rng) % 4;
+ if( shape >= 3 )
+ shape = CV_SHAPE_CUSTOM;
+ else
+ sizes[INPUT][1] = cvSize(0,0);
+ optype = cvtest::randInt(rng) % (optype_max - optype_min + 1) + optype_min;
+}
+
+
+double CV_MorphologyBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return test_mat[INPUT][0].depth() < CV_32F ||
+ (optype == CV_MOP_ERODE || optype == CV_MOP_DILATE ||
+ optype == CV_MOP_OPEN || optype == CV_MOP_CLOSE) ? 0 : 1e-5;
+}
+
+
+int CV_MorphologyBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_FilterBaseTest::prepare_test_case( test_case_idx );
+ vector<int> eldata;
+
+ if( code <= 0 )
+ return code;
+
+ if( shape == CV_SHAPE_CUSTOM )
+ {
+ eldata.resize(aperture_size.width*aperture_size.height);
+ uchar* src = test_mat[INPUT][1].data;
+ int srcstep = test_mat[INPUT][1].step;
+ int i, j, nonzero = 0;
+
+ for( i = 0; i < aperture_size.height; i++ )
+ {
+ for( j = 0; j < aperture_size.width; j++ )
+ {
+ eldata[i*aperture_size.width + j] = src[i*srcstep + j];
+ nonzero += src[i*srcstep + j] != 0;
+ }
+ }
+
+ if( nonzero == 0 )
+ eldata[anchor.y*aperture_size.width + anchor.x] = 1;
+ }
+
+ cvReleaseStructuringElement( &element );
+ element = cvCreateStructuringElementEx( aperture_size.width, aperture_size.height,
+ anchor.x, anchor.y, shape, eldata.empty() ? 0 : &eldata[0] );
+ return code;
+}
+
+
+void CV_MorphologyBaseTest::prepare_to_validation( int test_case_idx )
+{
+ Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
+ Mat _ielement(element->nRows, element->nCols, CV_32S, element->values);
+ Mat _element;
+ _ielement.convertTo(_element, CV_8U);
+ Point anchor(element->anchorX, element->anchorY);
+ int border = BORDER_REPLICATE;
+
+ if( optype == CV_MOP_ERODE )
+ {
+ cvtest::erode( src, dst, _element, anchor, border );
+ }
+ else if( optype == CV_MOP_DILATE )
+ {
+ cvtest::dilate( src, dst, _element, anchor, border );
+ }
+ else
+ {
+ Mat temp;
+ if( optype == CV_MOP_OPEN )
+ {
+ cvtest::erode( src, temp, _element, anchor, border );
+ cvtest::dilate( temp, dst, _element, anchor, border );
+ }
+ else if( optype == CV_MOP_CLOSE )
+ {
+ cvtest::dilate( src, temp, _element, anchor, border );
+ cvtest::erode( temp, dst, _element, anchor, border );
+ }
+ else if( optype == CV_MOP_GRADIENT )
+ {
+ cvtest::erode( src, temp, _element, anchor, border );
+ cvtest::dilate( src, dst, _element, anchor, border );
+ cvtest::add( dst, 1, temp, -1, Scalar::all(0), dst, dst.type() );
+ }
+ else if( optype == CV_MOP_TOPHAT )
+ {
+ cvtest::erode( src, temp, _element, anchor, border );
+ cvtest::dilate( temp, dst, _element, anchor, border );
+ cvtest::add( src, 1, dst, -1, Scalar::all(0), dst, dst.type() );
+ }
+ else if( optype == CV_MOP_BLACKHAT )
+ {
+ cvtest::dilate( src, temp, _element, anchor, border );
+ cvtest::erode( temp, dst, _element, anchor, border );
+ cvtest::add( dst, 1, src, -1, Scalar::all(0), dst, dst.type() );
+ }
+ else
+ CV_Error( CV_StsBadArg, "Unknown operation" );
+ }
+
+ cvReleaseStructuringElement( &element );
+}
+
+
+/////////////// erode ///////////////
+
+class CV_ErodeTest : public CV_MorphologyBaseTest
+{
+public:
+ CV_ErodeTest();
+protected:
+ void run_func();
+};
+
+
+CV_ErodeTest::CV_ErodeTest()
+{
+ optype_min = optype_max = CV_MOP_ERODE;
+}
+
+
+void CV_ErodeTest::run_func()
+{
+ cvErode( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
+ test_array[OUTPUT][0], element, 1 );
+}
+
+
+/////////////// dilate ///////////////
+
+class CV_DilateTest : public CV_MorphologyBaseTest
+{
+public:
+ CV_DilateTest();
+protected:
+ void run_func();
+};
+
+
+CV_DilateTest::CV_DilateTest()
+{
+ optype_min = optype_max = CV_MOP_DILATE;
+}
+
+
+void CV_DilateTest::run_func()
+{
+ cvDilate( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
+ test_array[OUTPUT][0], element, 1 );
+}
+
+/////////////// morphEx ///////////////
+
+class CV_MorphExTest : public CV_MorphologyBaseTest
+{
+public:
+ CV_MorphExTest();
+protected:
+ void run_func();
+};
+
+
+CV_MorphExTest::CV_MorphExTest()
+{
+ optype_min = CV_MOP_ERODE;
+ optype_max = CV_MOP_BLACKHAT;
+}
+
+
+void CV_MorphExTest::run_func()
+{
+ cvMorphologyEx( test_array[inplace ? OUTPUT : INPUT][0],
+ test_array[OUTPUT][0], 0, element, optype, 1 );
+}
+
+/////////////// generic filter ///////////////
+
+class CV_FilterTest : public CV_FilterBaseTest
+{
+public:
+ CV_FilterTest();
+
+protected:
+ void prepare_to_validation( int test_case_idx );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_FilterTest::CV_FilterTest() : CV_FilterBaseTest( true )
+{
+}
+
+
+void CV_FilterTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng)%3;
+ int cn = CV_MAT_CN(types[INPUT][0]);
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+}
+
+
+double CV_FilterTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 2 : depth <= CV_32S ? 32 :
+ depth == CV_32F ? 1e-4 : 1e-10;
+}
+
+
+void CV_FilterTest::run_func()
+{
+ CvMat kernel = test_mat[INPUT][1];
+ cvFilter2D( test_array[inplace ? OUTPUT : INPUT][0],
+ test_array[OUTPUT][0], &kernel, anchor );
+}
+
+
+void CV_FilterTest::prepare_to_validation( int test_case_idx )
+{
+ cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].type(),
+ test_mat[INPUT][1], anchor, 0, BORDER_REPLICATE );
+}
+
+
+////////////////////////
+
+class CV_DerivBaseTest : public CV_FilterBaseTest
+{
+public:
+ CV_DerivBaseTest();
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int _aperture_size;
+};
+
+
+CV_DerivBaseTest::CV_DerivBaseTest() : CV_FilterBaseTest( true )
+{
+ max_aperture_size = 7;
+}
+
+
+void CV_DerivBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = cvtest::randInt(rng) % 2;
+ depth = depth == 0 ? CV_8U : CV_32F;
+ types[INPUT][0] = CV_MAKETYPE(depth,1);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
+ _aperture_size = (cvtest::randInt(rng)%5)*2 - 1;
+ sizes[INPUT][1] = aperture_size = cvSize(_aperture_size, _aperture_size);
+}
+
+
+double CV_DerivBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 2 : 5e-4;
+}
+
+
+/////////////// sobel ///////////////
+
+class CV_SobelTest : public CV_DerivBaseTest
+{
+public:
+ CV_SobelTest();
+
+protected:
+ void prepare_to_validation( int test_case_idx );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ int dx, dy, origin;
+};
+
+
+CV_SobelTest::CV_SobelTest() {}
+
+
+void CV_SobelTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int max_d = _aperture_size > 0 ? 2 : 1;
+ origin = cvtest::randInt(rng) % 2;
+ dx = cvtest::randInt(rng) % (max_d + 1);
+ dy = cvtest::randInt(rng) % (max_d + 1 - dx);
+ if( dx == 0 && dy == 0 )
+ dx = 1;
+ if( cvtest::randInt(rng) % 2 )
+ {
+ int t;
+ CV_SWAP( dx, dy, t );
+ }
+
+ if( _aperture_size < 0 )
+ aperture_size = cvSize(3, 3);
+ else if( _aperture_size == 1 )
+ {
+ if( dx == 0 )
+ aperture_size = cvSize(1, 3);
+ else if( dy == 0 )
+ aperture_size = cvSize(3, 1);
+ else
+ {
+ _aperture_size = 3;
+ aperture_size = cvSize(3, 3);
+ }
+ }
+ else
+ aperture_size = cvSize(_aperture_size, _aperture_size);
+
+ sizes[INPUT][1] = aperture_size;
+ anchor.x = aperture_size.width / 2;
+ anchor.y = aperture_size.height / 2;
+}
+
+
+void CV_SobelTest::run_func()
+{
+ cvSobel( test_array[inplace ? OUTPUT : INPUT][0],
+ test_array[OUTPUT][0], dx, dy, _aperture_size );
+ /*cv::Sobel( test_mat[inplace ? OUTPUT : INPUT][0],
+ test_mat[OUTPUT][0], test_mat[OUTPUT][0].depth(),
+ dx, dy, _aperture_size, 1, 0, border );*/
+}
+
+
+void CV_SobelTest::prepare_to_validation( int test_case_idx )
+{
+ Mat kernel = cvtest::calcSobelKernel2D( dx, dy, _aperture_size, 0 );
+ cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
+ kernel, anchor, 0, BORDER_REPLICATE);
+}
+
+
+/////////////// laplace ///////////////
+
+class CV_LaplaceTest : public CV_DerivBaseTest
+{
+public:
+ CV_LaplaceTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int test_case_idx );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+};
+
+
+CV_LaplaceTest::CV_LaplaceTest()
+{
+}
+
+
+void CV_LaplaceTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_DerivBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ if( _aperture_size <= 1 )
+ {
+ if( _aperture_size < 0 )
+ _aperture_size = 1;
+ aperture_size = cvSize(3, 3);
+ }
+ else
+ aperture_size = cvSize(_aperture_size, _aperture_size);
+
+ sizes[INPUT][1] = aperture_size;
+ anchor.x = aperture_size.width / 2;
+ anchor.y = aperture_size.height / 2;
+}
+
+
+void CV_LaplaceTest::run_func()
+{
+ cvLaplace( test_array[inplace ? OUTPUT : INPUT][0],
+ test_array[OUTPUT][0], _aperture_size );
+}
+
+
+int CV_LaplaceTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_DerivBaseTest::prepare_test_case( test_case_idx );
+ return _aperture_size < 0 ? 0 : code;
+}
+
+
+void CV_LaplaceTest::prepare_to_validation( int test_case_idx )
+{
+ Mat kernel = cvtest::calcLaplaceKernel2D( _aperture_size );
+ cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
+ kernel, anchor, 0, BORDER_REPLICATE );
+}
+
+
+////////////////////////////////////////////////////////////
+
+class CV_SmoothBaseTest : public CV_FilterBaseTest
+{
+public:
+ CV_SmoothBaseTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ const char* smooth_type;
+};
+
+
+CV_SmoothBaseTest::CV_SmoothBaseTest() : CV_FilterBaseTest( true )
+{
+ smooth_type = "";
+}
+
+
+void CV_SmoothBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = cvtest::randInt(rng) % 2;
+ int cn = CV_MAT_CN(types[INPUT][0]);
+ depth = depth == 0 ? CV_8U : CV_32F;
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
+ anchor.x = cvtest::randInt(rng)%(max_aperture_size/2+1);
+ anchor.y = cvtest::randInt(rng)%(max_aperture_size/2+1);
+ aperture_size.width = anchor.x*2 + 1;
+ aperture_size.height = anchor.y*2 + 1;
+ sizes[INPUT][1] = aperture_size;
+}
+
+
+double CV_SmoothBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 1 : 1e-5;
+}
+
+
+/////////////// blur ///////////////
+
+class CV_BlurTest : public CV_SmoothBaseTest
+{
+public:
+ CV_BlurTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int test_case_idx );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ bool normalize;
+};
+
+
+CV_BlurTest::CV_BlurTest()
+{
+}
+
+
+void CV_BlurTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ normalize = cvtest::randInt(rng) % 2 != 0;
+ if( !normalize )
+ {
+ int depth = CV_MAT_DEPTH(types[INPUT][0]);
+ types[INPUT][0] = CV_MAKETYPE(depth, 1);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth==CV_8U?CV_16S:CV_32F,1);
+ }
+}
+
+
+void CV_BlurTest::run_func()
+{
+ cvSmooth( inplace ? test_array[OUTPUT][0] : test_array[INPUT][0],
+ test_array[OUTPUT][0], normalize ? CV_BLUR : CV_BLUR_NO_SCALE,
+ aperture_size.width, aperture_size.height );
+}
+
+
+int CV_BlurTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_SmoothBaseTest::prepare_test_case( test_case_idx );
+ return code > 0 && !normalize && test_mat[INPUT][0].channels() > 1 ? 0 : code;
+}
+
+
+void CV_BlurTest::prepare_to_validation( int test_case_idx )
+{
+ Mat kernel(aperture_size, CV_64F);
+ kernel.setTo(Scalar::all(normalize ? 1./(aperture_size.width*aperture_size.height) : 1.));
+ cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
+ kernel, anchor, 0, BORDER_REPLICATE );
+}
+
+
+/////////////// gaussian ///////////////
+
+class CV_GaussianBlurTest : public CV_SmoothBaseTest
+{
+public:
+ CV_GaussianBlurTest();
+
+protected:
+ void prepare_to_validation( int test_case_idx );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ );
+ double sigma;
+ int param1, param2;
+};
+
+
+CV_GaussianBlurTest::CV_GaussianBlurTest() : CV_SmoothBaseTest()
+{
+ sigma = 0.;
+ smooth_type = "Gaussian";
+}
+
+
+double CV_GaussianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 8 : 1e-5;
+}
+
+
+void CV_GaussianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int kernel_case = cvtest::randInt(rng) % 2;
+ CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ anchor = cvPoint(aperture_size.width/2,aperture_size.height/2);
+
+ sigma = exp(cvtest::randReal(rng)*5-2);
+ param1 = aperture_size.width;
+ param2 = aperture_size.height;
+
+ if( kernel_case == 0 )
+ sigma = 0.;
+}
+
+void CV_GaussianBlurTest::run_func()
+{
+ cvSmooth( test_array[inplace ? OUTPUT : INPUT][0],
+ test_array[OUTPUT][0], CV_GAUSSIAN,
+ param1, param2, sigma, sigma );
+}
+
+
+// !!! Copied from cvSmooth, if the code is changed in cvSmooth,
+// make sure to update this one too.
+#define SMALL_GAUSSIAN_SIZE 7
+static void
+calcGaussianKernel( int n, double sigma, vector<float>& kernel )
+{
+ static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
+ {
+ {1.f},
+ {0.25f, 0.5f, 0.25f},
+ {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
+ {0.03125, 0.109375, 0.21875, 0.28125, 0.21875, 0.109375, 0.03125}
+ };
+
+ kernel.resize(n);
+ if( n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 )
+ {
+ assert( n%2 == 1 );
+ memcpy( &kernel[0], small_gaussian_tab[n>>1], n*sizeof(kernel[0]));
+ }
+ else
+ {
+ double sigmaX = sigma > 0 ? sigma : (n/2 - 1)*0.3 + 0.8;
+ double scale2X = -0.5/(sigmaX*sigmaX);
+ double sum = 1.;
+ int i;
+ sum = kernel[n/2] = 1.f;
+
+ for( i = 1; i <= n/2; i++ )
+ {
+ kernel[n/2+i] = kernel[n/2-i] = (float)exp(scale2X*i*i);
+ sum += kernel[n/2+i]*2;
+ }
+
+ sum = 1./sum;
+ for( i = 0; i <= n/2; i++ )
+ kernel[n/2+i] = kernel[n/2-i] = (float)(kernel[n/2+i]*sum);
+ }
+}
+
+
+static Mat calcGaussianKernel2D( Size ksize, double sigma )
+{
+ vector<float> kx, ky;
+ Mat kernel(ksize, CV_32F);
+
+ calcGaussianKernel( kernel.cols, sigma, kx );
+ calcGaussianKernel( kernel.rows, sigma, ky );
+
+ for( int i = 0; i < kernel.rows; i++ )
+ for( int j = 0; j < kernel.cols; j++ )
+ kernel.at<float>(i, j) = kx[j]*ky[i];
+ return kernel;
+}
+
+
+void CV_GaussianBlurTest::prepare_to_validation( int test_case_idx )
+{
+ Mat kernel = calcGaussianKernel2D( aperture_size, sigma );
+ cvtest::filter2D( test_mat[INPUT][0], test_mat[REF_OUTPUT][0], test_mat[REF_OUTPUT][0].depth(),
+ kernel, anchor, 0, border & ~BORDER_ISOLATED );
+}
+
+
+/////////////// median ///////////////
+
+class CV_MedianBlurTest : public CV_SmoothBaseTest
+{
+public:
+ CV_MedianBlurTest();
+
+protected:
+ void prepare_to_validation( int test_case_idx );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+};
+
+
+CV_MedianBlurTest::CV_MedianBlurTest()
+{
+ smooth_type = "Median";
+}
+
+
+void CV_MedianBlurTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_SmoothBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = CV_8U;
+ int cn = CV_MAT_CN(types[INPUT][0]);
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
+ types[INPUT][1] = CV_MAKETYPE(depth,1);
+
+ aperture_size.height = aperture_size.width;
+ anchor.x = anchor.y = aperture_size.width / 2;
+ sizes[INPUT][1] = cvSize(aperture_size.width,aperture_size.height);
+
+ sizes[OUTPUT][0] = sizes[INPUT][0];
+ sizes[REF_OUTPUT][0] = sizes[INPUT][0];
+
+ inplace = false;
+ border = BORDER_REPLICATE | BORDER_ISOLATED;
+}
+
+
+double CV_MedianBlurTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 0;
+}
+
+
+void CV_MedianBlurTest::run_func()
+{
+ cvSmooth( test_array[INPUT][0], test_array[OUTPUT][0],
+ CV_MEDIAN, aperture_size.width );
+}
+
+
+struct median_pair
+{
+ int col;
+ int val;
+ median_pair() {};
+ median_pair( int _col, int _val ) : col(_col), val(_val) {};
+};
+
+
+static void test_medianFilter( const Mat& src, Mat& dst, int m )
+{
+ int i, j, k, l, m2 = m*m, n;
+ vector<int> col_buf(m+1);
+ vector<median_pair> _buf0(m*m+1), _buf1(m*m+1);
+ median_pair *buf0 = &_buf0[0], *buf1 = &_buf1[0];
+ int step = src.step/src.elemSize();
+
+ assert( src.rows == dst.rows + m - 1 && src.cols == dst.cols + m - 1 &&
+ src.type() == dst.type() && src.type() == CV_8UC1 );
+
+ for( i = 0; i < dst.rows; i++ )
+ {
+ uchar* dst1 = dst.ptr<uchar>(i);
+ for( k = 0; k < m; k++ )
+ {
+ const uchar* src1 = src.ptr<uchar>(i+k);
+ for( j = 0; j < m-1; j++ )
+ *buf0++ = median_pair(j, src1[j]);
+ }
+
+ n = m2 - m;
+ buf0 -= n;
+ for( k = n-1; k > 0; k-- )
+ {
+ int f = 0;
+ for( j = 0; j < k; j++ )
+ {
+ if( buf0[j].val > buf0[j+1].val )
+ {
+ median_pair t;
+ CV_SWAP( buf0[j], buf0[j+1], t );
+ f = 1;
+ }
+ }
+ if( !f )
+ break;
+ }
+
+ for( j = 0; j < dst.cols; j++ )
+ {
+ int ins_col = j + m - 1;
+ int del_col = j - 1;
+ const uchar* src1 = src.ptr<uchar>(i) + ins_col;
+ for( k = 0; k < m; k++, src1 += step )
+ {
+ col_buf[k] = src1[0];
+ for( l = k-1; l >= 0; l-- )
+ {
+ int t;
+ if( col_buf[l] < col_buf[l+1] )
+ break;
+ CV_SWAP( col_buf[l], col_buf[l+1], t );
+ }
+ }
+
+ col_buf[m] = INT_MAX;
+
+ for( k = 0, l = 0; k < n; )
+ {
+ if( buf0[k].col == del_col )
+ k++;
+ else if( buf0[k].val < col_buf[l] )
+ *buf1++ = buf0[k++];
+ else
+ {
+ assert( col_buf[l] < INT_MAX );
+ *buf1++ = median_pair(ins_col,col_buf[l++]);
+ }
+ }
+
+ for( ; l < m; l++ )
+ *buf1++ = median_pair(ins_col,col_buf[l]);
+
+ if( del_col < 0 )
+ n += m;
+ buf1 -= n;
+ assert( n == m2 );
+ dst1[j] = (uchar)buf1[n/2].val;
+ median_pair* tbuf;
+ CV_SWAP( buf0, buf1, tbuf );
+ }
+ }
+}
+
+
+void CV_MedianBlurTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ // CV_SmoothBaseTest::prepare_to_validation( test_case_idx );
+ const Mat& src0 = test_mat[INPUT][0];
+ Mat& dst0 = test_mat[REF_OUTPUT][0];
+ int i, cn = src0.channels();
+ int m = aperture_size.width;
+ Mat src(src0.rows + m - 1, src0.cols + m - 1, src0.depth());
+ Mat dst;
+ if( cn == 1 )
+ dst = dst0;
+ else
+ dst.create(src0.size(), src0.depth());
+
+ for( i = 0; i < cn; i++ )
+ {
+ Mat ptr = src0;
+ if( cn > 1 )
+ {
+ cvtest::extract( src0, dst, i );
+ ptr = dst;
+ }
+ cvtest::copyMakeBorder( ptr, src, m/2, m/2, m/2, m/2, border & ~BORDER_ISOLATED );
+ test_medianFilter( src, dst, m );
+ if( cn > 1 )
+ cvtest::insert( dst, dst0, i );
+ }
+}
+
+
+/////////////// pyramid tests ///////////////
+
+class CV_PyramidBaseTest : public CV_FilterBaseTest
+{
+public:
+ CV_PyramidBaseTest( bool downsample );
+
+protected:
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ bool downsample;
+ Mat kernel;
+};
+
+
+CV_PyramidBaseTest::CV_PyramidBaseTest( bool _downsample ) : CV_FilterBaseTest(true)
+{
+ static float kdata[] = { 1.f, 4.f, 6.f, 4.f, 1.f };
+ downsample = _downsample;
+ Mat kernel1d(1, 5, CV_32F, kdata);
+ kernel = (kernel1d.t()*kernel1d)*((downsample ? 1 : 4)/256.);
+}
+
+
+double CV_PyramidBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 1 : 1e-5;
+}
+
+
+void CV_PyramidBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CvSize sz;
+ CV_FilterBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ int depth = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
+ int cn = cvtest::randInt(rng) & 1 ? 3 : 1;
+
+ aperture_size = cvSize(5,5);
+ anchor = cvPoint(aperture_size.width/2, aperture_size.height/2);
+
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+
+ sz.width = MAX( sizes[INPUT][0].width/2, 1 );
+ sz.height = MAX( sizes[INPUT][0].height/2, 1 );
+
+ if( downsample )
+ {
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
+ sz.width *= 2;
+ sz.height *= 2;
+ sizes[INPUT][0] = sz;
+ }
+ else
+ {
+ sizes[INPUT][0] = sz;
+ sz.width *= 2;
+ sz.height *= 2;
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sz;
+ }
+
+ sizes[INPUT][1] = aperture_size;
+ inplace = false;
+}
+
+
+/////// pyrdown ////////
+
+class CV_PyramidDownTest : public CV_PyramidBaseTest
+{
+public:
+ CV_PyramidDownTest();
+
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_PyramidDownTest::CV_PyramidDownTest() : CV_PyramidBaseTest( true )
+{
+}
+
+
+void CV_PyramidDownTest::run_func()
+{
+ cvPyrDown( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
+}
+
+
+void CV_PyramidDownTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
+ Mat temp;
+ cvtest::filter2D(src, temp, src.depth(),
+ kernel, Point(kernel.cols/2, kernel.rows/2),
+ 0, BORDER_REFLECT_101);
+
+ size_t elem_size = temp.elemSize();
+ size_t ncols = dst.cols*elem_size;
+
+ for( int i = 0; i < dst.rows; i++ )
+ {
+ const uchar* src_row = temp.ptr(i*2);
+ uchar* dst_row = dst.ptr(i);
+
+ for( size_t j = 0; j < ncols; j += elem_size )
+ {
+ for( size_t k = 0; k < elem_size; k++ )
+ dst_row[j+k] = src_row[j*2+k];
+ }
+ }
+}
+
+
+/////// pyrup ////////
+
+class CV_PyramidUpTest : public CV_PyramidBaseTest
+{
+public:
+ CV_PyramidUpTest();
+
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_PyramidUpTest::CV_PyramidUpTest() : CV_PyramidBaseTest( false )
+{
+}
+
+
+void CV_PyramidUpTest::run_func()
+{
+ cvPyrUp( test_array[INPUT][0], test_array[OUTPUT][0], CV_GAUSSIAN_5x5 );
+}
+
+
+void CV_PyramidUpTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0], &dst = test_mat[REF_OUTPUT][0];
+ Mat temp(dst.size(), dst.type());
+
+ size_t elem_size = src.elemSize();
+ size_t ncols = src.cols*elem_size;
+
+ for( int i = 0; i < src.rows; i++ )
+ {
+ const uchar* src_row = src.ptr(i);
+ uchar* dst_row = temp.ptr(i*2);
+
+ if( i*2 + 1 < temp.rows )
+ memset( temp.ptr(i*2+1), 0, temp.cols*elem_size );
+ for( size_t j = 0; j < ncols; j += elem_size )
+ {
+ for( size_t k = 0; k < elem_size; k++ )
+ {
+ dst_row[j*2+k] = src_row[j+k];
+ dst_row[j*2+k+elem_size] = 0;
+ }
+ }
+ }
+
+ cvtest::filter2D(temp, dst, dst.depth(),
+ kernel, Point(kernel.cols/2, kernel.rows/2),
+ 0, BORDER_REFLECT_101);
+ // TODO: fix the problem with 2 bottom rows.
+ memset(dst.ptr(dst.rows-2), 0, dst.step*2);
+ memset(test_mat[OUTPUT][0].ptr(dst.rows-2), 0, test_mat[OUTPUT][0].step*2);
+}
+
+
+//////////////////////// feature selection //////////////////////////
+
+class CV_FeatureSelBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_FeatureSelBaseTest( int width_factor );
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int aperture_size, block_size;
+ int max_aperture_size;
+ int max_block_size;
+ int width_factor;
+};
+
+
+CV_FeatureSelBaseTest::CV_FeatureSelBaseTest( int _width_factor )
+{
+ max_aperture_size = 7;
+ max_block_size = 21;
+ // 1 input, 1 output, temp arrays are allocated in the reference functions
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = false;
+ width_factor = _width_factor;
+}
+
+
+int CV_FeatureSelBaseTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ max_aperture_size = cvReadInt( find_param( fs, "max_aperture_size" ), max_aperture_size );
+ max_aperture_size = cvtest::clipInt( max_aperture_size, 1, 9 );
+ max_block_size = cvReadInt( find_param( fs, "max_block_size" ), max_block_size );
+ max_block_size = cvtest::clipInt( max_aperture_size, 1, 100 );
+
+ return code;
+}
+
+
+double CV_FeatureSelBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth <= CV_8S ? 3e-2 : depth == CV_32F ? 1e-3 : 1e-10;
+}
+
+
+void CV_FeatureSelBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT && CV_MAT_DEPTH(type) == CV_32F )
+ {
+ low = Scalar::all(-10.);
+ high = Scalar::all(10.);
+ }
+}
+
+
+void CV_FeatureSelBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = cvtest::randInt(rng) % 2, asz;
+
+ depth = depth == 0 ? CV_8U : CV_32F;
+ types[INPUT][0] = depth;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
+
+ aperture_size = (cvtest::randInt(rng) % (max_aperture_size+2) - 1) | 1;
+ if( aperture_size == 1 )
+ aperture_size = 3;
+ if( depth == CV_8U )
+ aperture_size = MIN( aperture_size, 5 );
+ block_size = (cvtest::randInt(rng) % max_block_size + 1) | 1;
+ if( block_size <= 3 )
+ block_size = 3;
+ asz = aperture_size > 0 ? aperture_size : 3;
+
+ sizes[INPUT][0].width = MAX( sizes[INPUT][0].width, asz + block_size );
+ sizes[INPUT][0].height = MAX( sizes[INPUT][0].height, asz + block_size );
+ sizes[OUTPUT][0].height = sizes[REF_OUTPUT][0].height = sizes[INPUT][0].height;
+ sizes[OUTPUT][0].width = sizes[REF_OUTPUT][0].width = sizes[INPUT][0].width*width_factor;
+}
+
+
+static void
+test_cornerEigenValsVecs( const Mat& src, Mat& eigenv, Mat& ocv_eigenv,
+ int block_size, int _aperture_size, int mode )
+{
+ int i, j;
+ int aperture_size = _aperture_size < 0 ? 3 : _aperture_size;
+ Point anchor( aperture_size/2, aperture_size/2 );
+
+ CV_Assert( src.type() == CV_8UC1 || src.type() == CV_32FC1 );
+ CV_Assert( eigenv.type() == CV_32FC1 );
+ CV_Assert( src.rows == eigenv.rows &&
+ ((mode > 0 && src.cols == eigenv.cols) ||
+ (mode == 0 && src.cols*6 == eigenv.cols)) );
+
+ int type = src.type();
+ int ftype = CV_32FC1;
+ double kernel_scale = type != ftype ? 1./255 : 1;
+
+ Mat dx2, dy2, dxdy(src.size(), CV_32F), kernel;
+
+ kernel = cvtest::calcSobelKernel2D( 1, 0, _aperture_size );
+ cvtest::filter2D( src, dx2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE );
+ kernel = cvtest::calcSobelKernel2D( 0, 1, _aperture_size );
+ cvtest::filter2D( src, dy2, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE );
+
+ double denom = (1 << (aperture_size-1))*block_size;
+ denom = denom * denom;
+ if( _aperture_size < 0 )
+ denom *= 4;
+ denom = 1./denom;
+
+ for( i = 0; i < src.rows; i++ )
+ {
+ float* dxdyp = dxdy.ptr<float>(i);
+ float* dx2p = dx2.ptr<float>(i);
+ float* dy2p = dy2.ptr<float>(i);
+
+ for( j = 0; j < src.cols; j++ )
+ {
+ double xval = dx2p[j], yval = dy2p[j];
+ dxdyp[j] = (float)(xval*yval*denom);
+ dx2p[j] = (float)(xval*xval*denom);
+ dy2p[j] = (float)(yval*yval*denom);
+ }
+ }
+
+ kernel = Mat::ones(block_size, block_size, CV_32F);
+ anchor = Point(block_size/2, block_size/2);
+
+ cvtest::filter2D( dx2, dx2, ftype, kernel, anchor, 0, BORDER_REPLICATE );
+ cvtest::filter2D( dy2, dy2, ftype, kernel, anchor, 0, BORDER_REPLICATE );
+ cvtest::filter2D( dxdy, dxdy, ftype, kernel, anchor, 0, BORDER_REPLICATE );
+
+ if( mode == 0 )
+ {
+ for( i = 0; i < src.rows; i++ )
+ {
+ float* eigenvp = eigenv.ptr<float>(i);
+ float* ocv_eigenvp = ocv_eigenv.ptr<float>(i);
+ const float* dxdyp = dxdy.ptr<float>(i);
+ const float* dx2p = dx2.ptr<float>(i);
+ const float* dy2p = dy2.ptr<float>(i);
+
+ for( j = 0; j < src.cols; j++ )
+ {
+ double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
+ double d = sqrt((a-c)*(a-c) + 4*b*b);
+ double l1 = 0.5*(a + c + d);
+ double l2 = 0.5*(a + c - d);
+ double x1, y1, x2, y2, s;
+
+ if( fabs(a - l1) + fabs(b) >= 1e-3 )
+ x1 = b, y1 = l1 - a;
+ else
+ x1 = l1 - c, y1 = b;
+ s = 1./(sqrt(x1*x1+y1*y1)+DBL_EPSILON);
+ x1 *= s; y1 *= s;
+
+ if( fabs(a - l2) + fabs(b) >= 1e-3 )
+ x2 = b, y2 = l2 - a;
+ else
+ x2 = l2 - c, y2 = b;
+ s = 1./(sqrt(x2*x2+y2*y2)+DBL_EPSILON);
+ x2 *= s; y2 *= s;
+
+ /* the orientation of eigen vectors might be inversed relative to OpenCV function,
+ which is normal */
+ if( (fabs(x1) >= fabs(y1) && ocv_eigenvp[j*6+2]*x1 < 0) ||
+ (fabs(x1) < fabs(y1) && ocv_eigenvp[j*6+3]*y1 < 0) )
+ x1 = -x1, y1 = -y1;
+
+ if( (fabs(x2) >= fabs(y2) && ocv_eigenvp[j*6+4]*x2 < 0) ||
+ (fabs(x2) < fabs(y2) && ocv_eigenvp[j*6+5]*y2 < 0) )
+ x2 = -x2, y2 = -y2;
+
+ eigenvp[j*6] = (float)l1;
+ eigenvp[j*6+1] = (float)l2;
+ eigenvp[j*6+2] = (float)x1;
+ eigenvp[j*6+3] = (float)y1;
+ eigenvp[j*6+4] = (float)x2;
+ eigenvp[j*6+5] = (float)y2;
+ }
+ }
+ }
+ else if( mode == 1 )
+ {
+ for( i = 0; i < src.rows; i++ )
+ {
+ float* eigenvp = eigenv.ptr<float>(i);
+ const float* dxdyp = dxdy.ptr<float>(i);
+ const float* dx2p = dx2.ptr<float>(i);
+ const float* dy2p = dy2.ptr<float>(i);
+
+ for( j = 0; j < src.cols; j++ )
+ {
+ double a = dx2p[j], b = dxdyp[j], c = dy2p[j];
+ double d = sqrt((a-c)*(a-c) + 4*b*b);
+ eigenvp[j] = (float)(0.5*(a + c - d));
+ }
+ }
+ }
+}
+
+
+// min eigenval
+class CV_MinEigenValTest : public CV_FeatureSelBaseTest
+{
+public:
+ CV_MinEigenValTest();
+
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_MinEigenValTest::CV_MinEigenValTest() : CV_FeatureSelBaseTest( 1 )
+{
+}
+
+
+void CV_MinEigenValTest::run_func()
+{
+ cvCornerMinEigenVal( test_array[INPUT][0], test_array[OUTPUT][0],
+ block_size, aperture_size );
+}
+
+
+void CV_MinEigenValTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ test_mat[OUTPUT][0], block_size, aperture_size, 1 );
+}
+
+
+// eigenval's & vec's
+class CV_EigenValVecTest : public CV_FeatureSelBaseTest
+{
+public:
+ CV_EigenValVecTest();
+
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_EigenValVecTest::CV_EigenValVecTest() : CV_FeatureSelBaseTest( 6 )
+{
+}
+
+
+void CV_EigenValVecTest::run_func()
+{
+ cvCornerEigenValsAndVecs( test_array[INPUT][0], test_array[OUTPUT][0],
+ block_size, aperture_size );
+}
+
+
+void CV_EigenValVecTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_cornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ test_mat[OUTPUT][0], block_size, aperture_size, 0 );
+}
+
+
+// precornerdetect
+class CV_PreCornerDetectTest : public CV_FeatureSelBaseTest
+{
+public:
+ CV_PreCornerDetectTest();
+
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+ int prepare_test_case( int );
+};
+
+
+CV_PreCornerDetectTest::CV_PreCornerDetectTest() : CV_FeatureSelBaseTest( 1 )
+{
+}
+
+
+void CV_PreCornerDetectTest::run_func()
+{
+ cvPreCornerDetect( test_array[INPUT][0], test_array[OUTPUT][0], aperture_size );
+}
+
+
+int CV_PreCornerDetectTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_FeatureSelBaseTest::prepare_test_case( test_case_idx );
+ if( aperture_size < 0 )
+ aperture_size = 3;
+ return code;
+}
+
+
+void CV_PreCornerDetectTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ /*cvTsCornerEigenValsVecs( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ block_size, aperture_size, 0 );*/
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_OUTPUT][0];
+
+ int type = src.type(), ftype = CV_32FC1;
+ Point anchor(aperture_size/2, aperture_size/2);
+
+ double kernel_scale = type != ftype ? 1./255 : 1.;
+
+ Mat dx, dy, d2x, d2y, dxy, kernel;
+
+ kernel = cvtest::calcSobelKernel2D(1, 0, aperture_size);
+ cvtest::filter2D(src, dx, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
+ kernel = cvtest::calcSobelKernel2D(2, 0, aperture_size);
+ cvtest::filter2D(src, d2x, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
+ kernel = cvtest::calcSobelKernel2D(0, 1, aperture_size);
+ cvtest::filter2D(src, dy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
+ kernel = cvtest::calcSobelKernel2D(0, 2, aperture_size);
+ cvtest::filter2D(src, d2y, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
+ kernel = cvtest::calcSobelKernel2D(1, 1, aperture_size);
+ cvtest::filter2D(src, dxy, ftype, kernel*kernel_scale, anchor, 0, BORDER_REPLICATE);
+
+ double denom = 1 << (aperture_size-1);
+ denom = denom * denom * denom;
+ denom = 1./denom;
+
+ for( int i = 0; i < src.rows; i++ )
+ {
+ const float* _dx = dx.ptr<float>(i);
+ const float* _dy = dy.ptr<float>(i);
+ const float* _d2x = d2x.ptr<float>(i);
+ const float* _d2y = d2y.ptr<float>(i);
+ const float* _dxy = dxy.ptr<float>(i);
+ float* corner = dst.ptr<float>(i);
+
+ for( int j = 0; j < src.cols; j++ )
+ {
+ double x = _dx[j];
+ double y = _dy[j];
+
+ corner[j] = (float)(denom*(x*x*_d2y[j] + y*y*_d2x[j] - 2*x*y*_dxy[j]));
+ }
+ }
+}
+
+
+///////// integral /////////
+
+class CV_IntegralTest : public cvtest::ArrayTest
+{
+public:
+ CV_IntegralTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int prepare_test_case( int test_case_idx );
+};
+
+
+CV_IntegralTest::CV_IntegralTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = false;
+}
+
+
+void CV_IntegralTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ int depth = CV_MAT_DEPTH(type);
+ if( depth == CV_32F )
+ {
+ low = Scalar::all(-10.);
+ high = Scalar::all(10.);
+ }
+}
+
+
+void CV_IntegralTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2, sum_depth;
+ int cn = cvtest::randInt(rng) % 3 + 1;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ Size sum_size;
+
+ depth = depth == 0 ? CV_8U : CV_32F;
+ cn += cn == 2;
+ sum_depth = depth == CV_8U && (cvtest::randInt(rng) & 1) == 1 ? CV_32S : CV_64F;
+
+ types[INPUT][0] = CV_MAKETYPE(depth,cn);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] =
+ types[OUTPUT][2] = types[REF_OUTPUT][2] = CV_MAKETYPE(sum_depth, cn);
+ types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_MAKETYPE(CV_64F, cn);
+
+ sum_size.width = sizes[INPUT][0].width + 1;
+ sum_size.height = sizes[INPUT][0].height + 1;
+
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = sum_size;
+ sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] =
+ sizes[OUTPUT][2] = sizes[REF_OUTPUT][2] = Size(0,0);
+
+ if( cvtest::randInt(rng) % 3 > 0 )
+ {
+ sizes[OUTPUT][1] = sizes[REF_OUTPUT][1] = sum_size;
+ if( cvtest::randInt(rng) % 2 > 0 )
+ sizes[REF_OUTPUT][2] = sizes[OUTPUT][2] = sum_size;
+ }
+}
+
+
+double CV_IntegralTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ int depth = test_mat[i][j].depth();
+ return depth == CV_32S ? 0 : FLT_EPSILON;
+}
+
+
+int CV_IntegralTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ return code > 0 && ((test_array[OUTPUT][2] && test_mat[OUTPUT][2].channels() > 1) ||
+ test_mat[OUTPUT][0].depth() < test_mat[INPUT][0].depth()) ? 0 : code;
+}
+
+
+void CV_IntegralTest::run_func()
+{
+ cvIntegral( test_array[INPUT][0], test_array[OUTPUT][0],
+ test_array[OUTPUT][1], test_array[OUTPUT][2] );
+}
+
+
+static void test_integral( const Mat& img, Mat* sum, Mat* sqsum, Mat* tilted )
+{
+ CV_Assert( img.depth() == CV_32F );
+
+ sum->create(img.rows+1, img.cols+1, CV_64F);
+ if( sqsum )
+ sqsum->create(img.rows+1, img.cols+1, CV_64F);
+ if( tilted )
+ tilted->create(img.rows+1, img.cols+1, CV_64F);
+
+ const float* data = img.ptr<float>();
+ double* sdata = sum->ptr<double>();
+ double* sqdata = sqsum ? sqsum->ptr<double>() : 0;
+ double* tdata = tilted ? tilted->ptr<double>() : 0;
+ int step = img.step/sizeof(data[0]);
+ int sstep = sum->step/sizeof(sdata[0]);
+ int sqstep = sqsum ? sqsum->step/sizeof(sqdata[0]) : 0;
+ int tstep = tilted ? tilted->step/sizeof(tdata[0]) : 0;
+ Size size = img.size();
+
+ memset( sdata, 0, (size.width+1)*sizeof(sdata[0]) );
+ if( sqsum )
+ memset( sqdata, 0, (size.width+1)*sizeof(sqdata[0]) );
+ if( tilted )
+ memset( tdata, 0, (size.width+1)*sizeof(tdata[0]) );
+
+ for( ; size.height--; data += step )
+ {
+ double s = 0, sq = 0;
+ int x;
+ sdata += sstep;
+ sqdata += sqstep;
+ tdata += tstep;
+
+ for( x = 0; x <= size.width; x++ )
+ {
+ double t = x > 0 ? data[x-1] : 0, ts = t;
+ s += t;
+ sq += t*t;
+
+ sdata[x] = s + sdata[x - sstep];
+ if( sqdata )
+ sqdata[x] = sq + sqdata[x - sqstep];
+
+ if( !tdata )
+ continue;
+
+ if( x == 0 )
+ ts += tdata[-tstep+1];
+ else
+ {
+ ts += tdata[x-tstep-1];
+ if( data > img.ptr<float>() )
+ {
+ ts += data[x-step-1];
+ if( x < size.width )
+ ts += tdata[x-tstep+1] - tdata[x-tstep*2];
+ }
+ }
+
+ tdata[x] = ts;
+ }
+ }
+}
+
+
+void CV_IntegralTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0];
+ int cn = src.channels();
+
+ Mat* sum0 = &test_mat[REF_OUTPUT][0];
+ Mat* sqsum0 = test_array[REF_OUTPUT][1] ? &test_mat[REF_OUTPUT][1] : 0;
+ Mat* tsum0 = test_array[REF_OUTPUT][2] ? &test_mat[REF_OUTPUT][2] : 0;
+
+ Mat plane, srcf, psum, psqsum, ptsum, psum2, psqsum2, ptsum2;
+ if( cn == 1 )
+ {
+ plane = src;
+ psum2 = *sum0;
+ psqsum2 = sqsum0 ? *sqsum0 : Mat();
+ ptsum2 = tsum0 ? *tsum0 : Mat();
+ }
+
+ for( int i = 0; i < cn; i++ )
+ {
+ if( cn > 1 )
+ cvtest::extract(src, plane, i);
+ plane.convertTo(srcf, CV_32F);
+
+ test_integral( srcf, &psum, sqsum0 ? &psqsum : 0, tsum0 ? &ptsum : 0 );
+ psum.convertTo(psum2, sum0->depth());
+ if( sqsum0 )
+ psqsum.convertTo(psqsum2, sqsum0->depth());
+ if( tsum0 )
+ ptsum.convertTo(ptsum2, tsum0->depth());
+
+ if( cn > 1 )
+ {
+ cvtest::insert(psum2, *sum0, i);
+ if( sqsum0 )
+ cvtest::insert(psqsum2, *sqsum0, i);
+ if( tsum0 )
+ cvtest::insert(ptsum2, *tsum0, i);
+ }
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////////
+
+TEST(Imgproc_Erode, accuracy) { CV_ErodeTest test; test.safe_run(); }
+TEST(Imgproc_Dilate, accuracy) { CV_DilateTest test; test.safe_run(); }
+TEST(Imgproc_MorphologyEx, accuracy) { CV_MorphExTest test; test.safe_run(); }
+TEST(Imgproc_Filter2D, accuracy) { CV_FilterTest test; test.safe_run(); }
+TEST(Imgproc_Sobel, accuracy) { CV_SobelTest test; test.safe_run(); }
+TEST(Imgproc_Laplace, accuracy) { CV_LaplaceTest test; test.safe_run(); }
+TEST(Imgproc_Blur, accuracy) { CV_BlurTest test; test.safe_run(); }
+TEST(Imgproc_GaussianBlur, accuracy) { CV_GaussianBlurTest test; test.safe_run(); }
+TEST(Imgproc_MedianBlur, accuracy) { CV_MedianBlurTest test; test.safe_run(); }
+TEST(Imgproc_PyramidDown, accuracy) { CV_PyramidDownTest test; test.safe_run(); }
+TEST(Imgproc_PyramidUp, accuracy) { CV_PyramidUpTest test; test.safe_run(); }
+TEST(Imgproc_MinEigenVal, accuracy) { CV_MinEigenValTest test; test.safe_run(); }
+TEST(Imgproc_EigenValsVecs, accuracy) { CV_EigenValVecTest test; test.safe_run(); }
+TEST(Imgproc_PreCornerDetect, accuracy) { CV_PreCornerDetectTest test; test.safe_run(); }
+TEST(Imgproc_Integral, accuracy) { CV_IntegralTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_FloodFillTest : public cvtest::ArrayTest
+{
+public:
+ CV_FloodFillTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+
+ /*int write_default_params(CvFileStorage* fs);
+ void get_timing_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types
+ CvSize** whole_sizes, bool *are_images );
+ void print_timing_params( int test_case_idx, char* ptr, int params_left );*/
+ CvPoint seed_pt;
+ CvScalar new_val;
+ CvScalar l_diff, u_diff;
+ int connectivity;
+ bool use_mask, mask_only;
+ int range_type;
+ int new_mask_val;
+ bool test_cpp;
+};
+
+
+CV_FloodFillTest::CV_FloodFillTest()
+{
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ optional_mask = false;
+ element_wise_relative_error = true;
+
+ test_cpp = false;
+}
+
+
+void CV_FloodFillTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes,
+ vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth, cn;
+ int i;
+ double buf[8];
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ depth = cvtest::randInt(rng) % 2;
+ depth = depth == 0 ? CV_8U : CV_32F;
+ cn = cvtest::randInt(rng) & 1 ? 3 : 1;
+
+ use_mask = (cvtest::randInt(rng) & 1) != 0;
+ connectivity = (cvtest::randInt(rng) & 1) ? 4 : 8;
+ mask_only = use_mask && (cvtest::randInt(rng) & 1) != 0;
+ new_mask_val = cvtest::randInt(rng) & 255;
+ range_type = cvtest::randInt(rng) % 3;
+
+ types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+ types[INPUT_OUTPUT][1] = types[REF_INPUT_OUTPUT][1] = CV_8UC1;
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(9,1);
+
+ if( !use_mask )
+ sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(0,0);
+ else
+ {
+ CvSize sz = sizes[INPUT_OUTPUT][0];
+ sizes[INPUT_OUTPUT][1] = sizes[REF_INPUT_OUTPUT][1] = cvSize(sz.width+2,sz.height+2);
+ }
+
+ seed_pt.x = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].width;
+ seed_pt.y = cvtest::randInt(rng) % sizes[INPUT_OUTPUT][0].height;
+
+ if( range_type == 0 )
+ l_diff = u_diff = Scalar::all(0.);
+ else
+ {
+ Mat m( 1, 8, CV_16S, buf );
+ rng.fill( m, RNG::NORMAL, Scalar::all(0), Scalar::all(32) );
+ for( i = 0; i < 4; i++ )
+ {
+ l_diff.val[i] = fabs(m.at<short>(i)/16.);
+ u_diff.val[i] = fabs(m.at<short>(i+4)/16.);
+ }
+ }
+
+ new_val = Scalar::all(0.);
+ for( i = 0; i < cn; i++ )
+ new_val.val[i] = cvtest::randReal(rng)*255;
+
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+double CV_FloodFillTest::get_success_error_level( int /*test_case_idx*/, int i, int j )
+{
+ return i == OUTPUT ? FLT_EPSILON : j == 0 ? FLT_EPSILON : 0;
+}
+
+
+void CV_FloodFillTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ RNG& rng = ts->get_rng();
+
+ if( i != INPUT && i != INPUT_OUTPUT )
+ {
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+ return;
+ }
+
+ if( j == 0 )
+ {
+ Mat tmp = arr;
+ Scalar m = Scalar::all(128);
+ Scalar s = Scalar::all(10);
+
+ if( arr.depth() == CV_32FC1 )
+ tmp.create(arr.size(), CV_MAKETYPE(CV_8U, arr.channels()));
+
+ if( range_type == 0 )
+ s = Scalar::all(2);
+
+ rng.fill(tmp, RNG::NORMAL, m, s );
+ if( arr.data != tmp.data )
+ cvtest::convert(tmp, arr, arr.type());
+ }
+ else
+ {
+ Scalar l = Scalar::all(-2);
+ Scalar u = Scalar::all(2);
+ cvtest::randUni(rng, arr, l, u );
+ rectangle( arr, Point(0,0), Point(arr.cols-1,arr.rows-1), Scalar::all(1), 1, 8, 0 );
+ }
+}
+
+
+void CV_FloodFillTest::run_func()
+{
+ int flags = connectivity + (mask_only ? CV_FLOODFILL_MASK_ONLY : 0) +
+ (range_type == 1 ? CV_FLOODFILL_FIXED_RANGE : 0) + (new_mask_val << 8);
+ double* odata = test_mat[OUTPUT][0].ptr<double>();
+
+ if(!test_cpp)
+ {
+ CvConnectedComp comp;
+ cvFloodFill( test_array[INPUT_OUTPUT][0], seed_pt, new_val, l_diff, u_diff, &comp,
+ flags, test_array[INPUT_OUTPUT][1] );
+ odata[0] = comp.area;
+ odata[1] = comp.rect.x;
+ odata[2] = comp.rect.y;
+ odata[3] = comp.rect.width;
+ odata[4] = comp.rect.height;
+ odata[5] = comp.value.val[0];
+ odata[6] = comp.value.val[1];
+ odata[7] = comp.value.val[2];
+ odata[8] = comp.value.val[3];
+ }
+ else
+ {
+ cv::Mat img = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]),
+ mask = test_array[INPUT_OUTPUT][1] ? cv::cvarrToMat(test_array[INPUT_OUTPUT][1]) : cv::Mat();
+ cv::Rect rect;
+ int area;
+ if( !mask.data )
+ area = cv::floodFill( img, seed_pt, new_val, &rect, l_diff, u_diff, flags );
+ else
+ area = cv::floodFill( img, mask, seed_pt, new_val, &rect, l_diff, u_diff, flags );
+ odata[0] = area;
+ odata[1] = rect.x;
+ odata[2] = rect.y;
+ odata[3] = rect.width;
+ odata[4] = rect.height;
+ odata[5] = odata[6] = odata[7] = odata[8] = 0;
+ }
+}
+
+
+typedef struct ff_offset_pair_t
+{
+ int mofs, iofs;
+}
+ff_offset_pair_t;
+
+static void
+cvTsFloodFill( CvMat* _img, CvPoint seed_pt, CvScalar new_val,
+ CvScalar l_diff, CvScalar u_diff, CvMat* _mask,
+ double* comp, int connectivity, int range_type,
+ int new_mask_val, bool mask_only )
+{
+ CvMemStorage* st = cvCreateMemStorage();
+ ff_offset_pair_t p0, p;
+ CvSeq* seq = cvCreateSeq( 0, sizeof(CvSeq), sizeof(p0), st );
+ CvMat* tmp = _img;
+ CvMat* mask;
+ CvRect r = cvRect( 0, 0, -1, -1 );
+ int area = 0;
+ int i, j;
+ ushort* m;
+ float* img;
+ int mstep, step;
+ int cn = CV_MAT_CN(_img->type);
+ int mdelta[8], idelta[8], ncount;
+ int cols = _img->cols, rows = _img->rows;
+ int u0 = 0, u1 = 0, u2 = 0;
+ double s0 = 0, s1 = 0, s2 = 0;
+
+ if( CV_MAT_DEPTH(_img->type) == CV_8U )
+ {
+ tmp = cvCreateMat( rows, cols, CV_MAKETYPE(CV_32F,CV_MAT_CN(_img->type)) );
+ cvTsConvert(_img, tmp);
+ }
+
+ mask = cvCreateMat( rows + 2, cols + 2, CV_16UC1 );
+
+ if( _mask )
+ cvTsConvert( _mask, mask );
+ else
+ {
+ cvTsZero( mask );
+ cvRectangle( mask, cvPoint(0,0), cvPoint(mask->cols-1,mask->rows-1), Scalar::all(1.), 1, 8, 0 );
+ }
+
+ new_mask_val = (new_mask_val != 0 ? new_mask_val : 1) << 8;
+
+ m = (ushort*)(mask->data.ptr + mask->step) + 1;
+ mstep = mask->step / sizeof(m[0]);
+ img = tmp->data.fl;
+ step = tmp->step / sizeof(img[0]);
+
+ p0.mofs = seed_pt.y*mstep + seed_pt.x;
+ p0.iofs = seed_pt.y*step + seed_pt.x*cn;
+
+ if( m[p0.mofs] )
+ goto _exit_;
+
+ cvSeqPush( seq, &p0 );
+ m[p0.mofs] = (ushort)new_mask_val;
+
+ if( connectivity == 4 )
+ {
+ ncount = 4;
+ mdelta[0] = -mstep; idelta[0] = -step;
+ mdelta[1] = -1; idelta[1] = -cn;
+ mdelta[2] = 1; idelta[2] = cn;
+ mdelta[3] = mstep; idelta[3] = step;
+ }
+ else
+ {
+ ncount = 8;
+ mdelta[0] = -mstep-1; mdelta[1] = -mstep; mdelta[2] = -mstep+1;
+ idelta[0] = -step-cn; idelta[1] = -step; idelta[2] = -step+cn;
+
+ mdelta[3] = -1; mdelta[4] = 1;
+ idelta[3] = -cn; idelta[4] = cn;
+
+ mdelta[5] = mstep-1; mdelta[6] = mstep; mdelta[7] = mstep+1;
+ idelta[5] = step-cn; idelta[6] = step; idelta[7] = step+cn;
+ }
+
+ if( cn == 1 )
+ {
+ float a0 = (float)-l_diff.val[0];
+ float b0 = (float)u_diff.val[0];
+
+ s0 = img[p0.iofs];
+
+ if( range_type < 2 )
+ {
+ a0 += (float)s0; b0 += (float)s0;
+ }
+
+ while( seq->total )
+ {
+ cvSeqPop( seq, &p0 );
+ float a = a0, b = b0;
+ float* ptr = img + p0.iofs;
+ ushort* mptr = m + p0.mofs;
+
+ if( range_type == 2 )
+ a += ptr[0], b += ptr[0];
+
+ for( i = 0; i < ncount; i++ )
+ {
+ int md = mdelta[i], id = idelta[i];
+ float v;
+ if( !mptr[md] && a <= (v = ptr[id]) && v <= b )
+ {
+ mptr[md] = (ushort)new_mask_val;
+ p.mofs = p0.mofs + md;
+ p.iofs = p0.iofs + id;
+ cvSeqPush( seq, &p );
+ }
+ }
+ }
+ }
+ else
+ {
+ float a0 = (float)-l_diff.val[0];
+ float a1 = (float)-l_diff.val[1];
+ float a2 = (float)-l_diff.val[2];
+ float b0 = (float)u_diff.val[0];
+ float b1 = (float)u_diff.val[1];
+ float b2 = (float)u_diff.val[2];
+
+ s0 = img[p0.iofs];
+ s1 = img[p0.iofs + 1];
+ s2 = img[p0.iofs + 2];
+
+ if( range_type < 2 )
+ {
+ a0 += (float)s0; b0 += (float)s0;
+ a1 += (float)s1; b1 += (float)s1;
+ a2 += (float)s2; b2 += (float)s2;
+ }
+
+ while( seq->total )
+ {
+ cvSeqPop( seq, &p0 );
+ float _a0 = a0, _a1 = a1, _a2 = a2;
+ float _b0 = b0, _b1 = b1, _b2 = b2;
+ float* ptr = img + p0.iofs;
+ ushort* mptr = m + p0.mofs;
+
+ if( range_type == 2 )
+ {
+ _a0 += ptr[0]; _b0 += ptr[0];
+ _a1 += ptr[1]; _b1 += ptr[1];
+ _a2 += ptr[2]; _b2 += ptr[2];
+ }
+
+ for( i = 0; i < ncount; i++ )
+ {
+ int md = mdelta[i], id = idelta[i];
+ float v;
+ if( !mptr[md] &&
+ _a0 <= (v = ptr[id]) && v <= _b0 &&
+ _a1 <= (v = ptr[id+1]) && v <= _b1 &&
+ _a2 <= (v = ptr[id+2]) && v <= _b2 )
+ {
+ mptr[md] = (ushort)new_mask_val;
+ p.mofs = p0.mofs + md;
+ p.iofs = p0.iofs + id;
+ cvSeqPush( seq, &p );
+ }
+ }
+ }
+ }
+
+ r.x = r.width = seed_pt.x;
+ r.y = r.height = seed_pt.y;
+
+ if( !mask_only )
+ {
+ s0 = new_val.val[0];
+ s1 = new_val.val[1];
+ s2 = new_val.val[2];
+
+ if( tmp != _img )
+ {
+ u0 = saturate_cast<uchar>(s0);
+ u1 = saturate_cast<uchar>(s1);
+ u2 = saturate_cast<uchar>(s2);
+
+ s0 = u0;
+ s1 = u1;
+ s2 = u2;
+ }
+ }
+ else
+ s0 = s1 = s2 = 0;
+
+ new_mask_val >>= 8;
+
+ for( i = 0; i < rows; i++ )
+ {
+ float* ptr = img + i*step;
+ ushort* mptr = m + i*mstep;
+ uchar* dmptr = _mask ? _mask->data.ptr + (i+1)*_mask->step + 1 : 0;
+ uchar* dptr = tmp != _img ? _img->data.ptr + i*_img->step : 0;
+ double area0 = area;
+
+ for( j = 0; j < cols; j++ )
+ {
+ if( mptr[j] > 255 )
+ {
+ if( dmptr )
+ dmptr[j] = (uchar)new_mask_val;
+ if( !mask_only )
+ {
+ if( cn == 1 )
+ {
+ if( dptr )
+ dptr[j] = (uchar)u0;
+ else
+ ptr[j] = (float)s0;
+ }
+ else
+ {
+ if( dptr )
+ {
+ dptr[j*3] = (uchar)u0;
+ dptr[j*3+1] = (uchar)u1;
+ dptr[j*3+2] = (uchar)u2;
+ }
+ else
+ {
+ ptr[j*3] = (float)s0;
+ ptr[j*3+1] = (float)s1;
+ ptr[j*3+2] = (float)s2;
+ }
+ }
+ }
+ else
+ {
+ if( cn == 1 )
+ s0 += ptr[j];
+ else
+ {
+ s0 += ptr[j*3];
+ s1 += ptr[j*3+1];
+ s2 += ptr[j*3+2];
+ }
+ }
+
+ area++;
+ if( r.x > j )
+ r.x = j;
+ if( r.width < j )
+ r.width = j;
+ }
+ }
+
+ if( area != area0 )
+ {
+ if( r.y > i )
+ r.y = i;
+ if( r.height < i )
+ r.height = i;
+ }
+ }
+
+_exit_:
+ cvReleaseMat( &mask );
+ if( tmp != _img )
+ cvReleaseMat( &tmp );
+
+ comp[0] = area;
+ comp[1] = r.x;
+ comp[2] = r.y;
+ comp[3] = r.width - r.x + 1;
+ comp[4] = r.height - r.y + 1;
+ if( mask_only )
+ {
+ double t = area ? 1./area : 0;
+ s0 *= t;
+ s1 *= t;
+ s2 *= t;
+ }
+ comp[5] = s0;
+ comp[6] = s1;
+ comp[7] = s2;
+ comp[8] = 0;
+}
+
+
+void CV_FloodFillTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ double* comp = test_mat[REF_OUTPUT][0].ptr<double>();
+ CvMat _input = test_mat[REF_INPUT_OUTPUT][0];
+ CvMat _mask = test_mat[REF_INPUT_OUTPUT][1];
+ cvTsFloodFill( &_input, seed_pt, new_val, l_diff, u_diff,
+ _mask.data.ptr ? &_mask : 0,
+ comp, connectivity, range_type,
+ new_mask_val, mask_only );
+ if(test_cpp)
+ comp[5] = comp[6] = comp[7] = comp[8] = 0;
+}
+
+TEST(Imgproc_FloodFill, accuracy) { CV_FloodFillTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+
+using namespace std;
+using namespace cv;
+
+class CV_GrabcutTest : public cvtest::BaseTest
+{
+public:
+ CV_GrabcutTest();
+ ~CV_GrabcutTest();
+protected:
+ bool verify(const Mat& mask, const Mat& exp);
+ void run(int);
+};
+
+CV_GrabcutTest::CV_GrabcutTest() {}
+CV_GrabcutTest::~CV_GrabcutTest() {}
+
+bool CV_GrabcutTest::verify(const Mat& mask, const Mat& exp)
+{
+ const float maxDiffRatio = 0.005f;
+ int expArea = countNonZero( exp );
+ int nonIntersectArea = countNonZero( mask != exp );
+
+ float curRatio = (float)nonIntersectArea / (float)expArea;
+ ts->printf( cvtest::TS::LOG, "nonIntersectArea/expArea = %f\n", curRatio );
+ return curRatio < maxDiffRatio;
+}
+
+void CV_GrabcutTest::run( int /* start_from */)
+{
+ cvtest::DefaultRngAuto defRng;
+
+ Mat img = imread(string(ts->get_data_path()) + "shared/airplane.jpg");
+ Mat mask_prob = imread(string(ts->get_data_path()) + "grabcut/mask_prob.png", 0);
+ Mat exp_mask1 = imread(string(ts->get_data_path()) + "grabcut/exp_mask1.png", 0);
+ Mat exp_mask2 = imread(string(ts->get_data_path()) + "grabcut/exp_mask2.png", 0);
+
+ if (img.empty() || (!mask_prob.empty() && img.size() != mask_prob.size()) ||
+ (!exp_mask1.empty() && img.size() != exp_mask1.size()) ||
+ (!exp_mask2.empty() && img.size() != exp_mask2.size()) )
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISSING_TEST_DATA);
+ return;
+ }
+
+ Rect rect(Point(24, 126), Point(483, 294));
+ Mat exp_bgdModel, exp_fgdModel;
+
+ Mat mask;
+ mask = Scalar(0);
+ Mat bgdModel, fgdModel;
+ grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_RECT );
+ grabCut( img, mask, rect, bgdModel, fgdModel, 2, GC_EVAL );
+
+ // Multiply images by 255 for more visuality of test data.
+ if( mask_prob.empty() )
+ {
+ mask.copyTo( mask_prob );
+ imwrite(string(ts->get_data_path()) + "grabcut/mask_prob.png", mask_prob);
+ }
+ if( exp_mask1.empty() )
+ {
+ exp_mask1 = (mask & 1) * 255;
+ imwrite(string(ts->get_data_path()) + "grabcut/exp_mask1.png", exp_mask1);
+ }
+
+ if (!verify((mask & 1) * 255, exp_mask1))
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return;
+ }
+
+ mask = mask_prob;
+ bgdModel.release();
+ fgdModel.release();
+ rect = Rect();
+ grabCut( img, mask, rect, bgdModel, fgdModel, 0, GC_INIT_WITH_MASK );
+ grabCut( img, mask, rect, bgdModel, fgdModel, 1, GC_EVAL );
+
+ if( exp_mask2.empty() )
+ {
+ exp_mask2 = (mask & 1) * 255;
+ imwrite(string(ts->get_data_path()) + "grabcut/exp_mask2.png", exp_mask2);
+ }
+
+ if (!verify((mask & 1) * 255, exp_mask2))
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return;
+ }
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Imgproc_GrabCut, regression) { CV_GrabcutTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_BaseHistTest : public cvtest::BaseTest
+{
+public:
+ enum { MAX_HIST = 12 };
+
+ CV_BaseHistTest();
+ ~CV_BaseHistTest();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ virtual void init_hist( int test_case_idx, int i );
+
+ virtual void get_hist_params( int test_case_idx );
+ virtual float** get_hist_ranges( int test_case_idx );
+
+ int max_log_size;
+ int max_cdims;
+ int cdims;
+ int dims[CV_MAX_DIM];
+ int total_size;
+ int hist_type;
+ int hist_count;
+ int uniform;
+ int gen_random_hist;
+ double gen_hist_max_val, gen_hist_sparse_nz_ratio;
+
+ int init_ranges;
+ int img_type;
+ int img_max_log_size;
+ double low, high, range_delta;
+ CvSize img_size;
+
+ vector<CvHistogram*> hist;
+ vector<float> _ranges;
+ vector<float*> ranges;
+ bool test_cpp;
+};
+
+
+CV_BaseHistTest::CV_BaseHistTest()
+{
+ test_case_count = 100;
+ max_log_size = 20;
+ img_max_log_size = 8;
+ max_cdims = 6;
+ hist_count = 1;
+ init_ranges = 0;
+ gen_random_hist = 0;
+ gen_hist_max_val = 100;
+
+ test_cpp = false;
+}
+
+
+CV_BaseHistTest::~CV_BaseHistTest()
+{
+ clear();
+}
+
+
+void CV_BaseHistTest::clear()
+{
+ cvtest::BaseTest::clear();
+ for( size_t i = 0; i < hist.size(); i++ )
+ cvReleaseHist( &hist[i] );
+}
+
+
+int CV_BaseHistTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ test_case_count = cvReadInt( find_param( fs, "struct_count" ), test_case_count );
+ max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
+ max_log_size = cvtest::clipInt( max_log_size, 1, 20 );
+ img_max_log_size = cvReadInt( find_param( fs, "max_log_array_size" ), img_max_log_size );
+ img_max_log_size = cvtest::clipInt( img_max_log_size, 1, 9 );
+
+ max_cdims = cvReadInt( find_param( fs, "max_cdims" ), max_cdims );
+ max_cdims = cvtest::clipInt( max_cdims, 1, 6 );
+
+ return 0;
+}
+
+
+void CV_BaseHistTest::get_hist_params( int /*test_case_idx*/ )
+{
+ RNG& rng = ts->get_rng();
+ int i, max_dim_size, max_ni_dim_size = 31;
+ double hist_size;
+
+ cdims = cvtest::randInt(rng) % max_cdims + 1;
+ hist_size = exp(cvtest::randReal(rng)*max_log_size*CV_LOG2);
+ max_dim_size = cvRound(pow(hist_size,1./cdims));
+ total_size = 1;
+ uniform = cvtest::randInt(rng) % 2;
+ hist_type = cvtest::randInt(rng) % 2 ? CV_HIST_SPARSE : CV_HIST_ARRAY;
+
+ for( i = 0; i < cdims; i++ )
+ {
+ dims[i] = cvtest::randInt(rng) % (max_dim_size + 2) + 2;
+ if( !uniform )
+ dims[i] = MIN(dims[i], max_ni_dim_size);
+ total_size *= dims[i];
+ }
+
+ img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
+ img_size.width = cvRound( exp(cvtest::randReal(rng) * img_max_log_size * CV_LOG2) );
+ img_size.height = cvRound( exp(cvtest::randReal(rng) * img_max_log_size * CV_LOG2) );
+
+ if( img_type < CV_32F )
+ {
+ low = cvtest::getMinVal(img_type);
+ high = cvtest::getMaxVal(img_type);
+ }
+ else
+ {
+ high = 1000;
+ low = -high;
+ }
+
+ range_delta = (cvtest::randInt(rng) % 2)*(high-low)*0.05;
+}
+
+
+float** CV_BaseHistTest::get_hist_ranges( int /*test_case_idx*/ )
+{
+ double _low = low + range_delta, _high = high - range_delta;
+
+ if( !init_ranges )
+ return 0;
+
+ ranges.resize(cdims);
+
+ if( uniform )
+ {
+ _ranges.resize(cdims*2);
+ for( int i = 0; i < cdims; i++ )
+ {
+ _ranges[i*2] = (float)_low;
+ _ranges[i*2+1] = (float)_high;
+ ranges[i] = &_ranges[i*2];
+ }
+ }
+ else
+ {
+ int i, dims_sum = 0, ofs = 0;
+ for( i = 0; i < cdims; i++ )
+ dims_sum += dims[i] + 1;
+ _ranges.resize(dims_sum);
+
+ for( i = 0; i < cdims; i++ )
+ {
+ int j, n = dims[i];
+ // generate logarithmic scale
+ double delta, q, val;
+ for( j = 0; j < 10; j++ )
+ {
+ q = 1. + (j+1)*0.1;
+ if( (pow(q,(double)n)-1)/(q-1.) >= _high-_low )
+ break;
+ }
+
+ if( j == 0 )
+ {
+ delta = (_high-_low)/n;
+ q = 1.;
+ }
+ else
+ {
+ q = 1 + j*0.1;
+ delta = cvFloor((_high-_low)*(q-1)/(pow(q,(double)n) - 1));
+ delta = MAX(delta, 1.);
+ }
+ val = _low;
+
+ for( j = 0; j <= n; j++ )
+ {
+ _ranges[j+ofs] = (float)MIN(val,_high);
+ val += delta;
+ delta *= q;
+ }
+ ranges[i] = &_ranges[ofs];
+ ofs += n + 1;
+ }
+ }
+
+ return &ranges[0];
+}
+
+
+void CV_BaseHistTest::init_hist( int /*test_case_idx*/, int hist_i )
+{
+ if( gen_random_hist )
+ {
+ RNG& rng = ts->get_rng();
+
+ if( hist_type == CV_HIST_ARRAY )
+ {
+ Mat h = cvarrToMat(hist[hist_i]->bins);
+ cvtest::randUni(rng, h, Scalar::all(0), Scalar::all(gen_hist_max_val) );
+ }
+ else
+ {
+ CvArr* arr = hist[hist_i]->bins;
+ int i, j, total_size = 1, nz_count;
+ int idx[CV_MAX_DIM];
+ for( i = 0; i < cdims; i++ )
+ total_size *= dims[i];
+
+ nz_count = cvtest::randInt(rng) % MAX( total_size/4, 100 );
+ nz_count = MIN( nz_count, total_size );
+
+ // a zero number of non-zero elements should be allowed
+ for( i = 0; i < nz_count; i++ )
+ {
+ for( j = 0; j < cdims; j++ )
+ idx[j] = cvtest::randInt(rng) % dims[j];
+ cvSetRealND(arr, idx, cvtest::randReal(rng)*gen_hist_max_val);
+ }
+ }
+ }
+}
+
+
+int CV_BaseHistTest::prepare_test_case( int test_case_idx )
+{
+ int i;
+ float** r;
+
+ clear();
+
+ cvtest::BaseTest::prepare_test_case( test_case_idx );
+ get_hist_params( test_case_idx );
+ r = get_hist_ranges( test_case_idx );
+ hist.resize(hist_count);
+
+ for( i = 0; i < hist_count; i++ )
+ {
+ hist[i] = cvCreateHist( cdims, dims, hist_type, r, uniform );
+ init_hist( test_case_idx, i );
+ }
+ test_cpp = (cvtest::randInt(ts->get_rng()) % 2) != 0;
+
+ return 1;
+}
+
+
+void CV_BaseHistTest::run_func(void)
+{
+}
+
+
+int CV_BaseHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ return 0;
+}
+
+
+////////////// testing operation for reading/writing individual histogram bins //////////////
+
+class CV_QueryHistTest : public CV_BaseHistTest
+{
+public:
+ CV_QueryHistTest();
+ ~CV_QueryHistTest();
+ void clear();
+
+protected:
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void init_hist( int test_case_idx, int i );
+
+ CvMat* indices;
+ CvMat* values;
+ CvMat* values0;
+};
+
+
+
+CV_QueryHistTest::CV_QueryHistTest()
+{
+ hist_count = 1;
+ indices = 0;
+ values = 0;
+ values0 = 0;
+}
+
+
+CV_QueryHistTest::~CV_QueryHistTest()
+{
+ clear();
+}
+
+
+void CV_QueryHistTest::clear()
+{
+ cvReleaseMat( &indices );
+ cvReleaseMat( &values );
+ cvReleaseMat( &values0 );
+ CV_BaseHistTest::clear();
+}
+
+
+void CV_QueryHistTest::init_hist( int /*test_case_idx*/, int i )
+{
+ if( hist_type == CV_HIST_ARRAY )
+ cvZero( hist[i]->bins );
+}
+
+
+int CV_QueryHistTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ int i, j, iters;
+ float default_value = 0.f;
+ RNG& rng = ts->get_rng();
+ CvMat* bit_mask = 0;
+ int* idx;
+
+ iters = (cvtest::randInt(rng) % MAX(total_size/10,100)) + 1;
+ iters = MIN( iters, total_size*9/10 + 1 );
+
+ indices = cvCreateMat( 1, iters*cdims, CV_32S );
+ values = cvCreateMat( 1, iters, CV_32F );
+ values0 = cvCreateMat( 1, iters, CV_32F );
+ idx = indices->data.i;
+
+ //printf( "total_size = %d, cdims = %d, iters = %d\n", total_size, cdims, iters );
+
+ bit_mask = cvCreateMat( 1, (total_size + 7)/8, CV_8U );
+ cvZero( bit_mask );
+
+ #define GET_BIT(n) (bit_mask->data.ptr[(n)/8] & (1 << ((n)&7)))
+ #define SET_BIT(n) bit_mask->data.ptr[(n)/8] |= (1 << ((n)&7))
+
+ // set random histogram bins' values to the linear indices of the bins
+ for( i = 0; i < iters; i++ )
+ {
+ int lin_idx = 0;
+ for( j = 0; j < cdims; j++ )
+ {
+ int t = cvtest::randInt(rng) % dims[j];
+ idx[i*cdims + j] = t;
+ lin_idx = lin_idx*dims[j] + t;
+ }
+
+ if( cvtest::randInt(rng) % 8 || GET_BIT(lin_idx) )
+ {
+ values0->data.fl[i] = (float)(lin_idx+1);
+ SET_BIT(lin_idx);
+ }
+ else
+ // some histogram bins will not be initialized intentionally,
+ // they should be equal to the default value
+ values0->data.fl[i] = default_value;
+ }
+
+ // do the second pass to make values0 consistent with bit_mask
+ for( i = 0; i < iters; i++ )
+ {
+ int lin_idx = 0;
+ for( j = 0; j < cdims; j++ )
+ lin_idx = lin_idx*dims[j] + idx[i*cdims + j];
+
+ if( GET_BIT(lin_idx) )
+ values0->data.fl[i] = (float)(lin_idx+1);
+ }
+
+ cvReleaseMat( &bit_mask );
+ }
+
+ return code;
+}
+
+
+void CV_QueryHistTest::run_func(void)
+{
+ int i, iters = values->cols;
+ CvArr* h = hist[0]->bins;
+ const int* idx = indices->data.i;
+ float* val = values->data.fl;
+ float default_value = 0.f;
+
+ // stage 1: write bins
+ if( cdims == 1 )
+ for( i = 0; i < iters; i++ )
+ {
+ float v0 = values0->data.fl[i];
+ if( fabs(v0 - default_value) < FLT_EPSILON )
+ continue;
+ if( !(i % 2) )
+ {
+ if( !(i % 4) )
+ cvSetReal1D( h, idx[i], v0 );
+ else
+ *(float*)cvPtr1D( h, idx[i] ) = v0;
+ }
+ else
+ cvSetRealND( h, idx+i, v0 );
+ }
+ else if( cdims == 2 )
+ for( i = 0; i < iters; i++ )
+ {
+ float v0 = values0->data.fl[i];
+ if( fabs(v0 - default_value) < FLT_EPSILON )
+ continue;
+ if( !(i % 2) )
+ {
+ if( !(i % 4) )
+ cvSetReal2D( h, idx[i*2], idx[i*2+1], v0 );
+ else
+ *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] ) = v0;
+ }
+ else
+ cvSetRealND( h, idx+i*2, v0 );
+ }
+ else if( cdims == 3 )
+ for( i = 0; i < iters; i++ )
+ {
+ float v0 = values0->data.fl[i];
+ if( fabs(v0 - default_value) < FLT_EPSILON )
+ continue;
+ if( !(i % 2) )
+ {
+ if( !(i % 4) )
+ cvSetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2], v0 );
+ else
+ *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] ) = v0;
+ }
+ else
+ cvSetRealND( h, idx+i*3, v0 );
+ }
+ else
+ for( i = 0; i < iters; i++ )
+ {
+ float v0 = values0->data.fl[i];
+ if( fabs(v0 - default_value) < FLT_EPSILON )
+ continue;
+ if( !(i % 2) )
+ cvSetRealND( h, idx+i*cdims, v0 );
+ else
+ *(float*)cvPtrND( h, idx+i*cdims ) = v0;
+ }
+
+ // stage 2: read bins
+ if( cdims == 1 )
+ for( i = 0; i < iters; i++ )
+ {
+ if( !(i % 2) )
+ val[i] = *(float*)cvPtr1D( h, idx[i] );
+ else
+ val[i] = (float)cvGetReal1D( h, idx[i] );
+ }
+ else if( cdims == 2 )
+ for( i = 0; i < iters; i++ )
+ {
+ if( !(i % 2) )
+ val[i] = *(float*)cvPtr2D( h, idx[i*2], idx[i*2+1] );
+ else
+ val[i] = (float)cvGetReal2D( h, idx[i*2], idx[i*2+1] );
+ }
+ else if( cdims == 3 )
+ for( i = 0; i < iters; i++ )
+ {
+ if( !(i % 2) )
+ val[i] = *(float*)cvPtr3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
+ else
+ val[i] = (float)cvGetReal3D( h, idx[i*3], idx[i*3+1], idx[i*3+2] );
+ }
+ else
+ for( i = 0; i < iters; i++ )
+ {
+ if( !(i % 2) )
+ val[i] = *(float*)cvPtrND( h, idx+i*cdims );
+ else
+ val[i] = (float)cvGetRealND( h, idx+i*cdims );
+ }
+}
+
+
+int CV_QueryHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ int i, j, iters = values->cols;
+
+ for( i = 0; i < iters; i++ )
+ {
+ float v = values->data.fl[i], v0 = values0->data.fl[i];
+
+ if( cvIsNaN(v) || cvIsInf(v) )
+ {
+ ts->printf( cvtest::TS::LOG, "The bin #%d has invalid value\n", i );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ else if( fabs(v - v0) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "The bin #%d = %g, while it should be %g\n", i, v, v0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ if( code < 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "The bin index = (" );
+ for( j = 0; j < cdims; j++ )
+ ts->printf( cvtest::TS::LOG, "%d%s", indices->data.i[i*cdims + j],
+ j < cdims-1 ? ", " : ")\n" );
+ break;
+ }
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+////////////// cvGetMinMaxHistValue //////////////
+
+class CV_MinMaxHistTest : public CV_BaseHistTest
+{
+public:
+ CV_MinMaxHistTest();
+
+protected:
+ void run_func(void);
+ void init_hist(int, int);
+ int validate_test_results( int test_case_idx );
+ int min_idx[CV_MAX_DIM], max_idx[CV_MAX_DIM];
+ float min_val, max_val;
+ int min_idx0[CV_MAX_DIM], max_idx0[CV_MAX_DIM];
+ float min_val0, max_val0;
+};
+
+
+
+CV_MinMaxHistTest::CV_MinMaxHistTest()
+{
+ hist_count = 1;
+ gen_random_hist = 1;
+}
+
+
+void CV_MinMaxHistTest::init_hist(int test_case_idx, int hist_i)
+{
+ int i, eq = 1;
+ RNG& rng = ts->get_rng();
+ CV_BaseHistTest::init_hist( test_case_idx, hist_i );
+
+ for(;;)
+ {
+ for( i = 0; i < cdims; i++ )
+ {
+ min_idx0[i] = cvtest::randInt(rng) % dims[i];
+ max_idx0[i] = cvtest::randInt(rng) % dims[i];
+ eq &= min_idx0[i] == max_idx0[i];
+ }
+ if( !eq || total_size == 1 )
+ break;
+ }
+
+ min_val0 = (float)(-cvtest::randReal(rng)*10 - FLT_EPSILON);
+ max_val0 = (float)(cvtest::randReal(rng)*10 + FLT_EPSILON + gen_hist_max_val);
+
+ if( total_size == 1 )
+ min_val0 = max_val0;
+
+ cvSetRealND( hist[0]->bins, min_idx0, min_val0 );
+ cvSetRealND( hist[0]->bins, max_idx0, max_val0 );
+}
+
+
+void CV_MinMaxHistTest::run_func(void)
+{
+ if( hist_type != CV_HIST_ARRAY && test_cpp )
+ {
+ cv::SparseMat h((CvSparseMat*)hist[0]->bins);
+ double _min_val = 0, _max_val = 0;
+ cv::minMaxLoc(h, &_min_val, &_max_val, min_idx, max_idx );
+ min_val = (float)_min_val;
+ max_val = (float)_max_val;
+ }
+ else
+ cvGetMinMaxHistValue( hist[0], &min_val, &max_val, min_idx, max_idx );
+}
+
+
+int CV_MinMaxHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+
+ if( cvIsNaN(min_val) || cvIsInf(min_val) ||
+ cvIsNaN(max_val) || cvIsInf(max_val) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The extrema histogram bin values are invalid (min = %g, max = %g)\n", min_val, max_val );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ else if( fabs(min_val - min_val0) > FLT_EPSILON ||
+ fabs(max_val - max_val0) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The extrema histogram bin values are incorrect: (min = %g, should be = %g), (max = %g, should be = %g)\n",
+ min_val, min_val0, max_val, max_val0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ else
+ {
+ int i;
+ for( i = 0; i < cdims; i++ )
+ {
+ if( min_idx[i] != min_idx0[i] || max_idx[i] != max_idx0[i] )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The %d-th coordinates of extrema histogram bin values are incorrect: "
+ "(min = %d, should be = %d), (max = %d, should be = %d)\n",
+ i, min_idx[i], min_idx0[i], max_idx[i], max_idx0[i] );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ }
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+////////////// cvNormalizeHist //////////////
+
+class CV_NormHistTest : public CV_BaseHistTest
+{
+public:
+ CV_NormHistTest();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ double factor;
+};
+
+
+
+CV_NormHistTest::CV_NormHistTest()
+{
+ hist_count = 1;
+ gen_random_hist = 1;
+ factor = 0;
+}
+
+
+int CV_NormHistTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ RNG& rng = ts->get_rng();
+ factor = cvtest::randReal(rng)*10 + 0.1;
+ if( hist_type == CV_HIST_SPARSE &&
+ ((CvSparseMat*)hist[0]->bins)->heap->active_count == 0 )
+ factor = 0;
+ }
+
+ return code;
+}
+
+
+void CV_NormHistTest::run_func(void)
+{
+ if( hist_type != CV_HIST_ARRAY && test_cpp )
+ {
+ cv::SparseMat h((CvSparseMat*)hist[0]->bins);
+ cv::normalize(h, h, factor, CV_L1);
+ cvReleaseSparseMat((CvSparseMat**)&hist[0]->bins);
+ hist[0]->bins = (CvSparseMat*)h;
+ }
+ else
+ cvNormalizeHist( hist[0], factor );
+}
+
+
+int CV_NormHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ double sum = 0;
+
+ if( hist_type == CV_HIST_ARRAY )
+ {
+ int i;
+ const float* ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
+
+ for( i = 0; i < total_size; i++ )
+ sum += ptr[i];
+ }
+ else
+ {
+ CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode *node;
+
+ for( node = cvInitSparseMatIterator( sparse, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ))
+ {
+ sum += *(float*)CV_NODE_VAL(sparse,node);
+ }
+ }
+
+ if( cvIsNaN(sum) || cvIsInf(sum) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The normalized histogram has invalid sum =%g\n", sum );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ else if( fabs(sum - factor) > FLT_EPSILON*10*fabs(factor) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The normalized histogram has incorrect sum =%g, while it should be =%g\n", sum, factor );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+////////////// cvThreshHist //////////////
+
+class CV_ThreshHistTest : public CV_BaseHistTest
+{
+public:
+ CV_ThreshHistTest();
+ ~CV_ThreshHistTest();
+ void clear();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ CvMat* indices;
+ CvMat* values;
+ int orig_nz_count;
+
+ double threshold;
+};
+
+
+
+CV_ThreshHistTest::CV_ThreshHistTest()
+{
+ hist_count = 1;
+ gen_random_hist = 1;
+ threshold = 0;
+ indices = values = 0;
+}
+
+
+CV_ThreshHistTest::~CV_ThreshHistTest()
+{
+ clear();
+}
+
+
+void CV_ThreshHistTest::clear()
+{
+ cvReleaseMat( &indices );
+ cvReleaseMat( &values );
+ CV_BaseHistTest::clear();
+}
+
+
+int CV_ThreshHistTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ RNG& rng = ts->get_rng();
+ threshold = cvtest::randReal(rng)*gen_hist_max_val;
+
+ if( hist_type == CV_HIST_ARRAY )
+ {
+ orig_nz_count = total_size;
+
+ values = cvCreateMat( 1, total_size, CV_32F );
+ memcpy( values->data.fl, cvPtr1D( hist[0]->bins, 0 ), total_size*sizeof(float) );
+ }
+ else
+ {
+ CvSparseMat* sparse = (CvSparseMat*)hist[0]->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+ int i, k;
+
+ orig_nz_count = sparse->heap->active_count;
+
+ values = cvCreateMat( 1, orig_nz_count+1, CV_32F );
+ indices = cvCreateMat( 1, (orig_nz_count+1)*cdims, CV_32S );
+
+ for( node = cvInitSparseMatIterator( sparse, &iterator ), i = 0;
+ node != 0; node = cvGetNextSparseNode( &iterator ), i++ )
+ {
+ const int* idx = CV_NODE_IDX(sparse,node);
+
+ OPENCV_ASSERT( i < orig_nz_count, "CV_ThreshHistTest::prepare_test_case", "Buffer overflow" );
+
+ values->data.fl[i] = *(float*)CV_NODE_VAL(sparse,node);
+ for( k = 0; k < cdims; k++ )
+ indices->data.i[i*cdims + k] = idx[k];
+ }
+
+ OPENCV_ASSERT( i == orig_nz_count, "Unmatched buffer size",
+ "CV_ThreshHistTest::prepare_test_case" );
+ }
+ }
+
+ return code;
+}
+
+
+void CV_ThreshHistTest::run_func(void)
+{
+ cvThreshHist( hist[0], threshold );
+}
+
+
+int CV_ThreshHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ int i;
+ float* ptr0 = values->data.fl;
+ float* ptr = 0;
+ CvSparseMat* sparse = 0;
+
+ if( hist_type == CV_HIST_ARRAY )
+ ptr = (float*)cvPtr1D( hist[0]->bins, 0 );
+ else
+ sparse = (CvSparseMat*)hist[0]->bins;
+
+ if( code > 0 )
+ {
+ for( i = 0; i < orig_nz_count; i++ )
+ {
+ float v0 = ptr0[i], v;
+
+ if( hist_type == CV_HIST_ARRAY )
+ v = ptr[i];
+ else
+ {
+ v = (float)cvGetRealND( sparse, indices->data.i + i*cdims );
+ cvClearND( sparse, indices->data.i + i*cdims );
+ }
+
+ if( v0 <= threshold ) v0 = 0.f;
+ if( cvIsNaN(v) || cvIsInf(v) )
+ {
+ ts->printf( cvtest::TS::LOG, "The %d-th bin is invalid (=%g)\n", i, v );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+ else if( fabs(v0 - v) > FLT_EPSILON*10*fabs(v0) )
+ {
+ ts->printf( cvtest::TS::LOG, "The %d-th bin is incorrect (=%g, should be =%g)\n", i, v, v0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ break;
+ }
+ }
+ }
+
+ if( code > 0 && hist_type == CV_HIST_SPARSE )
+ {
+ if( sparse->heap->active_count > 0 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "There some extra histogram bins in the sparse histogram after the thresholding\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+////////////// cvCompareHist //////////////
+
+class CV_CompareHistTest : public CV_BaseHistTest
+{
+public:
+ enum { MAX_METHOD = 4 };
+
+ CV_CompareHistTest();
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ double result[MAX_METHOD+1];
+};
+
+
+
+CV_CompareHistTest::CV_CompareHistTest()
+{
+ hist_count = 2;
+ gen_random_hist = 1;
+}
+
+
+int CV_CompareHistTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ return code;
+}
+
+
+void CV_CompareHistTest::run_func(void)
+{
+ int k;
+ if( hist_type != CV_HIST_ARRAY && test_cpp )
+ {
+ cv::SparseMat h0((CvSparseMat*)hist[0]->bins);
+ cv::SparseMat h1((CvSparseMat*)hist[1]->bins);
+ for( k = 0; k < MAX_METHOD; k++ )
+ result[k] = cv::compareHist(h0, h1, k);
+ }
+ else
+ for( k = 0; k < MAX_METHOD; k++ )
+ result[k] = cvCompareHist( hist[0], hist[1], k );
+}
+
+
+int CV_CompareHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ int i;
+ double result0[MAX_METHOD+1];
+ double s0 = 0, s1 = 0, sq0 = 0, sq1 = 0, t;
+
+ for( i = 0; i < MAX_METHOD; i++ )
+ result0[i] = 0;
+
+ if( hist_type == CV_HIST_ARRAY )
+ {
+ float* ptr0 = (float*)cvPtr1D( hist[0]->bins, 0 );
+ float* ptr1 = (float*)cvPtr1D( hist[1]->bins, 0 );
+
+ for( i = 0; i < total_size; i++ )
+ {
+ double v0 = ptr0[i], v1 = ptr1[i];
+ result0[CV_COMP_CORREL] += v0*v1;
+ result0[CV_COMP_INTERSECT] += MIN(v0,v1);
+ if( fabs(v0 + v1) > DBL_EPSILON )
+ result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/(v0 + v1);
+ s0 += v0;
+ s1 += v1;
+ sq0 += v0*v0;
+ sq1 += v1*v1;
+ result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
+ }
+ }
+ else
+ {
+ CvSparseMat* sparse0 = (CvSparseMat*)hist[0]->bins;
+ CvSparseMat* sparse1 = (CvSparseMat*)hist[1]->bins;
+ CvSparseMatIterator iterator;
+ CvSparseNode* node;
+
+ for( node = cvInitSparseMatIterator( sparse0, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ) )
+ {
+ const int* idx = CV_NODE_IDX(sparse0, node);
+ double v0 = *(float*)CV_NODE_VAL(sparse0, node);
+ double v1 = (float)cvGetRealND(sparse1, idx);
+
+ result0[CV_COMP_CORREL] += v0*v1;
+ result0[CV_COMP_INTERSECT] += MIN(v0,v1);
+ if( fabs(v0 + v1) > DBL_EPSILON )
+ result0[CV_COMP_CHISQR] += (v0 - v1)*(v0 - v1)/(v0 + v1);
+ s0 += v0;
+ sq0 += v0*v0;
+ result0[CV_COMP_BHATTACHARYYA] += sqrt(v0*v1);
+ }
+
+ for( node = cvInitSparseMatIterator( sparse1, &iterator );
+ node != 0; node = cvGetNextSparseNode( &iterator ) )
+ {
+ const int* idx = CV_NODE_IDX(sparse1, node);
+ double v1 = *(float*)CV_NODE_VAL(sparse1, node);
+ double v0 = (float)cvGetRealND(sparse0, idx);
+
+ if( fabs(v0) < DBL_EPSILON )
+ result0[CV_COMP_CHISQR] += v1;
+ s1 += v1;
+ sq1 += v1*v1;
+ }
+ }
+
+ t = (sq0 - s0*s0/total_size)*(sq1 - s1*s1/total_size);
+ result0[CV_COMP_CORREL] = fabs(t) > DBL_EPSILON ?
+ (result0[CV_COMP_CORREL] - s0*s1/total_size)/sqrt(t) : 1;
+
+ s1 *= s0;
+ s0 = result0[CV_COMP_BHATTACHARYYA];
+ s0 = 1. - s0*(s1 > FLT_EPSILON ? 1./sqrt(s1) : 1.);
+ result0[CV_COMP_BHATTACHARYYA] = sqrt(MAX(s0,0.));
+
+ for( i = 0; i < MAX_METHOD; i++ )
+ {
+ double v = result[i], v0 = result0[i];
+ const char* method_name =
+ i == CV_COMP_CHISQR ? "Chi-Square" :
+ i == CV_COMP_CORREL ? "Correlation" :
+ i == CV_COMP_INTERSECT ? "Intersection" :
+ i == CV_COMP_BHATTACHARYYA ? "Bhattacharyya" : "Unknown";
+
+ if( cvIsNaN(v) || cvIsInf(v) )
+ {
+ ts->printf( cvtest::TS::LOG, "The comparison result using the method #%d (%s) is invalid (=%g)\n",
+ i, method_name, v );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+ else if( fabs(v0 - v) > FLT_EPSILON*10*MAX(fabs(v0),0.1) )
+ {
+ ts->printf( cvtest::TS::LOG, "The comparison result using the method #%d (%s)\n\tis inaccurate (=%g, should be =%g)\n",
+ i, method_name, v, v0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ break;
+ }
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+////////////// cvCalcHist //////////////
+
+class CV_CalcHistTest : public CV_BaseHistTest
+{
+public:
+ CV_CalcHistTest();
+ ~CV_CalcHistTest();
+ void clear();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ IplImage* images[CV_MAX_DIM+1];
+ int channels[CV_MAX_DIM+1];
+};
+
+
+
+CV_CalcHistTest::CV_CalcHistTest()
+{
+ int i;
+
+ hist_count = 2;
+ gen_random_hist = 0;
+ init_ranges = 1;
+
+ for( i = 0; i <= CV_MAX_DIM; i++ )
+ {
+ images[i] = 0;
+ channels[i] = 0;
+ }
+}
+
+
+CV_CalcHistTest::~CV_CalcHistTest()
+{
+ clear();
+}
+
+
+void CV_CalcHistTest::clear()
+{
+ int i;
+
+ for( i = 0; i <= CV_MAX_DIM; i++ )
+ cvReleaseImage( &images[i] );
+
+ CV_BaseHistTest::clear();
+}
+
+
+int CV_CalcHistTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ RNG& rng = ts->get_rng();
+ int i;
+
+ for( i = 0; i <= CV_MAX_DIM; i++ )
+ {
+ if( i < cdims )
+ {
+ int nch = 1; //cvtest::randInt(rng) % 3 + 1;
+ images[i] = cvCreateImage( img_size,
+ img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
+ channels[i] = cvtest::randInt(rng) % nch;
+ Mat images_i = cvarrToMat(images[i]);
+
+ cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) );
+ }
+ else if( i == CV_MAX_DIM && cvtest::randInt(rng) % 2 )
+ {
+ // create mask
+ images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );
+ Mat images_i = cvarrToMat(images[i]);
+
+ // make ~25% pixels in the mask non-zero
+ cvtest::randUni( rng, images_i, Scalar::all(-2), Scalar::all(2) );
+ }
+ }
+ }
+
+ return code;
+}
+
+
+void CV_CalcHistTest::run_func(void)
+{
+ cvCalcHist( images, hist[0], 0, images[CV_MAX_DIM] );
+}
+
+
+static void
+cvTsCalcHist( IplImage** _images, CvHistogram* hist, IplImage* _mask, int* channels )
+{
+ int x, y, k, cdims;
+ union
+ {
+ float* fl;
+ uchar* ptr;
+ }
+ plane[CV_MAX_DIM];
+ int nch[CV_MAX_DIM];
+ int dims[CV_MAX_DIM];
+ int uniform = CV_IS_UNIFORM_HIST(hist);
+ CvSize img_size = cvGetSize(_images[0]);
+ CvMat images[CV_MAX_DIM], mask = cvMat(1,1,CV_8U);
+ int img_depth = _images[0]->depth;
+
+ cdims = cvGetDims( hist->bins, dims );
+
+ cvZero( hist->bins );
+
+ for( k = 0; k < cdims; k++ )
+ {
+ cvGetMat( _images[k], &images[k] );
+ nch[k] = _images[k]->nChannels;
+ }
+
+ if( _mask )
+ cvGetMat( _mask, &mask );
+
+ for( y = 0; y < img_size.height; y++ )
+ {
+ const uchar* mptr = _mask ? &CV_MAT_ELEM(mask, uchar, y, 0 ) : 0;
+
+ if( img_depth == IPL_DEPTH_8U )
+ for( k = 0; k < cdims; k++ )
+ plane[k].ptr = &CV_MAT_ELEM(images[k], uchar, y, 0 ) + channels[k];
+ else
+ for( k = 0; k < cdims; k++ )
+ plane[k].fl = &CV_MAT_ELEM(images[k], float, y, 0 ) + channels[k];
+
+ for( x = 0; x < img_size.width; x++ )
+ {
+ float val[CV_MAX_DIM];
+ int idx[CV_MAX_DIM];
+
+ if( mptr && !mptr[x] )
+ continue;
+ if( img_depth == IPL_DEPTH_8U )
+ for( k = 0; k < cdims; k++ )
+ val[k] = plane[k].ptr[x*nch[k]];
+ else
+ for( k = 0; k < cdims; k++ )
+ val[k] = plane[k].fl[x*nch[k]];
+
+ idx[cdims-1] = -1;
+
+ if( uniform )
+ {
+ for( k = 0; k < cdims; k++ )
+ {
+ double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1];
+ idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo));
+ if( idx[k] < 0 || idx[k] >= dims[k] )
+ break;
+ }
+ }
+ else
+ {
+ for( k = 0; k < cdims; k++ )
+ {
+ float v = val[k];
+ float* t = hist->thresh2[k];
+ int j, n = dims[k];
+
+ for( j = 0; j <= n; j++ )
+ if( v < t[j] )
+ break;
+ if( j <= 0 || j > n )
+ break;
+ idx[k] = j-1;
+ }
+ }
+
+ if( k < cdims )
+ continue;
+
+ (*(float*)cvPtrND( hist->bins, idx ))++;
+ }
+ }
+}
+
+
+int CV_CalcHistTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ double diff;
+ cvTsCalcHist( images, hist[1], images[CV_MAX_DIM], channels );
+ diff = cvCompareHist( hist[0], hist[1], CV_COMP_CHISQR );
+ if( diff > DBL_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "The histogram does not match to the reference one\n" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+CV_CalcHistTest hist_calc_test;
+
+
+
+////////////// cvCalcBackProject //////////////
+
+class CV_CalcBackProjectTest : public CV_BaseHistTest
+{
+public:
+ CV_CalcBackProjectTest();
+ ~CV_CalcBackProjectTest();
+ void clear();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ IplImage* images[CV_MAX_DIM+3];
+ int channels[CV_MAX_DIM+3];
+};
+
+
+
+CV_CalcBackProjectTest::CV_CalcBackProjectTest()
+{
+ int i;
+
+ hist_count = 1;
+ gen_random_hist = 0;
+ init_ranges = 1;
+
+ for( i = 0; i < CV_MAX_DIM+3; i++ )
+ {
+ images[i] = 0;
+ channels[i] = 0;
+ }
+}
+
+
+CV_CalcBackProjectTest::~CV_CalcBackProjectTest()
+{
+ clear();
+}
+
+
+void CV_CalcBackProjectTest::clear()
+{
+ int i;
+
+ for( i = 0; i < CV_MAX_DIM+3; i++ )
+ cvReleaseImage( &images[i] );
+
+ CV_BaseHistTest::clear();
+}
+
+
+int CV_CalcBackProjectTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ RNG& rng = ts->get_rng();
+ int i, j, n, img_len = img_size.width*img_size.height;
+
+ for( i = 0; i < CV_MAX_DIM + 3; i++ )
+ {
+ if( i < cdims )
+ {
+ int nch = 1; //cvtest::randInt(rng) % 3 + 1;
+ images[i] = cvCreateImage( img_size,
+ img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
+ channels[i] = cvtest::randInt(rng) % nch;
+
+ Mat images_i = cvarrToMat(images[i]);
+ cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) );
+ }
+ else if( i == CV_MAX_DIM && cvtest::randInt(rng) % 2 )
+ {
+ // create mask
+ images[i] = cvCreateImage( img_size, IPL_DEPTH_8U, 1 );
+ Mat images_i = cvarrToMat(images[i]);
+ // make ~25% pixels in the mask non-zero
+ cvtest::randUni( rng, images_i, Scalar::all(-2), Scalar::all(2) );
+ }
+ else if( i > CV_MAX_DIM )
+ {
+ images[i] = cvCreateImage( img_size, images[0]->depth, 1 );
+ }
+ }
+
+ cvTsCalcHist( images, hist[0], images[CV_MAX_DIM], channels );
+
+ // now modify the images a bit to add some zeros go to the backprojection
+ n = cvtest::randInt(rng) % (img_len/20+1);
+ for( i = 0; i < cdims; i++ )
+ {
+ char* data = images[i]->imageData;
+ for( j = 0; j < n; j++ )
+ {
+ int idx = cvtest::randInt(rng) % img_len;
+ double val = cvtest::randReal(rng)*(high - low) + low;
+
+ if( img_type == CV_8U )
+ ((uchar*)data)[idx] = (uchar)cvRound(val);
+ else
+ ((float*)data)[idx] = (float)val;
+ }
+ }
+ }
+
+ return code;
+}
+
+
+void CV_CalcBackProjectTest::run_func(void)
+{
+ cvCalcBackProject( images, images[CV_MAX_DIM+1], hist[0] );
+}
+
+
+static void
+cvTsCalcBackProject( IplImage** images, IplImage* dst, CvHistogram* hist, int* channels )
+{
+ int x, y, k, cdims;
+ union
+ {
+ float* fl;
+ uchar* ptr;
+ }
+ plane[CV_MAX_DIM];
+ int nch[CV_MAX_DIM];
+ int dims[CV_MAX_DIM];
+ int uniform = CV_IS_UNIFORM_HIST(hist);
+ CvSize img_size = cvGetSize(images[0]);
+ int img_depth = images[0]->depth;
+
+ cdims = cvGetDims( hist->bins, dims );
+
+ for( k = 0; k < cdims; k++ )
+ nch[k] = images[k]->nChannels;
+
+ for( y = 0; y < img_size.height; y++ )
+ {
+ if( img_depth == IPL_DEPTH_8U )
+ for( k = 0; k < cdims; k++ )
+ plane[k].ptr = &CV_IMAGE_ELEM(images[k], uchar, y, 0 ) + channels[k];
+ else
+ for( k = 0; k < cdims; k++ )
+ plane[k].fl = &CV_IMAGE_ELEM(images[k], float, y, 0 ) + channels[k];
+
+ for( x = 0; x < img_size.width; x++ )
+ {
+ float val[CV_MAX_DIM];
+ float bin_val = 0;
+ int idx[CV_MAX_DIM];
+
+ if( img_depth == IPL_DEPTH_8U )
+ for( k = 0; k < cdims; k++ )
+ val[k] = plane[k].ptr[x*nch[k]];
+ else
+ for( k = 0; k < cdims; k++ )
+ val[k] = plane[k].fl[x*nch[k]];
+ idx[cdims-1] = -1;
+
+ if( uniform )
+ {
+ for( k = 0; k < cdims; k++ )
+ {
+ double v = val[k], lo = hist->thresh[k][0], hi = hist->thresh[k][1];
+ idx[k] = cvFloor((v - lo)*dims[k]/(hi - lo));
+ if( idx[k] < 0 || idx[k] >= dims[k] )
+ break;
+ }
+ }
+ else
+ {
+ for( k = 0; k < cdims; k++ )
+ {
+ float v = val[k];
+ float* t = hist->thresh2[k];
+ int j, n = dims[k];
+
+ for( j = 0; j <= n; j++ )
+ if( v < t[j] )
+ break;
+ if( j <= 0 || j > n )
+ break;
+ idx[k] = j-1;
+ }
+ }
+
+ if( k == cdims )
+ bin_val = (float)cvGetRealND( hist->bins, idx );
+
+ if( img_depth == IPL_DEPTH_8U )
+ {
+ int t = cvRound(bin_val);
+ CV_IMAGE_ELEM( dst, uchar, y, x ) = saturate_cast<uchar>(t);
+ }
+ else
+ CV_IMAGE_ELEM( dst, float, y, x ) = bin_val;
+ }
+ }
+}
+
+
+int CV_CalcBackProjectTest::validate_test_results( int test_case_idx )
+{
+ int code = cvtest::TS::OK;
+
+ cvTsCalcBackProject( images, images[CV_MAX_DIM+2], hist[0], channels );
+ Mat a = cvarrToMat(images[CV_MAX_DIM+1]), b = cvarrToMat(images[CV_MAX_DIM+2]);
+ double threshold = a.depth() == CV_8U ? 2 : FLT_EPSILON;
+ code = cvtest::cmpEps2( ts, a, b, threshold, true, "Back project image" );
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+
+ return code;
+}
+
+
+////////////// cvCalcBackProjectPatch //////////////
+
+class CV_CalcBackProjectPatchTest : public CV_BaseHistTest
+{
+public:
+ CV_CalcBackProjectPatchTest();
+ ~CV_CalcBackProjectPatchTest();
+ void clear();
+
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ IplImage* images[CV_MAX_DIM+2];
+ int channels[CV_MAX_DIM+2];
+
+ CvSize patch_size;
+ double factor;
+ int method;
+};
+
+
+
+CV_CalcBackProjectPatchTest::CV_CalcBackProjectPatchTest()
+{
+ int i;
+
+ hist_count = 1;
+ gen_random_hist = 0;
+ init_ranges = 1;
+ img_max_log_size = 6;
+
+ for( i = 0; i < CV_MAX_DIM+2; i++ )
+ {
+ images[i] = 0;
+ channels[i] = 0;
+ }
+}
+
+
+CV_CalcBackProjectPatchTest::~CV_CalcBackProjectPatchTest()
+{
+ clear();
+}
+
+
+void CV_CalcBackProjectPatchTest::clear()
+{
+ int i;
+
+ for( i = 0; i < CV_MAX_DIM+2; i++ )
+ cvReleaseImage( &images[i] );
+
+ CV_BaseHistTest::clear();
+}
+
+
+int CV_CalcBackProjectPatchTest::prepare_test_case( int test_case_idx )
+{
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ if( code > 0 )
+ {
+ RNG& rng = ts->get_rng();
+ int i, j, n, img_len = img_size.width*img_size.height;
+
+ patch_size.width = cvtest::randInt(rng) % img_size.width + 1;
+ patch_size.height = cvtest::randInt(rng) % img_size.height + 1;
+ patch_size.width = MIN( patch_size.width, 30 );
+ patch_size.height = MIN( patch_size.height, 30 );
+
+ factor = 1.;
+ method = cvtest::randInt(rng) % CV_CompareHistTest::MAX_METHOD;
+
+ for( i = 0; i < CV_MAX_DIM + 2; i++ )
+ {
+ if( i < cdims )
+ {
+ int nch = 1; //cvtest::randInt(rng) % 3 + 1;
+ images[i] = cvCreateImage( img_size,
+ img_type == CV_8U ? IPL_DEPTH_8U : IPL_DEPTH_32F, nch );
+ channels[i] = cvtest::randInt(rng) % nch;
+
+ Mat images_i = cvarrToMat(images[i]);
+ cvtest::randUni( rng, images_i, Scalar::all(low), Scalar::all(high) );
+ }
+ else if( i >= CV_MAX_DIM )
+ {
+ images[i] = cvCreateImage(
+ cvSize(img_size.width - patch_size.width + 1,
+ img_size.height - patch_size.height + 1),
+ IPL_DEPTH_32F, 1 );
+ }
+ }
+
+ cvTsCalcHist( images, hist[0], 0, channels );
+ cvNormalizeHist( hist[0], factor );
+
+ // now modify the images a bit
+ n = cvtest::randInt(rng) % (img_len/10+1);
+ for( i = 0; i < cdims; i++ )
+ {
+ char* data = images[i]->imageData;
+ for( j = 0; j < n; j++ )
+ {
+ int idx = cvtest::randInt(rng) % img_len;
+ double val = cvtest::randReal(rng)*(high - low) + low;
+
+ if( img_type == CV_8U )
+ ((uchar*)data)[idx] = (uchar)cvRound(val);
+ else
+ ((float*)data)[idx] = (float)val;
+ }
+ }
+ }
+
+ return code;
+}
+
+
+void CV_CalcBackProjectPatchTest::run_func(void)
+{
+ cvCalcBackProjectPatch( images, images[CV_MAX_DIM], patch_size, hist[0], method, factor );
+}
+
+
+static void
+cvTsCalcBackProjectPatch( IplImage** images, IplImage* dst, CvSize patch_size,
+ CvHistogram* hist, int method,
+ double factor, int* channels )
+{
+ CvHistogram* model = 0;
+
+ IplImage imgstub[CV_MAX_DIM], *img[CV_MAX_DIM];
+ IplROI roi;
+ int i, dims;
+ int x, y;
+ CvSize size = cvGetSize(dst);
+
+ dims = cvGetDims( hist->bins );
+ cvCopyHist( hist, &model );
+ cvNormalizeHist( hist, factor );
+ cvZero( dst );
+
+ for( i = 0; i < dims; i++ )
+ {
+ CvMat stub, *mat;
+ mat = cvGetMat( images[i], &stub, 0, 0 );
+ img[i] = cvGetImage( mat, &imgstub[i] );
+ img[i]->roi = &roi;
+ }
+
+ roi.coi = 0;
+
+ for( y = 0; y < size.height; y++ )
+ {
+ for( x = 0; x < size.width; x++ )
+ {
+ double result;
+
+ roi.xOffset = x;
+ roi.yOffset = y;
+ roi.width = patch_size.width;
+ roi.height = patch_size.height;
+
+ cvTsCalcHist( img, model, 0, channels );
+ cvNormalizeHist( model, factor );
+ result = cvCompareHist( model, hist, method );
+ CV_IMAGE_ELEM( dst, float, y, x ) = (float)result;
+ }
+ }
+
+ cvReleaseHist( &model );
+}
+
+
+int CV_CalcBackProjectPatchTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ double err_level = 5e-3;
+
+ cvTsCalcBackProjectPatch( images, images[CV_MAX_DIM+1],
+ patch_size, hist[0], method, factor, channels );
+
+ Mat a = cvarrToMat(images[CV_MAX_DIM]), b = cvarrToMat(images[CV_MAX_DIM+1]);
+ code = cvtest::cmpEps2( ts, a, b, err_level, true, "BackProjectPatch result" );
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+
+ return code;
+}
+
+
+////////////// cvCalcBayesianProb //////////////
+
+class CV_BayesianProbTest : public CV_BaseHistTest
+{
+public:
+ enum { MAX_METHOD = 4 };
+
+ CV_BayesianProbTest();
+protected:
+ int prepare_test_case( int test_case_idx );
+ void run_func(void);
+ int validate_test_results( int test_case_idx );
+ void init_hist( int test_case_idx, int i );
+ void get_hist_params( int test_case_idx );
+};
+
+
+
+CV_BayesianProbTest::CV_BayesianProbTest()
+{
+ hist_count = CV_MAX_DIM;
+ gen_random_hist = 1;
+}
+
+
+void CV_BayesianProbTest::get_hist_params( int test_case_idx )
+{
+ CV_BaseHistTest::get_hist_params( test_case_idx );
+ hist_type = CV_HIST_ARRAY;
+}
+
+
+void CV_BayesianProbTest::init_hist( int test_case_idx, int hist_i )
+{
+ if( hist_i < hist_count/2 )
+ CV_BaseHistTest::init_hist( test_case_idx, hist_i );
+}
+
+
+int CV_BayesianProbTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+
+ hist_count = (cvtest::randInt(rng) % (MAX_HIST/2-1) + 2)*2;
+ hist_count = MIN( hist_count, MAX_HIST );
+ int code = CV_BaseHistTest::prepare_test_case( test_case_idx );
+
+ return code;
+}
+
+
+void CV_BayesianProbTest::run_func(void)
+{
+ cvCalcBayesianProb( &hist[0], hist_count/2, &hist[hist_count/2] );
+}
+
+
+int CV_BayesianProbTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ int i, j, n = hist_count/2;
+ double s[CV_MAX_DIM];
+ const double err_level = 1e-5;
+
+ for( i = 0; i < total_size; i++ )
+ {
+ double sum = 0;
+ for( j = 0; j < n; j++ )
+ {
+ double v = hist[j]->mat.data.fl[i];
+ sum += v;
+ s[j] = v;
+ }
+ sum = sum > DBL_EPSILON ? 1./sum : 0;
+
+ for( j = 0; j < n; j++ )
+ {
+ double v0 = s[j]*sum;
+ double v = hist[j+n]->mat.data.fl[i];
+
+ if( cvIsNaN(v) || cvIsInf(v) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The element #%d in the destination histogram #%d is invalid (=%g)\n",
+ i, j, v );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ break;
+ }
+ else if( fabs(v0 - v) > err_level*fabs(v0) )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The element #%d in the destination histogram #%d is inaccurate (=%g, should be =%g)\n",
+ i, j, v, v0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ break;
+ }
+ }
+ if( j < n )
+ break;
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TEST(Imgproc_Hist_Calc, accuracy) { CV_CalcHistTest test; test.safe_run(); }
+TEST(Imgproc_Hist_Query, accuracy) { CV_QueryHistTest test; test.safe_run(); }
+
+TEST(Imgproc_Hist_Compare, accuracy) { CV_CompareHistTest test; test.safe_run(); }
+TEST(Imgproc_Hist_Threshold, accuracy) { CV_ThreshHistTest test; test.safe_run(); }
+TEST(Imgproc_Hist_Normalize, accuracy) { CV_NormHistTest test; test.safe_run(); }
+TEST(Imgproc_Hist_MinMaxVal, accuracy) { CV_MinMaxHistTest test; test.safe_run(); }
+
+TEST(Imgproc_Hist_CalcBackProject, accuracy) { CV_CalcBackProjectTest test; test.safe_run(); }
+TEST(Imgproc_Hist_CalcBackProjectPatch, accuracy) { CV_CalcBackProjectPatchTest test; test.safe_run(); }
+TEST(Imgproc_Hist_BayesianProb, accuracy) { CV_BayesianProbTest test; test.safe_run(); }
+
+/* End Of File */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_ImgWarpBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_ImgWarpBaseTest( bool warp_matrix );
+
+protected:
+ int read_params( CvFileStorage* fs );
+ int prepare_test_case( int test_case_idx );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+
+ int interpolation;
+ int max_interpolation;
+ double spatial_scale_zoom, spatial_scale_decimate;
+};
+
+
+CV_ImgWarpBaseTest::CV_ImgWarpBaseTest( bool warp_matrix )
+{
+ test_array[INPUT].push_back(NULL);
+ if( warp_matrix )
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ max_interpolation = 5;
+ interpolation = 0;
+ element_wise_relative_error = false;
+ spatial_scale_zoom = 0.01;
+ spatial_scale_decimate = 0.005;
+}
+
+
+int CV_ImgWarpBaseTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ return code;
+}
+
+
+void CV_ImgWarpBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( CV_MAT_DEPTH(type) == CV_32F )
+ {
+ low = Scalar::all(-10.);
+ high = Scalar::all(10);
+ }
+}
+
+
+void CV_ImgWarpBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 3;
+ int cn = cvtest::randInt(rng) % 3 + 1;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : CV_32F;
+ cn += cn == 2;
+
+ types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(depth, cn);
+ if( test_array[INPUT].size() > 1 )
+ types[INPUT][1] = cvtest::randInt(rng) & 1 ? CV_32FC1 : CV_64FC1;
+
+ interpolation = cvtest::randInt(rng) % max_interpolation;
+}
+
+
+void CV_ImgWarpBaseTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i != INPUT || j != 0 )
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+}
+
+int CV_ImgWarpBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ Mat& img = test_mat[INPUT][0];
+ int i, j, cols = img.cols;
+ int type = img.type(), depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
+ double scale = depth == CV_16U ? 1000. : 255.*0.5;
+ double space_scale = spatial_scale_decimate;
+ vector<float> buffer(img.cols*cn);
+
+ if( code <= 0 )
+ return code;
+
+ if( test_mat[INPUT_OUTPUT][0].cols >= img.cols &&
+ test_mat[INPUT_OUTPUT][0].rows >= img.rows )
+ space_scale = spatial_scale_zoom;
+
+ for( i = 0; i < img.rows; i++ )
+ {
+ uchar* ptr = img.ptr(i);
+ switch( cn )
+ {
+ case 1:
+ for( j = 0; j < cols; j++ )
+ buffer[j] = (float)((sin((i+1)*space_scale)*sin((j+1)*space_scale)+1.)*scale);
+ break;
+ case 2:
+ for( j = 0; j < cols; j++ )
+ {
+ buffer[j*2] = (float)((sin((i+1)*space_scale)+1.)*scale);
+ buffer[j*2+1] = (float)((sin((i+j)*space_scale)+1.)*scale);
+ }
+ break;
+ case 3:
+ for( j = 0; j < cols; j++ )
+ {
+ buffer[j*3] = (float)((sin((i+1)*space_scale)+1.)*scale);
+ buffer[j*3+1] = (float)((sin(j*space_scale)+1.)*scale);
+ buffer[j*3+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
+ }
+ break;
+ case 4:
+ for( j = 0; j < cols; j++ )
+ {
+ buffer[j*4] = (float)((sin((i+1)*space_scale)+1.)*scale);
+ buffer[j*4+1] = (float)((sin(j*space_scale)+1.)*scale);
+ buffer[j*4+2] = (float)((sin((i+j)*space_scale)+1.)*scale);
+ buffer[j*4+3] = (float)((sin((i-j)*space_scale)+1.)*scale);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ /*switch( depth )
+ {
+ case CV_8U:
+ for( j = 0; j < cols*cn; j++ )
+ ptr[j] = (uchar)cvRound(buffer[j]);
+ break;
+ case CV_16U:
+ for( j = 0; j < cols*cn; j++ )
+ ((ushort*)ptr)[j] = (ushort)cvRound(buffer[j]);
+ break;
+ case CV_32F:
+ for( j = 0; j < cols*cn; j++ )
+ ((float*)ptr)[j] = (float)buffer[j];
+ break;
+ default:
+ assert(0);
+ }*/
+ cv::Mat src(1, cols*cn, CV_32F, &buffer[0]);
+ cv::Mat dst(1, cols*cn, depth, ptr);
+ src.convertTo(dst, dst.type());
+ }
+
+ return code;
+}
+
+
+/////////////////////////
+
+class CV_ResizeTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_ResizeTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_ResizeTest::CV_ResizeTest() : CV_ImgWarpBaseTest( false )
+{
+}
+
+
+void CV_ResizeTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize sz;
+
+ sz.width = (cvtest::randInt(rng) % sizes[INPUT][0].width) + 1;
+ sz.height = (cvtest::randInt(rng) % sizes[INPUT][0].height) + 1;
+
+ if( cvtest::randInt(rng) & 1 )
+ {
+ int xfactor = cvtest::randInt(rng) % 10 + 1;
+ int yfactor = cvtest::randInt(rng) % 10 + 1;
+
+ if( cvtest::randInt(rng) & 1 )
+ yfactor = xfactor;
+
+ sz.width = sizes[INPUT][0].width / xfactor;
+ sz.width = MAX(sz.width,1);
+ sz.height = sizes[INPUT][0].height / yfactor;
+ sz.height = MAX(sz.height,1);
+ sizes[INPUT][0].width = sz.width * xfactor;
+ sizes[INPUT][0].height = sz.height * yfactor;
+ }
+
+ if( cvtest::randInt(rng) & 1 )
+ sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sz;
+ else
+ {
+ sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = sizes[INPUT][0];
+ sizes[INPUT][0] = sz;
+ }
+ if( interpolation == 4 &&
+ (MIN(sizes[INPUT][0].width,sizes[INPUT_OUTPUT][0].width) < 4 ||
+ MIN(sizes[INPUT][0].height,sizes[INPUT_OUTPUT][0].height) < 4))
+ interpolation = 2;
+}
+
+
+void CV_ResizeTest::run_func()
+{
+ cvResize( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], interpolation );
+}
+
+
+double CV_ResizeTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 1e-1;
+}
+
+
+void CV_ResizeTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ CvMat _src = test_mat[INPUT][0], _dst = test_mat[REF_INPUT_OUTPUT][0];
+ CvMat *src = &_src, *dst = &_dst;
+ int i, j, k;
+ CvMat* x_idx = cvCreateMat( 1, dst->cols, CV_32SC1 );
+ CvMat* y_idx = cvCreateMat( 1, dst->rows, CV_32SC1 );
+ int* x_tab = x_idx->data.i;
+ int elem_size = CV_ELEM_SIZE(src->type);
+ int drows = dst->rows, dcols = dst->cols;
+
+ if( interpolation == CV_INTER_NN )
+ {
+ for( j = 0; j < dcols; j++ )
+ {
+ int t = (j*src->cols*2 + MIN(src->cols,dcols) - 1)/(dcols*2);
+ t -= t >= src->cols;
+ x_idx->data.i[j] = t*elem_size;
+ }
+
+ for( j = 0; j < drows; j++ )
+ {
+ int t = (j*src->rows*2 + MIN(src->rows,drows) - 1)/(drows*2);
+ t -= t >= src->rows;
+ y_idx->data.i[j] = t;
+ }
+ }
+ else
+ {
+ double scale_x = (double)src->cols/dcols;
+ double scale_y = (double)src->rows/drows;
+
+ for( j = 0; j < dcols; j++ )
+ {
+ double f = ((j+0.5)*scale_x - 0.5);
+ i = cvRound(f);
+ x_idx->data.i[j] = (i < 0 ? 0 : i >= src->cols ? src->cols - 1 : i)*elem_size;
+ }
+
+ for( j = 0; j < drows; j++ )
+ {
+ double f = ((j+0.5)*scale_y - 0.5);
+ i = cvRound(f);
+ y_idx->data.i[j] = i < 0 ? 0 : i >= src->rows ? src->rows - 1 : i;
+ }
+ }
+
+ for( i = 0; i < drows; i++ )
+ {
+ uchar* dptr = dst->data.ptr + dst->step*i;
+ const uchar* sptr0 = src->data.ptr + src->step*y_idx->data.i[i];
+
+ for( j = 0; j < dcols; j++, dptr += elem_size )
+ {
+ const uchar* sptr = sptr0 + x_tab[j];
+ for( k = 0; k < elem_size; k++ )
+ dptr[k] = sptr[k];
+ }
+ }
+
+ cvReleaseMat( &x_idx );
+ cvReleaseMat( &y_idx );
+}
+
+
+/////////////////////////
+
+static void test_remap( const Mat& src, Mat& dst, const Mat& mapx, const Mat& mapy,
+ Mat* mask=0, int interpolation=CV_INTER_LINEAR )
+{
+ int x, y, k;
+ int drows = dst.rows, dcols = dst.cols;
+ int srows = src.rows, scols = src.cols;
+ uchar* sptr0 = src.data;
+ int depth = src.depth(), cn = src.channels();
+ int elem_size = (int)src.elemSize();
+ int step = src.step / CV_ELEM_SIZE(depth);
+ int delta;
+
+ if( interpolation != CV_INTER_CUBIC )
+ {
+ delta = 0;
+ scols -= 1; srows -= 1;
+ }
+ else
+ {
+ delta = 1;
+ scols = MAX(scols - 3, 0);
+ srows = MAX(srows - 3, 0);
+ }
+
+ int scols1 = MAX(scols - 2, 0);
+ int srows1 = MAX(srows - 2, 0);
+
+ if( mask )
+ *mask = Scalar::all(0);
+
+ for( y = 0; y < drows; y++ )
+ {
+ uchar* dptr = dst.ptr(y);
+ const float* mx = mapx.ptr<float>(y);
+ const float* my = mapy.ptr<float>(y);
+ uchar* m = mask ? mask->ptr(y) : 0;
+
+ for( x = 0; x < dcols; x++, dptr += elem_size )
+ {
+ float xs = mx[x];
+ float ys = my[x];
+ int ixs = cvFloor(xs);
+ int iys = cvFloor(ys);
+
+ if( (unsigned)(ixs - delta - 1) >= (unsigned)scols1 ||
+ (unsigned)(iys - delta - 1) >= (unsigned)srows1 )
+ {
+ if( m )
+ m[x] = 1;
+ if( (unsigned)(ixs - delta) >= (unsigned)scols ||
+ (unsigned)(iys - delta) >= (unsigned)srows )
+ continue;
+ }
+
+ xs -= ixs;
+ ys -= iys;
+
+ switch( depth )
+ {
+ case CV_8U:
+ {
+ const uchar* sptr = sptr0 + iys*step + ixs*cn;
+ for( k = 0; k < cn; k++ )
+ {
+ float v00 = sptr[k];
+ float v01 = sptr[cn + k];
+ float v10 = sptr[step + k];
+ float v11 = sptr[step + cn + k];
+
+ v00 = v00 + xs*(v01 - v00);
+ v10 = v10 + xs*(v11 - v10);
+ v00 = v00 + ys*(v10 - v00);
+ dptr[k] = (uchar)cvRound(v00);
+ }
+ }
+ break;
+ case CV_16U:
+ {
+ const ushort* sptr = (const ushort*)sptr0 + iys*step + ixs*cn;
+ for( k = 0; k < cn; k++ )
+ {
+ float v00 = sptr[k];
+ float v01 = sptr[cn + k];
+ float v10 = sptr[step + k];
+ float v11 = sptr[step + cn + k];
+
+ v00 = v00 + xs*(v01 - v00);
+ v10 = v10 + xs*(v11 - v10);
+ v00 = v00 + ys*(v10 - v00);
+ ((ushort*)dptr)[k] = (ushort)cvRound(v00);
+ }
+ }
+ break;
+ case CV_32F:
+ {
+ const float* sptr = (const float*)sptr0 + iys*step + ixs*cn;
+ for( k = 0; k < cn; k++ )
+ {
+ float v00 = sptr[k];
+ float v01 = sptr[cn + k];
+ float v10 = sptr[step + k];
+ float v11 = sptr[step + cn + k];
+
+ v00 = v00 + xs*(v01 - v00);
+ v10 = v10 + xs*(v11 - v10);
+ v00 = v00 + ys*(v10 - v00);
+ ((float*)dptr)[k] = (float)v00;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+ }
+ }
+}
+
+/////////////////////////
+
+class CV_WarpAffineTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_WarpAffineTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_WarpAffineTest::CV_WarpAffineTest() : CV_ImgWarpBaseTest( true )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ spatial_scale_decimate = spatial_scale_zoom;
+}
+
+
+void CV_WarpAffineTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize sz = sizes[INPUT][0];
+ // run for the second time to get output of a different size
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ sizes[INPUT][0] = sz;
+ sizes[INPUT][1] = cvSize( 3, 2 );
+}
+
+
+void CV_WarpAffineTest::run_func()
+{
+ CvMat mtx = test_mat[INPUT][1];
+ cvWarpAffine( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation );
+}
+
+
+double CV_WarpAffineTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
+}
+
+
+int CV_WarpAffineTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+ const Mat& src = test_mat[INPUT][0];
+ const Mat& dst = test_mat[INPUT_OUTPUT][0];
+ Mat& mat = test_mat[INPUT][1];
+ CvPoint2D32f center;
+ double scale, angle;
+
+ if( code <= 0 )
+ return code;
+
+ double buf[6];
+ Mat tmp( 2, 3, mat.type(), buf );
+
+ center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols);
+ center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows);
+ angle = cvtest::randReal(rng)*360;
+ scale = ((double)dst.rows/src.rows + (double)dst.cols/src.cols)*0.5;
+ getRotationMatrix2D(center, angle, scale).convertTo(mat, mat.depth());
+ rng.fill( tmp, CV_RAND_NORMAL, cvScalarAll(1.), cvScalarAll(0.01) );
+ cv::max(tmp, 0.9, tmp);
+ cv::min(tmp, 1.1, tmp);
+ cv::multiply(tmp, mat, mat, 1.);
+
+ return code;
+}
+
+
+void CV_WarpAffineTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ Mat& dst0 = test_mat[INPUT_OUTPUT][0];
+ Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F);
+ double m[6];
+ Mat srcAb, dstAb( 2, 3, CV_64FC1, m );
+
+ //cvInvert( &tM, &M, CV_LU );
+ // [R|t] -> [R^-1 | -(R^-1)*t]
+ test_mat[INPUT][1].convertTo( srcAb, CV_64F );
+ Mat A = srcAb.colRange(0, 2);
+ Mat b = srcAb.col(2);
+ Mat invA = dstAb.colRange(0, 2);
+ Mat invAb = dstAb.col(2);
+ cv::invert(A, invA, CV_SVD);
+ cv::gemm(invA, b, -1, Mat(), 0, invAb);
+
+ for( int y = 0; y < dst.rows; y++ )
+ for( int x = 0; x < dst.cols; x++ )
+ {
+ mapx.at<float>(y, x) = (float)(x*m[0] + y*m[1] + m[2]);
+ mapy.at<float>(y, x) = (float)(x*m[3] + y*m[4] + m[5]);
+ }
+
+ Mat mask( dst.size(), CV_8U );
+ test_remap( src, dst, mapx, mapy, &mask );
+ dst.setTo(Scalar::all(0), mask);
+ dst0.setTo(Scalar::all(0), mask);
+}
+
+
+/////////////////////////
+
+class CV_WarpPerspectiveTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_WarpPerspectiveTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_WarpPerspectiveTest::CV_WarpPerspectiveTest() : CV_ImgWarpBaseTest( true )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ spatial_scale_decimate = spatial_scale_zoom;
+}
+
+
+void CV_WarpPerspectiveTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize sz = sizes[INPUT][0];
+ // run for the second time to get output of a different size
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ sizes[INPUT][0] = sz;
+ sizes[INPUT][1] = cvSize( 3, 3 );
+}
+
+
+void CV_WarpPerspectiveTest::run_func()
+{
+ CvMat mtx = test_mat[INPUT][1];
+ cvWarpPerspective( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx, interpolation );
+}
+
+
+double CV_WarpPerspectiveTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
+}
+
+
+int CV_WarpPerspectiveTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+ const CvMat& src = test_mat[INPUT][0];
+ const CvMat& dst = test_mat[INPUT_OUTPUT][0];
+ Mat& mat = test_mat[INPUT][1];
+ Point2f s[4], d[4];
+ int i;
+
+ if( code <= 0 )
+ return code;
+
+ s[0] = Point2f(0,0);
+ d[0] = Point2f(0,0);
+ s[1] = Point2f(src.cols-1,0);
+ d[1] = Point2f(dst.cols-1,0);
+ s[2] = Point2f(src.cols-1,src.rows-1);
+ d[2] = Point2f(dst.cols-1,dst.rows-1);
+ s[3] = Point2f(0,src.rows-1);
+ d[3] = Point2f(0,dst.rows-1);
+
+ float buf[16];
+ Mat tmp( 1, 16, CV_32FC1, buf );
+
+ rng.fill( tmp, CV_RAND_NORMAL, cvScalarAll(0.), cvScalarAll(0.1) );
+
+ for( i = 0; i < 4; i++ )
+ {
+ s[i].x += buf[i*4]*src.cols/2;
+ s[i].y += buf[i*4+1]*src.rows/2;
+ d[i].x += buf[i*4+2]*dst.cols/2;
+ d[i].y += buf[i*4+3]*dst.rows/2;
+ }
+
+ cv::getPerspectiveTransform( s, d ).convertTo( mat, mat.depth() );
+ return code;
+}
+
+
+void CV_WarpPerspectiveTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ Mat& dst0 = test_mat[INPUT_OUTPUT][0];
+ Mat mapx(dst.size(), CV_32F), mapy(dst.size(), CV_32F);
+ double m[9];
+ Mat srcM, dstM(3, 3, CV_64F, m);
+
+ //cvInvert( &tM, &M, CV_LU );
+ // [R|t] -> [R^-1 | -(R^-1)*t]
+ test_mat[INPUT][1].convertTo( srcM, CV_64F );
+ cv::invert(srcM, dstM, CV_SVD);
+
+ for( int y = 0; y < dst.rows; y++ )
+ {
+ for( int x = 0; x < dst.cols; x++ )
+ {
+ double xs = x*m[0] + y*m[1] + m[2];
+ double ys = x*m[3] + y*m[4] + m[5];
+ double ds = x*m[6] + y*m[7] + m[8];
+
+ ds = ds ? 1./ds : 0;
+ xs *= ds;
+ ys *= ds;
+
+ mapx.at<float>(y, x) = (float)xs;
+ mapy.at<float>(y, x) = (float)ys;
+ }
+ }
+
+ Mat mask( dst.size(), CV_8U );
+ test_remap( src, dst, mapx, mapy, &mask );
+ dst.setTo(Scalar::all(0), mask);
+ dst0.setTo(Scalar::all(0), mask);
+}
+
+
+/////////////////////////
+
+class CV_RemapTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_RemapTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+};
+
+
+CV_RemapTest::CV_RemapTest() : CV_ImgWarpBaseTest( false )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+
+ spatial_scale_decimate = spatial_scale_zoom;
+}
+
+
+void CV_RemapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ types[INPUT][1] = types[INPUT][2] = CV_32FC1;
+ interpolation = CV_INTER_LINEAR;
+}
+
+
+void CV_RemapTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i != INPUT )
+ CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+void CV_RemapTest::run_func()
+{
+ cvRemap( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
+ test_array[INPUT][1], test_array[INPUT][2], interpolation );
+}
+
+
+double CV_RemapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
+}
+
+
+int CV_RemapTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+ const Mat& src = test_mat[INPUT][0];
+ double a[9] = {0,0,0,0,0,0,0,0,1}, k[4];
+ Mat _a( 3, 3, CV_64F, a );
+ Mat _k( 4, 1, CV_64F, k );
+ double sz = MAX(src.rows, src.cols);
+
+ if( code <= 0 )
+ return code;
+
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ a[4] = aspect_ratio*a[0];
+ k[0] = cvtest::randReal(rng)*0.06 - 0.03;
+ k[1] = cvtest::randReal(rng)*0.06 - 0.03;
+ if( k[0]*k[1] > 0 )
+ k[1] = -k[1];
+ k[2] = cvtest::randReal(rng)*0.004 - 0.002;
+ k[3] = cvtest::randReal(rng)*0.004 - 0.002;
+
+ cvtest::initUndistortMap( _a, _k, test_mat[INPUT][1].size(), test_mat[INPUT][1], test_mat[INPUT][2] );
+ return code;
+}
+
+
+void CV_RemapTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ Mat& dst0 = test_mat[INPUT_OUTPUT][0];
+ Mat mask( dst.size(), CV_8U );
+ test_remap(test_mat[INPUT][0], dst, test_mat[INPUT][1],
+ test_mat[INPUT][2], &mask, interpolation );
+ dst.setTo(Scalar::all(0), mask);
+ dst0.setTo(Scalar::all(0), mask);
+}
+
+
+////////////////////////////// undistort /////////////////////////////////
+
+class CV_UndistortTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_UndistortTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+
+private:
+ bool useCPlus;
+ cv::Mat input0;
+ cv::Mat input1;
+ cv::Mat input2;
+ cv::Mat input_new_cam;
+ cv::Mat input_output;
+
+ bool zero_new_cam;
+ bool zero_distortion;
+};
+
+
+CV_UndistortTest::CV_UndistortTest() : CV_ImgWarpBaseTest( false )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+
+ spatial_scale_decimate = spatial_scale_zoom;
+}
+
+
+void CV_UndistortTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int type = types[INPUT][0];
+ type = CV_MAKETYPE( CV_8U, CV_MAT_CN(type) );
+ types[INPUT][0] = types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = type;
+ types[INPUT][1] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ types[INPUT][2] = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+ sizes[INPUT][1] = cvSize(3,3);
+ sizes[INPUT][2] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
+ types[INPUT][3] = types[INPUT][1];
+ sizes[INPUT][3] = sizes[INPUT][1];
+ interpolation = CV_INTER_LINEAR;
+}
+
+
+void CV_UndistortTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i != INPUT )
+ CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+void CV_UndistortTest::run_func()
+{
+ if (!useCPlus)
+ {
+ CvMat a = test_mat[INPUT][1], k = test_mat[INPUT][2];
+ cvUndistort2( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &a, &k);
+ }
+ else
+ {
+ if (zero_distortion)
+ {
+ cv::undistort(input0,input_output,input1,cv::Mat());
+ }
+ else
+ {
+ cv::undistort(input0,input_output,input1,input2);
+ }
+ }
+}
+
+
+double CV_UndistortTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth == CV_8U ? 16 : depth == CV_16U ? 1024 : 5e-2;
+}
+
+
+int CV_UndistortTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+
+ const Mat& src = test_mat[INPUT][0];
+ double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
+ double new_cam[9] = {0,0,0,0,0,0,0,0,1};
+ double sz = MAX(src.rows, src.cols);
+
+ Mat& _new_cam0 = test_mat[INPUT][3];
+ Mat _new_cam(test_mat[INPUT][3].rows,test_mat[INPUT][3].cols,CV_64F,new_cam);
+ Mat& _a0 = test_mat[INPUT][1];
+ Mat _a(3,3,CV_64F,a);
+ Mat& _k0 = test_mat[INPUT][2];
+ Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k);
+
+ if( code <= 0 )
+ return code;
+
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ a[2] = (src.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[5] = (src.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ a[4] = aspect_ratio*a[0];
+ k[0] = cvtest::randReal(rng)*0.06 - 0.03;
+ k[1] = cvtest::randReal(rng)*0.06 - 0.03;
+ if( k[0]*k[1] > 0 )
+ k[1] = -k[1];
+ if( cvtest::randInt(rng)%4 != 0 )
+ {
+ k[2] = cvtest::randReal(rng)*0.004 - 0.002;
+ k[3] = cvtest::randReal(rng)*0.004 - 0.002;
+ }
+ else
+ k[2] = k[3] = 0;
+
+ new_cam[0] = a[0] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[0]; //10%
+ new_cam[4] = a[4] + (cvtest::randReal(rng) - (double)0.5)*0.2*a[4]; //10%
+ new_cam[2] = a[2] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].rows; //15%
+ new_cam[5] = a[5] + (cvtest::randReal(rng) - (double)0.5)*0.3*test_mat[INPUT][0].cols; //15%
+
+ _a.convertTo(_a0, _a0.depth());
+
+ zero_distortion = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ _k.convertTo(_k0, _k0.depth());
+
+ zero_new_cam = (cvtest::randInt(rng)%2) == 0 ? false : true;
+ _new_cam.convertTo(_new_cam0, _new_cam0.depth());
+
+ //Testing C++ code
+ useCPlus = ((cvtest::randInt(rng) % 2)!=0);
+ if (useCPlus)
+ {
+ input0 = test_mat[INPUT][0];
+ input1 = test_mat[INPUT][1];
+ input2 = test_mat[INPUT][2];
+ input_new_cam = test_mat[INPUT][3];
+ }
+
+ return code;
+}
+
+
+void CV_UndistortTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ if (useCPlus)
+ {
+ Mat& output = test_mat[INPUT_OUTPUT][0];
+ input_output.convertTo(output, output.type());
+ }
+ Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ Mat& dst0 = test_mat[INPUT_OUTPUT][0];
+ Mat mapx, mapy;
+ cvtest::initUndistortMap( test_mat[INPUT][1], test_mat[INPUT][2], dst.size(), mapx, mapy );
+ Mat mask( dst.size(), CV_8U );
+ test_remap( src, dst, mapx, mapy, &mask, interpolation );
+ dst.setTo(Scalar::all(0), mask);
+ dst0.setTo(Scalar::all(0), mask);
+}
+
+
+class CV_UndistortMapTest : public cvtest::ArrayTest
+{
+public:
+ CV_UndistortMapTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+
+private:
+ bool dualChannel;
+};
+
+
+CV_UndistortMapTest::CV_UndistortMapTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+
+ element_wise_relative_error = false;
+}
+
+
+void CV_UndistortMapTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int depth = cvtest::randInt(rng)%2 ? CV_64F : CV_32F;
+
+ CvSize sz = sizes[OUTPUT][0];
+ types[INPUT][0] = types[INPUT][1] = depth;
+ dualChannel = cvtest::randInt(rng)%2 == 0;
+ types[OUTPUT][0] = types[OUTPUT][1] =
+ types[REF_OUTPUT][0] = types[REF_OUTPUT][1] = dualChannel ? CV_32FC2 : CV_32F;
+ sizes[INPUT][0] = cvSize(3,3);
+ sizes[INPUT][1] = cvtest::randInt(rng)%2 ? cvSize(4,1) : cvSize(1,4);
+
+ sz.width = MAX(sz.width,16);
+ sz.height = MAX(sz.height,16);
+ sizes[OUTPUT][0] = sizes[OUTPUT][1] =
+ sizes[REF_OUTPUT][0] = sizes[REF_OUTPUT][1] = sz;
+}
+
+
+void CV_UndistortMapTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i != INPUT )
+ cvtest::ArrayTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+void CV_UndistortMapTest::run_func()
+{
+ CvMat a = test_mat[INPUT][0], k = test_mat[INPUT][1];
+
+ if (!dualChannel )
+ cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], test_array[OUTPUT][1] );
+ else
+ cvInitUndistortMap( &a, &k, test_array[OUTPUT][0], 0 );
+}
+
+
+double CV_UndistortMapTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 1e-3;
+}
+
+
+int CV_UndistortMapTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ const Mat& mapx = test_mat[OUTPUT][0];
+ double k[4], a[9] = {0,0,0,0,0,0,0,0,1};
+ double sz = MAX(mapx.rows, mapx.cols);
+ Mat& _a0 = test_mat[INPUT][0], &_k0 = test_mat[INPUT][1];
+ Mat _a(3,3,CV_64F,a);
+ Mat _k(_k0.rows,_k0.cols, CV_MAKETYPE(CV_64F,_k0.channels()),k);
+
+ if( code <= 0 )
+ return code;
+
+ double aspect_ratio = cvtest::randReal(rng)*0.6 + 0.7;
+ a[2] = (mapx.cols - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[5] = (mapx.rows - 1)*0.5 + cvtest::randReal(rng)*10 - 5;
+ a[0] = sz/(0.9 - cvtest::randReal(rng)*0.6);
+ a[4] = aspect_ratio*a[0];
+ k[0] = cvtest::randReal(rng)*0.06 - 0.03;
+ k[1] = cvtest::randReal(rng)*0.06 - 0.03;
+ if( k[0]*k[1] > 0 )
+ k[1] = -k[1];
+ k[2] = cvtest::randReal(rng)*0.004 - 0.002;
+ k[3] = cvtest::randReal(rng)*0.004 - 0.002;
+
+ _a.convertTo(_a0, _a0.depth());
+ _k.convertTo(_k0, _k0.depth());
+
+ if (dualChannel)
+ {
+ test_mat[REF_OUTPUT][1] = Scalar::all(0);
+ test_mat[OUTPUT][1] = Scalar::all(0);
+ }
+
+ return code;
+}
+
+
+void CV_UndistortMapTest::prepare_to_validation( int )
+{
+ Mat mapx, mapy;
+ cvtest::initUndistortMap( test_mat[INPUT][0], test_mat[INPUT][1], test_mat[REF_OUTPUT][0].size(), mapx, mapy );
+ if( !dualChannel )
+ {
+ mapx.copyTo(test_mat[REF_OUTPUT][0]);
+ mapy.copyTo(test_mat[REF_OUTPUT][1]);
+ }
+ else
+ {
+ Mat p[2] = {mapx, mapy};
+ cv::merge(p, 2, test_mat[REF_OUTPUT][0]);
+ }
+}
+
+////////////////////////////// GetRectSubPix /////////////////////////////////
+
+static void
+test_getQuadrangeSubPix( const Mat& src, Mat& dst, double* a )
+{
+ int sstep = src.step / sizeof(float);
+ int scols = src.cols, srows = src.rows;
+
+ CV_Assert( src.depth() == CV_32F && src.type() == dst.type() );
+
+ int cn = dst.channels();
+
+ for( int y = 0; y < dst.rows; y++ )
+ for( int x = 0; x < dst.cols; x++ )
+ {
+ float* d = dst.ptr<float>(y) + x*cn;
+ float sx = (float)(a[0]*x + a[1]*y + a[2]);
+ float sy = (float)(a[3]*x + a[4]*y + a[5]);
+ int ix = cvFloor(sx), iy = cvFloor(sy);
+ int dx = cn, dy = sstep;
+ const float* s;
+ sx -= ix; sy -= iy;
+
+ if( (unsigned)ix >= (unsigned)(scols-1) )
+ ix = ix < 0 ? 0 : scols - 1, sx = 0, dx = 0;
+ if( (unsigned)iy >= (unsigned)(srows-1) )
+ iy = iy < 0 ? 0 : srows - 1, sy = 0, dy = 0;
+
+ s = src.ptr<float>(iy) + ix*cn;
+ for( int k = 0; k < cn; k++, s++ )
+ {
+ float t0 = s[0] + sx*(s[dx] - s[0]);
+ float t1 = s[dy] + sx*(s[dy + dx] - s[dy]);
+ d[k] = t0 + sy*(t1 - t0);
+ }
+ }
+}
+
+
+class CV_GetRectSubPixTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_GetRectSubPixTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void fill_array( int test_case_idx, int i, int j, Mat& arr );
+
+ CvPoint2D32f center;
+ bool test_cpp;
+};
+
+
+CV_GetRectSubPixTest::CV_GetRectSubPixTest() : CV_ImgWarpBaseTest( false )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ spatial_scale_decimate = spatial_scale_zoom;
+ test_cpp = false;
+}
+
+
+void CV_GetRectSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int src_depth = cvtest::randInt(rng) % 2, dst_depth;
+ int cn = cvtest::randInt(rng) % 2 ? 3 : 1;
+ CvSize src_size, dst_size;
+
+ dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
+ if( src_depth < CV_32F && cvtest::randInt(rng) % 2 )
+ dst_depth = CV_32F;
+
+ types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
+ types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
+
+ src_size = sizes[INPUT][0];
+ dst_size.width = cvRound(sqrt(cvtest::randReal(rng)*src_size.width) + 1);
+ dst_size.height = cvRound(sqrt(cvtest::randReal(rng)*src_size.height) + 1);
+ dst_size.width = MIN(dst_size.width,src_size.width);
+ dst_size.height = MIN(dst_size.width,src_size.height);
+ sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dst_size;
+
+ center.x = (float)(cvtest::randReal(rng)*src_size.width);
+ center.y = (float)(cvtest::randReal(rng)*src_size.height);
+ interpolation = CV_INTER_LINEAR;
+
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+void CV_GetRectSubPixTest::fill_array( int test_case_idx, int i, int j, Mat& arr )
+{
+ if( i != INPUT )
+ CV_ImgWarpBaseTest::fill_array( test_case_idx, i, j, arr );
+}
+
+
+void CV_GetRectSubPixTest::run_func()
+{
+ if(!test_cpp)
+ cvGetRectSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], center );
+ else
+ {
+ cv::Mat _out = cv::cvarrToMat(test_array[INPUT_OUTPUT][0]);
+ cv::getRectSubPix( cv::cvarrToMat(test_array[INPUT][0]), _out.size(), center, _out, _out.type());
+ }
+}
+
+
+double CV_GetRectSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int in_depth = test_mat[INPUT][0].depth();
+ int out_depth = test_mat[INPUT_OUTPUT][0].depth();
+
+ return in_depth >= CV_32F ? 1e-3 : out_depth >= CV_32F ? 1e-2 : 1;
+}
+
+
+int CV_GetRectSubPixTest::prepare_test_case( int test_case_idx )
+{
+ return CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+}
+
+
+void CV_GetRectSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src0 = test_mat[INPUT][0];
+ Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0];
+ Mat src = src0, dst = dst0;
+ int ftype = CV_MAKETYPE(CV_32F,src0.channels());
+ double a[] = { 1, 0, center.x - dst.cols*0.5 + 0.5,
+ 0, 1, center.y - dst.rows*0.5 + 0.5 };
+ if( src.depth() != CV_32F )
+ src0.convertTo(src, CV_32F);
+
+ if( dst.depth() != CV_32F )
+ dst.create(dst0.size(), ftype);
+
+ test_getQuadrangeSubPix( src, dst, a );
+
+ if( dst.data != dst0.data )
+ dst.convertTo(dst0, dst0.depth());
+}
+
+
+class CV_GetQuadSubPixTest : public CV_ImgWarpBaseTest
+{
+public:
+ CV_GetQuadSubPixTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void run_func();
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ double get_success_error_level( int test_case_idx, int i, int j );
+};
+
+
+CV_GetQuadSubPixTest::CV_GetQuadSubPixTest() : CV_ImgWarpBaseTest( true )
+{
+ //spatial_scale_zoom = spatial_scale_decimate;
+ spatial_scale_decimate = spatial_scale_zoom;
+}
+
+
+void CV_GetQuadSubPixTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ int min_size = 4;
+ CV_ImgWarpBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize sz = sizes[INPUT][0], dsz;
+ RNG& rng = ts->get_rng();
+ int msz, src_depth = cvtest::randInt(rng) % 2, dst_depth;
+ int cn = cvtest::randInt(rng) % 2 ? 3 : 1;
+
+ dst_depth = src_depth = src_depth == 0 ? CV_8U : CV_32F;
+ if( src_depth < CV_32F && cvtest::randInt(rng) % 2 )
+ dst_depth = CV_32F;
+
+ types[INPUT][0] = CV_MAKETYPE(src_depth,cn);
+ types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(dst_depth,cn);
+
+ sz.width = MAX(sz.width,min_size);
+ sz.height = MAX(sz.height,min_size);
+ sizes[INPUT][0] = sz;
+ msz = MIN( sz.width, sz.height );
+
+ dsz.width = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1);
+ dsz.height = cvRound(sqrt(cvtest::randReal(rng)*msz) + 1);
+ dsz.width = MIN(dsz.width,msz);
+ dsz.height = MIN(dsz.width,msz);
+ dsz.width = MAX(dsz.width,min_size);
+ dsz.height = MAX(dsz.height,min_size);
+ sizes[INPUT_OUTPUT][0] = sizes[REF_INPUT_OUTPUT][0] = dsz;
+ sizes[INPUT][1] = cvSize( 3, 2 );
+}
+
+
+void CV_GetQuadSubPixTest::run_func()
+{
+ CvMat mtx = test_mat[INPUT][1];
+ cvGetQuadrangleSubPix( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], &mtx );
+}
+
+
+double CV_GetQuadSubPixTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int in_depth = test_mat[INPUT][0].depth();
+ //int out_depth = test_mat[INPUT_OUTPUT][0].depth();
+
+ return in_depth >= CV_32F ? 1e-2 : 4;
+}
+
+
+int CV_GetQuadSubPixTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = CV_ImgWarpBaseTest::prepare_test_case( test_case_idx );
+ const Mat& src = test_mat[INPUT][0];
+ Mat& mat = test_mat[INPUT][1];
+ CvPoint2D32f center;
+ double scale, angle;
+
+ if( code <= 0 )
+ return code;
+
+ double a[6];
+ Mat A( 2, 3, CV_64FC1, a );
+
+ center.x = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.cols);
+ center.y = (float)((cvtest::randReal(rng)*1.2 - 0.1)*src.rows);
+ angle = cvtest::randReal(rng)*360;
+ scale = cvtest::randReal(rng)*0.2 + 0.9;
+
+ // y = Ax + b -> x = A^-1(y - b) = A^-1*y - A^-1*b
+ scale = 1./scale;
+ angle = angle*(CV_PI/180.);
+ a[0] = a[4] = cos(angle)*scale;
+ a[1] = sin(angle)*scale;
+ a[3] = -a[1];
+ a[2] = center.x - a[0]*center.x - a[1]*center.y;
+ a[5] = center.y - a[3]*center.x - a[4]*center.y;
+ A.convertTo( mat, mat.depth() );
+
+ return code;
+}
+
+
+void CV_GetQuadSubPixTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src0 = test_mat[INPUT][0];
+ Mat& dst0 = test_mat[REF_INPUT_OUTPUT][0];
+ Mat src = src0, dst = dst0;
+ int ftype = CV_MAKETYPE(CV_32F,src0.channels());
+ double a[6], dx = (dst0.cols - 1)*0.5, dy = (dst0.rows - 1)*0.5;
+ Mat A( 2, 3, CV_64F, a );
+
+ if( src.depth() != CV_32F )
+ src0.convertTo(src, CV_32F);
+
+ if( dst.depth() != CV_32F )
+ dst.create(dst0.size(), ftype);
+
+ test_mat[INPUT][1].convertTo( A, CV_64F );
+ a[2] -= a[0]*dx + a[1]*dy;
+ a[5] -= a[3]*dx + a[4]*dy;
+ test_getQuadrangeSubPix( src, dst, a );
+
+ if( dst.data != dst0.data )
+ dst.convertTo(dst0, dst0.depth());
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+
+TEST(Imgproc_Resize, accuracy) { CV_ResizeTest test; test.safe_run(); }
+TEST(Imgproc_WarpAffine, accuracy) { CV_WarpAffineTest test; test.safe_run(); }
+TEST(Imgproc_WarpPerspective, accuracy) { CV_WarpPerspectiveTest test; test.safe_run(); }
+TEST(Imgproc_Remap, accuracy) { CV_RemapTest test; test.safe_run(); }
+TEST(Imgproc_Undistort, accuracy) { CV_UndistortTest test; test.safe_run(); }
+TEST(Imgproc_InitUndistortMap, accuracy) { CV_UndistortMapTest test; test.safe_run(); }
+TEST(Imgproc_GetRectSubPix, accuracy) { CV_GetRectSubPixTest test; test.safe_run(); }
+TEST(Imgproc_GetQuadSubPix, accuracy) { CV_GetQuadSubPixTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <string>
+
+using namespace cv;
+
+class CV_InpaintTest : public cvtest::BaseTest
+{
+public:
+ CV_InpaintTest();
+ ~CV_InpaintTest();
+protected:
+ void run(int);
+};
+
+CV_InpaintTest::CV_InpaintTest()
+{
+}
+CV_InpaintTest::~CV_InpaintTest() {}
+
+void CV_InpaintTest::run( int )
+{
+ string folder = string(ts->get_data_path()) + "inpaint/";
+ Mat orig = imread(folder + "orig.jpg");
+ Mat exp1 = imread(folder + "exp1.png");
+ Mat exp2 = imread(folder + "exp2.png");
+ Mat mask = imread(folder + "mask.png");
+
+ if (orig.empty() || exp1.empty() || exp2.empty() || mask.empty())
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ Mat inv_mask;
+ mask.convertTo(inv_mask, CV_8UC3, -1.0, 255.0);
+
+ Mat mask1ch;
+ cv::cvtColor(mask, mask1ch, CV_BGR2GRAY);
+
+ Mat test = orig.clone();
+ test.setTo(Scalar::all(255), mask1ch);
+
+ Mat res1, res2;
+ inpaint( test, mask1ch, res1, 5, CV_INPAINT_NS );
+ inpaint( test, mask1ch, res2, 5, CV_INPAINT_TELEA );
+
+ imwrite("d:/exp1.png", res1);
+ imwrite("d:/exp2.png", res2);
+
+ Mat diff1, diff2;
+ absdiff( orig, res1, diff1 );
+ absdiff( orig, res2, diff2 );
+
+ double n1 = norm(diff1.reshape(1), NORM_INF, inv_mask.reshape(1));
+ double n2 = norm(diff2.reshape(1), NORM_INF, inv_mask.reshape(1));
+
+ if (n1 != 0 || n2 != 0)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ return;
+ }
+
+ absdiff( exp1, res1, diff1 );
+ absdiff( exp2, res2, diff2 );
+
+ n1 = norm(diff1.reshape(1), NORM_INF, mask.reshape(1));
+ n2 = norm(diff2.reshape(1), NORM_INF, mask.reshape(1));
+
+ const int jpeg_thres = 3;
+ if (n1 > jpeg_thres || n2 > jpeg_thres)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
+ return;
+ }
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Imgproc_Inpaint, regression) { CV_InpaintTest test; test.safe_run(); }
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+// image moments
+class CV_MomentsTest : public cvtest::ArrayTest
+{
+public:
+ CV_MomentsTest();
+
+protected:
+
+ enum { MOMENT_COUNT = 25 };
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ int coi;
+ bool is_binary;
+};
+
+
+CV_MomentsTest::CV_MomentsTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ coi = -1;
+ is_binary = false;
+ //element_wise_relative_error = false;
+}
+
+
+void CV_MomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ int depth = CV_MAT_DEPTH(type);
+
+ if( depth == CV_16U )
+ {
+ low = Scalar::all(0);
+ high = Scalar::all(1000);
+ }
+ else if( depth == CV_16S )
+ {
+ low = Scalar::all(-1000);
+ high = Scalar::all(1000);
+ }
+ else if( depth == CV_32F )
+ {
+ low = Scalar::all(-1);
+ high = Scalar::all(1);
+ }
+}
+
+
+void CV_MomentsTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ int cn = cvtest::randInt(rng) % 4 + 1;
+ int depth = cvtest::randInt(rng) % 4;
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_16U : depth == 2 ? CV_16S : CV_32F;
+ if( cn == 2 )
+ cn = 1;
+
+ types[INPUT][0] = CV_MAKETYPE(depth, cn);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(MOMENT_COUNT,1);
+
+ is_binary = cvtest::randInt(rng) % 2 != 0;
+ coi = 0;
+ cvmat_allowed = true;
+ if( cn > 1 )
+ {
+ coi = cvtest::randInt(rng) % cn;
+ cvmat_allowed = false;
+ }
+}
+
+
+double CV_MomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ int depth = test_mat[INPUT][0].depth();
+ return depth != CV_32F ? FLT_EPSILON*10 : FLT_EPSILON*100;
+}
+
+int CV_MomentsTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ int cn = test_mat[INPUT][0].channels();
+ if( cn > 1 )
+ cvSetImageCOI( (IplImage*)test_array[INPUT][0], coi + 1 );
+ }
+
+ return code;
+}
+
+
+void CV_MomentsTest::run_func()
+{
+ CvMoments* m = (CvMoments*)test_mat[OUTPUT][0].ptr<double>();
+ double* others = (double*)(m + 1);
+ cvMoments( test_array[INPUT][0], m, is_binary );
+ others[0] = cvGetNormalizedCentralMoment( m, 2, 0 );
+ others[1] = cvGetNormalizedCentralMoment( m, 1, 1 );
+ others[2] = cvGetNormalizedCentralMoment( m, 0, 2 );
+ others[3] = cvGetNormalizedCentralMoment( m, 3, 0 );
+ others[4] = cvGetNormalizedCentralMoment( m, 2, 1 );
+ others[5] = cvGetNormalizedCentralMoment( m, 1, 2 );
+ others[6] = cvGetNormalizedCentralMoment( m, 0, 3 );
+}
+
+
+void CV_MomentsTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ Mat& src = test_mat[INPUT][0];
+ CvMoments m;
+ double* mdata = test_mat[REF_OUTPUT][0].ptr<double>();
+ int depth = src.depth();
+ int cn = src.channels();
+ int i, y, x, cols = src.cols;
+ double xc = 0., yc = 0.;
+
+ memset( &m, 0, sizeof(m));
+
+ for( y = 0; y < src.rows; y++ )
+ {
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0;
+ uchar* ptr = src.ptr(y);
+ for( x = 0; x < cols; x++ )
+ {
+ double val;
+ if( depth == CV_8U )
+ val = ptr[x*cn + coi];
+ else if( depth == CV_16U )
+ val = ((ushort*)ptr)[x*cn + coi];
+ else if( depth == CV_16S )
+ val = ((short*)ptr)[x*cn + coi];
+ else
+ val = ((float*)ptr)[x*cn + coi];
+
+ if( is_binary )
+ val = val != 0;
+
+ s0 += val;
+ s1 += val*x;
+ s2 += val*x*x;
+ s3 += ((val*x)*x)*x;
+ }
+
+ m.m00 += s0;
+ m.m01 += s0*y;
+ m.m02 += (s0*y)*y;
+ m.m03 += ((s0*y)*y)*y;
+
+ m.m10 += s1;
+ m.m11 += s1*y;
+ m.m12 += (s1*y)*y;
+
+ m.m20 += s2;
+ m.m21 += s2*y;
+
+ m.m30 += s3;
+ }
+
+ if( m.m00 != 0 )
+ {
+ xc = m.m10/m.m00, yc = m.m01/m.m00;
+ m.inv_sqrt_m00 = 1./sqrt(fabs(m.m00));
+ }
+
+ for( y = 0; y < src.rows; y++ )
+ {
+ double s0 = 0, s1 = 0, s2 = 0, s3 = 0, y1 = y - yc;
+ uchar* ptr = src.ptr(y);
+ for( x = 0; x < cols; x++ )
+ {
+ double val, x1 = x - xc;
+ if( depth == CV_8U )
+ val = ptr[x*cn + coi];
+ else if( depth == CV_16U )
+ val = ((ushort*)ptr)[x*cn + coi];
+ else if( depth == CV_16S )
+ val = ((short*)ptr)[x*cn + coi];
+ else
+ val = ((float*)ptr)[x*cn + coi];
+
+ if( is_binary )
+ val = val != 0;
+
+ s0 += val;
+ s1 += val*x1;
+ s2 += val*x1*x1;
+ s3 += ((val*x1)*x1)*x1;
+ }
+
+ m.mu02 += s0*y1*y1;
+ m.mu03 += ((s0*y1)*y1)*y1;
+
+ m.mu11 += s1*y1;
+ m.mu12 += (s1*y1)*y1;
+
+ m.mu20 += s2;
+ m.mu21 += s2*y1;
+
+ m.mu30 += s3;
+ }
+
+ memcpy( mdata, &m, sizeof(m));
+ mdata += sizeof(m)/sizeof(m.m00);
+
+ /* calc normalized moments */
+ {
+ double inv_m00 = m.inv_sqrt_m00*m.inv_sqrt_m00;
+ double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */
+ double s3 = s2*m.inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */
+
+ mdata[0] = m.mu20 * s2;
+ mdata[1] = m.mu11 * s2;
+ mdata[2] = m.mu02 * s2;
+
+ mdata[3] = m.mu30 * s3;
+ mdata[4] = m.mu21 * s3;
+ mdata[5] = m.mu12 * s3;
+ mdata[6] = m.mu03 * s3;
+ }
+
+ double* a = test_mat[REF_OUTPUT][0].ptr<double>();
+ double* b = test_mat[OUTPUT][0].ptr<double>();
+ for( i = 0; i < MOMENT_COUNT; i++ )
+ {
+ if( fabs(a[i]) < 1e-3 )
+ a[i] = 0;
+ if( fabs(b[i]) < 1e-3 )
+ b[i] = 0;
+ }
+}
+
+
+// Hu invariants
+class CV_HuMomentsTest : public cvtest::ArrayTest
+{
+public:
+ CV_HuMomentsTest();
+
+protected:
+
+ enum { MOMENT_COUNT = 18, HU_MOMENT_COUNT = 7 };
+
+ int prepare_test_case( int test_case_idx );
+ void prepare_to_validation( int /*test_case_idx*/ );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+};
+
+
+CV_HuMomentsTest::CV_HuMomentsTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+}
+
+
+void CV_HuMomentsTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ low = Scalar::all(-10000);
+ high = Scalar::all(10000);
+}
+
+
+void CV_HuMomentsTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_64FC1;
+ sizes[INPUT][0] = cvSize(MOMENT_COUNT,1);
+ sizes[OUTPUT][0] = sizes[REF_OUTPUT][0] = cvSize(HU_MOMENT_COUNT,1);
+}
+
+
+double CV_HuMomentsTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return FLT_EPSILON;
+}
+
+
+
+int CV_HuMomentsTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ // ...
+ }
+
+ return code;
+}
+
+
+void CV_HuMomentsTest::run_func()
+{
+ cvGetHuMoments( (CvMoments*)test_mat[INPUT][0].data,
+ (CvHuMoments*)test_mat[OUTPUT][0].data );
+}
+
+
+void CV_HuMomentsTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ CvMoments* m = (CvMoments*)test_mat[INPUT][0].data;
+ CvHuMoments* hu = (CvHuMoments*)test_mat[REF_OUTPUT][0].data;
+
+ double inv_m00 = m->inv_sqrt_m00*m->inv_sqrt_m00;
+ double s2 = inv_m00*inv_m00; /* 1./(m00 ^ (2/2 + 1)) */
+ double s3 = s2*m->inv_sqrt_m00; /* 1./(m00 ^ (3/2 + 1)) */
+
+ double nu20 = m->mu20 * s2;
+ double nu11 = m->mu11 * s2;
+ double nu02 = m->mu02 * s2;
+
+ double nu30 = m->mu30 * s3;
+ double nu21 = m->mu21 * s3;
+ double nu12 = m->mu12 * s3;
+ double nu03 = m->mu03 * s3;
+
+ #undef sqr
+ #define sqr(a) ((a)*(a))
+
+ hu->hu1 = nu20 + nu02;
+ hu->hu2 = sqr(nu20 - nu02) + 4*sqr(nu11);
+ hu->hu3 = sqr(nu30 - 3*nu12) + sqr(3*nu21 - nu03);
+ hu->hu4 = sqr(nu30 + nu12) + sqr(nu21 + nu03);
+ hu->hu5 = (nu30 - 3*nu12)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) +
+ (3*nu21 - nu03)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03));
+ hu->hu6 = (nu20 - nu02)*(sqr(nu30 + nu12) - sqr(nu21 + nu03)) +
+ 4*nu11*(nu30 + nu12)*(nu21 + nu03);
+ hu->hu7 = (3*nu21 - nu03)*(nu30 + nu12)*(sqr(nu30 + nu12) - 3*sqr(nu21 + nu03)) +
+ (3*nu12 - nu30)*(nu21 + nu03)*(3*sqr(nu30 + nu12) - sqr(nu21 + nu03));
+}
+
+
+TEST(Imgproc_Moments, accuracy) { CV_MomentsTest test; test.safe_run(); }
+TEST(Imgproc_HuMoments, accuracy) { CV_HuMomentsTest test; test.safe_run(); }
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/highgui/highgui.hpp"
+#include "opencv2/highgui/highgui_c.h"
+#include <iostream>
+
+#endif
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_PyrSegmentationTest : public cvtest::BaseTest
+{
+public:
+ CV_PyrSegmentationTest();
+protected:
+ void run(int);
+};
+
+#define SCAN 0
+
+CV_PyrSegmentationTest::CV_PyrSegmentationTest()
+{
+}
+
+void CV_PyrSegmentationTest::run( int /*start_from*/ )
+{
+ Mat _image_f, _image, _image_s;
+ const int level = 5;
+ const double range = 15;
+
+ int code = cvtest::TS::OK;
+
+ CvPoint _cp[] ={{33,33}, {43,33}, {43,43}, {33,43}};
+ CvPoint _cp2[] ={{50,50}, {70,50}, {70,70}, {50,70}};
+ CvPoint* cp = _cp;
+ CvPoint* cp2 = _cp2;
+ CvConnectedComp *dst_comp[3];
+ CvRect rect[3] = {{50,50,21,21}, {0,0,128,128}, {33,33,11,11}};
+ double a[3] = {441.0, 15822.0, 121.0};
+
+/* ippiPoint cp3[] ={130,130, 150,130, 150,150, 130,150}; */
+/* CvPoint cp[] ={0,0, 5,5, 5,0, 10,5, 10,0, 15,5, 15,0}; */
+ int nPoints = 4;
+ int block_size = 1000;
+
+ CvMemStorage *storage; /* storage for connected component writing */
+ CvSeq *comp;
+
+ RNG& rng = ts->get_rng();
+ int i, j, iter;
+
+ IplImage *image, *image_f, *image_s;
+ CvSize size = {128, 128};
+ const int threshold1 = 50, threshold2 = 50;
+
+ rect[1].width = size.width;
+ rect[1].height = size.height;
+ a[1] = size.width*size.height - a[0] - a[2];
+
+ OPENCV_CALL( storage = cvCreateMemStorage( block_size ) );
+
+ for( iter = 0; iter < 2; iter++ )
+ {
+ int channels = iter == 0 ? 1 : 3;
+ int mask[] = {0,0,0};
+
+ image = cvCreateImage(size, 8, channels );
+ image_s = cvCloneImage( image );
+ image_f = cvCloneImage( image );
+
+ if( channels == 1 )
+ {
+ int color1 = 30, color2 = 110, color3 = 190;
+
+ cvSet( image, cvScalarAll(color1));
+ cvFillPoly( image, &cp, &nPoints, 1, cvScalar(color2));
+ cvFillPoly( image, &cp2, &nPoints, 1, cvScalar(color3));
+ }
+ else
+ {
+ CvScalar color1 = CV_RGB(30,30,30), color2 = CV_RGB(255,0,0), color3 = CV_RGB(0,255,0);
+
+ assert( channels == 3 );
+ cvSet( image, color1 );
+ cvFillPoly( image, &cp, &nPoints, 1, color2);
+ cvFillPoly( image, &cp2, &nPoints, 1, color3);
+ }
+
+ _image_f = cvarrToMat(image_f);
+ cvtest::randUni( rng, _image_f, cvScalarAll(0), cvScalarAll(range*2) );
+ cvAddWeighted( image, 1, image_f, 1, -range, image_f );
+
+ cvPyrSegmentation( image_f, image_s,
+ storage, &comp,
+ level, threshold1, threshold2 );
+
+ if(comp->total != 3)
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The segmentation function returned %d (not 3) components\n", comp->total );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ /* read the connected components */
+ dst_comp[0] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 0 );
+ dst_comp[1] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 1 );
+ dst_comp[2] = (CvConnectedComp*)CV_GET_SEQ_ELEM( CvConnectedComp, comp, 2 );
+
+ /*{
+ for( i = 0; i < 3; i++ )
+ {
+ CvRect r = dst_comp[i]->rect;
+ cvRectangle( image_s, cvPoint(r.x,r.y), cvPoint(r.x+r.width,r.y+r.height),
+ CV_RGB(255,255,255), 3, 8, 0 );
+ }
+
+ cvNamedWindow( "test", 1 );
+ cvShowImage( "test", image_s );
+ cvWaitKey(0);
+ }*/
+
+ _image = cvarrToMat(image);
+ _image_s = cvarrToMat(image_s);
+ code = cvtest::cmpEps2( ts, _image, _image_s, 10, false, "the output image" );
+ if( code < 0 )
+ goto _exit_;
+
+ for( i = 0; i < 3; i++)
+ {
+ for( j = 0; j < 3; j++ )
+ {
+ if( !mask[j] && dst_comp[i]->area == a[j] &&
+ dst_comp[i]->rect.x == rect[j].x &&
+ dst_comp[i]->rect.y == rect[j].y &&
+ dst_comp[i]->rect.width == rect[j].width &&
+ dst_comp[i]->rect.height == rect[j].height )
+ {
+ mask[j] = 1;
+ break;
+ }
+ }
+ if( j == 3 )
+ {
+ ts->printf( cvtest::TS::LOG, "The component #%d is incorrect\n", i );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ }
+
+ cvReleaseImage(&image_f);
+ cvReleaseImage(&image);
+ cvReleaseImage(&image_s);
+ }
+
+_exit_:
+
+ cvReleaseMemStorage( &storage );
+ cvReleaseImage(&image_f);
+ cvReleaseImage(&image);
+ cvReleaseImage(&image_s);
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Imgproc_PyrSegmentation, regression) { CV_PyrSegmentationTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_SubdivTest : public cvtest::BaseTest
+{
+public:
+ CV_SubdivTest();
+ ~CV_SubdivTest();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void run_func();
+
+ int min_log_img_size, max_log_img_size;
+ CvSize img_size;
+ int min_log_point_count;
+ int max_log_point_count;
+ int point_count;
+ CvSubdiv2D* subdiv;
+ CvMemStorage* storage;
+};
+
+
+CV_SubdivTest::CV_SubdivTest()
+{
+ test_case_count = 100;
+ min_log_point_count = 1;
+ max_log_point_count = 10;
+ min_log_img_size = 1;
+ max_log_img_size = 10;
+
+ storage = 0;
+}
+
+
+CV_SubdivTest::~CV_SubdivTest()
+{
+ clear();
+}
+
+
+void CV_SubdivTest::clear()
+{
+ cvtest::BaseTest::clear();
+ cvReleaseMemStorage( &storage );
+}
+
+
+int CV_SubdivTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ int t;
+
+ if( code < 0 )
+ return code;
+
+ test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
+ min_log_point_count = cvReadInt( find_param( fs, "min_log_point_count" ), min_log_point_count );
+ max_log_point_count = cvReadInt( find_param( fs, "max_log_point_count" ), max_log_point_count );
+ min_log_img_size = cvReadInt( find_param( fs, "min_log_img_size" ), min_log_img_size );
+ max_log_img_size = cvReadInt( find_param( fs, "max_log_img_size" ), max_log_img_size );
+
+ min_log_point_count = cvtest::clipInt( min_log_point_count, 1, 10 );
+ max_log_point_count = cvtest::clipInt( max_log_point_count, 1, 10 );
+ if( min_log_point_count > max_log_point_count )
+ CV_SWAP( min_log_point_count, max_log_point_count, t );
+
+ min_log_img_size = cvtest::clipInt( min_log_img_size, 1, 10 );
+ max_log_img_size = cvtest::clipInt( max_log_img_size, 1, 10 );
+ if( min_log_img_size > max_log_img_size )
+ CV_SWAP( min_log_img_size, max_log_img_size, t );
+
+ return 0;
+}
+
+
+int CV_SubdivTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ int code = cvtest::BaseTest::prepare_test_case( test_case_idx );
+ if( code < 0 )
+ return code;
+
+ clear();
+
+ point_count = cvRound(exp((cvtest::randReal(rng)*
+ (max_log_point_count - min_log_point_count) + min_log_point_count)*CV_LOG2));
+ img_size.width = cvRound(exp((cvtest::randReal(rng)*
+ (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+ img_size.height = cvRound(exp((cvtest::randReal(rng)*
+ (max_log_img_size - min_log_img_size) + min_log_img_size)*CV_LOG2));
+
+ storage = cvCreateMemStorage( 1 << 10 );
+ return 1;
+}
+
+
+void CV_SubdivTest::run_func()
+{
+}
+
+
+static inline double sqdist( CvPoint2D32f pt1, CvPoint2D32f pt2 )
+{
+ double dx = pt1.x - pt2.x;
+ double dy = pt1.y - pt2.y;
+
+ return dx*dx + dy*dy;
+}
+
+
+static int
+subdiv2DCheck( CvSubdiv2D* subdiv )
+{
+ int i, j, total = subdiv->edges->total;
+ CV_Assert( subdiv != 0 );
+
+ for( i = 0; i < total; i++ )
+ {
+ CvQuadEdge2D* edge = (CvQuadEdge2D*)cvGetSetElem(subdiv->edges,i);
+
+ if( edge && CV_IS_SET_ELEM( edge ))
+ {
+ for( j = 0; j < 4; j++ )
+ {
+ CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge + j;
+ CvSubdiv2DEdge o_next = cvSubdiv2DNextEdge(e);
+ CvSubdiv2DEdge o_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_ORG );
+ CvSubdiv2DEdge d_prev = cvSubdiv2DGetEdge(e, CV_PREV_AROUND_DST );
+ CvSubdiv2DEdge d_next = cvSubdiv2DGetEdge(e, CV_NEXT_AROUND_DST );
+
+ // check points
+ if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_next))
+ return 0;
+ if( cvSubdiv2DEdgeOrg(e) != cvSubdiv2DEdgeOrg(o_prev))
+ return 0;
+ if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_next))
+ return 0;
+ if( cvSubdiv2DEdgeDst(e) != cvSubdiv2DEdgeDst(d_prev))
+ return 0;
+ if( j % 2 == 0 )
+ {
+ if( cvSubdiv2DEdgeDst(o_next) != cvSubdiv2DEdgeOrg(d_prev))
+ return 0;
+ if( cvSubdiv2DEdgeDst(o_prev) != cvSubdiv2DEdgeOrg(d_next))
+ return 0;
+ if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
+ e,CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT),CV_NEXT_AROUND_LEFT) != e )
+ return 0;
+ if( cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(cvSubdiv2DGetEdge(
+ e,CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT),CV_NEXT_AROUND_RIGHT) != e)
+ return 0;
+ }
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+// the whole testing is done here, run_func() is not utilized in this test
+int CV_SubdivTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ RNG& rng = ts->get_rng();
+ int j, k, real_count = point_count;
+ double xrange = img_size.width*(1 - FLT_EPSILON);
+ double yrange = img_size.height*(1 - FLT_EPSILON);
+
+ subdiv = subdiv = cvCreateSubdivDelaunay2D(
+ cvRect( 0, 0, img_size.width, img_size.height ), storage );
+
+ CvSeq* seq = cvCreateSeq( 0, sizeof(*seq), sizeof(CvPoint2D32f), storage );
+ CvSeqWriter writer;
+ cvStartAppendToSeq( seq, &writer );
+
+ // insert random points
+ for( j = 0; j < point_count; j++ )
+ {
+ CvPoint2D32f pt;
+ CvSubdiv2DPoint* point;
+
+ pt.x = (float)(cvtest::randReal(rng)*xrange);
+ pt.y = (float)(cvtest::randReal(rng)*yrange);
+
+ CvSubdiv2DPointLocation loc =
+ cvSubdiv2DLocate( subdiv, pt, 0, &point );
+
+ if( loc == CV_PTLOC_VERTEX )
+ {
+ int index = cvSeqElemIdx( (CvSeq*)subdiv, point );
+ CvPoint2D32f* pt1;
+ cvFlushSeqWriter( &writer );
+ pt1 = (CvPoint2D32f*)cvGetSeqElem( seq, index - 3 );
+
+ if( !pt1 ||
+ fabs(pt1->x - pt.x) > FLT_EPSILON ||
+ fabs(pt1->y - pt.y) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "The point #%d: (%.1f,%.1f) is said to coinside with a subdivision vertex, "
+ "however it could be found in a sequence of inserted points\n", j, pt.x, pt.y );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ real_count--;
+ }
+
+ point = cvSubdivDelaunay2DInsert( subdiv, pt );
+ if( point->pt.x != pt.x || point->pt.y != pt.y )
+ {
+ ts->printf( cvtest::TS::LOG, "The point #%d: (%.1f,%.1f) has been incorrectly added\n", j, pt.x, pt.y );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ if( (j + 1) % 10 == 0 || j == point_count - 1 )
+ {
+ if( !subdiv2DCheck( subdiv ))
+ {
+ ts->printf( cvtest::TS::LOG, "Subdivision consistency check failed after inserting the point #%d\n", j );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+ }
+
+ if( loc != CV_PTLOC_VERTEX )
+ {
+ CV_WRITE_SEQ_ELEM( pt, writer );
+ }
+ }
+
+ if( code < 0 )
+ goto _exit_;
+
+ cvCalcSubdivVoronoi2D( subdiv );
+ seq = cvEndWriteSeq( &writer );
+
+ if( !subdiv2DCheck( subdiv ))
+ {
+ ts->printf( cvtest::TS::LOG, "The subdivision failed consistency check after building the Voronoi tesselation\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ for( j = 0; j < MAX((point_count - 5)/10 + 5, 10); j++ )
+ {
+ CvPoint2D32f pt;
+ double minDistance;
+
+ pt.x = (float)(cvtest::randReal(rng)*xrange);
+ pt.y = (float)(cvtest::randReal(rng)*yrange);
+
+ CvSubdiv2DPoint* point = cvFindNearestPoint2D( subdiv, pt );
+ CvSeqReader reader;
+
+ if( !point )
+ {
+ ts->printf( cvtest::TS::LOG, "There is no nearest point (?!) for the point (%.1f, %.1f) in the subdivision\n",
+ pt.x, pt.y );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ cvStartReadSeq( seq, &reader );
+ minDistance = sqdist( pt, point->pt );
+
+ for( k = 0; k < seq->total; k++ )
+ {
+ CvPoint2D32f ptt;
+ CV_READ_SEQ_ELEM( ptt, reader );
+
+ double distance = sqdist( pt, ptt );
+ if( minDistance > distance && sqdist(ptt, point->pt) > FLT_EPSILON*1000 )
+ {
+ ts->printf( cvtest::TS::LOG, "The triangulation vertex (%.3f,%.3f) was said to be nearest to (%.3f,%.3f),\n"
+ "whereas another vertex (%.3f,%.3f) is closer\n",
+ point->pt.x, point->pt.y, pt.x, pt.y, ptt.x, ptt.y );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ }
+ }
+
+_exit_:
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+
+ return code;
+}
+
+TEST(Imgproc_Subdiv, correctness) { CV_SubdivTest test; test.safe_run(); }
+
+/* End of file. */
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_TemplMatchTest : public cvtest::ArrayTest
+{
+public:
+ CV_TemplMatchTest();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int max_template_size;
+ int method;
+ bool test_cpp;
+};
+
+
+CV_TemplMatchTest::CV_TemplMatchTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ element_wise_relative_error = false;
+ max_template_size = 100;
+ method = 0;
+ test_cpp = false;
+}
+
+
+int CV_TemplMatchTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::ArrayTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ max_template_size = cvReadInt( find_param( fs, "max_template_size" ), max_template_size );
+ max_template_size = cvtest::clipInt( max_template_size, 1, 100 );
+
+ return code;
+}
+
+
+void CV_TemplMatchTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ int depth = CV_MAT_DEPTH(type);
+ if( depth == CV_32F )
+ {
+ low = Scalar::all(-10.);
+ high = Scalar::all(10.);
+ }
+}
+
+
+void CV_TemplMatchTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth = depth == 0 ? CV_8U : CV_32F;
+
+ types[INPUT][0] = types[INPUT][1] = CV_MAKETYPE(depth,cn);
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_32FC1;
+
+ sizes[INPUT][1].width = cvtest::randInt(rng)%MIN(sizes[INPUT][1].width,max_template_size) + 1;
+ sizes[INPUT][1].height = cvtest::randInt(rng)%MIN(sizes[INPUT][1].height,max_template_size) + 1;
+ sizes[OUTPUT][0].width = sizes[INPUT][0].width - sizes[INPUT][1].width + 1;
+ sizes[OUTPUT][0].height = sizes[INPUT][0].height - sizes[INPUT][1].height + 1;
+ sizes[REF_OUTPUT][0] = sizes[OUTPUT][0];
+
+ method = cvtest::randInt(rng)%6;
+ test_cpp = (cvtest::randInt(rng) & 256) == 0;
+}
+
+
+double CV_TemplMatchTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ if( test_mat[INPUT][1].depth() == CV_8U ||
+ (method >= CV_TM_CCOEFF && test_mat[INPUT][1].cols*test_mat[INPUT][1].rows <= 2) )
+ return 1e-2;
+ else
+ return 1e-3;
+}
+
+
+void CV_TemplMatchTest::run_func()
+{
+ if(!test_cpp)
+ cvMatchTemplate( test_array[INPUT][0], test_array[INPUT][1], test_array[OUTPUT][0], method );
+ else
+ {
+ cv::Mat _out = cv::cvarrToMat(test_array[OUTPUT][0]);
+ cv::matchTemplate(cv::cvarrToMat(test_array[INPUT][0]), cv::cvarrToMat(test_array[INPUT][1]), _out, method);
+ }
+}
+
+
+static void cvTsMatchTemplate( const CvMat* img, const CvMat* templ, CvMat* result, int method )
+{
+ int i, j, k, l;
+ int depth = CV_MAT_DEPTH(img->type), cn = CV_MAT_CN(img->type);
+ int width_n = templ->cols*cn, height = templ->rows;
+ int a_step = img->step / CV_ELEM_SIZE(img->type & CV_MAT_DEPTH_MASK);
+ int b_step = templ->step / CV_ELEM_SIZE(templ->type & CV_MAT_DEPTH_MASK);
+ CvScalar b_mean, b_sdv;
+ double b_denom = 1., b_sum2 = 0;
+ int area = templ->rows*templ->cols;
+
+ cvAvgSdv(templ, &b_mean, &b_sdv);
+
+ for( i = 0; i < cn; i++ )
+ b_sum2 += (b_sdv.val[i]*b_sdv.val[i] + b_mean.val[i]*b_mean.val[i])*area;
+
+ if( b_sdv.val[0]*b_sdv.val[0] + b_sdv.val[1]*b_sdv.val[1] +
+ b_sdv.val[2]*b_sdv.val[2] + b_sdv.val[3]*b_sdv.val[3] < DBL_EPSILON &&
+ method == CV_TM_CCOEFF_NORMED )
+ {
+ cvSet( result, cvScalarAll(1.) );
+ return;
+ }
+
+ if( method & 1 )
+ {
+ b_denom = 0;
+ if( method != CV_TM_CCOEFF_NORMED )
+ {
+ b_denom = b_sum2;
+ }
+ else
+ {
+ for( i = 0; i < cn; i++ )
+ b_denom += b_sdv.val[i]*b_sdv.val[i]*area;
+ }
+ b_denom = sqrt(b_denom);
+ if( b_denom == 0 )
+ b_denom = 1.;
+ }
+
+ assert( CV_TM_SQDIFF <= method && method <= CV_TM_CCOEFF_NORMED );
+
+ for( i = 0; i < result->rows; i++ )
+ {
+ for( j = 0; j < result->cols; j++ )
+ {
+ CvScalar a_sum = {{ 0, 0, 0, 0 }}, a_sum2 = {{ 0, 0, 0, 0 }};
+ CvScalar ccorr = {{ 0, 0, 0, 0 }};
+ double value = 0.;
+
+ if( depth == CV_8U )
+ {
+ const uchar* a = img->data.ptr + i*img->step + j*cn;
+ const uchar* b = templ->data.ptr;
+
+ if( cn == 1 || method < CV_TM_CCOEFF )
+ {
+ for( k = 0; k < height; k++, a += a_step, b += b_step )
+ for( l = 0; l < width_n; l++ )
+ {
+ ccorr.val[0] += a[l]*b[l];
+ a_sum.val[0] += a[l];
+ a_sum2.val[0] += a[l]*a[l];
+ }
+ }
+ else
+ {
+ for( k = 0; k < height; k++, a += a_step, b += b_step )
+ for( l = 0; l < width_n; l += 3 )
+ {
+ ccorr.val[0] += a[l]*b[l];
+ ccorr.val[1] += a[l+1]*b[l+1];
+ ccorr.val[2] += a[l+2]*b[l+2];
+ a_sum.val[0] += a[l];
+ a_sum.val[1] += a[l+1];
+ a_sum.val[2] += a[l+2];
+ a_sum2.val[0] += a[l]*a[l];
+ a_sum2.val[1] += a[l+1]*a[l+1];
+ a_sum2.val[2] += a[l+2]*a[l+2];
+ }
+ }
+ }
+ else
+ {
+ const float* a = (const float*)(img->data.ptr + i*img->step) + j*cn;
+ const float* b = (const float*)templ->data.ptr;
+
+ if( cn == 1 || method < CV_TM_CCOEFF )
+ {
+ for( k = 0; k < height; k++, a += a_step, b += b_step )
+ for( l = 0; l < width_n; l++ )
+ {
+ ccorr.val[0] += a[l]*b[l];
+ a_sum.val[0] += a[l];
+ a_sum2.val[0] += a[l]*a[l];
+ }
+ }
+ else
+ {
+ for( k = 0; k < height; k++, a += a_step, b += b_step )
+ for( l = 0; l < width_n; l += 3 )
+ {
+ ccorr.val[0] += a[l]*b[l];
+ ccorr.val[1] += a[l+1]*b[l+1];
+ ccorr.val[2] += a[l+2]*b[l+2];
+ a_sum.val[0] += a[l];
+ a_sum.val[1] += a[l+1];
+ a_sum.val[2] += a[l+2];
+ a_sum2.val[0] += a[l]*a[l];
+ a_sum2.val[1] += a[l+1]*a[l+1];
+ a_sum2.val[2] += a[l+2]*a[l+2];
+ }
+ }
+ }
+
+ switch( method )
+ {
+ case CV_TM_CCORR:
+ case CV_TM_CCORR_NORMED:
+ value = ccorr.val[0];
+ break;
+ case CV_TM_SQDIFF:
+ case CV_TM_SQDIFF_NORMED:
+ value = (a_sum2.val[0] + b_sum2 - 2*ccorr.val[0]);
+ break;
+ default:
+ value = (ccorr.val[0] - a_sum.val[0]*b_mean.val[0]+
+ ccorr.val[1] - a_sum.val[1]*b_mean.val[1]+
+ ccorr.val[2] - a_sum.val[2]*b_mean.val[2]);
+ }
+
+ if( method & 1 )
+ {
+ double denom;
+
+ // calc denominator
+ if( method != CV_TM_CCOEFF_NORMED )
+ {
+ denom = a_sum2.val[0] + a_sum2.val[1] + a_sum2.val[2];
+ }
+ else
+ {
+ denom = a_sum2.val[0] - (a_sum.val[0]*a_sum.val[0])/area;
+ denom += a_sum2.val[1] - (a_sum.val[1]*a_sum.val[1])/area;
+ denom += a_sum2.val[2] - (a_sum.val[2]*a_sum.val[2])/area;
+ }
+ denom = sqrt(MAX(denom,0))*b_denom;
+ if( fabs(value) < denom )
+ value /= denom;
+ else if( fabs(value) < denom*1.125 )
+ value = value > 0 ? 1 : -1;
+ else
+ value = method != CV_TM_SQDIFF_NORMED ? 0 : 1;
+ }
+
+ ((float*)(result->data.ptr + result->step*i))[j] = (float)value;
+ }
+ }
+}
+
+
+void CV_TemplMatchTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ CvMat _input = test_mat[INPUT][0], _templ = test_mat[INPUT][1];
+ CvMat _output = test_mat[REF_OUTPUT][0];
+ cvTsMatchTemplate( &_input, &_templ, &_output, method );
+
+ //if( ts->get_current_test_info()->test_case_idx == 0 )
+ /*{
+ CvFileStorage* fs = cvOpenFileStorage( "_match_template.yml", 0, CV_STORAGE_WRITE );
+ cvWrite( fs, "image", &test_mat[INPUT][0] );
+ cvWrite( fs, "template", &test_mat[INPUT][1] );
+ cvWrite( fs, "ref", &test_mat[REF_OUTPUT][0] );
+ cvWrite( fs, "opencv", &test_mat[OUTPUT][0] );
+ cvWriteInt( fs, "method", method );
+ cvReleaseFileStorage( &fs );
+ }*/
+
+ if( method >= CV_TM_CCOEFF )
+ {
+ // avoid numerical stability problems in singular cases (when the results are near to 0)
+ const double delta = 10.;
+ test_mat[REF_OUTPUT][0] += Scalar::all(delta);
+ test_mat[OUTPUT][0] += Scalar::all(delta);
+ }
+}
+
+TEST(Imgproc_MatchTemplate, accuracy) { CV_TemplMatchTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_ThreshTest : public cvtest::ArrayTest
+{
+public:
+ CV_ThreshTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ int thresh_type;
+ float thresh_val;
+ float max_val;
+};
+
+
+CV_ThreshTest::CV_ThreshTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ optional_mask = false;
+ element_wise_relative_error = true;
+}
+
+
+void CV_ThreshTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 2, cn = cvtest::randInt(rng) % 4 + 1;
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth = depth == 0 ? CV_8U : CV_32F;
+
+ types[INPUT][0] = types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_MAKETYPE(depth,cn);
+ thresh_type = cvtest::randInt(rng) % 5;
+
+ if( depth == CV_8U )
+ {
+ thresh_val = (float)(cvtest::randReal(rng)*350. - 50.);
+ max_val = (float)(cvtest::randReal(rng)*350. - 50.);
+ if( cvtest::randInt(rng)%4 == 0 )
+ max_val = 255;
+ }
+ else
+ {
+ thresh_val = (float)(cvtest::randReal(rng)*1000. - 500.);
+ max_val = (float)(cvtest::randReal(rng)*1000. - 500.);
+ }
+}
+
+
+double CV_ThreshTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return FLT_EPSILON*10;
+}
+
+
+void CV_ThreshTest::run_func()
+{
+ cvThreshold( test_array[INPUT][0], test_array[OUTPUT][0],
+ thresh_val, max_val, thresh_type );
+}
+
+
+static void test_threshold( const Mat& _src, Mat& _dst,
+ float thresh, float maxval, int thresh_type )
+{
+ int i, j;
+ int depth = _src.depth(), cn = _src.channels();
+ int width_n = _src.cols*cn, height = _src.rows;
+ int ithresh = cvFloor(thresh), ithresh2, imaxval = cvRound(maxval);
+ const uchar* src = _src.data;
+ uchar* dst = _dst.data;
+ size_t srcstep = _src.step, dststep = _dst.step;
+
+ ithresh2 = saturate_cast<uchar>(ithresh);
+ imaxval = saturate_cast<uchar>(imaxval);
+
+ assert( depth == CV_8U || depth == CV_32F );
+
+ switch( thresh_type )
+ {
+ case CV_THRESH_BINARY:
+ for( i = 0; i < height; i++, src += srcstep, dst += dststep )
+ {
+ if( depth == CV_8U )
+ for( j = 0; j < width_n; j++ )
+ dst[j] = (uchar)(src[j] > ithresh ? imaxval : 0);
+ else
+ for( j = 0; j < width_n; j++ )
+ ((float*)dst)[j] = ((const float*)src)[j] > thresh ? maxval : 0.f;
+ }
+ break;
+ case CV_THRESH_BINARY_INV:
+ for( i = 0; i < height; i++, src += srcstep, dst += dststep )
+ {
+ if( depth == CV_8U )
+ for( j = 0; j < width_n; j++ )
+ dst[j] = (uchar)(src[j] > ithresh ? 0 : imaxval);
+ else
+ for( j = 0; j < width_n; j++ )
+ ((float*)dst)[j] = ((const float*)src)[j] > thresh ? 0.f : maxval;
+ }
+ break;
+ case CV_THRESH_TRUNC:
+ for( i = 0; i < height; i++, src += srcstep, dst += dststep )
+ {
+ if( depth == CV_8U )
+ for( j = 0; j < width_n; j++ )
+ {
+ int s = src[j];
+ dst[j] = (uchar)(s > ithresh ? ithresh2 : s);
+ }
+ else
+ for( j = 0; j < width_n; j++ )
+ {
+ float s = ((const float*)src)[j];
+ ((float*)dst)[j] = s > thresh ? thresh : s;
+ }
+ }
+ break;
+ case CV_THRESH_TOZERO:
+ for( i = 0; i < height; i++, src += srcstep, dst += dststep )
+ {
+ if( depth == CV_8U )
+ for( j = 0; j < width_n; j++ )
+ {
+ int s = src[j];
+ dst[j] = (uchar)(s > ithresh ? s : 0);
+ }
+ else
+ for( j = 0; j < width_n; j++ )
+ {
+ float s = ((const float*)src)[j];
+ ((float*)dst)[j] = s > thresh ? s : 0.f;
+ }
+ }
+ break;
+ case CV_THRESH_TOZERO_INV:
+ for( i = 0; i < height; i++, src += srcstep, dst += dststep )
+ {
+ if( depth == CV_8U )
+ for( j = 0; j < width_n; j++ )
+ {
+ int s = src[j];
+ dst[j] = (uchar)(s > ithresh ? 0 : s);
+ }
+ else
+ for( j = 0; j < width_n; j++ )
+ {
+ float s = ((const float*)src)[j];
+ ((float*)dst)[j] = s > thresh ? 0.f : s;
+ }
+ }
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+void CV_ThreshTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_threshold( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ thresh_val, max_val, thresh_type );
+}
+
+TEST(Imgproc_Threshold, accuracy) { CV_ThreshTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include <string>
+
+using namespace cv;
+using namespace std;
+
+class CV_WatershedTest : public cvtest::BaseTest
+{
+public:
+ CV_WatershedTest();
+ ~CV_WatershedTest();
+protected:
+ void run(int);
+};
+
+CV_WatershedTest::CV_WatershedTest() {}
+CV_WatershedTest::~CV_WatershedTest() {}
+
+void CV_WatershedTest::run( int /* start_from */)
+{
+ string exp_path = string(ts->get_data_path()) + "watershed/wshed_exp.png";
+ Mat exp = imread(exp_path, 0);
+ Mat orig = imread(string(ts->get_data_path()) + "inpaint/orig.jpg");
+ FileStorage fs(string(ts->get_data_path()) + "watershed/comp.xml", FileStorage::READ);
+
+ if (orig.empty() || !fs.isOpened())
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ CvSeq* cnts = (CvSeq*)fs["contours"].readObj();
+
+ Mat markers(orig.size(), CV_32SC1);
+ markers = Scalar(0);
+ IplImage iplmrks = markers;
+
+ vector<unsigned char> colors(1);
+ for(int i = 0; cnts != 0; cnts = cnts->h_next, ++i )
+ {
+ cvDrawContours( &iplmrks, cnts, Scalar::all(i + 1), Scalar::all(i + 1), -1, CV_FILLED);
+ Point* p = (Point*)cvGetSeqElem(cnts, 0);
+
+ //expected image was added with 1 in order to save to png
+ //so now we substract 1 to get real color
+ if(exp.data)
+ colors.push_back(exp.ptr(p->y)[p->x] - 1);
+ }
+ fs.release();
+ const int compNum = (int)(colors.size() - 1);
+
+ watershed(orig, markers);
+
+ for(int j = 0; j < markers.rows; ++j)
+ {
+ int* line = markers.ptr<int>(j);
+ for(int i = 0; i < markers.cols; ++i)
+ {
+ int& pixel = line[i];
+
+ if (pixel == -1) // border
+ continue;
+
+ if (pixel <= 0 || pixel > compNum)
+ continue; // bad result, doing nothing and going to get error latter;
+
+ // repaint in saved color to compare with expected;
+ if(exp.data)
+ pixel = colors[pixel];
+ }
+ }
+
+ Mat markers8U;
+ markers.convertTo(markers8U, CV_8U, 1, 1);
+
+ if( exp.empty() || orig.size() != exp.size() )
+ {
+ imwrite(exp_path, markers8U);
+ exp = markers8U;
+ }
+
+ if (0 != norm(markers8U, exp, NORM_INF))
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ return;
+ }
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Imgproc_Watershed, regression) { CV_WatershedTest test; test.safe_run(); }
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace std;
+using namespace cv;
+
+void defaultDistribs( vector<Mat>& means, vector<Mat>& covs )
+{
+ float mp0[] = {0.0f, 0.0f}, cp0[] = {0.67f, 0.0f, 0.0f, 0.67f};
+ float mp1[] = {5.0f, 0.0f}, cp1[] = {1.0f, 0.0f, 0.0f, 1.0f};
+ float mp2[] = {1.0f, 5.0f}, cp2[] = {1.0f, 0.0f, 0.0f, 1.0f};
+ Mat m0( 1, 2, CV_32FC1, mp0 ), c0( 2, 2, CV_32FC1, cp0 );
+ Mat m1( 1, 2, CV_32FC1, mp1 ), c1( 2, 2, CV_32FC1, cp1 );
+ Mat m2( 1, 2, CV_32FC1, mp2 ), c2( 2, 2, CV_32FC1, cp2 );
+ means.resize(3), covs.resize(3);
+ m0.copyTo(means[0]), c0.copyTo(covs[0]);
+ m1.copyTo(means[1]), c1.copyTo(covs[1]);
+ m2.copyTo(means[2]), c2.copyTo(covs[2]);
+}
+
+// generate points sets by normal distributions
+void generateData( Mat& data, Mat& labels, const vector<int>& sizes, const vector<Mat>& means, const vector<Mat>& covs, int labelType )
+{
+ vector<int>::const_iterator sit = sizes.begin();
+ int total = 0;
+ for( ; sit != sizes.end(); ++sit )
+ total += *sit;
+ assert( means.size() == sizes.size() && covs.size() == sizes.size() );
+ assert( !data.empty() && data.rows == total );
+ assert( data.type() == CV_32FC1 );
+
+ labels.create( data.rows, 1, labelType );
+
+ randn( data, Scalar::all(0.0), Scalar::all(1.0) );
+ vector<Mat>::const_iterator mit = means.begin(), cit = covs.begin();
+ int bi, ei = 0;
+ sit = sizes.begin();
+ for( int p = 0, l = 0; sit != sizes.end(); ++sit, ++mit, ++cit, l++ )
+ {
+ bi = ei;
+ ei = bi + *sit;
+ assert( mit->rows == 1 && mit->cols == data.cols );
+ assert( cit->rows == data.cols && cit->cols == data.cols );
+ for( int i = bi; i < ei; i++, p++ )
+ {
+ Mat r(1, data.cols, CV_32FC1, data.ptr<float>(i));
+ r = r * (*cit) + *mit;
+ if( labelType == CV_32FC1 )
+ labels.at<float>(p, 0) = (float)l;
+ else
+ labels.at<int>(p, 0) = l;
+ }
+ }
+}
+
+int maxIdx( const vector<int>& count )
+{
+ int idx = -1;
+ int maxVal = -1;
+ vector<int>::const_iterator it = count.begin();
+ for( int i = 0; it != count.end(); ++it, i++ )
+ {
+ if( *it > maxVal)
+ {
+ maxVal = *it;
+ idx = i;
+ }
+ }
+ assert( idx >= 0);
+ return idx;
+}
+
+bool getLabelsMap( const Mat& labels, const vector<int>& sizes, vector<int>& labelsMap )
+{
+ int total = 0, setCount = (int)sizes.size();
+ vector<int>::const_iterator sit = sizes.begin();
+ for( ; sit != sizes.end(); ++sit )
+ total += *sit;
+ assert( !labels.empty() );
+ assert( labels.rows == total && labels.cols == 1 );
+ assert( labels.type() == CV_32SC1 || labels.type() == CV_32FC1 );
+
+ bool isFlt = labels.type() == CV_32FC1;
+ labelsMap.resize(setCount);
+ vector<int>::iterator lmit = labelsMap.begin();
+ vector<bool> buzy(setCount, false);
+ int bi, ei = 0;
+ for( sit = sizes.begin(); sit != sizes.end(); ++sit, ++lmit )
+ {
+ vector<int> count( setCount, 0 );
+ bi = ei;
+ ei = bi + *sit;
+ if( isFlt )
+ {
+ for( int i = bi; i < ei; i++ )
+ count[(int)labels.at<float>(i, 0)]++;
+ }
+ else
+ {
+ for( int i = bi; i < ei; i++ )
+ count[labels.at<int>(i, 0)]++;
+ }
+
+ *lmit = maxIdx( count );
+ if( buzy[*lmit] )
+ return false;
+ buzy[*lmit] = true;
+ }
+ return true;
+}
+
+float calcErr( const Mat& labels, const Mat& origLabels, const vector<int>& sizes, bool labelsEquivalent = true )
+{
+ int err = 0;
+ assert( !labels.empty() && !origLabels.empty() );
+ assert( labels.cols == 1 && origLabels.cols == 1 );
+ assert( labels.rows == origLabels.rows );
+ assert( labels.type() == origLabels.type() );
+ assert( labels.type() == CV_32SC1 || labels.type() == CV_32FC1 );
+
+ vector<int> labelsMap;
+ bool isFlt = labels.type() == CV_32FC1;
+ if( !labelsEquivalent )
+ {
+ getLabelsMap( labels, sizes, labelsMap );
+ for( int i = 0; i < labels.rows; i++ )
+ if( isFlt )
+ err += labels.at<float>(i, 0) != labelsMap[(int)origLabels.at<float>(i, 0)];
+ else
+ err += labels.at<int>(i, 0) != labelsMap[origLabels.at<int>(i, 0)];
+ }
+ else
+ {
+ for( int i = 0; i < labels.rows; i++ )
+ if( isFlt )
+ err += labels.at<float>(i, 0) != origLabels.at<float>(i, 0);
+ else
+ err += labels.at<int>(i, 0) != origLabels.at<int>(i, 0);
+ }
+ return (float)err / (float)labels.rows;
+}
+
+//--------------------------------------------------------------------------------------------
+class CV_KMeansTest : public cvtest::BaseTest {
+public:
+ CV_KMeansTest() {}
+protected:
+ virtual void run( int start_from );
+};
+
+void CV_KMeansTest::run( int /*start_from*/ )
+{
+ const int iters = 100;
+ int sizesArr[] = { 5000, 7000, 8000 };
+ int pointsCount = sizesArr[0]+ sizesArr[1] + sizesArr[2];
+
+ Mat data( pointsCount, 2, CV_32FC1 ), labels;
+ vector<int> sizes( sizesArr, sizesArr + sizeof(sizesArr) / sizeof(sizesArr[0]) );
+ vector<Mat> means, covs;
+ defaultDistribs( means, covs );
+ generateData( data, labels, sizes, means, covs, CV_32SC1 );
+
+ int code = cvtest::TS::OK;
+ Mat bestLabels;
+ // 1. flag==KMEANS_PP_CENTERS
+ kmeans( data, 3, bestLabels, TermCriteria( TermCriteria::COUNT, iters, 0.0), 0, KMEANS_PP_CENTERS, 0 );
+ if( calcErr( bestLabels, labels, sizes, false ) > 0.01f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy if flag==KMEANS_PP_CENTERS" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // 2. flag==KMEANS_RANDOM_CENTERS
+ kmeans( data, 3, bestLabels, TermCriteria( TermCriteria::COUNT, iters, 0.0), 0, KMEANS_RANDOM_CENTERS, 0 );
+ if( calcErr( bestLabels, labels, sizes, false ) > 0.01f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy if flag==KMEANS_PP_CENTERS" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // 3. flag==KMEANS_USE_INITIAL_LABELS
+ labels.copyTo( bestLabels );
+ RNG rng;
+ for( int i = 0; i < 0.5f * pointsCount; i++ )
+ bestLabels.at<int>( rng.next() % pointsCount, 0 ) = rng.next() % 3;
+ kmeans( data, 3, bestLabels, TermCriteria( TermCriteria::COUNT, iters, 0.0), 0, KMEANS_USE_INITIAL_LABELS, 0 );
+ if( calcErr( bestLabels, labels, sizes, false ) > 0.01f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy if flag==KMEANS_PP_CENTERS" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ ts->set_failed_test_info( code );
+}
+
+//--------------------------------------------------------------------------------------------
+class CV_KNearestTest : public cvtest::BaseTest {
+public:
+ CV_KNearestTest() {}
+protected:
+ virtual void run( int start_from );
+};
+
+void CV_KNearestTest::run( int /*start_from*/ )
+{
+ int sizesArr[] = { 500, 700, 800 };
+ int pointsCount = sizesArr[0]+ sizesArr[1] + sizesArr[2];
+
+ // train data
+ Mat trainData( pointsCount, 2, CV_32FC1 ), trainLabels;
+ vector<int> sizes( sizesArr, sizesArr + sizeof(sizesArr) / sizeof(sizesArr[0]) );
+ vector<Mat> means, covs;
+ defaultDistribs( means, covs );
+ generateData( trainData, trainLabels, sizes, means, covs, CV_32FC1 );
+
+ // test data
+ Mat testData( pointsCount, 2, CV_32FC1 ), testLabels, bestLabels;
+ generateData( testData, testLabels, sizes, means, covs, CV_32FC1 );
+
+ int code = cvtest::TS::OK;
+ KNearest knearest;
+ knearest.train( trainData, trainLabels );
+ knearest.find_nearest( testData, 4, &bestLabels );
+ if( calcErr( bestLabels, testLabels, sizes, true ) > 0.01f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy on test data" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ ts->set_failed_test_info( code );
+}
+
+//--------------------------------------------------------------------------------------------
+class CV_EMTest : public cvtest::BaseTest {
+public:
+ CV_EMTest() {}
+protected:
+ virtual void run( int start_from );
+};
+
+void CV_EMTest::run( int /*start_from*/ )
+{
+ int sizesArr[] = { 5000, 7000, 8000 };
+ int pointsCount = sizesArr[0]+ sizesArr[1] + sizesArr[2];
+
+ // train data
+ Mat trainData( pointsCount, 2, CV_32FC1 ), trainLabels;
+ vector<int> sizes( sizesArr, sizesArr + sizeof(sizesArr) / sizeof(sizesArr[0]) );
+ vector<Mat> means, covs;
+ defaultDistribs( means, covs );
+ generateData( trainData, trainLabels, sizes, means, covs, CV_32SC1 );
+
+ // test data
+ Mat testData( pointsCount, 2, CV_32FC1 ), testLabels, bestLabels;
+ generateData( testData, testLabels, sizes, means, covs, CV_32SC1 );
+
+ int code = cvtest::TS::OK;
+ ExpectationMaximization em;
+ CvEMParams params;
+ params.nclusters = 3;
+ em.train( trainData, Mat(), params, &bestLabels );
+
+ // check train error
+ if( calcErr( bestLabels, trainLabels, sizes, true ) > 0.002f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy on train data" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ // check test error
+ bestLabels.create( testData.rows, 1, CV_32SC1 );
+ for( int i = 0; i < testData.rows; i++ )
+ {
+ Mat sample( 1, testData.cols, CV_32FC1, testData.ptr<float>(i));
+ bestLabels.at<int>(i,0) = (int)em.predict( sample, 0 );
+ }
+ if( calcErr( bestLabels, testLabels, sizes, true ) > 0.005f )
+ {
+ ts->printf( cvtest::TS::LOG, "bad accuracy on test data" );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ ts->set_failed_test_info( code );
+}
+
+TEST(ML_KMeans, accuracy) { CV_KMeansTest test; test.safe_run(); }
+TEST(ML_KNearest, accuracy) { CV_KNearestTest test; test.safe_run(); }
+TEST(ML_EMTest, accuracy) { CV_EMTest test; test.safe_run(); }
--- /dev/null
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <fstream>
+#include <iostream>
+
+using namespace std;
+
+
+class CV_GBTreesTest : public cvtest::BaseTest
+{
+public:
+ CV_GBTreesTest();
+ ~CV_GBTreesTest();
+
+protected:
+ void run(int);
+
+ int TestTrainPredict(int test_num);
+ int TestSaveLoad();
+
+ int checkPredictError(int test_num);
+ int checkLoadSave();
+
+ //string model_file_name1;
+ //string model_file_name2;
+ char model_file_name1[50];
+ char model_file_name2[50];
+ string* datasets;
+ string data_path;
+
+ CvMLData* data;
+ CvGBTrees* gtb;
+
+ vector<float> test_resps1;
+ vector<float> test_resps2;
+};
+
+
+int _get_len(const CvMat* mat)
+{
+ return (mat->cols > mat->rows) ? mat->cols : mat->rows;
+}
+
+
+CV_GBTreesTest::CV_GBTreesTest()
+{
+ datasets = 0;
+ data = 0;
+ gtb = 0;
+}
+
+CV_GBTreesTest::~CV_GBTreesTest()
+{
+ if (data)
+ delete data;
+ delete[] datasets;
+}
+
+
+int CV_GBTreesTest::TestTrainPredict(int test_num)
+{
+ int code = cvtest::TS::OK;
+
+ int weak_count = 200;
+ float shrinkage = 0.1f;
+ float subsample_portion = 0.5f;
+ int max_depth = 5;
+ bool use_surrogates = true;
+ int loss_function_type = 0;
+ switch (test_num)
+ {
+ case (1) : loss_function_type = CvGBTrees::SQUARED_LOSS; break;
+ case (2) : loss_function_type = CvGBTrees::ABSOLUTE_LOSS; break;
+ case (3) : loss_function_type = CvGBTrees::HUBER_LOSS; break;
+ case (0) : loss_function_type = CvGBTrees::DEVIANCE_LOSS; break;
+ default :
+ {
+ ts->printf( cvtest::TS::LOG, "Bad test_num value in CV_GBTreesTest::TestTrainPredict(..) function." );
+ return cvtest::TS::FAIL_BAD_ARG_CHECK;
+ }
+ }
+
+ int dataset_num = test_num == 0 ? 0 : 1;
+ if (!data)
+ {
+ data = new CvMLData();
+ data->set_delimiter(',');
+
+ if (data->read_csv(datasets[dataset_num].c_str()))
+ {
+ ts->printf( cvtest::TS::LOG, "File reading error." );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+
+ if (test_num == 0)
+ {
+ data->set_response_idx(57);
+ data->set_var_types("ord[0-56],cat[57]");
+ }
+ else
+ {
+ data->set_response_idx(13);
+ data->set_var_types("ord[0-2,4-13],cat[3]");
+ subsample_portion = 0.7f;
+ }
+
+ int train_sample_count = cvFloor(_get_len(data->get_responses())*0.5f);
+ CvTrainTestSplit spl( train_sample_count );
+ data->set_train_test_split( &spl );
+ }
+
+ data->mix_train_and_test_idx();
+
+
+ if (gtb) delete gtb;
+ gtb = new CvGBTrees();
+ bool tmp_code = true;
+ tmp_code = gtb->train(data, CvGBTreesParams(loss_function_type, weak_count,
+ shrinkage, subsample_portion,
+ max_depth, use_surrogates));
+
+ if (!tmp_code)
+ {
+ ts->printf( cvtest::TS::LOG, "Model training was failed.");
+ return cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+
+ code = checkPredictError(test_num);
+
+ return code;
+
+}
+
+
+int CV_GBTreesTest::checkPredictError(int test_num)
+{
+ if (!gtb)
+ return cvtest::TS::FAIL_GENERIC;
+
+ float mean[] = {5.430247f, 13.5654f, 12.6569f, 13.1661f};
+ float sigma[] = {0.4162694f, 3.21161f, 3.43297f, 3.00624f};
+
+ float current_error = gtb->calc_error(data, CV_TEST_ERROR);
+
+ if ( abs( current_error - mean[test_num]) > 6*sigma[test_num] )
+ {
+ ts->printf( cvtest::TS::LOG, "Test error is out of range:\n"
+ "abs(%f/*curEr*/ - %f/*mean*/ > %f/*6*sigma*/",
+ current_error, mean[test_num], 6*sigma[test_num] );
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ return cvtest::TS::OK;
+
+}
+
+
+int CV_GBTreesTest::TestSaveLoad()
+{
+ if (!gtb)
+ return cvtest::TS::FAIL_GENERIC;
+
+ tmpnam(model_file_name1);
+ tmpnam(model_file_name2);
+
+ if(model_file_name1[0] == '\\')
+ model_file_name1[0] = '_';
+ if(model_file_name2[0] == '\\')
+ model_file_name2[0] = '_';
+
+ gtb->save(model_file_name1);
+ gtb->calc_error(data, CV_TEST_ERROR, &test_resps1);
+ gtb->load(model_file_name1);
+ gtb->calc_error(data, CV_TEST_ERROR, &test_resps2);
+ gtb->save(model_file_name2);
+
+ return checkLoadSave();
+
+}
+
+
+
+int CV_GBTreesTest::checkLoadSave()
+{
+ int code = cvtest::TS::OK;
+
+ // 1. compare files
+ ifstream f1( model_file_name1 ), f2( model_file_name2 );
+ string s1, s2;
+ int lineIdx = 0;
+ CV_Assert( f1.is_open() && f2.is_open() );
+ for( ; !f1.eof() && !f2.eof(); lineIdx++ )
+ {
+ getline( f1, s1 );
+ getline( f2, s2 );
+ if( s1.compare(s2) )
+ {
+ ts->printf( cvtest::TS::LOG, "first and second saved files differ in %n-line; first %n line: %s; second %n-line: %s",
+ lineIdx, lineIdx, s1.c_str(), lineIdx, s2.c_str() );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ }
+ if( !f1.eof() || !f2.eof() )
+ {
+ ts->printf( cvtest::TS::LOG, "First and second saved files differ in %n-line; first %n line: %s; second %n-line: %s",
+ lineIdx, lineIdx, s1.c_str(), lineIdx, s2.c_str() );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ f1.close();
+ f2.close();
+ // delete temporary files
+ remove( model_file_name1 );
+ remove( model_file_name2 );
+
+ // 2. compare responses
+ CV_Assert( test_resps1.size() == test_resps2.size() );
+ vector<float>::const_iterator it1 = test_resps1.begin(), it2 = test_resps2.begin();
+ for( ; it1 != test_resps1.end(); ++it1, ++it2 )
+ {
+ if( fabs(*it1 - *it2) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "Responses predicted before saving and after loading are different" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ }
+ return code;
+}
+
+
+
+void CV_GBTreesTest::run(int)
+{
+
+ string data_path = string(ts->get_data_path());
+ datasets = new string[2];
+ datasets[0] = data_path + string("spambase.data"); /*string("dataset_classification.csv");*/
+ datasets[1] = data_path + string("housing_.data"); /*string("dataset_regression.csv");*/
+
+ int code = cvtest::TS::OK;
+
+ for (int i = 0; i < 4; i++)
+ {
+
+ int temp_code = TestTrainPredict(i);
+ if (temp_code != cvtest::TS::OK)
+ {
+ code = temp_code;
+ break;
+ }
+
+ else if (i==0)
+ {
+ temp_code = TestSaveLoad();
+ if (temp_code != cvtest::TS::OK)
+ code = temp_code;
+ delete data;
+ data = 0;
+ }
+
+ delete gtb;
+ gtb = 0;
+ }
+ delete data;
+ data = 0;
+
+ ts->set_failed_test_info( code );
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//////////////////// test registration /////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+
+TEST(ML_GBTrees, regression) { CV_GBTreesTest test; test.safe_run(); }
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("ml")
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+CV_AMLTest::CV_AMLTest( const char* _modelName ) : CV_MLBaseTest( _modelName )
+{
+ validationFN = "avalidation.xml";
+}
+
+int CV_AMLTest::run_test_case( int testCaseIdx )
+{
+ int code = cvtest::TS::OK;
+ code = prepare_test_case( testCaseIdx );
+
+ if (code == cvtest::TS::OK)
+ {
+ //#define GET_STAT
+#ifdef GET_STAT
+ const char* data_name = ((CvFileNode*)cvGetSeqElem( dataSetNames, testCaseIdx ))->data.str.ptr;
+ printf("%s, %s ", name, data_name);
+ const int icount = 100;
+ float res[icount];
+ for (int k = 0; k < icount; k++)
+ {
+#endif
+ data.mix_train_and_test_idx();
+ code = train( testCaseIdx );
+#ifdef GET_STAT
+ float case_result = get_error();
+
+ res[k] = case_result;
+ }
+ float mean = 0, sigma = 0;
+ for (int k = 0; k < icount; k++)
+ {
+ mean += res[k];
+ }
+ mean = mean /icount;
+ for (int k = 0; k < icount; k++)
+ {
+ sigma += (res[k] - mean)*(res[k] - mean);
+ }
+ sigma = sqrt(sigma/icount);
+ printf("%f, %f\n", mean, sigma);
+#endif
+ }
+ return code;
+}
+
+int CV_AMLTest::validate_test_results( int testCaseIdx )
+{
+ int iters;
+ float mean, sigma;
+ // read validation params
+ FileNode resultNode =
+ validationFS.getFirstTopLevelNode()["validation"][modelName][dataSetNames[testCaseIdx]]["result"];
+ resultNode["iter_count"] >> iters;
+ if ( iters > 0)
+ {
+ resultNode["mean"] >> mean;
+ resultNode["sigma"] >> sigma;
+ float curErr = get_error( testCaseIdx, CV_TEST_ERROR );
+ const int coeff = 4;
+ ts->printf( cvtest::TS::LOG, "Test case = %d; test error = %f; mean error = %f (diff=%f), %d*sigma = %f",
+ testCaseIdx, curErr, mean, abs( curErr - mean), coeff, coeff*sigma );
+ if ( abs( curErr - mean) > coeff*sigma )
+ {
+ ts->printf( cvtest::TS::LOG, "abs(%f - %f) > %f - OUT OF RANGE!\n", curErr, mean, coeff*sigma, coeff );
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ else
+ ts->printf( cvtest::TS::LOG, ".\n" );
+
+ }
+ else
+ {
+ ts->printf( cvtest::TS::LOG, "validation info is not suitable" );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ return cvtest::TS::OK;
+}
+
+TEST(ML_DTree, regression) { CV_AMLTest test( CV_DTREE ); test.safe_run(); }
+TEST(ML_Boost, regression) { CV_AMLTest test( CV_BOOST ); test.safe_run(); }
+TEST(ML_RTrees, regression) { CV_AMLTest test( CV_RTREES ); test.safe_run(); }
+TEST(ML_ERTrees, regression) { CV_AMLTest test( CV_ERTREES ); test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+// auxiliary functions
+// 1. nbayes
+void nbayes_check_data( CvMLData* _data )
+{
+ if( _data->get_missing() )
+ CV_Error( CV_StsBadArg, "missing values are not supported" );
+ const CvMat* var_types = _data->get_var_types();
+ bool is_classifier = var_types->data.ptr[var_types->cols-1] == CV_VAR_CATEGORICAL;
+ if( ( fabs( cvNorm( var_types, 0, CV_L1 ) -
+ (var_types->rows + var_types->cols - 2)*CV_VAR_ORDERED - CV_VAR_CATEGORICAL ) > FLT_EPSILON ) ||
+ !is_classifier )
+ CV_Error( CV_StsBadArg, "incorrect types of predictors or responses" );
+}
+bool nbayes_train( CvNormalBayesClassifier* nbayes, CvMLData* _data )
+{
+ nbayes_check_data( _data );
+ const CvMat* values = _data->get_values();
+ const CvMat* responses = _data->get_responses();
+ const CvMat* train_sidx = _data->get_train_sample_idx();
+ const CvMat* var_idx = _data->get_var_idx();
+ return nbayes->train( values, responses, var_idx, train_sidx );
+}
+float nbayes_calc_error( CvNormalBayesClassifier* nbayes, CvMLData* _data, int type, vector<float> *resp )
+{
+ float err = 0;
+ nbayes_check_data( _data );
+ const CvMat* values = _data->get_values();
+ const CvMat* response = _data->get_responses();
+ const CvMat* sample_idx = (type == CV_TEST_ERROR) ? _data->get_test_sample_idx() : _data->get_train_sample_idx();
+ int* sidx = sample_idx ? sample_idx->data.i : 0;
+ int r_step = CV_IS_MAT_CONT(response->type) ?
+ 1 : response->step / CV_ELEM_SIZE(response->type);
+ int sample_count = sample_idx ? sample_idx->cols : 0;
+ sample_count = (type == CV_TRAIN_ERROR && sample_count == 0) ? values->rows : sample_count;
+ float* pred_resp = 0;
+ if( resp && (sample_count > 0) )
+ {
+ resp->resize( sample_count );
+ pred_resp = &((*resp)[0]);
+ }
+
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( values, &sample, si );
+ float r = (float)nbayes->predict( &sample, 0 );
+ if( pred_resp )
+ pred_resp[i] = r;
+ int d = fabs((double)r - response->data.fl[si*r_step]) <= FLT_EPSILON ? 0 : 1;
+ err += d;
+ }
+ err = sample_count ? err / (float)sample_count * 100 : -FLT_MAX;
+ return err;
+}
+
+// 2. knearest
+void knearest_check_data_and_get_predictors( CvMLData* _data, CvMat* _predictors )
+{
+ const CvMat* values = _data->get_values();
+ const CvMat* var_idx = _data->get_var_idx();
+ if( var_idx->cols + var_idx->rows != values->cols )
+ CV_Error( CV_StsBadArg, "var_idx is not supported" );
+ if( _data->get_missing() )
+ CV_Error( CV_StsBadArg, "missing values are not supported" );
+ int resp_idx = _data->get_response_idx();
+ if( resp_idx == 0)
+ cvGetCols( values, _predictors, 1, values->cols );
+ else if( resp_idx == values->cols - 1 )
+ cvGetCols( values, _predictors, 0, values->cols - 1 );
+ else
+ CV_Error( CV_StsBadArg, "responses must be in the first or last column; other cases are not supported" );
+}
+bool knearest_train( CvKNearest* knearest, CvMLData* _data )
+{
+ const CvMat* responses = _data->get_responses();
+ const CvMat* train_sidx = _data->get_train_sample_idx();
+ bool is_regression = _data->get_var_type( _data->get_response_idx() ) == CV_VAR_ORDERED;
+ CvMat predictors;
+ knearest_check_data_and_get_predictors( _data, &predictors );
+ return knearest->train( &predictors, responses, train_sidx, is_regression );
+}
+float knearest_calc_error( CvKNearest* knearest, CvMLData* _data, int k, int type, vector<float> *resp )
+{
+ float err = 0;
+ const CvMat* response = _data->get_responses();
+ const CvMat* sample_idx = (type == CV_TEST_ERROR) ? _data->get_test_sample_idx() : _data->get_train_sample_idx();
+ int* sidx = sample_idx ? sample_idx->data.i : 0;
+ int r_step = CV_IS_MAT_CONT(response->type) ?
+ 1 : response->step / CV_ELEM_SIZE(response->type);
+ bool is_regression = _data->get_var_type( _data->get_response_idx() ) == CV_VAR_ORDERED;
+ CvMat predictors;
+ knearest_check_data_and_get_predictors( _data, &predictors );
+ int sample_count = sample_idx ? sample_idx->cols : 0;
+ sample_count = (type == CV_TRAIN_ERROR && sample_count == 0) ? predictors.rows : sample_count;
+ float* pred_resp = 0;
+ if( resp && (sample_count > 0) )
+ {
+ resp->resize( sample_count );
+ pred_resp = &((*resp)[0]);
+ }
+ if ( !is_regression )
+ {
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( &predictors, &sample, si );
+ float r = knearest->find_nearest( &sample, k );
+ if( pred_resp )
+ pred_resp[i] = r;
+ int d = fabs((double)r - response->data.fl[si*r_step]) <= FLT_EPSILON ? 0 : 1;
+ err += d;
+ }
+ err = sample_count ? err / (float)sample_count * 100 : -FLT_MAX;
+ }
+ else
+ {
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( &predictors, &sample, si );
+ float r = knearest->find_nearest( &sample, k );
+ if( pred_resp )
+ pred_resp[i] = r;
+ float d = r - response->data.fl[si*r_step];
+ err += d*d;
+ }
+ err = sample_count ? err / (float)sample_count : -FLT_MAX;
+ }
+ return err;
+}
+
+// 3. svm
+int str_to_svm_type(string& str)
+{
+ if( !str.compare("C_SVC") )
+ return CvSVM::C_SVC;
+ if( !str.compare("NU_SVC") )
+ return CvSVM::NU_SVC;
+ if( !str.compare("ONE_CLASS") )
+ return CvSVM::ONE_CLASS;
+ if( !str.compare("EPS_SVR") )
+ return CvSVM::EPS_SVR;
+ if( !str.compare("NU_SVR") )
+ return CvSVM::NU_SVR;
+ CV_Error( CV_StsBadArg, "incorrect svm type string" );
+ return -1;
+}
+int str_to_svm_kernel_type( string& str )
+{
+ if( !str.compare("LINEAR") )
+ return CvSVM::LINEAR;
+ if( !str.compare("POLY") )
+ return CvSVM::POLY;
+ if( !str.compare("RBF") )
+ return CvSVM::RBF;
+ if( !str.compare("SIGMOID") )
+ return CvSVM::SIGMOID;
+ CV_Error( CV_StsBadArg, "incorrect svm type string" );
+ return -1;
+}
+void svm_check_data( CvMLData* _data )
+{
+ if( _data->get_missing() )
+ CV_Error( CV_StsBadArg, "missing values are not supported" );
+ const CvMat* var_types = _data->get_var_types();
+ for( int i = 0; i < var_types->cols-1; i++ )
+ if (var_types->data.ptr[i] == CV_VAR_CATEGORICAL)
+ {
+ char msg[50];
+ sprintf( msg, "incorrect type of %d-predictor", i );
+ CV_Error( CV_StsBadArg, msg );
+ }
+}
+bool svm_train( CvSVM* svm, CvMLData* _data, CvSVMParams _params )
+{
+ svm_check_data(_data);
+ const CvMat* _train_data = _data->get_values();
+ const CvMat* _responses = _data->get_responses();
+ const CvMat* _var_idx = _data->get_var_idx();
+ const CvMat* _sample_idx = _data->get_train_sample_idx();
+ return svm->train( _train_data, _responses, _var_idx, _sample_idx, _params );
+}
+bool svm_train_auto( CvSVM* svm, CvMLData* _data, CvSVMParams _params,
+ int k_fold, CvParamGrid C_grid, CvParamGrid gamma_grid,
+ CvParamGrid p_grid, CvParamGrid nu_grid, CvParamGrid coef_grid,
+ CvParamGrid degree_grid )
+{
+ svm_check_data(_data);
+ const CvMat* _train_data = _data->get_values();
+ const CvMat* _responses = _data->get_responses();
+ const CvMat* _var_idx = _data->get_var_idx();
+ const CvMat* _sample_idx = _data->get_train_sample_idx();
+ return svm->train_auto( _train_data, _responses, _var_idx,
+ _sample_idx, _params, k_fold, C_grid, gamma_grid, p_grid, nu_grid, coef_grid, degree_grid );
+}
+float svm_calc_error( CvSVM* svm, CvMLData* _data, int type, vector<float> *resp )
+{
+ svm_check_data(_data);
+ float err = 0;
+ const CvMat* values = _data->get_values();
+ const CvMat* response = _data->get_responses();
+ const CvMat* sample_idx = (type == CV_TEST_ERROR) ? _data->get_test_sample_idx() : _data->get_train_sample_idx();
+ const CvMat* var_types = _data->get_var_types();
+ int* sidx = sample_idx ? sample_idx->data.i : 0;
+ int r_step = CV_IS_MAT_CONT(response->type) ?
+ 1 : response->step / CV_ELEM_SIZE(response->type);
+ bool is_classifier = var_types->data.ptr[var_types->cols-1] == CV_VAR_CATEGORICAL;
+ int sample_count = sample_idx ? sample_idx->cols : 0;
+ sample_count = (type == CV_TRAIN_ERROR && sample_count == 0) ? values->rows : sample_count;
+ float* pred_resp = 0;
+ if( resp && (sample_count > 0) )
+ {
+ resp->resize( sample_count );
+ pred_resp = &((*resp)[0]);
+ }
+ if ( is_classifier )
+ {
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( values, &sample, si );
+ float r = svm->predict( &sample );
+ if( pred_resp )
+ pred_resp[i] = r;
+ int d = fabs((double)r - response->data.fl[si*r_step]) <= FLT_EPSILON ? 0 : 1;
+ err += d;
+ }
+ err = sample_count ? err / (float)sample_count * 100 : -FLT_MAX;
+ }
+ else
+ {
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( values, &sample, si );
+ float r = svm->predict( &sample );
+ if( pred_resp )
+ pred_resp[i] = r;
+ float d = r - response->data.fl[si*r_step];
+ err += d*d;
+ }
+ err = sample_count ? err / (float)sample_count : -FLT_MAX;
+ }
+ return err;
+}
+
+// 4. em
+// 5. ann
+int str_to_ann_train_method( string& str )
+{
+ if( !str.compare("BACKPROP") )
+ return CvANN_MLP_TrainParams::BACKPROP;
+ if( !str.compare("RPROP") )
+ return CvANN_MLP_TrainParams::RPROP;
+ CV_Error( CV_StsBadArg, "incorrect ann train method string" );
+ return -1;
+}
+void ann_check_data_and_get_predictors( CvMLData* _data, CvMat* _inputs )
+{
+ const CvMat* values = _data->get_values();
+ const CvMat* var_idx = _data->get_var_idx();
+ if( var_idx->cols + var_idx->rows != values->cols )
+ CV_Error( CV_StsBadArg, "var_idx is not supported" );
+ if( _data->get_missing() )
+ CV_Error( CV_StsBadArg, "missing values are not supported" );
+ int resp_idx = _data->get_response_idx();
+ if( resp_idx == 0)
+ cvGetCols( values, _inputs, 1, values->cols );
+ else if( resp_idx == values->cols - 1 )
+ cvGetCols( values, _inputs, 0, values->cols - 1 );
+ else
+ CV_Error( CV_StsBadArg, "outputs must be in the first or last column; other cases are not supported" );
+}
+void ann_get_new_responses( CvMLData* _data, Mat& new_responses, map<int, int>& cls_map )
+{
+ const CvMat* train_sidx = _data->get_train_sample_idx();
+ int* train_sidx_ptr = train_sidx->data.i;
+ const CvMat* responses = _data->get_responses();
+ float* responses_ptr = responses->data.fl;
+ int r_step = CV_IS_MAT_CONT(responses->type) ?
+ 1 : responses->step / CV_ELEM_SIZE(responses->type);
+ int cls_count = 0;
+ // construct cls_map
+ cls_map.clear();
+ for( int si = 0; si < train_sidx->cols; si++ )
+ {
+ int sidx = train_sidx_ptr[si];
+ int r = cvRound(responses_ptr[sidx*r_step]);
+ CV_DbgAssert( fabs(responses_ptr[sidx*r_step]-r) < FLT_EPSILON );
+ int cls_map_size = (int)cls_map.size();
+ cls_map[r];
+ if ( (int)cls_map.size() > cls_map_size )
+ cls_map[r] = cls_count++;
+ }
+ new_responses.create( responses->rows, cls_count, CV_32F );
+ new_responses.setTo( 0 );
+ for( int si = 0; si < train_sidx->cols; si++ )
+ {
+ int sidx = train_sidx_ptr[si];
+ int r = cvRound(responses_ptr[sidx*r_step]);
+ int cidx = cls_map[r];
+ new_responses.ptr<float>(sidx)[cidx] = 1;
+ }
+}
+int ann_train( CvANN_MLP* ann, CvMLData* _data, Mat& new_responses, CvANN_MLP_TrainParams _params, int flags = 0 )
+{
+ const CvMat* train_sidx = _data->get_train_sample_idx();
+ CvMat predictors;
+ ann_check_data_and_get_predictors( _data, &predictors );
+ CvMat _new_responses = CvMat( new_responses );
+ return ann->train( &predictors, &_new_responses, 0, train_sidx, _params, flags );
+}
+float ann_calc_error( CvANN_MLP* ann, CvMLData* _data, map<int, int>& cls_map, int type , vector<float> *resp_labels )
+{
+ float err = 0;
+ const CvMat* responses = _data->get_responses();
+ const CvMat* sample_idx = (type == CV_TEST_ERROR) ? _data->get_test_sample_idx() : _data->get_train_sample_idx();
+ int* sidx = sample_idx ? sample_idx->data.i : 0;
+ int r_step = CV_IS_MAT_CONT(responses->type) ?
+ 1 : responses->step / CV_ELEM_SIZE(responses->type);
+ CvMat predictors;
+ ann_check_data_and_get_predictors( _data, &predictors );
+ int sample_count = sample_idx ? sample_idx->cols : 0;
+ sample_count = (type == CV_TRAIN_ERROR && sample_count == 0) ? predictors.rows : sample_count;
+ float* pred_resp = 0;
+ vector<float> innresp;
+ if( sample_count > 0 )
+ {
+ if( resp_labels )
+ {
+ resp_labels->resize( sample_count );
+ pred_resp = &((*resp_labels)[0]);
+ }
+ else
+ {
+ innresp.resize( sample_count );
+ pred_resp = &(innresp[0]);
+ }
+ }
+ int cls_count = (int)cls_map.size();
+ Mat output( 1, cls_count, CV_32FC1 );
+ CvMat _output = CvMat(output);
+ map<int, int>::iterator b_it = cls_map.begin();
+ for( int i = 0; i < sample_count; i++ )
+ {
+ CvMat sample;
+ int si = sidx ? sidx[i] : i;
+ cvGetRow( &predictors, &sample, si );
+ ann->predict( &sample, &_output );
+ CvPoint best_cls = {0,0};
+ cvMinMaxLoc( &_output, 0, 0, 0, &best_cls, 0 );
+ int r = cvRound(responses->data.fl[si*r_step]);
+ CV_DbgAssert( fabs(responses->data.fl[si*r_step]-r) < FLT_EPSILON );
+ r = cls_map[r];
+ int d = best_cls.x == r ? 0 : 1;
+ err += d;
+ pred_resp[i] = (float)best_cls.x;
+ }
+ err = sample_count ? err / (float)sample_count * 100 : -FLT_MAX;
+ return err;
+}
+
+// 6. dtree
+// 7. boost
+int str_to_boost_type( string& str )
+{
+ if ( !str.compare("DISCRETE") )
+ return CvBoost::DISCRETE;
+ if ( !str.compare("REAL") )
+ return CvBoost::REAL;
+ if ( !str.compare("LOGIT") )
+ return CvBoost::LOGIT;
+ if ( !str.compare("GENTLE") )
+ return CvBoost::GENTLE;
+ CV_Error( CV_StsBadArg, "incorrect boost type string" );
+ return -1;
+}
+
+// 8. rtrees
+// 9. ertrees
+
+// ---------------------------------- MLBaseTest ---------------------------------------------------
+
+CV_MLBaseTest::CV_MLBaseTest(const char* _modelName)
+{
+ int64 seeds[] = { CV_BIG_INT(0x00009fff4f9c8d52),
+ CV_BIG_INT(0x0000a17166072c7c),
+ CV_BIG_INT(0x0201b32115cd1f9a),
+ CV_BIG_INT(0x0513cb37abcd1234),
+ CV_BIG_INT(0x0001a2b3c4d5f678)
+ };
+
+ int seedCount = sizeof(seeds)/sizeof(seeds[0]);
+ RNG& rng = theRNG();
+
+ initSeed = rng.state;
+
+ rng.state = seeds[rng(seedCount)];
+
+ modelName = _modelName;
+ nbayes = 0;
+ knearest = 0;
+ svm = 0;
+ em = 0;
+ ann = 0;
+ dtree = 0;
+ boost = 0;
+ rtrees = 0;
+ ertrees = 0;
+ if( !modelName.compare(CV_NBAYES) )
+ nbayes = new CvNormalBayesClassifier;
+ else if( !modelName.compare(CV_KNEAREST) )
+ knearest = new CvKNearest;
+ else if( !modelName.compare(CV_SVM) )
+ svm = new CvSVM;
+ else if( !modelName.compare(CV_EM) )
+ em = new CvEM;
+ else if( !modelName.compare(CV_ANN) )
+ ann = new CvANN_MLP;
+ else if( !modelName.compare(CV_DTREE) )
+ dtree = new CvDTree;
+ else if( !modelName.compare(CV_BOOST) )
+ boost = new CvBoost;
+ else if( !modelName.compare(CV_RTREES) )
+ rtrees = new CvRTrees;
+ else if( !modelName.compare(CV_ERTREES) )
+ ertrees = new CvERTrees;
+}
+
+CV_MLBaseTest::~CV_MLBaseTest()
+{
+ if( validationFS.isOpened() )
+ validationFS.release();
+ if( nbayes )
+ delete nbayes;
+ if( knearest )
+ delete knearest;
+ if( svm )
+ delete svm;
+ if( em )
+ delete em;
+ if( ann )
+ delete ann;
+ if( dtree )
+ delete dtree;
+ if( boost )
+ delete boost;
+ if( rtrees )
+ delete rtrees;
+ if( ertrees )
+ delete ertrees;
+ theRNG().state = initSeed;
+}
+
+int CV_MLBaseTest::read_params( CvFileStorage* _fs )
+{
+ if( !_fs )
+ test_case_count = -1;
+ else
+ {
+ CvFileNode* fn = cvGetRootFileNode( _fs, 0 );
+ fn = (CvFileNode*)cvGetSeqElem( fn->data.seq, 0 );
+ fn = cvGetFileNodeByName( _fs, fn, "run_params" );
+ CvSeq* dataSetNamesSeq = cvGetFileNodeByName( _fs, fn, modelName.c_str() )->data.seq;
+ test_case_count = dataSetNamesSeq ? dataSetNamesSeq->total : -1;
+ if( test_case_count > 0 )
+ {
+ dataSetNames.resize( test_case_count );
+ vector<string>::iterator it = dataSetNames.begin();
+ for( int i = 0; i < test_case_count; i++, it++ )
+ *it = ((CvFileNode*)cvGetSeqElem( dataSetNamesSeq, i ))->data.str.ptr;
+ }
+ }
+ return cvtest::TS::OK;;
+}
+
+void CV_MLBaseTest::run( int start_from )
+{
+ string filename = ts->get_data_path();
+ filename += get_validation_filename();
+ validationFS.open( filename, FileStorage::READ );
+ read_params( *validationFS );
+
+ int code = cvtest::TS::OK;
+ start_from = 0;
+ for (int i = 0; i < test_case_count; i++)
+ {
+ int temp_code = run_test_case( i );
+ if (temp_code == cvtest::TS::OK)
+ temp_code = validate_test_results( i );
+ if (temp_code != cvtest::TS::OK)
+ code = temp_code;
+ }
+ if ( test_case_count <= 0)
+ {
+ ts->printf( cvtest::TS::LOG, "validation file is not determined or not correct" );
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ ts->set_failed_test_info( code );
+}
+
+int CV_MLBaseTest::prepare_test_case( int test_case_idx )
+{
+ int trainSampleCount, respIdx;
+ string varTypes;
+ clear();
+
+ string dataPath = ts->get_data_path();
+ if ( dataPath.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "data path is empty" );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+
+ string dataName = dataSetNames[test_case_idx],
+ filename = dataPath + dataName + ".data";
+ if ( data.read_csv( filename.c_str() ) != 0)
+ {
+ char msg[100];
+ sprintf( msg, "file %s can not be read", filename.c_str() );
+ ts->printf( cvtest::TS::LOG, msg );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+
+ FileNode dataParamsNode = validationFS.getFirstTopLevelNode()["validation"][modelName][dataName]["data_params"];
+ CV_DbgAssert( !dataParamsNode.empty() );
+
+ CV_DbgAssert( !dataParamsNode["LS"].empty() );
+ dataParamsNode["LS"] >> trainSampleCount;
+ CvTrainTestSplit spl( trainSampleCount );
+ data.set_train_test_split( &spl );
+
+ CV_DbgAssert( !dataParamsNode["resp_idx"].empty() );
+ dataParamsNode["resp_idx"] >> respIdx;
+ data.set_response_idx( respIdx );
+
+ CV_DbgAssert( !dataParamsNode["types"].empty() );
+ dataParamsNode["types"] >> varTypes;
+ data.set_var_types( varTypes.c_str() );
+
+ return cvtest::TS::OK;
+}
+
+string& CV_MLBaseTest::get_validation_filename()
+{
+ return validationFN;
+}
+
+int CV_MLBaseTest::train( int testCaseIdx )
+{
+ bool is_trained = false;
+ FileNode modelParamsNode =
+ validationFS.getFirstTopLevelNode()["validation"][modelName][dataSetNames[testCaseIdx]]["model_params"];
+
+ if( !modelName.compare(CV_NBAYES) )
+ is_trained = nbayes_train( nbayes, &data );
+ else if( !modelName.compare(CV_KNEAREST) )
+ {
+ assert( 0 );
+ //is_trained = knearest->train( &data );
+ }
+ else if( !modelName.compare(CV_SVM) )
+ {
+ string svm_type_str, kernel_type_str;
+ modelParamsNode["svm_type"] >> svm_type_str;
+ modelParamsNode["kernel_type"] >> kernel_type_str;
+ CvSVMParams params;
+ params.svm_type = str_to_svm_type( svm_type_str );
+ params.kernel_type = str_to_svm_kernel_type( kernel_type_str );
+ modelParamsNode["degree"] >> params.degree;
+ modelParamsNode["gamma"] >> params.gamma;
+ modelParamsNode["coef0"] >> params.coef0;
+ modelParamsNode["C"] >> params.C;
+ modelParamsNode["nu"] >> params.nu;
+ modelParamsNode["p"] >> params.p;
+ is_trained = svm_train( svm, &data, params );
+ }
+ else if( !modelName.compare(CV_EM) )
+ {
+ assert( 0 );
+ }
+ else if( !modelName.compare(CV_ANN) )
+ {
+ string train_method_str;
+ double param1, param2;
+ modelParamsNode["train_method"] >> train_method_str;
+ modelParamsNode["param1"] >> param1;
+ modelParamsNode["param2"] >> param2;
+ Mat new_responses;
+ ann_get_new_responses( &data, new_responses, cls_map );
+ int layer_sz[] = { data.get_values()->cols - 1, 100, 100, (int)cls_map.size() };
+ CvMat layer_sizes =
+ cvMat( 1, (int)(sizeof(layer_sz)/sizeof(layer_sz[0])), CV_32S, layer_sz );
+ ann->create( &layer_sizes );
+ is_trained = ann_train( ann, &data, new_responses, CvANN_MLP_TrainParams(cvTermCriteria(CV_TERMCRIT_ITER,300,0.01),
+ str_to_ann_train_method(train_method_str), param1, param2) ) >= 0;
+ }
+ else if( !modelName.compare(CV_DTREE) )
+ {
+ int MAX_DEPTH, MIN_SAMPLE_COUNT, MAX_CATEGORIES, CV_FOLDS;
+ float REG_ACCURACY = 0;
+ bool USE_SURROGATE, IS_PRUNED;
+ modelParamsNode["max_depth"] >> MAX_DEPTH;
+ modelParamsNode["min_sample_count"] >> MIN_SAMPLE_COUNT;
+ modelParamsNode["use_surrogate"] >> USE_SURROGATE;
+ modelParamsNode["max_categories"] >> MAX_CATEGORIES;
+ modelParamsNode["cv_folds"] >> CV_FOLDS;
+ modelParamsNode["is_pruned"] >> IS_PRUNED;
+ is_trained = dtree->train( &data,
+ CvDTreeParams(MAX_DEPTH, MIN_SAMPLE_COUNT, REG_ACCURACY, USE_SURROGATE,
+ MAX_CATEGORIES, CV_FOLDS, false, IS_PRUNED, 0 )) != 0;
+ }
+ else if( !modelName.compare(CV_BOOST) )
+ {
+ int BOOST_TYPE, WEAK_COUNT, MAX_DEPTH;
+ float WEIGHT_TRIM_RATE;
+ bool USE_SURROGATE;
+ string typeStr;
+ modelParamsNode["type"] >> typeStr;
+ BOOST_TYPE = str_to_boost_type( typeStr );
+ modelParamsNode["weak_count"] >> WEAK_COUNT;
+ modelParamsNode["weight_trim_rate"] >> WEIGHT_TRIM_RATE;
+ modelParamsNode["max_depth"] >> MAX_DEPTH;
+ modelParamsNode["use_surrogate"] >> USE_SURROGATE;
+ is_trained = boost->train( &data,
+ CvBoostParams(BOOST_TYPE, WEAK_COUNT, WEIGHT_TRIM_RATE, MAX_DEPTH, USE_SURROGATE, 0) ) != 0;
+ }
+ else if( !modelName.compare(CV_RTREES) )
+ {
+ int MAX_DEPTH, MIN_SAMPLE_COUNT, MAX_CATEGORIES, CV_FOLDS, NACTIVE_VARS, MAX_TREES_NUM;
+ float REG_ACCURACY = 0, OOB_EPS = 0.0;
+ bool USE_SURROGATE, IS_PRUNED;
+ modelParamsNode["max_depth"] >> MAX_DEPTH;
+ modelParamsNode["min_sample_count"] >> MIN_SAMPLE_COUNT;
+ modelParamsNode["use_surrogate"] >> USE_SURROGATE;
+ modelParamsNode["max_categories"] >> MAX_CATEGORIES;
+ modelParamsNode["cv_folds"] >> CV_FOLDS;
+ modelParamsNode["is_pruned"] >> IS_PRUNED;
+ modelParamsNode["nactive_vars"] >> NACTIVE_VARS;
+ modelParamsNode["max_trees_num"] >> MAX_TREES_NUM;
+ is_trained = rtrees->train( &data, CvRTParams( MAX_DEPTH, MIN_SAMPLE_COUNT, REG_ACCURACY,
+ USE_SURROGATE, MAX_CATEGORIES, 0, true, // (calc_var_importance == true) <=> RF processes variable importance
+ NACTIVE_VARS, MAX_TREES_NUM, OOB_EPS, CV_TERMCRIT_ITER)) != 0;
+ }
+ else if( !modelName.compare(CV_ERTREES) )
+ {
+ int MAX_DEPTH, MIN_SAMPLE_COUNT, MAX_CATEGORIES, CV_FOLDS, NACTIVE_VARS, MAX_TREES_NUM;
+ float REG_ACCURACY = 0, OOB_EPS = 0.0;
+ bool USE_SURROGATE, IS_PRUNED;
+ modelParamsNode["max_depth"] >> MAX_DEPTH;
+ modelParamsNode["min_sample_count"] >> MIN_SAMPLE_COUNT;
+ modelParamsNode["use_surrogate"] >> USE_SURROGATE;
+ modelParamsNode["max_categories"] >> MAX_CATEGORIES;
+ modelParamsNode["cv_folds"] >> CV_FOLDS;
+ modelParamsNode["is_pruned"] >> IS_PRUNED;
+ modelParamsNode["nactive_vars"] >> NACTIVE_VARS;
+ modelParamsNode["max_trees_num"] >> MAX_TREES_NUM;
+ is_trained = ertrees->train( &data, CvRTParams( MAX_DEPTH, MIN_SAMPLE_COUNT, REG_ACCURACY,
+ USE_SURROGATE, MAX_CATEGORIES, 0, false, // (calc_var_importance == true) <=> RF processes variable importance
+ NACTIVE_VARS, MAX_TREES_NUM, OOB_EPS, CV_TERMCRIT_ITER)) != 0;
+ }
+
+ if( !is_trained )
+ {
+ ts->printf( cvtest::TS::LOG, "in test case %d model training was failed", testCaseIdx );
+ return cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ return cvtest::TS::OK;
+}
+
+float CV_MLBaseTest::get_error( int testCaseIdx, int type, vector<float> *resp )
+{
+ float err = 0;
+ if( !modelName.compare(CV_NBAYES) )
+ err = nbayes_calc_error( nbayes, &data, type, resp );
+ else if( !modelName.compare(CV_KNEAREST) )
+ {
+ assert( 0 );
+ testCaseIdx = 0;
+ /*int k = 2;
+ validationFS.getFirstTopLevelNode()["validation"][modelName][dataSetNames[testCaseIdx]]["model_params"]["k"] >> k;
+ err = knearest->calc_error( &data, k, type, resp );*/
+ }
+ else if( !modelName.compare(CV_SVM) )
+ err = svm_calc_error( svm, &data, type, resp );
+ else if( !modelName.compare(CV_EM) )
+ assert( 0 );
+ else if( !modelName.compare(CV_ANN) )
+ err = ann_calc_error( ann, &data, cls_map, type, resp );
+ else if( !modelName.compare(CV_DTREE) )
+ err = dtree->calc_error( &data, type, resp );
+ else if( !modelName.compare(CV_BOOST) )
+ err = boost->calc_error( &data, type, resp );
+ else if( !modelName.compare(CV_RTREES) )
+ err = rtrees->calc_error( &data, type, resp );
+ else if( !modelName.compare(CV_ERTREES) )
+ err = ertrees->calc_error( &data, type, resp );
+ return err;
+}
+
+void CV_MLBaseTest::save( const char* filename )
+{
+ if( !modelName.compare(CV_NBAYES) )
+ nbayes->save( filename );
+ else if( !modelName.compare(CV_KNEAREST) )
+ knearest->save( filename );
+ else if( !modelName.compare(CV_SVM) )
+ svm->save( filename );
+ else if( !modelName.compare(CV_EM) )
+ em->save( filename );
+ else if( !modelName.compare(CV_ANN) )
+ ann->save( filename );
+ else if( !modelName.compare(CV_DTREE) )
+ dtree->save( filename );
+ else if( !modelName.compare(CV_BOOST) )
+ boost->save( filename );
+ else if( !modelName.compare(CV_RTREES) )
+ rtrees->save( filename );
+ else if( !modelName.compare(CV_ERTREES) )
+ ertrees->save( filename );
+}
+
+void CV_MLBaseTest::load( const char* filename )
+{
+ if( !modelName.compare(CV_NBAYES) )
+ nbayes->load( filename );
+ else if( !modelName.compare(CV_KNEAREST) )
+ knearest->load( filename );
+ else if( !modelName.compare(CV_SVM) )
+ svm->load( filename );
+ else if( !modelName.compare(CV_EM) )
+ em->load( filename );
+ else if( !modelName.compare(CV_ANN) )
+ ann->load( filename );
+ else if( !modelName.compare(CV_DTREE) )
+ dtree->load( filename );
+ else if( !modelName.compare(CV_BOOST) )
+ boost->load( filename );
+ else if( !modelName.compare(CV_RTREES) )
+ rtrees->load( filename );
+ else if( !modelName.compare(CV_ERTREES) )
+ ertrees->load( filename );
+}
+
+/* End of file. */
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/ml/ml.hpp"
+#include "opencv2/core/core_c.h"
+#include <iostream>
+#include <map>
+
+#define CV_NBAYES "nbayes"
+#define CV_KNEAREST "knearest"
+#define CV_SVM "svm"
+#define CV_EM "em"
+#define CV_ANN "ann"
+#define CV_DTREE "dtree"
+#define CV_BOOST "boost"
+#define CV_RTREES "rtrees"
+#define CV_ERTREES "ertrees"
+
+class CV_MLBaseTest : public cvtest::BaseTest
+{
+public:
+ CV_MLBaseTest( const char* _modelName );
+ virtual ~CV_MLBaseTest();
+protected:
+ virtual int read_params( CvFileStorage* fs );
+ virtual void run( int startFrom );
+ virtual int prepare_test_case( int testCaseIdx );
+ virtual std::string& get_validation_filename();
+ virtual int run_test_case( int testCaseIdx ) = 0;
+ virtual int validate_test_results( int testCaseIdx ) = 0;
+
+ int train( int testCaseIdx );
+ float get_error( int testCaseIdx, int type, std::vector<float> *resp = 0 );
+ void save( const char* filename );
+ void load( const char* filename );
+
+ CvMLData data;
+ std::string modelName, validationFN;
+ std::vector<std::string> dataSetNames;
+ cv::FileStorage validationFS;
+
+ // MLL models
+ CvNormalBayesClassifier* nbayes;
+ CvKNearest* knearest;
+ CvSVM* svm;
+ CvEM* em;
+ CvANN_MLP* ann;
+ CvDTree* dtree;
+ CvBoost* boost;
+ CvRTrees* rtrees;
+ CvERTrees* ertrees;
+
+ std::map<int, int> cls_map;
+
+ int64 initSeed;
+};
+
+class CV_AMLTest : public CV_MLBaseTest
+{
+public:
+ CV_AMLTest( const char* _modelName );
+protected:
+ virtual int run_test_case( int testCaseIdx );
+ virtual int validate_test_results( int testCaseIdx );
+};
+
+class CV_SLMLTest : public CV_MLBaseTest
+{
+public:
+ CV_SLMLTest( const char* _modelName );
+protected:
+ virtual int run_test_case( int testCaseIdx );
+ virtual int validate_test_results( int testCaseIdx );
+
+ std::vector<float> test_resps1, test_resps2; // predicted responses for test data
+ char fname1[50], fname2[50];
+};
+
+#endif
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <iostream>
+#include <fstream>
+
+using namespace cv;
+using namespace std;
+
+CV_SLMLTest::CV_SLMLTest( const char* _modelName ) : CV_MLBaseTest( _modelName )
+{
+ validationFN = "slvalidation.xml";
+}
+
+int CV_SLMLTest::run_test_case( int testCaseIdx )
+{
+ int code = cvtest::TS::OK;
+ code = prepare_test_case( testCaseIdx );
+
+ if( code == cvtest::TS::OK )
+ {
+ data.mix_train_and_test_idx();
+ code = train( testCaseIdx );
+ if( code == cvtest::TS::OK )
+ {
+ get_error( testCaseIdx, CV_TEST_ERROR, &test_resps1 );
+ tmpnam(fname1);
+ if(fname1[0] == '\\') fname1[0] = '_';
+ save( fname1 );
+ load( fname1);
+ get_error( testCaseIdx, CV_TEST_ERROR, &test_resps2 );
+ tmpnam(fname2);
+ if(fname2[0] == '\\') fname2[0] = '_';
+ save( fname2 );
+ }
+ else
+ ts->printf( cvtest::TS::LOG, "model can not be trained" );
+ }
+ return code;
+}
+
+int CV_SLMLTest::validate_test_results( int testCaseIdx )
+{
+ int code = cvtest::TS::OK;
+
+ // 1. compare files
+ ifstream f1( fname1 ), f2( fname2 );
+ string s1, s2;
+ int lineIdx = 0;
+ CV_Assert( f1.is_open() && f2.is_open() );
+ for( ; !f1.eof() && !f2.eof(); lineIdx++ )
+ {
+ getline( f1, s1 );
+ getline( f2, s2 );
+ if( s1.compare(s2) )
+ {
+ ts->printf( cvtest::TS::LOG, "first and second saved files differ in %n-line; first %n line: %s; second %n-line: %s",
+ lineIdx, lineIdx, s1.c_str(), lineIdx, s2.c_str() );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ }
+ if( !f1.eof() || !f2.eof() )
+ {
+ ts->printf( cvtest::TS::LOG, "in test case %d first and second saved files differ in %n-line; first %n line: %s; second %n-line: %s",
+ testCaseIdx, lineIdx, lineIdx, s1.c_str(), lineIdx, s2.c_str() );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ f1.close();
+ f2.close();
+ // delete temporary files
+ remove( fname1 );
+ remove( fname2 );
+
+ // 2. compare responses
+ CV_Assert( test_resps1.size() == test_resps2.size() );
+ vector<float>::const_iterator it1 = test_resps1.begin(), it2 = test_resps2.begin();
+ for( ; it1 != test_resps1.end(); ++it1, ++it2 )
+ {
+ if( fabs(*it1 - *it2) > FLT_EPSILON )
+ {
+ ts->printf( cvtest::TS::LOG, "in test case %d responses predicted before saving and after loading is different", testCaseIdx );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ }
+ }
+ return code;
+}
+
+TEST(ML_NaiveBayes, save_load) { CV_SLMLTest test( CV_NBAYES ); test.safe_run(); }
+//CV_SLMLTest lsmlknearest( CV_KNEAREST, "slknearest" ); // does not support save!
+TEST(ML_SVM, save_load) { CV_SLMLTest test( CV_SVM ); test.safe_run(); }
+//CV_SLMLTest lsmlem( CV_EM, "slem" ); // does not support save!
+TEST(ML_ANN, save_load) { CV_SLMLTest test( CV_ANN ); test.safe_run(); }
+TEST(ML_DTree, save_load) { CV_SLMLTest test( CV_DTREE ); test.safe_run(); }
+TEST(ML_Boost, save_load) { CV_SLMLTest test( CV_BOOST ); test.safe_run(); }
+TEST(ML_RTrees, save_load) { CV_SLMLTest test( CV_RTREES ); test.safe_run(); }
+TEST(ML_ERTrees, save_load) { CV_SLMLTest test( CV_ERTREES ); test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+
+using namespace cv;
+using namespace std;
+
+//#define GET_STAT
+
+#define DIST_E "distE"
+#define S_E "sE"
+#define NO_PAIR_E "noPairE"
+//#define TOTAL_NO_PAIR_E "totalNoPairE"
+
+#define DETECTOR_NAMES "detector_names"
+#define DETECTORS "detectors"
+#define IMAGE_FILENAMES "image_filenames"
+#define VALIDATION "validation"
+#define FILENAME "fn"
+
+#define C_SCALE_CASCADE "scale_cascade"
+
+class CV_DetectorTest : public cvtest::BaseTest
+{
+public:
+ CV_DetectorTest();
+protected:
+ virtual int prepareData( FileStorage& fs );
+ virtual void run( int startFrom );
+ virtual string& getValidationFilename();
+
+ virtual void readDetector( const FileNode& fn ) = 0;
+ virtual void writeDetector( FileStorage& fs, int di ) = 0;
+ int runTestCase( int detectorIdx, vector<vector<Rect> >& objects );
+ virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects ) = 0;
+ int validate( int detectorIdx, vector<vector<Rect> >& objects );
+
+ struct
+ {
+ float dist;
+ float s;
+ float noPair;
+ //float totalNoPair;
+ } eps;
+ vector<string> detectorNames;
+ vector<string> detectorFilenames;
+ vector<string> imageFilenames;
+ vector<Mat> images;
+ string validationFilename;
+ FileStorage validationFS;
+};
+
+CV_DetectorTest::CV_DetectorTest()
+{
+}
+
+string& CV_DetectorTest::getValidationFilename()
+{
+ return validationFilename;
+}
+
+int CV_DetectorTest::prepareData( FileStorage& _fs )
+{
+ if( !_fs.isOpened() )
+ test_case_count = -1;
+ else
+ {
+ FileNode fn = _fs.getFirstTopLevelNode();
+
+ fn[DIST_E] >> eps.dist;
+ fn[S_E] >> eps.s;
+ fn[NO_PAIR_E] >> eps.noPair;
+// fn[TOTAL_NO_PAIR_E] >> eps.totalNoPair;
+
+ // read detectors
+ if( fn[DETECTOR_NAMES].node->data.seq != 0 )
+ {
+ FileNodeIterator it = fn[DETECTOR_NAMES].begin();
+ for( ; it != fn[DETECTOR_NAMES].end(); )
+ {
+ string name;
+ it >> name;
+ detectorNames.push_back(name);
+ readDetector(fn[DETECTORS][name]);
+ }
+ }
+ test_case_count = (int)detectorNames.size();
+
+ // read images filenames and images
+ string dataPath = ts->get_data_path();
+ if( fn[IMAGE_FILENAMES].node->data.seq != 0 )
+ {
+ for( FileNodeIterator it = fn[IMAGE_FILENAMES].begin(); it != fn[IMAGE_FILENAMES].end(); )
+ {
+ string filename;
+ it >> filename;
+ imageFilenames.push_back(filename);
+ Mat img = imread( dataPath+filename, 1 );
+ images.push_back( img );
+ }
+ }
+ }
+ return cvtest::TS::OK;
+}
+
+void CV_DetectorTest::run( int )
+{
+ string dataPath = ts->get_data_path();
+ validationFS.open( dataPath + getValidationFilename(), FileStorage::READ );
+ int code = prepareData( validationFS );
+ if( code < 0 )
+ {
+ ts->set_failed_test_info( code );
+ return;
+ }
+
+#ifdef GET_STAT
+ validationFS.release();
+ string filename = ts->get_data_path();
+ filename += getValidationFilename();
+ validationFS.open( filename, FileStorage::WRITE );
+ validationFS << FileStorage::getDefaultObjectName(validationFilename) << "{";
+
+ validationFS << DIST_E << eps.dist;
+ validationFS << S_E << eps.s;
+ validationFS << NO_PAIR_E << eps.noPair;
+// validationFS << TOTAL_NO_PAIR_E << eps.totalNoPair;
+
+ // write detector names
+ validationFS << DETECTOR_NAMES << "[";
+ vector<string>::const_iterator nit = detectorNames.begin();
+ for( ; nit != detectorNames.end(); ++nit )
+ {
+ validationFS << *nit;
+ }
+ validationFS << "]"; // DETECTOR_NAMES
+
+ // write detectors
+ validationFS << DETECTORS << "{";
+ assert( detectorNames.size() == detectorFilenames.size() );
+ nit = detectorNames.begin();
+ for( int di = 0; di < detectorNames.size(), nit != detectorNames.end(); ++nit, di++ )
+ {
+ validationFS << *nit << "{";
+ writeDetector( validationFS, di );
+ validationFS << "}";
+ }
+ validationFS << "}";
+
+ // write image filenames
+ validationFS << IMAGE_FILENAMES << "[";
+ vector<string>::const_iterator it = imageFilenames.begin();
+ for( int ii = 0; it != imageFilenames.end(); ++it, ii++ )
+ {
+ char buf[10];
+ sprintf( buf, "%s%d", "img_", ii );
+ cvWriteComment( validationFS.fs, buf, 0 );
+ validationFS << *it;
+ }
+ validationFS << "]"; // IMAGE_FILENAMES
+
+ validationFS << VALIDATION << "{";
+#endif
+
+ int progress = 0;
+ for( int di = 0; di < test_case_count; di++ )
+ {
+ progress = update_progress( progress, di, test_case_count, 0 );
+#ifdef GET_STAT
+ validationFS << detectorNames[di] << "{";
+#endif
+ vector<vector<Rect> > objects;
+ int temp_code = runTestCase( di, objects );
+#ifndef GET_STAT
+ if (temp_code == cvtest::TS::OK)
+ temp_code = validate( di, objects );
+#endif
+ if (temp_code != cvtest::TS::OK)
+ code = temp_code;
+#ifdef GET_STAT
+ validationFS << "}"; // detectorNames[di]
+#endif
+ }
+
+#ifdef GET_STAT
+ validationFS << "}"; // VALIDATION
+ validationFS << "}"; // getDefaultObjectName
+#endif
+ if ( test_case_count <= 0 || imageFilenames.size() <= 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "validation file is not determined or not correct" );
+ code = cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ ts->set_failed_test_info( code );
+}
+
+int CV_DetectorTest::runTestCase( int detectorIdx, vector<vector<Rect> >& objects )
+{
+ string dataPath = ts->get_data_path(), detectorFilename;
+ if( !detectorFilenames[detectorIdx].empty() )
+ detectorFilename = dataPath + detectorFilenames[detectorIdx];
+
+ for( int ii = 0; ii < (int)imageFilenames.size(); ++ii )
+ {
+ vector<Rect> imgObjects;
+ Mat image = images[ii];
+ if( image.empty() )
+ {
+ char msg[30];
+ sprintf( msg, "%s %d %s", "image ", ii, " can not be read" );
+ ts->printf( cvtest::TS::LOG, msg );
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ int code = detectMultiScale( detectorIdx, image, imgObjects );
+ if( code != cvtest::TS::OK )
+ return code;
+
+ objects.push_back( imgObjects );
+
+#ifdef GET_STAT
+ char buf[10];
+ sprintf( buf, "%s%d", "img_", ii );
+ string imageIdxStr = buf;
+ validationFS << imageIdxStr << "[:";
+ for( vector<Rect>::const_iterator it = imgObjects.begin();
+ it != imgObjects.end(); ++it )
+ {
+ validationFS << it->x << it->y << it->width << it->height;
+ }
+ validationFS << "]"; // imageIdxStr
+#endif
+ }
+ return cvtest::TS::OK;
+}
+
+
+bool isZero( uchar i ) {return i == 0;}
+
+int CV_DetectorTest::validate( int detectorIdx, vector<vector<Rect> >& objects )
+{
+ assert( imageFilenames.size() == objects.size() );
+ int imageIdx = 0;
+ int totalNoPair = 0, totalValRectCount = 0;
+
+ for( vector<vector<Rect> >::const_iterator it = objects.begin();
+ it != objects.end(); ++it, imageIdx++ ) // for image
+ {
+ Size imgSize = images[imageIdx].size();
+ float dist = min(imgSize.height, imgSize.width) * eps.dist;
+ float wDiff = imgSize.width * eps.s;
+ float hDiff = imgSize.height * eps.s;
+
+ int noPair = 0;
+
+ // read validation rectangles
+ char buf[10];
+ sprintf( buf, "%s%d", "img_", imageIdx );
+ string imageIdxStr = buf;
+ FileNode node = validationFS.getFirstTopLevelNode()[VALIDATION][detectorNames[detectorIdx]][imageIdxStr];
+ vector<Rect> valRects;
+ if( node.node->data.seq != 0 )
+ {
+ for( FileNodeIterator it = node.begin(); it != node.end(); )
+ {
+ Rect r;
+ it >> r.x >> r.y >> r.width >> r.height;
+ valRects.push_back(r);
+ }
+ }
+ totalValRectCount += (int)valRects.size();
+
+ // compare rectangles
+ vector<uchar> map(valRects.size(), 0);
+ for( vector<Rect>::const_iterator cr = it->begin();
+ cr != it->end(); ++cr )
+ {
+ // find nearest rectangle
+ Point2f cp1 = Point2f( cr->x + (float)cr->width/2.0f, cr->y + (float)cr->height/2.0f );
+ int minIdx = -1, vi = 0;
+ float minDist = (float)norm( Point(imgSize.width, imgSize.height) );
+ for( vector<Rect>::const_iterator vr = valRects.begin();
+ vr != valRects.end(); ++vr, vi++ )
+ {
+ Point2f cp2 = Point2f( vr->x + (float)vr->width/2.0f, vr->y + (float)vr->height/2.0f );
+ float curDist = (float)norm(cp1-cp2);
+ if( curDist < minDist )
+ {
+ minIdx = vi;
+ minDist = curDist;
+ }
+ }
+ if( minIdx == -1 )
+ {
+ noPair++;
+ }
+ else
+ {
+ Rect vr = valRects[minIdx];
+ if( map[minIdx] != 0 || (minDist > dist) || (abs(cr->width - vr.width) > wDiff) ||
+ (abs(cr->height - vr.height) > hDiff) )
+ noPair++;
+ else
+ map[minIdx] = 1;
+ }
+ }
+ noPair += (int)count_if( map.begin(), map.end(), isZero );
+ totalNoPair += noPair;
+ if( noPair > cvRound(valRects.size()*eps.noPair)+1 )
+ break;
+ }
+ if( imageIdx < (int)imageFilenames.size() )
+ {
+ char msg[500];
+ sprintf( msg, "detector %s has overrated count of rectangles without pair on %s-image\n",
+ detectorNames[detectorIdx].c_str(), imageFilenames[imageIdx].c_str() );
+ ts->printf( cvtest::TS::LOG, msg );
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ if ( totalNoPair > cvRound(totalValRectCount*eps./*total*/noPair)+1 )
+ {
+ ts->printf( cvtest::TS::LOG, "overrated count of rectangles without pair on all images set" );
+ return cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ return cvtest::TS::OK;
+}
+
+//----------------------------------------------- CascadeDetectorTest -----------------------------------
+class CV_CascadeDetectorTest : public CV_DetectorTest
+{
+public:
+ CV_CascadeDetectorTest();
+protected:
+ virtual void readDetector( const FileNode& fn );
+ virtual void writeDetector( FileStorage& fs, int di );
+ virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects );
+ vector<int> flags;
+};
+
+CV_CascadeDetectorTest::CV_CascadeDetectorTest()
+{
+ validationFilename = "cascadeandhog/cascade.xml";
+}
+
+void CV_CascadeDetectorTest::readDetector( const FileNode& fn )
+{
+ string filename;
+ int flag;
+ fn[FILENAME] >> filename;
+ detectorFilenames.push_back(filename);
+ fn[C_SCALE_CASCADE] >> flag;
+ if( flag )
+ flags.push_back( 0 );
+ else
+ flags.push_back( CV_HAAR_SCALE_IMAGE );
+}
+
+void CV_CascadeDetectorTest::writeDetector( FileStorage& fs, int di )
+{
+ int sc = flags[di] & CV_HAAR_SCALE_IMAGE ? 0 : 1;
+ fs << FILENAME << detectorFilenames[di];
+ fs << C_SCALE_CASCADE << sc;
+}
+
+int CV_CascadeDetectorTest::detectMultiScale( int di, const Mat& img,
+ vector<Rect>& objects)
+{
+ string dataPath = ts->get_data_path(), filename;
+ filename = dataPath + detectorFilenames[di];
+ CascadeClassifier cascade( filename );
+ if( cascade.empty() )
+ {
+ ts->printf( cvtest::TS::LOG, "cascade %s can not be opened");
+ return cvtest::TS::FAIL_INVALID_TEST_DATA;
+ }
+ Mat grayImg;
+ cvtColor( img, grayImg, CV_BGR2GRAY );
+ equalizeHist( grayImg, grayImg );
+ cascade.detectMultiScale( grayImg, objects, 1.1, 3, flags[di] );
+ return cvtest::TS::OK;
+}
+
+//----------------------------------------------- HOGDetectorTest -----------------------------------
+class CV_HOGDetectorTest : public CV_DetectorTest
+{
+public:
+ CV_HOGDetectorTest();
+protected:
+ virtual void readDetector( const FileNode& fn );
+ virtual void writeDetector( FileStorage& fs, int di );
+ virtual int detectMultiScale( int di, const Mat& img, vector<Rect>& objects );
+};
+
+CV_HOGDetectorTest::CV_HOGDetectorTest()
+{
+ validationFilename = "cascadeandhog/hog.xml";
+}
+
+void CV_HOGDetectorTest::readDetector( const FileNode& fn )
+{
+ string filename;
+ if( fn[FILENAME].node->data.seq != 0 )
+ fn[FILENAME] >> filename;
+ detectorFilenames.push_back( filename);
+}
+
+void CV_HOGDetectorTest::writeDetector( FileStorage& fs, int di )
+{
+ fs << FILENAME << detectorFilenames[di];
+}
+
+int CV_HOGDetectorTest::detectMultiScale( int di, const Mat& img,
+ vector<Rect>& objects)
+{
+ HOGDescriptor hog;
+ if( detectorFilenames[di].empty() )
+ hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
+ else
+ assert(0);
+ hog.detectMultiScale(img, objects);
+ return cvtest::TS::OK;
+}
+
+TEST(Objdetect_CascadeDetector, regression) { CV_CascadeDetectorTest test; test.safe_run(); }
+TEST(Objdetect_HOGDetector, regression) { CV_HOGDetectorTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+
+using namespace cv;
+
+const int num_detections = 3;
+const float true_scores[3] = {-0.383931f, -0.825876f, -0.959934f};
+const float score_thr = 0.05f;
+const CvRect true_bounding_boxes[3] = {cvRect(0, 45, 362, 452), cvRect(304, 0, 64, 80), cvRect(236, 0, 108, 59)};
+
+class CV_LatentSVMDetectorTest : public cvtest::BaseTest
+{
+public:
+ CV_LatentSVMDetectorTest();
+ ~CV_LatentSVMDetectorTest();
+protected:
+ void run(int);
+private:
+ bool isEqual(CvRect r1, CvRect r2);
+};
+
+CV_LatentSVMDetectorTest::CV_LatentSVMDetectorTest()
+{
+}
+
+CV_LatentSVMDetectorTest::~CV_LatentSVMDetectorTest() {}
+
+bool CV_LatentSVMDetectorTest::isEqual(CvRect r1, CvRect r2)
+{
+ return ((r1.x == r2.x) && (r1.y == r2.y) && (r1.width == r2.width) && (r1.height == r2.height));
+}
+
+void CV_LatentSVMDetectorTest::run( int /* start_from */)
+{
+ string img_path = string(ts->get_data_path()) + "latentsvmdetector/cat.jpg";
+ string model_path = string(ts->get_data_path()) + "latentsvmdetector/cat.xml";
+
+ IplImage* image = cvLoadImage(img_path.c_str());
+ if (!image)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return;
+ }
+
+ CvLatentSvmDetector* detector = cvLoadLatentSvmDetector(model_path.c_str());
+ if (!detector)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ cvReleaseImage(&image);
+ return;
+ }
+
+ CvMemStorage* storage = cvCreateMemStorage(0);
+ CvSeq* detections = 0;
+ detections = cvLatentSvmDetectObjects(image, detector, storage);
+
+ if (detections->total != num_detections)
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ }
+ else
+ {
+ ts->set_failed_test_info(cvtest::TS::OK);
+ for (int i = 0; i < detections->total; i++)
+ {
+ CvObjectDetection detection = *(CvObjectDetection*)cvGetSeqElem( detections, i );
+ CvRect bounding_box = detection.rect;
+ float score = detection.score;
+ if ((!isEqual(bounding_box, true_bounding_boxes[i])) || (fabs(score - true_scores[i]) > score_thr))
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_MISMATCH );
+ break;
+ }
+ }
+ }
+
+ cvReleaseMemStorage( &storage );
+ cvReleaseLatentSvmDetector( &detector );
+ cvReleaseImage( &image );
+}
+
+TEST(Objdetect_LatentSVMDetector, regression) { CV_LatentSVMDetectorTest test; test.safe_run(); }
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/objdetect/objdetect.hpp"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/highgui/highgui.hpp"
+#include <iostream>
+
+#endif
CV_EXPORTS_W double calcGlobalOrientation( const Mat& orientation, const Mat& mask,
const Mat& mhi, double timestamp,
double duration );
-// TODO: need good API for cvSegmentMotion
+
+CV_EXPORTS_W void segmentMotion(const Mat& mhi, Mat& segmask,
+ vector<Rect>& boundingRects,
+ double timestamp, double segThresh);
//! updates the object tracking window using CAMSHIFT algorithm
CV_EXPORTS_W RotatedRect CamShift( const Mat& probImage, CV_IN_OUT Rect& window,
return cvCalcGlobalOrientation(&_orientation, &_mask, &_mhi, timestamp, duration);
}
+void cv::segmentMotion(const Mat& mhi, Mat& segmask,
+ vector<Rect>& boundingRects,
+ double timestamp, double segThresh)
+{
+ segmask.create(mhi.size(), CV_32F);
+ CvMat c_mhi = mhi, c_segmask = segmask;
+ Ptr<CvMemStorage> storage = cvCreateMemStorage();
+ Seq<CvConnectedComp> comps = cvSegmentMotion(&c_mhi, &c_segmask, storage, timestamp, segThresh);
+ Seq<CvConnectedComp>::const_iterator it(comps);
+ size_t i, ncomps = comps.size();
+ boundingRects.resize(ncomps);
+ for( i = 0; i < ncomps; i++, ++it)
+ boundingRects[i] = (*it).rect;
+}
+
/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_AccumBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_AccumBaseTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ double alpha;
+};
+
+
+CV_AccumBaseTest::CV_AccumBaseTest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ test_array[MASK].push_back(NULL);
+ optional_mask = true;
+ element_wise_relative_error = false;
+} // ctor
+
+
+void CV_AccumBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ int depth = cvtest::randInt(rng) % 3, cn = cvtest::randInt(rng) & 1 ? 3 : 1;
+ int accdepth = std::max((int)(cvtest::randInt(rng) % 2 + 1), depth);
+ int i, input_count = test_array[INPUT].size();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ depth = depth == 0 ? CV_8U : depth == 1 ? CV_32F : CV_64F;
+ accdepth = accdepth == 1 ? CV_32F : CV_64F;
+ accdepth = MAX(accdepth, depth);
+
+ for( i = 0; i < input_count; i++ )
+ types[INPUT][i] = CV_MAKETYPE(depth,cn);
+
+ types[INPUT_OUTPUT][0] = types[REF_INPUT_OUTPUT][0] = CV_MAKETYPE(accdepth,cn);
+
+ alpha = cvtest::randReal(rng);
+}
+
+
+double CV_AccumBaseTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return test_mat[INPUT_OUTPUT][0].depth() < CV_64F ||
+ test_mat[INPUT][0].depth() == CV_32F ? FLT_EPSILON*100 : DBL_EPSILON*1000;
+}
+
+
+/// acc
+class CV_AccTest : public CV_AccumBaseTest
+{
+public:
+ CV_AccTest() {};
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+void CV_AccTest::run_func(void)
+{
+ cvAcc( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
+}
+
+
+void CV_AccTest::prepare_to_validation( int )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
+ Mat temp;
+ cvtest::add( src, 1, dst, 1, cvScalarAll(0.), temp, dst.type() );
+ cvtest::copy( temp, dst, mask );
+}
+
+
+/// square acc
+class CV_SquareAccTest : public CV_AccumBaseTest
+{
+public:
+ CV_SquareAccTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_SquareAccTest::CV_SquareAccTest()
+{
+}
+
+
+void CV_SquareAccTest::run_func()
+{
+ cvSquareAcc( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
+}
+
+
+void CV_SquareAccTest::prepare_to_validation( int )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
+ Mat temp;
+
+ cvtest::convert( src, temp, dst.type() );
+ cvtest::multiply( temp, temp, temp, 1 );
+ cvtest::add( temp, 1, dst, 1, cvScalarAll(0.), temp, dst.depth() );
+ cvtest::copy( temp, dst, mask );
+}
+
+
+/// multiply acc
+class CV_MultiplyAccTest : public CV_AccumBaseTest
+{
+public:
+ CV_MultiplyAccTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_MultiplyAccTest::CV_MultiplyAccTest()
+{
+ test_array[INPUT].push_back(NULL);
+}
+
+
+void CV_MultiplyAccTest::run_func()
+{
+ cvMultiplyAcc( test_array[INPUT][0], test_array[INPUT][1],
+ test_array[INPUT_OUTPUT][0], test_array[MASK][0] );
+}
+
+
+void CV_MultiplyAccTest::prepare_to_validation( int )
+{
+ const Mat& src1 = test_mat[INPUT][0];
+ const Mat& src2 = test_mat[INPUT][1];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
+ Mat temp1, temp2;
+
+ cvtest::convert( src1, temp1, dst.type() );
+ cvtest::convert( src2, temp2, dst.type() );
+
+ cvtest::multiply( temp1, temp2, temp1, 1 );
+ cvtest::add( temp1, 1, dst, 1, cvScalarAll(0.), temp1, dst.depth() );
+ cvtest::copy( temp1, dst, mask );
+}
+
+
+/// running average
+class CV_RunningAvgTest : public CV_AccumBaseTest
+{
+public:
+ CV_RunningAvgTest();
+protected:
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_RunningAvgTest::CV_RunningAvgTest()
+{
+}
+
+
+void CV_RunningAvgTest::run_func()
+{
+ cvRunningAvg( test_array[INPUT][0], test_array[INPUT_OUTPUT][0],
+ alpha, test_array[MASK][0] );
+}
+
+
+void CV_RunningAvgTest::prepare_to_validation( int )
+{
+ const Mat& src = test_mat[INPUT][0];
+ Mat& dst = test_mat[REF_INPUT_OUTPUT][0];
+ Mat temp;
+ const Mat& mask = test_array[MASK][0] ? test_mat[MASK][0] : Mat();
+ double a[1], b[1];
+ int accdepth = test_mat[INPUT_OUTPUT][0].depth();
+ CvMat A = cvMat(1,1,accdepth,a), B = cvMat(1,1,accdepth,b);
+ cvSetReal1D( &A, 0, alpha);
+ cvSetReal1D( &B, 0, 1 - cvGetReal1D(&A, 0));
+
+ cvtest::convert( src, temp, dst.type() );
+ cvtest::add( src, cvGetReal1D(&A, 0), dst, cvGetReal1D(&B, 0), cvScalarAll(0.), temp, temp.depth() );
+ cvtest::copy( temp, dst, mask );
+}
+
+
+TEST(Video_Acc, accuracy) { CV_AccTest test; test.safe_run(); }
+TEST(Video_AccSquared, accuracy) { CV_SquareAccTest test; test.safe_run(); }
+TEST(Video_AccProduct, accuracy) { CV_MultiplyAccTest test; test.safe_run(); }
+TEST(Video_RunningAvg, accuracy) { CV_RunningAvgTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+class CV_TrackBaseTest : public cvtest::BaseTest
+{
+public:
+ CV_TrackBaseTest();
+ virtual ~CV_TrackBaseTest();
+ void clear();
+
+protected:
+ int read_params( CvFileStorage* fs );
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void generate_object();
+
+ int min_log_size, max_log_size;
+ CvMat* img;
+ CvBox2D box0;
+ CvSize img_size;
+ CvTermCriteria criteria;
+ int img_type;
+};
+
+
+CV_TrackBaseTest::CV_TrackBaseTest()
+{
+ img = 0;
+ test_case_count = 100;
+ min_log_size = 5;
+ max_log_size = 8;
+}
+
+
+CV_TrackBaseTest::~CV_TrackBaseTest()
+{
+ clear();
+}
+
+
+void CV_TrackBaseTest::clear()
+{
+ cvReleaseMat( &img );
+ cvtest::BaseTest::clear();
+}
+
+
+int CV_TrackBaseTest::read_params( CvFileStorage* fs )
+{
+ int code = cvtest::BaseTest::read_params( fs );
+ if( code < 0 )
+ return code;
+
+ test_case_count = cvReadInt( find_param( fs, "test_case_count" ), test_case_count );
+ min_log_size = cvReadInt( find_param( fs, "min_log_size" ), min_log_size );
+ max_log_size = cvReadInt( find_param( fs, "max_log_size" ), max_log_size );
+
+ min_log_size = cvtest::clipInt( min_log_size, 1, 10 );
+ max_log_size = cvtest::clipInt( max_log_size, 1, 10 );
+ if( min_log_size > max_log_size )
+ {
+ int t;
+ CV_SWAP( min_log_size, max_log_size, t );
+ }
+
+ return 0;
+}
+
+
+void CV_TrackBaseTest::generate_object()
+{
+ int x, y;
+ double cx = box0.center.x;
+ double cy = box0.center.y;
+ double width = box0.size.width*0.5;
+ double height = box0.size.height*0.5;
+ double angle = box0.angle*CV_PI/180.;
+ double a = sin(angle), b = -cos(angle);
+ double inv_ww = 1./(width*width), inv_hh = 1./(height*height);
+
+ img = cvCreateMat( img_size.height, img_size.width, img_type );
+ cvZero( img );
+
+ // use the straightforward algorithm: for every pixel check if it is inside the ellipse
+ for( y = 0; y < img_size.height; y++ )
+ {
+ uchar* ptr = img->data.ptr + img->step*y;
+ float* fl = (float*)ptr;
+ double x_ = (y - cy)*b, y_ = (y - cy)*a;
+
+ for( x = 0; x < img_size.width; x++ )
+ {
+ double x1 = (x - cx)*a - x_;
+ double y1 = (x - cx)*b + y_;
+
+ if( x1*x1*inv_hh + y1*y1*inv_ww <= 1. )
+ {
+ if( img_type == CV_8U )
+ ptr[x] = (uchar)1;
+ else
+ fl[x] = (float)1.f;
+ }
+ }
+ }
+}
+
+
+int CV_TrackBaseTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::BaseTest::prepare_test_case( test_case_idx );
+ float m;
+
+ clear();
+
+ box0.size.width = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
+ box0.size.height = (float)exp((cvtest::randReal(rng) * (max_log_size - min_log_size) + min_log_size)*CV_LOG2);
+ box0.angle = (float)(cvtest::randReal(rng)*180.);
+
+ if( box0.size.width > box0.size.height )
+ {
+ float t;
+ CV_SWAP( box0.size.width, box0.size.height, t );
+ }
+
+ m = MAX( box0.size.width, box0.size.height );
+ img_size.width = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
+ img_size.height = cvRound(cvtest::randReal(rng)*m*0.5 + m + 1);
+ img_type = cvtest::randInt(rng) % 2 ? CV_32F : CV_8U;
+ img_type = CV_8U;
+
+ box0.center.x = (float)(img_size.width*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.width - m));
+ box0.center.y = (float)(img_size.height*0.5 + (cvtest::randReal(rng)-0.5)*(img_size.height - m));
+
+ criteria = cvTermCriteria( CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1 );
+
+ generate_object();
+
+ return 1;
+}
+
+
+void CV_TrackBaseTest::run_func(void)
+{
+}
+
+
+int CV_TrackBaseTest::validate_test_results( int /*test_case_idx*/ )
+{
+ return 0;
+}
+
+
+
+///////////////////////// CamShift //////////////////////////////
+
+class CV_CamShiftTest : public CV_TrackBaseTest
+{
+public:
+ CV_CamShiftTest();
+
+protected:
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void generate_object();
+
+ CvBox2D box;
+ CvRect init_rect;
+ CvConnectedComp comp;
+ int area0;
+};
+
+
+CV_CamShiftTest::CV_CamShiftTest()
+{
+}
+
+
+int CV_CamShiftTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ double m;
+ int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
+ int i, area;
+
+ if( code <= 0 )
+ return code;
+
+ area0 = cvCountNonZero(img);
+
+ for(i = 0; i < 100; i++)
+ {
+ CvMat temp;
+
+ m = MAX(box0.size.width,box0.size.height)*0.8;
+ init_rect.x = cvFloor(box0.center.x - m*(0.45 + cvtest::randReal(rng)*0.2));
+ init_rect.y = cvFloor(box0.center.y - m*(0.45 + cvtest::randReal(rng)*0.2));
+ init_rect.width = cvCeil(box0.center.x + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.x);
+ init_rect.height = cvCeil(box0.center.y + m*(0.45 + cvtest::randReal(rng)*0.2) - init_rect.y);
+
+ if( init_rect.x < 0 || init_rect.y < 0 ||
+ init_rect.x + init_rect.width >= img_size.width ||
+ init_rect.y + init_rect.height >= img_size.height )
+ continue;
+
+ cvGetSubRect( img, &temp, init_rect );
+ area = cvCountNonZero( &temp );
+
+ if( area >= 0.1*area0 )
+ break;
+ }
+
+ return i < 100 ? code : 0;
+}
+
+
+void CV_CamShiftTest::run_func(void)
+{
+ cvCamShift( img, init_rect, criteria, &comp, &box );
+}
+
+
+int CV_CamShiftTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+
+ double m = MAX(box0.size.width, box0.size.height), delta;
+ double diff_angle;
+
+ if( cvIsNaN(box.size.width) || cvIsInf(box.size.width) || box.size.width <= 0 ||
+ cvIsNaN(box.size.height) || cvIsInf(box.size.height) || box.size.height <= 0 ||
+ cvIsNaN(box.center.x) || cvIsInf(box.center.x) ||
+ cvIsNaN(box.center.y) || cvIsInf(box.center.y) ||
+ cvIsNaN(box.angle) || cvIsInf(box.angle) || box.angle < -180 || box.angle > 180 ||
+ cvIsNaN(comp.area) || cvIsInf(comp.area) || comp.area <= 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Invalid CvBox2D or CvConnectedComp was returned by cvCamShift\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ box.angle = (float)(180 - box.angle);
+
+ if( fabs(box.size.width - box0.size.width) > box0.size.width*0.2 ||
+ fabs(box.size.height - box0.size.height) > box0.size.height*0.3 )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D size (=%.1f x %.1f, should be %.1f x %.1f)\n",
+ box.size.width, box.size.height, box0.size.width, box0.size.height );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( fabs(box.center.x - box0.center.x) > m*0.1 ||
+ fabs(box.center.y - box0.center.y) > m*0.1 )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
+ box.center.x, box.center.y, box0.center.x, box0.center.y );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( box.angle < 0 )
+ box.angle += 180;
+
+ diff_angle = fabs(box0.angle - box.angle);
+ diff_angle = MIN( diff_angle, fabs(box0.angle - box.angle + 180));
+
+ if( fabs(diff_angle) > 30 && box0.size.height > box0.size.width*1.2 )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D angle (=%1.f, should be %1.f)\n",
+ box.angle, box0.angle );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ delta = m*0.7;
+
+ if( comp.rect.x < box0.center.x - delta ||
+ comp.rect.y < box0.center.y - delta ||
+ comp.rect.x + comp.rect.width > box0.center.x + delta ||
+ comp.rect.y + comp.rect.height > box0.center.y + delta )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Incorrect CvConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
+ comp.rect.x, comp.rect.y, comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height,
+ box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( fabs(comp.area - area0) > area0*0.15 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Incorrect CvConnectedComp area (=%.1f, should be %d)\n", comp.area, area0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ if( code < 0 )
+ {
+#if defined _DEBUG && defined WIN32
+ IplImage* dst = cvCreateImage( img_size, 8, 3 );
+ cvNamedWindow( "test", 1 );
+ cvCmpS( img, 0, img, CV_CMP_GT );
+ cvCvtColor( img, dst, CV_GRAY2BGR );
+ cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
+ cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
+ CV_RGB(255,0,0), 3, 8, 0 );
+ cvEllipseBox( dst, box, CV_RGB(0,255,0), 3, 8, 0 );
+ cvShowImage( "test", dst );
+ cvReleaseImage( &dst );
+ cvWaitKey();
+#endif
+ ts->set_failed_test_info( code );
+ }
+ return code;
+}
+
+
+///////////////////////// MeanShift //////////////////////////////
+
+class CV_MeanShiftTest : public CV_TrackBaseTest
+{
+public:
+ CV_MeanShiftTest();
+
+protected:
+ void run_func(void);
+ int prepare_test_case( int test_case_idx );
+ int validate_test_results( int test_case_idx );
+ void generate_object();
+
+ CvRect init_rect;
+ CvConnectedComp comp;
+ int area0, area;
+};
+
+
+CV_MeanShiftTest::CV_MeanShiftTest()
+{
+}
+
+
+int CV_MeanShiftTest::prepare_test_case( int test_case_idx )
+{
+ RNG& rng = ts->get_rng();
+ double m;
+ int code = CV_TrackBaseTest::prepare_test_case( test_case_idx );
+ int i;
+
+ if( code <= 0 )
+ return code;
+
+ area0 = cvCountNonZero(img);
+
+ for(i = 0; i < 100; i++)
+ {
+ CvMat temp;
+
+ m = (box0.size.width + box0.size.height)*0.5;
+ init_rect.x = cvFloor(box0.center.x - m*(0.4 + cvtest::randReal(rng)*0.2));
+ init_rect.y = cvFloor(box0.center.y - m*(0.4 + cvtest::randReal(rng)*0.2));
+ init_rect.width = cvCeil(box0.center.x + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.x);
+ init_rect.height = cvCeil(box0.center.y + m*(0.4 + cvtest::randReal(rng)*0.2) - init_rect.y);
+
+ if( init_rect.x < 0 || init_rect.y < 0 ||
+ init_rect.x + init_rect.width >= img_size.width ||
+ init_rect.y + init_rect.height >= img_size.height )
+ continue;
+
+ cvGetSubRect( img, &temp, init_rect );
+ area = cvCountNonZero( &temp );
+
+ if( area >= 0.5*area0 )
+ break;
+ }
+
+ return i < 100 ? code : 0;
+}
+
+
+void CV_MeanShiftTest::run_func(void)
+{
+ cvMeanShift( img, init_rect, criteria, &comp );
+}
+
+
+int CV_MeanShiftTest::validate_test_results( int /*test_case_idx*/ )
+{
+ int code = cvtest::TS::OK;
+ CvPoint2D32f c;
+ double m = MAX(box0.size.width, box0.size.height), delta;
+
+ if( cvIsNaN(comp.area) || cvIsInf(comp.area) || comp.area <= 0 )
+ {
+ ts->printf( cvtest::TS::LOG, "Invalid CvConnectedComp was returned by cvMeanShift\n" );
+ code = cvtest::TS::FAIL_INVALID_OUTPUT;
+ goto _exit_;
+ }
+
+ c.x = (float)(comp.rect.x + comp.rect.width*0.5);
+ c.y = (float)(comp.rect.y + comp.rect.height*0.5);
+
+ if( fabs(c.x - box0.center.x) > m*0.1 ||
+ fabs(c.y - box0.center.y) > m*0.1 )
+ {
+ ts->printf( cvtest::TS::LOG, "Incorrect CvBox2D position (=(%.1f, %.1f), should be (%.1f, %.1f))\n",
+ c.x, c.y, box0.center.x, box0.center.y );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ delta = m*0.7;
+
+ if( comp.rect.x < box0.center.x - delta ||
+ comp.rect.y < box0.center.y - delta ||
+ comp.rect.x + comp.rect.width > box0.center.x + delta ||
+ comp.rect.y + comp.rect.height > box0.center.y + delta )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Incorrect CvConnectedComp ((%d,%d,%d,%d) is not within (%.1f,%.1f,%.1f,%.1f))\n",
+ comp.rect.x, comp.rect.y, comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height,
+ box0.center.x - delta, box0.center.y - delta, box0.center.x + delta, box0.center.y + delta );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ if( fabs((double)(comp.area - area0)) > fabs((double)(area - area0)) + area0*0.05 )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "Incorrect CvConnectedComp area (=%.1f, should be %d)\n", comp.area, area0 );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ if( code < 0 )
+ {
+#if defined _DEBUG && defined WIN32
+ IplImage* dst = cvCreateImage( img_size, 8, 3 );
+ cvNamedWindow( "test", 1 );
+ cvCmpS( img, 0, img, CV_CMP_GT );
+ cvCvtColor( img, dst, CV_GRAY2BGR );
+ cvRectangle( dst, cvPoint(init_rect.x, init_rect.y),
+ cvPoint(init_rect.x + init_rect.width, init_rect.y + init_rect.height),
+ CV_RGB(255,0,0), 3, 8, 0 );
+ cvRectangle( dst, cvPoint(comp.rect.x, comp.rect.y),
+ cvPoint(comp.rect.x + comp.rect.width, comp.rect.y + comp.rect.height),
+ CV_RGB(0,255,0), 3, 8, 0 );
+ cvShowImage( "test", dst );
+ cvReleaseImage( &dst );
+ cvWaitKey();
+#endif
+ ts->set_failed_test_info( code );
+ }
+ return code;
+}
+
+
+TEST(Video_CAMShift, accuracy) { CV_CamShiftTest test; test.safe_run(); }
+TEST(Video_MeanShift, accuracy) { CV_MeanShiftTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+using namespace cv;
+using namespace std;
+
+class CV_RigidTransform_Test : public cvtest::BaseTest
+{
+public:
+ CV_RigidTransform_Test();
+ ~CV_RigidTransform_Test();
+protected:
+ void run(int);
+
+ bool testNPoints(int);
+ bool testImage();
+};
+
+CV_RigidTransform_Test::CV_RigidTransform_Test()
+{
+}
+CV_RigidTransform_Test::~CV_RigidTransform_Test() {}
+
+struct WrapAff2D
+{
+ const double *F;
+ WrapAff2D(const Mat& aff) : F(aff.ptr<double>()) {}
+ Point2f operator()(const Point2f& p)
+ {
+ return Point2d( p.x * F[0] + p.y * F[1] + F[2],
+ p.x * F[3] + p.y * F[4] + F[5]);
+ }
+};
+
+bool CV_RigidTransform_Test::testNPoints(int from)
+{
+ cv::RNG rng = ts->get_rng();
+
+ int progress = 0;
+ int k, ntests = 10000;
+
+ for( k = from; k < ntests; k++ )
+ {
+ ts->update_context( this, k, true );
+ progress = update_progress(progress, k, ntests, 0);
+
+ Mat aff(2, 3, CV_64F);
+ rng.fill(aff, CV_RAND_UNI, Scalar(-2), Scalar(2));
+
+ int n = (unsigned)rng % 100 + 10;
+
+ Mat fpts(1, n, CV_32FC2);
+ Mat tpts(1, n, CV_32FC2);
+
+ rng.fill(fpts, CV_RAND_UNI, Scalar(0,0), Scalar(10,10));
+ transform(fpts.ptr<Point2f>(), fpts.ptr<Point2f>() + n, tpts.ptr<Point2f>(), WrapAff2D(aff));
+
+ Mat noise(1, n, CV_32FC2);
+ rng.fill(noise, CV_RAND_NORMAL, Scalar::all(0), Scalar::all(0.001*(n<=7 ? 0 : n <= 30 ? 1 : 10)));
+ tpts += noise;
+
+ Mat aff_est = estimateRigidTransform(fpts, tpts, true);
+
+ double thres = 0.1*norm(aff);
+ double d = norm(aff_est, aff, NORM_L2);
+ if (d > thres)
+ {
+ double dB=0, nB=0;
+ if (n <= 4)
+ {
+ Mat A = fpts.reshape(1, 3);
+ Mat B = A - repeat(A.row(0), 3, 1), Bt = B.t();
+ B = Bt*B;
+ dB = cv::determinant(B);
+ nB = norm(B);
+ if( fabs(dB) < 0.01*nB )
+ continue;
+ }
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres, d );
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CV_RigidTransform_Test::testImage()
+{
+ Mat img;
+ pyrDown(imread( string(ts->get_data_path()) + "shared/graffiti.png", 1), img);
+
+ Mat aff = cv::getRotationMatrix2D(Point(img.cols/2, img.rows/2), 1, 0.99);
+ aff.ptr<double>()[2]+=3;
+ aff.ptr<double>()[5]+=3;
+
+ Mat rotated;
+ warpAffine(img, rotated, aff, img.size());
+
+ Mat aff_est = estimateRigidTransform(img, rotated, true);
+
+ const double thres = 0.03;
+ if (norm(aff_est, aff, NORM_INF) > thres)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_BAD_ACCURACY);
+ ts->printf( cvtest::TS::LOG, "Threshold = %f, norm of difference = %f", thres,
+ norm(aff_est, aff, NORM_INF) );
+ return false;
+ }
+
+ return true;
+}
+
+void CV_RigidTransform_Test::run( int start_from )
+{
+ cvtest::DefaultRngAuto dra;
+
+ if (!testNPoints(start_from))
+ return;
+
+ if (!testImage())
+ return;
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+TEST(Video_RigidFlow, accuracy) { CV_RigidTransform_Test test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+
+class CV_KalmanTest : public cvtest::BaseTest
+{
+public:
+ CV_KalmanTest();
+protected:
+ void run(int);
+};
+
+
+CV_KalmanTest::CV_KalmanTest()
+{
+}
+
+void CV_KalmanTest::run( int )
+{
+ int code = cvtest::TS::OK;
+ const int Dim = 7;
+ const int Steps = 100;
+ const double max_init = 1;
+ const double max_noise = 0.1;
+
+ const double EPSILON = 1.000;
+ RNG& rng = ts->get_rng();
+ CvKalman* Kalm;
+ int i, j;
+
+ CvMat* Sample = cvCreateMat(Dim,1,CV_32F);
+ CvMat* Temp = cvCreateMat(Dim,1,CV_32F);
+
+ Kalm = cvCreateKalman(Dim, Dim);
+ CvMat Dyn = cvMat(Dim,Dim,CV_32F,Kalm->DynamMatr);
+ CvMat Mes = cvMat(Dim,Dim,CV_32F,Kalm->MeasurementMatr);
+ CvMat PNC = cvMat(Dim,Dim,CV_32F,Kalm->PNCovariance);
+ CvMat MNC = cvMat(Dim,Dim,CV_32F,Kalm->MNCovariance);
+ CvMat PriErr = cvMat(Dim,Dim,CV_32F,Kalm->PriorErrorCovariance);
+ CvMat PostErr = cvMat(Dim,Dim,CV_32F,Kalm->PosterErrorCovariance);
+ CvMat PriState = cvMat(Dim,1,CV_32F,Kalm->PriorState);
+ CvMat PostState = cvMat(Dim,1,CV_32F,Kalm->PosterState);
+ cvSetIdentity(&PNC);
+ cvSetIdentity(&PriErr);
+ cvSetIdentity(&PostErr);
+ cvSetZero(&MNC);
+ cvSetZero(&PriState);
+ cvSetZero(&PostState);
+ cvSetIdentity(&Mes);
+ cvSetIdentity(&Dyn);
+ Mat _Sample = cvarrToMat(Sample);
+ cvtest::randUni(rng, _Sample, cvScalarAll(-max_init), cvScalarAll(max_init));
+ cvKalmanCorrect(Kalm, Sample);
+ for(i = 0; i<Steps; i++)
+ {
+ cvKalmanPredict(Kalm);
+ for(j = 0; j<Dim; j++)
+ {
+ float t = 0;
+ for(int k=0; k<Dim; k++)
+ {
+ t += Dyn.data.fl[j*Dim+k]*Sample->data.fl[k];
+ }
+ Temp->data.fl[j]= (float)(t+(cvtest::randReal(rng)*2-1)*max_noise);
+ }
+ cvCopy( Temp, Sample );
+ cvKalmanCorrect(Kalm,Temp);
+ }
+
+ Mat _state_post = cvarrToMat(Kalm->state_post);
+ code = cvtest::cmpEps2( ts, _Sample, _state_post, EPSILON, false, "The final estimated state" );
+
+ cvReleaseMat(&Sample);
+ cvReleaseMat(&Temp);
+ cvReleaseKalman(&Kalm);
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+TEST(Video_Kalman, accuracy) { CV_KalmanTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+using namespace cv;
+using namespace std;
+
+///////////////////// base MHI class ///////////////////////
+class CV_MHIBaseTest : public cvtest::ArrayTest
+{
+public:
+ CV_MHIBaseTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ int prepare_test_case( int test_case_idx );
+ double timestamp, duration, max_log_duration;
+ int mhi_i, mhi_ref_i;
+ double silh_ratio;
+};
+
+
+CV_MHIBaseTest::CV_MHIBaseTest()
+{
+ timestamp = duration = 0;
+ max_log_duration = 9;
+ mhi_i = mhi_ref_i = -1;
+
+ silh_ratio = 0.25;
+}
+
+
+void CV_MHIBaseTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ cvtest::ArrayTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT && CV_MAT_DEPTH(type) == CV_8U )
+ {
+ low = Scalar::all(cvRound(-1./silh_ratio)+2.);
+ high = Scalar::all(2);
+ }
+ else if( i == mhi_i || i == mhi_ref_i )
+ {
+ low = Scalar::all(-exp(max_log_duration));
+ high = Scalar::all(0.);
+ }
+}
+
+
+void CV_MHIBaseTest::get_test_array_types_and_sizes( int test_case_idx,
+ vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ cvtest::ArrayTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ types[INPUT][0] = CV_8UC1;
+ types[mhi_i][0] = types[mhi_ref_i][0] = CV_32FC1;
+ duration = exp(cvtest::randReal(rng)*max_log_duration);
+ timestamp = duration + cvtest::randReal(rng)*30.-10.;
+}
+
+
+int CV_MHIBaseTest::prepare_test_case( int test_case_idx )
+{
+ int code = cvtest::ArrayTest::prepare_test_case( test_case_idx );
+ if( code > 0 )
+ {
+ Mat& mat = test_mat[mhi_i][0];
+ mat += Scalar::all(duration);
+ cv::max(mat, 0, mat);
+ if( mhi_i != mhi_ref_i )
+ {
+ Mat& mat0 = test_mat[mhi_ref_i][0];
+ cvtest::copy( mat, mat0 );
+ }
+ }
+
+ return code;
+}
+
+
+///////////////////// update motion history ////////////////////////////
+
+static void test_updateMHI( const Mat& silh, Mat& mhi, double timestamp, double duration )
+{
+ int i, j;
+ float delbound = (float)(timestamp - duration);
+ for( i = 0; i < mhi.rows; i++ )
+ {
+ const uchar* silh_row = silh.ptr(i);
+ float* mhi_row = mhi.ptr<float>(i);
+
+ for( j = 0; j < mhi.cols; j++ )
+ {
+ if( silh_row[j] )
+ mhi_row[j] = (float)timestamp;
+ else if( mhi_row[j] < delbound )
+ mhi_row[j] = 0.f;
+ }
+ }
+}
+
+
+class CV_UpdateMHITest : public CV_MHIBaseTest
+{
+public:
+ CV_UpdateMHITest();
+
+protected:
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+};
+
+
+CV_UpdateMHITest::CV_UpdateMHITest()
+{
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT_OUTPUT].push_back(NULL);
+ test_array[REF_INPUT_OUTPUT].push_back(NULL);
+ mhi_i = INPUT_OUTPUT; mhi_ref_i = REF_INPUT_OUTPUT;
+}
+
+
+double CV_UpdateMHITest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 0;
+}
+
+
+void CV_UpdateMHITest::run_func()
+{
+ cvUpdateMotionHistory( test_array[INPUT][0], test_array[INPUT_OUTPUT][0], timestamp, duration );
+}
+
+
+void CV_UpdateMHITest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_updateMHI( test_mat[INPUT][0], test_mat[REF_INPUT_OUTPUT][0], timestamp, duration );
+}
+
+
+///////////////////// calc motion gradient ////////////////////////////
+
+static void test_MHIGradient( const Mat& mhi, Mat& mask, Mat& orientation,
+ double delta1, double delta2, int aperture_size )
+{
+ Point anchor( aperture_size/2, aperture_size/2 );
+ double limit = 1e-4*aperture_size*aperture_size;
+
+ Mat dx, dy, min_mhi, max_mhi;
+
+ Mat kernel = cvtest::calcSobelKernel2D( 1, 0, aperture_size );
+ cvtest::filter2D( mhi, dx, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
+ kernel = cvtest::calcSobelKernel2D( 0, 1, aperture_size );
+ cvtest::filter2D( mhi, dy, CV_32F, kernel, anchor, 0, BORDER_REPLICATE );
+
+ kernel = Mat::ones(aperture_size, aperture_size, CV_8U);
+ cvtest::erode(mhi, min_mhi, kernel, anchor, 0, BORDER_REPLICATE);
+ cvtest::dilate(mhi, max_mhi, kernel, anchor, 0, BORDER_REPLICATE);
+
+ if( delta1 > delta2 )
+ {
+ double t;
+ CV_SWAP( delta1, delta2, t );
+ }
+
+ for( int i = 0; i < mhi.rows; i++ )
+ {
+ uchar* mask_row = mask.ptr(i);
+ float* orient_row = orientation.ptr<float>(i);
+ const float* dx_row = dx.ptr<float>(i);
+ const float* dy_row = dy.ptr<float>(i);
+ const float* min_row = min_mhi.ptr<float>(i);
+ const float* max_row = max_mhi.ptr<float>(i);
+
+ for( int j = 0; j < mhi.cols; j++ )
+ {
+ double delta = max_row[j] - min_row[j];
+ double _dx = dx_row[j], _dy = dy_row[j];
+
+ if( delta1 <= delta && delta <= delta2 &&
+ (fabs(_dx) > limit || fabs(_dy) > limit) )
+ {
+ mask_row[j] = 1;
+ double angle = atan2( _dy, _dx ) * (180/CV_PI);
+ if( angle < 0 )
+ angle += 360.;
+ orient_row[j] = (float)angle;
+ }
+ else
+ {
+ mask_row[j] = 0;
+ orient_row[j] = 0.f;
+ }
+ }
+ }
+}
+
+
+class CV_MHIGradientTest : public CV_MHIBaseTest
+{
+public:
+ CV_MHIGradientTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ void run_func();
+ void prepare_to_validation( int );
+
+ double delta1, delta2, delta_range_log;
+ int aperture_size;
+};
+
+
+CV_MHIGradientTest::CV_MHIGradientTest()
+{
+ mhi_i = mhi_ref_i = INPUT;
+ test_array[INPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ test_array[REF_OUTPUT].push_back(NULL);
+ delta1 = delta2 = 0;
+ aperture_size = 0;
+ delta_range_log = 4;
+}
+
+
+void CV_MHIGradientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+
+ types[OUTPUT][0] = types[REF_OUTPUT][0] = CV_8UC1;
+ types[OUTPUT][1] = types[REF_OUTPUT][1] = CV_32FC1;
+ delta1 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
+ delta2 = exp(cvtest::randReal(rng)*delta_range_log + 1.);
+ aperture_size = (cvtest::randInt(rng)%3)*2+3;
+ //duration = exp(cvtest::randReal(rng)*max_log_duration);
+ //timestamp = duration + cvtest::randReal(rng)*30.-10.;
+}
+
+
+double CV_MHIGradientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int j )
+{
+ return j == 0 ? 0 : 2e-1;
+}
+
+
+void CV_MHIGradientTest::run_func()
+{
+ cvCalcMotionGradient( test_array[INPUT][0], test_array[OUTPUT][0],
+ test_array[OUTPUT][1], delta1, delta2, aperture_size );
+}
+
+
+void CV_MHIGradientTest::prepare_to_validation( int /*test_case_idx*/ )
+{
+ test_MHIGradient( test_mat[INPUT][0], test_mat[REF_OUTPUT][0],
+ test_mat[REF_OUTPUT][1], delta1, delta2, aperture_size );
+ test_mat[REF_OUTPUT][0] += Scalar::all(1);
+ test_mat[OUTPUT][0] += Scalar::all(1);
+}
+
+
+////////////////////// calc global orientation /////////////////////////
+
+static double test_calcGlobalOrientation( const Mat& orient, const Mat& mask,
+ const Mat& mhi, double timestamp, double duration )
+{
+ const int HIST_SIZE = 12;
+ int y, x;
+ int histogram[HIST_SIZE];
+ int max_bin = 0;
+
+ double base_orientation = 0, delta_orientation = 0, weight = 0;
+ double low_time, global_orientation;
+
+ memset( histogram, 0, sizeof( histogram ));
+ timestamp = 0;
+
+ for( y = 0; y < orient.rows; y++ )
+ {
+ const float* orient_data = orient.ptr<float>(y);
+ const uchar* mask_data = mask.ptr(y);
+ const float* mhi_data = mhi.ptr<float>(y);
+ for( x = 0; x < orient.cols; x++ )
+ if( mask_data[x] )
+ {
+ int bin = cvFloor( (orient_data[x]*HIST_SIZE)/360 );
+ histogram[bin < 0 ? 0 : bin >= HIST_SIZE ? HIST_SIZE-1 : bin]++;
+ if( mhi_data[x] > timestamp )
+ timestamp = mhi_data[x];
+ }
+ }
+
+ low_time = timestamp - duration;
+
+ for( x = 1; x < HIST_SIZE; x++ )
+ {
+ if( histogram[x] > histogram[max_bin] )
+ max_bin = x;
+ }
+
+ base_orientation = ((double)max_bin*360)/HIST_SIZE;
+
+ for( y = 0; y < orient.rows; y++ )
+ {
+ const float* orient_data = orient.ptr<float>(y);
+ const float* mhi_data = mhi.ptr<float>(y);
+ const uchar* mask_data = mask.ptr(y);
+
+ for( x = 0; x < orient.cols; x++ )
+ {
+ if( mask_data[x] && mhi_data[x] > low_time )
+ {
+ double diff = orient_data[x] - base_orientation;
+ double delta_weight = (((mhi_data[x] - low_time)/duration)*254 + 1)/255;
+
+ if( diff < -180 ) diff += 360;
+ if( diff > 180 ) diff -= 360;
+
+ if( delta_weight > 0 && fabs(diff) < 45 )
+ {
+ delta_orientation += diff*delta_weight;
+ weight += delta_weight;
+ }
+ }
+ }
+ }
+
+ if( weight == 0 )
+ global_orientation = base_orientation;
+ else
+ {
+ global_orientation = base_orientation + delta_orientation/weight;
+ if( global_orientation < 0 ) global_orientation += 360;
+ if( global_orientation > 360 ) global_orientation -= 360;
+ }
+
+ return global_orientation;
+}
+
+
+class CV_MHIGlobalOrientTest : public CV_MHIBaseTest
+{
+public:
+ CV_MHIGlobalOrientTest();
+
+protected:
+ void get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types );
+ void get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high );
+ double get_success_error_level( int test_case_idx, int i, int j );
+ int validate_test_results( int test_case_idx );
+ void run_func();
+ double angle, min_angle, max_angle;
+};
+
+
+CV_MHIGlobalOrientTest::CV_MHIGlobalOrientTest()
+{
+ mhi_i = mhi_ref_i = INPUT;
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ test_array[INPUT].push_back(NULL);
+ min_angle = max_angle = 0;
+}
+
+
+void CV_MHIGlobalOrientTest::get_test_array_types_and_sizes( int test_case_idx, vector<vector<Size> >& sizes, vector<vector<int> >& types )
+{
+ RNG& rng = ts->get_rng();
+ CV_MHIBaseTest::get_test_array_types_and_sizes( test_case_idx, sizes, types );
+ CvSize size = sizes[INPUT][0];
+
+ size.width = MAX( size.width, 16 );
+ size.height = MAX( size.height, 16 );
+ sizes[INPUT][0] = sizes[INPUT][1] = sizes[INPUT][2] = size;
+
+ types[INPUT][1] = CV_8UC1; // mask
+ types[INPUT][2] = CV_32FC1; // orientation
+
+ min_angle = cvtest::randReal(rng)*359.9;
+ max_angle = cvtest::randReal(rng)*359.9;
+ if( min_angle >= max_angle )
+ {
+ double t;
+ CV_SWAP( min_angle, max_angle, t );
+ }
+ max_angle += 0.1;
+ duration = exp(cvtest::randReal(rng)*max_log_duration);
+ timestamp = duration + cvtest::randReal(rng)*30.-10.;
+}
+
+
+void CV_MHIGlobalOrientTest::get_minmax_bounds( int i, int j, int type, Scalar& low, Scalar& high )
+{
+ CV_MHIBaseTest::get_minmax_bounds( i, j, type, low, high );
+ if( i == INPUT && j == 2 )
+ {
+ low = Scalar::all(min_angle);
+ high = Scalar::all(max_angle);
+ }
+}
+
+
+double CV_MHIGlobalOrientTest::get_success_error_level( int /*test_case_idx*/, int /*i*/, int /*j*/ )
+{
+ return 15;
+}
+
+
+void CV_MHIGlobalOrientTest::run_func()
+{
+ angle = cvCalcGlobalOrientation( test_array[INPUT][2], test_array[INPUT][1],
+ test_array[INPUT][0], timestamp, duration );
+}
+
+
+int CV_MHIGlobalOrientTest::validate_test_results( int test_case_idx )
+{
+ //printf("%d. rows=%d, cols=%d, nzmask=%d\n", test_case_idx, test_mat[INPUT][1].rows, test_mat[INPUT][1].cols,
+ // cvCountNonZero(test_array[INPUT][1]));
+
+ double ref_angle = test_calcGlobalOrientation( test_mat[INPUT][2], test_mat[INPUT][1],
+ test_mat[INPUT][0], timestamp, duration );
+ double err_level = get_success_error_level( test_case_idx, 0, 0 );
+ int code = cvtest::TS::OK;
+ int nz = cvCountNonZero( test_array[INPUT][1] );
+
+ if( nz > 32 && !(min_angle - err_level <= angle &&
+ max_angle + err_level >= angle) &&
+ !(min_angle - err_level <= angle+360 &&
+ max_angle + err_level >= angle+360) )
+ {
+ ts->printf( cvtest::TS::LOG, "The angle=%g is outside (%g,%g) range\n",
+ angle, min_angle - err_level, max_angle + err_level );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+ else if( fabs(angle - ref_angle) > err_level &&
+ fabs(360 - fabs(angle - ref_angle)) > err_level )
+ {
+ ts->printf( cvtest::TS::LOG, "The angle=%g differs too much from reference value=%g\n",
+ angle, ref_angle );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ }
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+ return code;
+}
+
+
+TEST(Video_MHIUpdate, accuracy) { CV_UpdateMHITest test; test.safe_run(); }
+TEST(Video_MHIGradient, accuracy) { CV_MHIGradientTest test; test.safe_run(); }
+TEST(Video_MHIGlobalOrient, accuracy) { CV_MHIGlobalOrientTest test; test.safe_run(); }
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of the copyright holders may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <iterator>
+#include <limits>
+
+using namespace cv;
+using namespace std;
+
+class CV_OptFlowTest : public cvtest::BaseTest
+{
+public:
+ CV_OptFlowTest();
+ ~CV_OptFlowTest();
+protected:
+ void run(int);
+
+ bool runDense(const Point& shift = Point(3, 0));
+ bool runSparse();
+};
+
+CV_OptFlowTest::CV_OptFlowTest() {}
+CV_OptFlowTest::~CV_OptFlowTest() {}
+
+
+Mat copnvert2flow(const Mat& velx, const Mat& vely)
+{
+ Mat flow(velx.size(), CV_32FC2);
+ for(int y = 0 ; y < flow.rows; ++y)
+ for(int x = 0 ; x < flow.cols; ++x)
+ flow.at<Point2f>(y, x) = Point2f(velx.at<float>(y, x), vely.at<float>(y, x));
+ return flow;
+}
+
+void calcOpticalFlowLK( const Mat& prev, const Mat& curr, Size winSize, Mat& flow )
+{
+ Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
+ CvMat cvvelx = velx; CvMat cvvely = vely;
+ CvMat cvprev = prev; CvMat cvcurr = curr;
+ cvCalcOpticalFlowLK( &cvprev, &cvcurr, winSize, &cvvelx, &cvvely );
+ flow = copnvert2flow(velx, vely);
+}
+
+void calcOpticalFlowBM( const Mat& prev, const Mat& curr, Size bSize, Size shiftSize, Size maxRange, int usePrevious, Mat& flow )
+{
+ Size sz((curr.cols - bSize.width)/shiftSize.width, (curr.rows - bSize.height)/shiftSize.height);
+ Mat velx(sz, CV_32F), vely(sz, CV_32F);
+
+ CvMat cvvelx = velx; CvMat cvvely = vely;
+ CvMat cvprev = prev; CvMat cvcurr = curr;
+ cvCalcOpticalFlowBM( &cvprev, &cvcurr, bSize, shiftSize, maxRange, usePrevious, &cvvelx, &cvvely);
+ flow = copnvert2flow(velx, vely);
+}
+
+void calcOpticalFlowHS( const Mat& prev, const Mat& curr, int usePrevious, double lambda, TermCriteria criteria, Mat& flow)
+{
+ Mat velx(prev.size(), CV_32F), vely(prev.size(), CV_32F);
+ CvMat cvvelx = velx; CvMat cvvely = vely;
+ CvMat cvprev = prev; CvMat cvcurr = curr;
+ cvCalcOpticalFlowHS( &cvprev, &cvcurr, usePrevious, &cvvelx, &cvvely, lambda, criteria );
+ flow = copnvert2flow(velx, vely);
+}
+
+void calcAffineFlowPyrLK( const Mat& prev, const Mat& curr,
+ const vector<Point2f>& prev_features, vector<Point2f>& curr_features,
+ vector<uchar>& status, vector<float>& track_error, vector<float>& matrices,
+ TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30, 0.01),
+ Size win_size = Size(15, 15), int level = 3, int flags = 0)
+{
+ CvMat cvprev = prev;
+ CvMat cvcurr = curr;
+
+ size_t count = prev_features.size();
+ curr_features.resize(count);
+ status.resize(count);
+ track_error.resize(count);
+ matrices.resize(count * 6);
+
+ cvCalcAffineFlowPyrLK( &cvprev, &cvcurr, 0, 0,
+ (const CvPoint2D32f*)&prev_features[0], (CvPoint2D32f*)&curr_features[0], &matrices[0],
+ (int)count, win_size, level, (char*)&status[0], &track_error[0], criteria, flags );
+}
+
+double showFlowAndCalcError(const string& name, const Mat& gray, const Mat& flow,
+ const Rect& where, const Point& d,
+ bool showImages = false, bool writeError = false)
+{
+ const int mult = 16;
+
+ if (showImages)
+ {
+ Mat tmp, cflow;
+ resize(gray, tmp, gray.size() * mult, 0, 0, INTER_NEAREST);
+ cvtColor(tmp, cflow, CV_GRAY2BGR);
+
+ const float m2 = 0.3f;
+ const float minVel = 0.1f;
+
+ for(int y = 0; y < flow.rows; ++y)
+ for(int x = 0; x < flow.cols; ++x)
+ {
+ Point2f f = flow.at<Point2f>(y, x);
+
+ if (f.x * f.x + f.y * f.y > minVel * minVel)
+ {
+ Point p1 = Point(x, y) * mult;
+ Point p2 = Point(cvRound((x + f.x*m2) * mult), cvRound((y + f.y*m2) * mult));
+
+ line(cflow, p1, p2, CV_RGB(0, 255, 0));
+ circle(cflow, Point(x, y) * mult, 2, CV_RGB(255, 0, 0));
+ }
+ }
+
+ rectangle(cflow, (where.tl() + d) * mult, (where.br() + d - Point(1,1)) * mult, CV_RGB(0, 0, 255));
+ namedWindow(name, 1); imshow(name, cflow);
+ }
+
+ double angle = atan2((float)d.y, (float)d.x);
+ double error = 0;
+
+ bool all = true;
+ Mat inner = flow(where);
+ for(int y = 0; y < inner.rows; ++y)
+ for(int x = 0; x < inner.cols; ++x)
+ {
+ const Point2f f = inner.at<Point2f>(y, x);
+
+ if (f.x == 0 && f.y == 0)
+ continue;
+
+ all = false;
+
+ double a = atan2(f.y, f.x);
+ error += fabs(angle - a);
+ }
+ double res = all ? numeric_limits<double>::max() : error / (inner.cols * inner.rows);
+
+ if (writeError)
+ cout << "Error " + name << " = " << res << endl;
+
+ return res;
+}
+
+
+Mat generateImage(const Size& sz, bool doBlur = true)
+{
+ RNG rng;
+ Mat mat(sz, CV_8U);
+ mat = Scalar(0);
+ for(int y = 0; y < mat.rows; ++y)
+ for(int x = 0; x < mat.cols; ++x)
+ mat.at<uchar>(y, x) = (uchar)rng;
+ if (doBlur)
+ blur(mat, mat, Size(3, 3));
+ return mat;
+}
+
+Mat generateSample(const Size& sz)
+{
+ Mat smpl(sz, CV_8U);
+ smpl = Scalar(0);
+ Point sc(smpl.cols/2, smpl.rows/2);
+ rectangle(smpl, Point(0,0), sc - Point(1,1), Scalar(255), CV_FILLED);
+ rectangle(smpl, sc, Point(smpl.cols, smpl.rows), Scalar(255), CV_FILLED);
+ return smpl;
+}
+
+bool CV_OptFlowTest::runDense(const Point& d)
+{
+ Size matSize(40, 40);
+ Size movSize(8, 8);
+
+ Mat smpl = generateSample(movSize);
+ Mat prev = generateImage(matSize);
+ Mat curr = prev.clone();
+
+ Rect rect(Point(prev.cols/2, prev.rows/2) - Point(movSize.width/2, movSize.height/2), movSize);
+
+ Mat flowLK, flowBM, flowHS, flowFB, flowFB_G, flowBM_received, m1;
+
+ m1 = prev(rect); smpl.copyTo(m1);
+ m1 = curr(Rect(rect.tl() + d, rect.br() + d)); smpl.copyTo(m1);
+
+ calcOpticalFlowLK( prev, curr, Size(15, 15), flowLK);
+ calcOpticalFlowBM( prev, curr, Size(15, 15), Size(1, 1), Size(15, 15), 0, flowBM_received);
+ calcOpticalFlowHS( prev, curr, 0, 5, TermCriteria(TermCriteria::MAX_ITER, 400, 0), flowHS);
+ calcOpticalFlowFarneback( prev, curr, flowFB, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, 0);
+ calcOpticalFlowFarneback( prev, curr, flowFB_G, 0.5, 3, std::max(d.x, d.y) + 10, 100, 6, 2, OPTFLOW_FARNEBACK_GAUSSIAN);
+
+ flowBM.create(prev.size(), CV_32FC2);
+ flowBM = Scalar(0);
+ Point origin((flowBM.cols - flowBM_received.cols)/2, (flowBM.rows - flowBM_received.rows)/2);
+ Mat wcp = flowBM(Rect(origin, flowBM_received.size()));
+ flowBM_received.copyTo(wcp);
+
+ double errorLK = showFlowAndCalcError("LK", prev, flowLK, rect, d);
+ double errorBM = showFlowAndCalcError("BM", prev, flowBM, rect, d);
+ double errorFB = showFlowAndCalcError("FB", prev, flowFB, rect, d);
+ double errorFBG = showFlowAndCalcError("FBG", prev, flowFB_G, rect, d);
+ double errorHS = showFlowAndCalcError("HS", prev, flowHS, rect, d); (void)errorHS;
+ //waitKey();
+
+ const double thres = 0.2;
+ if (errorLK > thres || errorBM > thres || errorFB > thres || errorFBG > thres /*|| errorHS > thres */)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ return true;
+}
+
+
+bool CV_OptFlowTest::runSparse()
+{
+ Mat prev = imread(string(ts->get_data_path()) + "optflow/rock_1.bmp", 0);
+ Mat next = imread(string(ts->get_data_path()) + "optflow/rock_2.bmp", 0);
+
+ if (prev.empty() || next.empty())
+ {
+ ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
+ return false;
+ }
+
+ Mat cprev, cnext;
+ cvtColor(prev, cprev, CV_GRAY2BGR);
+ cvtColor(next, cnext, CV_GRAY2BGR);
+
+ vector<Point2f> prev_pts;
+ vector<Point2f> next_ptsOpt;
+ vector<Point2f> next_ptsAff;
+ vector<uchar> status_Opt;
+ vector<uchar> status_Aff;
+ vector<float> error;
+ vector<float> matrices;
+
+ Size netSize(10, 10);
+ Point2f center = Point(prev.cols/2, prev.rows/2);
+
+ for(int i = 0 ; i < netSize.width; ++i)
+ for(int j = 0 ; j < netSize.width; ++j)
+ {
+ Point2f p(i * float(prev.cols)/netSize.width, j * float(prev.rows)/netSize.height);
+ prev_pts.push_back((p - center) * 0.5f + center);
+ }
+
+ calcOpticalFlowPyrLK( prev, next, prev_pts, next_ptsOpt, status_Opt, error );
+ calcAffineFlowPyrLK ( prev, next, prev_pts, next_ptsAff, status_Aff, error, matrices);
+
+ const double expected_shift = 25;
+ const double thres = 1;
+ for(size_t i = 0; i < prev_pts.size(); ++i)
+ {
+ circle(cprev, prev_pts[i], 2, CV_RGB(255, 0, 0));
+
+ if (status_Opt[i])
+ {
+ circle(cnext, next_ptsOpt[i], 2, CV_RGB(0, 0, 255));
+ Point2f shift = prev_pts[i] - next_ptsOpt[i];
+
+ double n = sqrt(shift.ddot(shift));
+ if (fabs(n - expected_shift) > thres)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ }
+
+ if (status_Aff[i])
+ {
+ circle(cnext, next_ptsAff[i], 4, CV_RGB(0, 255, 0));
+ Point2f shift = prev_pts[i] - next_ptsAff[i];
+
+ double n = sqrt(shift.ddot(shift));
+ if (fabs(n - expected_shift) > thres)
+ {
+ ts->set_failed_test_info(cvtest::TS::FAIL_MISMATCH);
+ return false;
+ }
+ }
+
+ }
+
+ /*namedWindow("P"); imshow("P", cprev);
+ namedWindow("N"); imshow("N", cnext);
+ waitKey();*/
+
+ return true;
+}
+
+
+void CV_OptFlowTest::run( int /* start_from */)
+{
+
+ if (!runDense(Point(3, 0)))
+ return;
+
+ if (!runDense(Point(0, 3)))
+ return;
+
+ //if (!runDense(Point(3, 3))) return; //probably LK works incorrectly in this case.
+
+ if (!runSparse())
+ return;
+
+ ts->set_failed_test_info(cvtest::TS::OK);
+}
+
+
+TEST(Video_OpticalFlow, accuracy) { CV_OptFlowTest test; test.safe_run(); }
+
+
--- /dev/null
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+// By downloading, copying, installing or using the software you agree to this license.
+// If you do not agree to this license, do not download, install,
+// copy or use the software.
+//
+//
+// Intel License Agreement
+// For Open Source Computer Vision Library
+//
+// Copyright (C) 2000, Intel Corporation, all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistribution's of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// * Redistribution's in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// * The name of Intel Corporation may not be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#include "test_precomp.hpp"
+
+/* ///////////////////// pyrlk_test ///////////////////////// */
+
+class CV_OptFlowPyrLKTest : public cvtest::BaseTest
+{
+public:
+ CV_OptFlowPyrLKTest();
+protected:
+ void run(int);
+};
+
+
+CV_OptFlowPyrLKTest::CV_OptFlowPyrLKTest() {}
+
+void CV_OptFlowPyrLKTest::run( int )
+{
+ int code = cvtest::TS::OK;
+
+ const double success_error_level = 0.2;
+ const int bad_points_max = 2;
+
+ /* test parameters */
+ double max_err = 0., sum_err = 0;
+ int pt_cmpd = 0;
+ int pt_exceed = 0;
+ int merr_i = 0, merr_j = 0, merr_k = 0;
+ char filename[1000];
+
+ CvPoint2D32f *u = 0, *v = 0, *v2 = 0;
+ CvMat *_u = 0, *_v = 0, *_v2 = 0;
+ char* status = 0;
+
+ IplImage* imgI = 0;
+ IplImage* imgJ = 0;
+
+ int n = 0, i = 0;
+
+ sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "lk_prev.dat" );
+ _u = (CvMat*)cvLoad( filename );
+
+ if( !_u )
+ {
+ ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "lk_next.dat" );
+ _v = (CvMat*)cvLoad( filename );
+
+ if( !_v )
+ {
+ ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ if( _u->cols != 2 || CV_MAT_TYPE(_u->type) != CV_32F ||
+ _v->cols != 2 || CV_MAT_TYPE(_v->type) != CV_32F || _v->rows != _u->rows )
+ {
+ ts->printf( cvtest::TS::LOG, "the loaded matrices of points are not valid\n" );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+
+ }
+
+ u = (CvPoint2D32f*)_u->data.fl;
+ v = (CvPoint2D32f*)_v->data.fl;
+
+ /* allocate adidtional buffers */
+ _v2 = cvCloneMat( _u );
+ v2 = (CvPoint2D32f*)_v2->data.fl;
+
+ /* read first image */
+ sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "rock_1.bmp" );
+ imgI = cvLoadImage( filename, -1 );
+
+ if( !imgI )
+ {
+ ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ /* read second image */
+ sprintf( filename, "%soptflow/%s", ts->get_data_path().c_str(), "rock_2.bmp" );
+ imgJ = cvLoadImage( filename, -1 );
+
+ if( !imgJ )
+ {
+ ts->printf( cvtest::TS::LOG, "could not read %s\n", filename );
+ code = cvtest::TS::FAIL_MISSING_TEST_DATA;
+ goto _exit_;
+ }
+
+ n = _u->rows;
+ status = (char*)cvAlloc(n*sizeof(status[0]));
+
+ /* calculate flow */
+ cvCalcOpticalFlowPyrLK( imgI, imgJ, 0, 0, u, v2, n, cvSize( 20, 20 ),
+ 4, status, 0, cvTermCriteria( CV_TERMCRIT_ITER|
+ CV_TERMCRIT_EPS, 30, 0.01f ), 0 );
+
+ /* compare results */
+ for( i = 0; i < n; i++ )
+ {
+ if( status[i] != 0 )
+ {
+ double err;
+ if( cvIsNaN(v[i].x) )
+ {
+ merr_j++;
+ continue;
+ }
+
+ err = fabs(v2[i].x - v[i].x) + fabs(v2[i].y - v[i].y);
+ if( err > max_err )
+ {
+ max_err = err;
+ merr_i = i;
+ }
+
+ pt_exceed += err > success_error_level;
+ if( pt_exceed > bad_points_max )
+ {
+ ts->printf( cvtest::TS::LOG,
+ "The number of poorly tracked points is too big (>=%d)\n", pt_exceed );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+ sum_err += err;
+ pt_cmpd++;
+ }
+ else
+ {
+ if( !cvIsNaN( v[i].x ))
+ {
+ merr_i = i;
+ merr_k++;
+ ts->printf( cvtest::TS::LOG, "The algorithm lost the point #%d\n", i );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+ }
+ }
+
+ if( max_err > 1 )
+ {
+ ts->printf( cvtest::TS::LOG, "Maximum tracking error is too big (=%g)\n", max_err );
+ code = cvtest::TS::FAIL_BAD_ACCURACY;
+ goto _exit_;
+ }
+
+_exit_:
+
+ cvFree( &status );
+ cvReleaseMat( &_u );
+ cvReleaseMat( &_v );
+ cvReleaseMat( &_v2 );
+
+ cvReleaseImage( &imgI );
+ cvReleaseImage( &imgJ );
+
+ if( code < 0 )
+ ts->set_failed_test_info( code );
+}
+
+
+TEST(Video_OpticalFlowPyrLK, accuracy) { CV_OptFlowPyrLKTest test; test.safe_run(); }
+
+/* End of file. */
--- /dev/null
+#include "test_precomp.hpp"
--- /dev/null
+#ifndef __OPENCV_TEST_PRECOMP_HPP__
+#define __OPENCV_TEST_PRECOMP_HPP__
+
+#include "opencv2/ts/ts.hpp"
+#include "opencv2/imgproc/imgproc.hpp"
+#include "opencv2/imgproc/imgproc_c.h"
+#include "opencv2/video/tracking.hpp"
+#include "opencv2/highgui/highgui.hpp"
+#include <iostream>
+
+#endif
-ENABLE_TESTING()
+#ENABLE_TESTING()
-add_subdirectory(cv)
-add_subdirectory(cxcore)
-add_subdirectory(ml)
-add_subdirectory(cxts)
+#add_subdirectory(cv)
+#add_subdirectory(cxcore)
+#add_subdirectory(ml)
+#add_subdirectory(cxts)
#if(WITH_CUDA)
# set (BUILD_TESTS_GPU OFF CACHE BOOL "Build tests GPU")