reworked nearly all of the OpenCV tests (except for opencv_gpu tests) - they now...
authorVadim Pisarevsky <no@email>
Wed, 9 Feb 2011 20:55:11 +0000 (20:55 +0000)
committerVadim Pisarevsky <no@email>
Wed, 9 Feb 2011 20:55:11 +0000 (20:55 +0000)
122 files changed:
CMakeLists.txt
OpenCVModule.cmake
modules/CMakeLists.txt
modules/calib3d/include/opencv2/calib3d/calib3d.hpp
modules/calib3d/src/quadsubpix.cpp [moved from modules/contrib/src/quadsubpix.cpp with 100% similarity]
modules/calib3d/test/test_affine3d_estimator.cpp [new file with mode: 0644]
modules/calib3d/test/test_cameracalibration.cpp [new file with mode: 0644]
modules/calib3d/test/test_cameracalibration_artificial.cpp [new file with mode: 0644]
modules/calib3d/test/test_cameracalibration_badarg.cpp [new file with mode: 0644]
modules/calib3d/test/test_chessboardgenerator.cpp [new file with mode: 0644]
modules/calib3d/test/test_chessboardgenerator.hpp [new file with mode: 0644]
modules/calib3d/test/test_chesscorners.cpp [new file with mode: 0644]
modules/calib3d/test/test_chesscorners_badarg.cpp [new file with mode: 0644]
modules/calib3d/test/test_chesscorners_timing.cpp [new file with mode: 0644]
modules/calib3d/test/test_compose_rt.cpp [new file with mode: 0644]
modules/calib3d/test/test_cornerssubpix.cpp [new file with mode: 0644]
modules/calib3d/test/test_fundam.cpp [new file with mode: 0644]
modules/calib3d/test/test_main.cpp [new file with mode: 0644]
modules/calib3d/test/test_posit.cpp [new file with mode: 0644]
modules/calib3d/test/test_precomp.cpp [new file with mode: 0644]
modules/calib3d/test/test_precomp.hpp [new file with mode: 0644]
modules/calib3d/test/test_reproject_image_to_3d.cpp [new file with mode: 0644]
modules/calib3d/test/test_stereomatching.cpp [new file with mode: 0755]
modules/calib3d/test/test_undistort.cpp [new file with mode: 0644]
modules/calib3d/test/test_undistort_badarg.cpp [new file with mode: 0644]
modules/contrib/include/opencv2/contrib/contrib.hpp
modules/core/include/opencv2/core/internal.hpp
modules/core/include/opencv2/core/types_c.h
modules/core/src/arithm.cpp
modules/core/src/convert.cpp
modules/core/src/mathfuncs.cpp
modules/core/src/matrix.cpp
modules/core/src/stat.cpp
modules/core/test/test_arithm.cpp
modules/core/test/test_ds.cpp [new file with mode: 0644]
modules/core/test/test_dxt.cpp [new file with mode: 0644]
modules/core/test/test_io.cpp [new file with mode: 0644]
modules/core/test/test_main.cpp
modules/core/test/test_mat.cpp [new file with mode: 0644]
modules/core/test/test_math.cpp [new file with mode: 0644]
modules/core/test/test_operations.cpp [new file with mode: 0644]
modules/core/test/test_precomp.hpp
modules/core/test/test_rand.cpp [new file with mode: 0644]
modules/features2d/test/test_bruteforcematcher.cpp [new file with mode: 0644]
modules/features2d/test/test_detectordescriptor_evaluation.cpp [new file with mode: 0644]
modules/features2d/test/test_detectors.cpp [new file with mode: 0644]
modules/features2d/test/test_fast.cpp [new file with mode: 0644]
modules/features2d/test/test_features2d.cpp [new file with mode: 0644]
modules/features2d/test/test_main.cpp [new file with mode: 0644]
modules/features2d/test/test_mser.cpp [new file with mode: 0644]
modules/features2d/test/test_nearestneighbors.cpp [new file with mode: 0644]
modules/features2d/test/test_precomp.cpp [new file with mode: 0644]
modules/features2d/test/test_precomp.hpp [new file with mode: 0644]
modules/gtest/CMakeLists.txt [deleted file]
modules/gtest/README [deleted file]
modules/gtest/include/opencv2/gtest/gtest.h [deleted file]
modules/gtest/include/opencv2/gtest/gtest_main.hpp [deleted file]
modules/gtest/include/opencv2/gtest/gtestcv.hpp [deleted file]
modules/gtest/src/gtest.cpp [deleted file]
modules/gtest/src/gtestcv.cpp [deleted file]
modules/gtest/src/precomp.cpp [deleted file]
modules/gtest/src/precomp.hpp [deleted file]
modules/highgui/test/test_drawing.cpp [new file with mode: 0644]
modules/highgui/test/test_gui.cpp [new file with mode: 0644]
modules/highgui/test/test_main.cpp [new file with mode: 0644]
modules/highgui/test/test_precomp.cpp [new file with mode: 0644]
modules/highgui/test/test_precomp.hpp [new file with mode: 0644]
modules/highgui/test/test_video_io.cpp [new file with mode: 0644]
modules/imgproc/include/opencv2/imgproc/imgproc.hpp
modules/imgproc/src/emd.cpp
modules/imgproc/src/filter.cpp
modules/imgproc/src/pyramids.cpp
modules/imgproc/src/undistort.cpp
modules/imgproc/test/test_approxpoly.cpp [new file with mode: 0644]
modules/imgproc/test/test_canny.cpp [new file with mode: 0644]
modules/imgproc/test/test_color.cpp [new file with mode: 0644]
modules/imgproc/test/test_contours.cpp [new file with mode: 0644]
modules/imgproc/test/test_convhull.cpp [new file with mode: 0644]
modules/imgproc/test/test_distancetransform.cpp [new file with mode: 0644]
modules/imgproc/test/test_emd.cpp [new file with mode: 0644]
modules/imgproc/test/test_filter.cpp [new file with mode: 0644]
modules/imgproc/test/test_floodfill.cpp [new file with mode: 0644]
modules/imgproc/test/test_grabcut.cpp [new file with mode: 0644]
modules/imgproc/test/test_histograms.cpp [new file with mode: 0644]
modules/imgproc/test/test_imgwarp.cpp [new file with mode: 0644]
modules/imgproc/test/test_inpaint.cpp [new file with mode: 0644]
modules/imgproc/test/test_main.cpp [new file with mode: 0644]
modules/imgproc/test/test_moments.cpp [new file with mode: 0644]
modules/imgproc/test/test_precomp.cpp [new file with mode: 0644]
modules/imgproc/test/test_precomp.hpp [new file with mode: 0644]
modules/imgproc/test/test_pyrsegmentation.cpp [new file with mode: 0644]
modules/imgproc/test/test_subdivisions.cpp [new file with mode: 0644]
modules/imgproc/test/test_templmatch.cpp [new file with mode: 0644]
modules/imgproc/test/test_thresh.cpp [new file with mode: 0644]
modules/imgproc/test/test_watershed.cpp [new file with mode: 0644]
modules/ml/test/test_emknearestkmeans.cpp [new file with mode: 0644]
modules/ml/test/test_gbttest.cpp [new file with mode: 0644]
modules/ml/test/test_main.cpp [new file with mode: 0644]
modules/ml/test/test_mltests.cpp [new file with mode: 0644]
modules/ml/test/test_mltests2.cpp [new file with mode: 0644]
modules/ml/test/test_precomp.cpp [new file with mode: 0644]
modules/ml/test/test_precomp.hpp [new file with mode: 0644]
modules/ml/test/test_save_load.cpp [new file with mode: 0644]
modules/objdetect/test/test_cascadeandhog.cpp [new file with mode: 0644]
modules/objdetect/test/test_latentsvmdetector.cpp [new file with mode: 0644]
modules/objdetect/test/test_main.cpp [new file with mode: 0644]
modules/objdetect/test/test_precomp.cpp [new file with mode: 0644]
modules/objdetect/test/test_precomp.hpp [new file with mode: 0644]
modules/python/hdr_parser.pyc [new file with mode: 0755]
modules/video/include/opencv2/video/tracking.hpp
modules/video/src/motempl.cpp
modules/video/test/test_accum.cpp [new file with mode: 0644]
modules/video/test/test_camshift.cpp [new file with mode: 0644]
modules/video/test/test_estimaterigid.cpp [new file with mode: 0644]
modules/video/test/test_kalman.cpp [new file with mode: 0644]
modules/video/test/test_main.cpp [new file with mode: 0644]
modules/video/test/test_motiontemplates.cpp [new file with mode: 0644]
modules/video/test/test_optflow.cpp [new file with mode: 0644]
modules/video/test/test_optflowpyrlk.cpp [new file with mode: 0644]
modules/video/test/test_precomp.cpp [new file with mode: 0644]
modules/video/test/test_precomp.hpp [new file with mode: 0644]
tests/CMakeLists.txt

index 5c6a3e9..79a3125 100644 (file)
@@ -1275,10 +1275,10 @@ if(BUILD_EXAMPLES OR INSTALL_PYTHON_EXAMPLES)
     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
index a09acf7..16916d1 100644 (file)
@@ -82,13 +82,13 @@ macro(define_opencv_module name)
         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()
@@ -101,7 +101,7 @@ macro(define_opencv_module name)
         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})
 
@@ -123,10 +123,10 @@ macro(define_opencv_module name)
             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)
@@ -138,66 +138,3 @@ macro(define_opencv_module name)
     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()
-
-
index d981b25..ce50df3 100644 (file)
@@ -13,7 +13,7 @@ if(MSVC OR MINGW)
    endif()
 endif()
 
-add_subdirectory(gtest)
+add_subdirectory(ts)
 add_subdirectory(highgui)
 add_subdirectory(imgproc)
 add_subdirectory(legacy)
index d1599cf..61324b3 100644 (file)
@@ -534,6 +534,10 @@ CV_EXPORTS_W bool findChessboardCorners( const Mat& image, Size patternSize,
                                          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,
diff --git a/modules/calib3d/test/test_affine3d_estimator.cpp b/modules/calib3d/test/test_affine3d_estimator.cpp
new file mode 100644 (file)
index 0000000..95742a9
--- /dev/null
@@ -0,0 +1,195 @@
+/*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(); }
+
diff --git a/modules/calib3d/test/test_cameracalibration.cpp b/modules/calib3d/test/test_cameracalibration.cpp
new file mode 100644 (file)
index 0000000..c14b70b
--- /dev/null
@@ -0,0 +1,1717 @@
+/*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(); }
diff --git a/modules/calib3d/test/test_cameracalibration_artificial.cpp b/modules/calib3d/test/test_cameracalibration_artificial.cpp
new file mode 100644 (file)
index 0000000..390fa71
--- /dev/null
@@ -0,0 +1,428 @@
+/*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(); }
diff --git a/modules/calib3d/test/test_cameracalibration_badarg.cpp b/modules/calib3d/test/test_cameracalibration_badarg.cpp
new file mode 100644 (file)
index 0000000..adfea50
--- /dev/null
@@ -0,0 +1,738 @@
+/*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(); }
+
+
diff --git a/modules/calib3d/test/test_chessboardgenerator.cpp b/modules/calib3d/test/test_chessboardgenerator.cpp
new file mode 100644 (file)
index 0000000..bf05a0f
--- /dev/null
@@ -0,0 +1,332 @@
+/*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);      
+}
+
diff --git a/modules/calib3d/test/test_chessboardgenerator.hpp b/modules/calib3d/test/test_chessboardgenerator.hpp
new file mode 100644 (file)
index 0000000..f3a7243
--- /dev/null
@@ -0,0 +1,40 @@
+#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
diff --git a/modules/calib3d/test/test_chesscorners.cpp b/modules/calib3d/test/test_chesscorners.cpp
new file mode 100644 (file)
index 0000000..0bca4e0
--- /dev/null
@@ -0,0 +1,443 @@
+/*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. */
diff --git a/modules/calib3d/test/test_chesscorners_badarg.cpp b/modules/calib3d/test/test_chesscorners_badarg.cpp
new file mode 100644 (file)
index 0000000..5710cf6
--- /dev/null
@@ -0,0 +1,145 @@
+/*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. */
diff --git a/modules/calib3d/test/test_chesscorners_timing.cpp b/modules/calib3d/test/test_chesscorners_timing.cpp
new file mode 100644 (file)
index 0000000..cc76257
--- /dev/null
@@ -0,0 +1,189 @@
+/*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. */
diff --git a/modules/calib3d/test/test_compose_rt.cpp b/modules/calib3d/test/test_compose_rt.cpp
new file mode 100644 (file)
index 0000000..b55318c
--- /dev/null
@@ -0,0 +1,216 @@
+/*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(); }
+
diff --git a/modules/calib3d/test/test_cornerssubpix.cpp b/modules/calib3d/test/test_cornerssubpix.cpp
new file mode 100644 (file)
index 0000000..6afcfc6
--- /dev/null
@@ -0,0 +1,242 @@
+/*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. */
diff --git a/modules/calib3d/test/test_fundam.cpp b/modules/calib3d/test/test_fundam.cpp
new file mode 100644 (file)
index 0000000..4315ee0
--- /dev/null
@@ -0,0 +1,1363 @@
+/*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. */
diff --git a/modules/calib3d/test/test_main.cpp b/modules/calib3d/test/test_main.cpp
new file mode 100644 (file)
index 0000000..6b24993
--- /dev/null
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/modules/calib3d/test/test_posit.cpp b/modules/calib3d/test/test_posit.cpp
new file mode 100644 (file)
index 0000000..7bf187a
--- /dev/null
@@ -0,0 +1,221 @@
+/*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. */
diff --git a/modules/calib3d/test/test_precomp.cpp b/modules/calib3d/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/calib3d/test/test_precomp.hpp b/modules/calib3d/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..43792d6
--- /dev/null
@@ -0,0 +1,17 @@
+#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
+
diff --git a/modules/calib3d/test/test_reproject_image_to_3d.cpp b/modules/calib3d/test/test_reproject_image_to_3d.cpp
new file mode 100644 (file)
index 0000000..3e6c6c6
--- /dev/null
@@ -0,0 +1,175 @@
+/*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(); }
+
diff --git a/modules/calib3d/test/test_stereomatching.cpp b/modules/calib3d/test/test_stereomatching.cpp
new file mode 100755 (executable)
index 0000000..60f20de
--- /dev/null
@@ -0,0 +1,832 @@
+/*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(); }
diff --git a/modules/calib3d/test/test_undistort.cpp b/modules/calib3d/test/test_undistort.cpp
new file mode 100644 (file)
index 0000000..8225626
--- /dev/null
@@ -0,0 +1,928 @@
+/*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(); }
diff --git a/modules/calib3d/test/test_undistort_badarg.cpp b/modules/calib3d/test/test_undistort_badarg.cpp
new file mode 100644 (file)
index 0000000..38aae65
--- /dev/null
@@ -0,0 +1,518 @@
+/*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. */
index f867a76..4f56c3f 100644 (file)
@@ -549,8 +549,6 @@ namespace cv
     };
     
     
-    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,
index c5aff62..cd19a0b 100644 (file)
@@ -288,14 +288,6 @@ CV_INLINE IppiSize ippiSize(int width, int height)
 /* ! 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
index d938d23..53b9108 100644 (file)
 #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
index bf6dde9..8675ddd 100644 (file)
@@ -1158,10 +1158,10 @@ div_( const Mat& srcmat1, const Mat& srcmat2, Mat& dstmat, double scale )
                 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;
@@ -1193,7 +1193,7 @@ void divide(const Mat& src1, const Mat& src2, Mat& dst, double scale)
     };
 
     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 )
     {
@@ -1446,7 +1446,7 @@ void addWeighted( const Mat& src1, double alpha, const Mat& src2,
         addWeighted_<ushort, float>,
         addWeighted_<short, float>,
         addWeighted_<int, double>,
-        addWeighted_<float, float>,
+        addWeighted_<float, double>,
         addWeighted_<double, double>,
         0
     };
@@ -1952,7 +1952,7 @@ void compare( const Mat& src1, double value, Mat& dst, int cmpOp )
         {
             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;
     }
index 5d4d70e..3dd9542 100644 (file)
@@ -619,7 +619,7 @@ static const int FBITS = 15;
 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[] =
     {
@@ -632,15 +632,27 @@ void convertScaleAbs( const Mat& src, Mat& dst, double scale, double shift )
         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] =
@@ -699,7 +711,7 @@ void Mat::convertTo(Mat& dst, int _type, double alpha, double beta) const
             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,
         },
 
@@ -709,7 +721,7 @@ void Mat::convertTo(Mat& dst, int _type, double alpha, double beta) const
             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,
         },
 
@@ -719,7 +731,7 @@ void Mat::convertTo(Mat& dst, int _type, double alpha, double beta) const
             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,
         },
 
index 2c0c8d6..7b63616 100644 (file)
@@ -47,37 +47,17 @@ namespace cv
 {
 
 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);
 }
 
@@ -95,15 +75,20 @@ static CvStatus CV_STDCALL FastAtan2_32f(const float *Y, const float *X, float *
         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);
@@ -121,15 +106,19 @@ static CvStatus CV_STDCALL FastAtan2_32f(const float *Y, const float *X, float *
     }
 #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;
index c92019e..e574d80 100644 (file)
@@ -102,6 +102,7 @@ static inline void setSize( Mat& m, int _dims, const int* _sz,
             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;
         }
     }
     
@@ -711,10 +712,19 @@ void insertImageCOI(const Mat& ch, CvArr* arr, int coi)
 
 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;
 
index 1000d8d..44f981a 100644 (file)
@@ -409,7 +409,7 @@ template<> inline Vec<double, 4> SqrC4<uchar, double>::operator() (const Vec<uch
 
 
 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;
@@ -430,20 +430,13 @@ meanStdDev_( const Mat& srcmat, Scalar& _mean, Scalar& _stddev )
             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;
@@ -470,20 +463,15 @@ meanStdDevMask_( const Mat& srcmat, const Mat& maskmat,
                 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 )
 {
@@ -551,55 +539,53 @@ 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 );
 }
 
 
@@ -607,45 +593,46 @@ void meanStdDev( const Mat& m, Scalar& mean, Scalar& stddev, const Mat& mask )
 *                                       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() &&
@@ -654,54 +641,40 @@ minMaxIndxMask_( const Mat& srcmat, const Mat& maskmat,
     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 )
@@ -709,15 +682,20 @@ void minMaxLoc( const Mat& img, double* minVal, double* maxVal,
     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 );
 
@@ -725,36 +703,41 @@ void minMaxLoc( const Mat& img, double* minVal, double* maxVal,
     {
         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;
@@ -764,10 +747,20 @@ void minMaxLoc( const Mat& img, double* minVal, double* maxVal,
 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;
     }
 }
 
@@ -780,43 +773,60 @@ void minMaxIdx(const Mat& a, double* minVal,
         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);
 }    
     
 /****************************************************************************************\
@@ -922,6 +932,7 @@ static double normMaskBlock_( const Mat& srcmat, const Mat& maskmat )
     ST s0 = 0;
     WT s = 0;
     int y, remaining = BLOCK_SIZE;
+    int cn = srcmat.channels();
 
     for( y = 0; y < size.height; y++ )
     {
@@ -933,21 +944,25 @@ static double normMaskBlock_( const Mat& srcmat, const Mat& maskmat )
             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) )
             {
@@ -971,27 +986,31 @@ static double normMask_( const Mat& srcmat, const Mat& maskmat )
     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;
@@ -1085,6 +1104,7 @@ static double normDiffMaskBlock_( const Mat& srcmat1, const Mat& srcmat2, const
     ST s0 = 0;
     WT s = 0;
     int y, remaining = BLOCK_SIZE;
+    int cn = srcmat1.channels();
 
     for( y = 0; y < size.height; y++ )
     {
@@ -1097,20 +1117,24 @@ static double normDiffMaskBlock_( const Mat& srcmat1, const Mat& srcmat2, const
             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);
@@ -1132,28 +1156,31 @@ static double normDiffMask_( const Mat& srcmat1, const Mat& srcmat2, const Mat&
     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;
 }
@@ -1265,8 +1292,7 @@ double norm( const Mat& a, int normType, const Mat& mask )
         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);
     
@@ -1405,7 +1431,7 @@ double norm( const Mat& a, const Mat& b, int normType, const Mat& mask )
     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);
index c7b0252..c6022ce 100644 (file)
 #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)));
diff --git a/modules/core/test/test_ds.cpp b/modules/core/test/test_ds.cpp
new file mode 100644 (file)
index 0000000..f19c6bb
--- /dev/null
@@ -0,0 +1,2122 @@
+#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(); }
+
+
diff --git a/modules/core/test/test_dxt.cpp b/modules/core/test/test_dxt.cpp
new file mode 100644 (file)
index 0000000..b6f7078
--- /dev/null
@@ -0,0 +1,829 @@
+#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(); }
+
diff --git a/modules/core/test/test_io.cpp b/modules/core/test/test_io.cpp
new file mode 100644 (file)
index 0000000..2edcfbd
--- /dev/null
@@ -0,0 +1,382 @@
+#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\"&amp;&lt;&gt;&amp;&apos;@#$@$%$%&%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(); }
index c2cc775..6b24993 100644 (file)
@@ -1,2 +1,3 @@
 #include "test_precomp.hpp"
-#include "opencv2/gtest/gtest_main.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/modules/core/test/test_mat.cpp b/modules/core/test/test_mat.cpp
new file mode 100644 (file)
index 0000000..ae5f442
--- /dev/null
@@ -0,0 +1,811 @@
+#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(); }
diff --git a/modules/core/test/test_math.cpp b/modules/core/test/test_math.cpp
new file mode 100644 (file)
index 0000000..1b68a6f
--- /dev/null
@@ -0,0 +1,2372 @@
+//////////////////////////////////////////////////////////////////////////////////////////
+/////////////////// 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. */
+
diff --git a/modules/core/test/test_operations.cpp b/modules/core/test/test_operations.cpp
new file mode 100644 (file)
index 0000000..1abaf14
--- /dev/null
@@ -0,0 +1,829 @@
+/*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(); }
index 38e714a..887f915 100644 (file)
@@ -1,2 +1,8 @@
-#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
diff --git a/modules/core/test/test_rand.cpp b/modules/core/test/test_rand.cpp
new file mode 100644 (file)
index 0000000..d05b16a
--- /dev/null
@@ -0,0 +1,303 @@
+#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(); }
+
+
diff --git a/modules/features2d/test/test_bruteforcematcher.cpp b/modules/features2d/test/test_bruteforcematcher.cpp
new file mode 100644 (file)
index 0000000..f2fdca1
--- /dev/null
@@ -0,0 +1,122 @@
+#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
diff --git a/modules/features2d/test/test_detectordescriptor_evaluation.cpp b/modules/features2d/test/test_detectordescriptor_evaluation.cpp
new file mode 100644 (file)
index 0000000..4980bb9
--- /dev/null
@@ -0,0 +1,1186 @@
+/*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" );
+
diff --git a/modules/features2d/test/test_detectors.cpp b/modules/features2d/test/test_detectors.cpp
new file mode 100644 (file)
index 0000000..75bc521
--- /dev/null
@@ -0,0 +1,317 @@
+/*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(); }
+
+
+
diff --git a/modules/features2d/test/test_fast.cpp b/modules/features2d/test/test_fast.cpp
new file mode 100644 (file)
index 0000000..416fe14
--- /dev/null
@@ -0,0 +1,126 @@
+/*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(); }
+
diff --git a/modules/features2d/test/test_features2d.cpp b/modules/features2d/test/test_features2d.cpp
new file mode 100644 (file)
index 0000000..cab7b0b
--- /dev/null
@@ -0,0 +1,1038 @@
+/*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();
+}
+
diff --git a/modules/features2d/test/test_main.cpp b/modules/features2d/test/test_main.cpp
new file mode 100644 (file)
index 0000000..6b24993
--- /dev/null
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/modules/features2d/test/test_mser.cpp b/modules/features2d/test/test_mser.cpp
new file mode 100644 (file)
index 0000000..efb5b22
--- /dev/null
@@ -0,0 +1,203 @@
+/*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(); }
+
diff --git a/modules/features2d/test/test_nearestneighbors.cpp b/modules/features2d/test/test_nearestneighbors.cpp
new file mode 100644 (file)
index 0000000..b97f597
--- /dev/null
@@ -0,0 +1,523 @@
+/*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(); }
diff --git a/modules/features2d/test/test_precomp.cpp b/modules/features2d/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/features2d/test/test_precomp.hpp b/modules/features2d/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..b787504
--- /dev/null
@@ -0,0 +1,11 @@
+#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
diff --git a/modules/gtest/CMakeLists.txt b/modules/gtest/CMakeLists.txt
deleted file mode 100644 (file)
index 4a912b4..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-if(BUILD_SHARED_LIBS)
-add_definitions(-DGTEST_CREATE_SHARED_LIBRARY=1)
-endif()
-define_opencv_module(gtest opencv_core)
diff --git a/modules/gtest/README b/modules/gtest/README
deleted file mode 100644 (file)
index 8312bbc..0000000
+++ /dev/null
@@ -1,422 +0,0 @@
-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!
diff --git a/modules/gtest/include/opencv2/gtest/gtest.h b/modules/gtest/include/opencv2/gtest/gtest.h
deleted file mode 100644 (file)
index c0a1902..0000000
+++ /dev/null
@@ -1,18007 +0,0 @@
-// 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, &gtest_regex, \
-        __FILE__, __LINE__, &gtest_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(&parameter_);
-    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 &current_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 &current_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 &current_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 &current_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 &current_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 &current_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 &current_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 &current_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 &current_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, \
-                  &gtest_##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_
diff --git a/modules/gtest/include/opencv2/gtest/gtest_main.hpp b/modules/gtest/include/opencv2/gtest/gtest_main.hpp
deleted file mode 100644 (file)
index c1ab632..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-int main(int argc, char **argv)
-{
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/modules/gtest/include/opencv2/gtest/gtestcv.hpp b/modules/gtest/include/opencv2/gtest/gtestcv.hpp
deleted file mode 100644 (file)
index 2da7feb..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#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
-
diff --git a/modules/gtest/src/gtest.cpp b/modules/gtest/src/gtest.cpp
deleted file mode 100644 (file)
index 43a5b5c..0000000
+++ /dev/null
@@ -1,8510 +0,0 @@
-// 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(\
-        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
-    {\
-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
-          ::testing::ScopedFakeTestPartResultReporter:: \
-          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
-        &gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
-    {\
-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
-          ::testing::ScopedFakeTestPartResultReporter:: \
-          INTERCEPT_ALL_THREADS, &gtest_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(\
-        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
-        (substr));\
-    {\
-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
-          ::testing::ScopedFakeTestPartResultReporter:: \
-          INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
-        &gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
-        (substr));\
-    {\
-      ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
-          ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS,\
-          &gtest_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 << "&lt;";
-          break;
-        case '>':
-          m << "&gt;";
-          break;
-        case '&':
-          m << "&amp;";
-          break;
-        case '\'':
-          if (is_attribute)
-            m << "&apos;";
-          else
-            m << '\'';
-          break;
-        case '"':
-          if (is_attribute)
-            m << "&quot;";
-          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 << "]]>]]&gt;<![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,
-                      &GTEST_FLAG(also_run_disabled_tests)) ||
-        ParseBoolFlag(arg, kBreakOnFailureFlag,
-                      &GTEST_FLAG(break_on_failure)) ||
-        ParseBoolFlag(arg, kCatchExceptionsFlag,
-                      &GTEST_FLAG(catch_exceptions)) ||
-        ParseStringFlag(arg, kColorFlag, &GTEST_FLAG(color)) ||
-        ParseStringFlag(arg, kDeathTestStyleFlag,
-                        &GTEST_FLAG(death_test_style)) ||
-        ParseBoolFlag(arg, kDeathTestUseFork,
-                      &GTEST_FLAG(death_test_use_fork)) ||
-        ParseStringFlag(arg, kFilterFlag, &GTEST_FLAG(filter)) ||
-        ParseStringFlag(arg, kInternalRunDeathTestFlag,
-                        &GTEST_FLAG(internal_run_death_test)) ||
-        ParseBoolFlag(arg, kListTestsFlag, &GTEST_FLAG(list_tests)) ||
-        ParseStringFlag(arg, kOutputFlag, &GTEST_FLAG(output)) ||
-        ParseBoolFlag(arg, kPrintTimeFlag, &GTEST_FLAG(print_time)) ||
-        ParseInt32Flag(arg, kRandomSeedFlag, &GTEST_FLAG(random_seed)) ||
-        ParseInt32Flag(arg, kRepeatFlag, &GTEST_FLAG(repeat)) ||
-        ParseBoolFlag(arg, kShuffleFlag, &GTEST_FLAG(shuffle)) ||
-        ParseInt32Flag(arg, kStackTraceDepthFlag,
-                       &GTEST_FLAG(stack_trace_depth)) ||
-        ParseBoolFlag(arg, kThrowOnFailureFlag, &GTEST_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
diff --git a/modules/gtest/src/gtestcv.cpp b/modules/gtest/src/gtestcv.cpp
deleted file mode 100644 (file)
index 3b3b695..0000000
+++ /dev/null
@@ -1,1443 +0,0 @@
-#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;
-}
-
-}
diff --git a/modules/gtest/src/precomp.cpp b/modules/gtest/src/precomp.cpp
deleted file mode 100644 (file)
index c149df1..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "precomp.hpp"
diff --git a/modules/gtest/src/precomp.hpp b/modules/gtest/src/precomp.hpp
deleted file mode 100644 (file)
index 03117ec..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "opencv2/gtest/gtestcv.hpp"
diff --git a/modules/highgui/test/test_drawing.cpp b/modules/highgui/test/test_drawing.cpp
new file mode 100644 (file)
index 0000000..908ea41
--- /dev/null
@@ -0,0 +1,410 @@
+/*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;
diff --git a/modules/highgui/test/test_gui.cpp b/modules/highgui/test/test_gui.cpp
new file mode 100644 (file)
index 0000000..59c0f0e
--- /dev/null
@@ -0,0 +1,107 @@
+/*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;
+
+
diff --git a/modules/highgui/test/test_main.cpp b/modules/highgui/test/test_main.cpp
new file mode 100644 (file)
index 0000000..db32ab1
--- /dev/null
@@ -0,0 +1,2 @@
+#include "test_precomp.hpp"
+#include "opencv2/ts/ts_main.hpp"
diff --git a/modules/highgui/test/test_precomp.cpp b/modules/highgui/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/highgui/test/test_precomp.hpp b/modules/highgui/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..7d837ce
--- /dev/null
@@ -0,0 +1,9 @@
+#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
diff --git a/modules/highgui/test/test_video_io.cpp b/modules/highgui/test/test_video_io.cpp
new file mode 100644 (file)
index 0000000..de2c895
--- /dev/null
@@ -0,0 +1,314 @@
+/*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
+
index 8fc9857..7f81b0d 100644 (file)
@@ -666,6 +666,10 @@ CV_EXPORTS double compareHist( const SparseMat& H1, const SparseMat& H2, int met
 
 //! 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 );
index e6be13e..d6cbf80 100644 (file)
@@ -1137,5 +1137,23 @@ icvDistC( const float *x, const float *y, void *user_param )
     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. */
index 9d5fda6..27fb2a0 100644 (file)
@@ -3025,8 +3025,8 @@ void sepFilter2D( const Mat& src, Mat& dst, int ddepth,
     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 );
 }
 
 }
index 5408c3a..8e5cb82 100644 (file)
@@ -45,8 +45,6 @@
 namespace cv
 {
 
-//#undef CV_SSE2
-
 template<typename T, int shift> struct FixPtCast
 {
     typedef int type1;
index 6bd05ab..de328e5 100644 (file)
@@ -380,7 +380,7 @@ void undistortPoints( const Mat& src, Mat& dst,
                           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());
diff --git a/modules/imgproc/test/test_approxpoly.cpp b/modules/imgproc/test/test_approxpoly.cpp
new file mode 100644 (file)
index 0000000..be1751a
--- /dev/null
@@ -0,0 +1,359 @@
+/*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(); }
+
diff --git a/modules/imgproc/test/test_canny.cpp b/modules/imgproc/test/test_canny.cpp
new file mode 100644 (file)
index 0000000..c07c76f
--- /dev/null
@@ -0,0 +1,287 @@
+/*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. */
diff --git a/modules/imgproc/test/test_color.cpp b/modules/imgproc/test/test_color.cpp
new file mode 100644 (file)
index 0000000..d7a4c34
--- /dev/null
@@ -0,0 +1,1645 @@
+/*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(); }
diff --git a/modules/imgproc/test/test_contours.cpp b/modules/imgproc/test/test_contours.cpp
new file mode 100644 (file)
index 0000000..3e07488
--- /dev/null
@@ -0,0 +1,393 @@
+/*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. */
diff --git a/modules/imgproc/test/test_convhull.cpp b/modules/imgproc/test/test_convhull.cpp
new file mode 100644 (file)
index 0000000..a4b61f5
--- /dev/null
@@ -0,0 +1,1583 @@
+/*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, &center, &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. */
+
diff --git a/modules/imgproc/test/test_distancetransform.cpp b/modules/imgproc/test/test_distancetransform.cpp
new file mode 100644 (file)
index 0000000..bdf205b
--- /dev/null
@@ -0,0 +1,297 @@
+/*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(); }
+
+
diff --git a/modules/imgproc/test/test_emd.cpp b/modules/imgproc/test/test_emd.cpp
new file mode 100644 (file)
index 0000000..1880bb3
--- /dev/null
@@ -0,0 +1,95 @@
+/*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. */
diff --git a/modules/imgproc/test/test_filter.cpp b/modules/imgproc/test/test_filter.cpp
new file mode 100644 (file)
index 0000000..53ecff7
--- /dev/null
@@ -0,0 +1,1776 @@
+/*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(); }
diff --git a/modules/imgproc/test/test_floodfill.cpp b/modules/imgproc/test/test_floodfill.cpp
new file mode 100644 (file)
index 0000000..1357e34
--- /dev/null
@@ -0,0 +1,533 @@
+/*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. */
diff --git a/modules/imgproc/test/test_grabcut.cpp b/modules/imgproc/test/test_grabcut.cpp
new file mode 100644 (file)
index 0000000..61eca24
--- /dev/null
@@ -0,0 +1,141 @@
+/*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(); }
+
diff --git a/modules/imgproc/test/test_histograms.cpp b/modules/imgproc/test/test_histograms.cpp
new file mode 100644 (file)
index 0000000..07633be
--- /dev/null
@@ -0,0 +1,1842 @@
+/*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 */
diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp
new file mode 100644 (file)
index 0000000..6bd1b86
--- /dev/null
@@ -0,0 +1,1387 @@
+/*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. */
diff --git a/modules/imgproc/test/test_inpaint.cpp b/modules/imgproc/test/test_inpaint.cpp
new file mode 100644 (file)
index 0000000..b1da5cc
--- /dev/null
@@ -0,0 +1,121 @@
+/*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(); }
diff --git a/modules/imgproc/test/test_main.cpp b/modules/imgproc/test/test_main.cpp
new file mode 100644 (file)
index 0000000..6a686e6
--- /dev/null
@@ -0,0 +1,4 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
+
diff --git a/modules/imgproc/test/test_moments.cpp b/modules/imgproc/test/test_moments.cpp
new file mode 100644 (file)
index 0000000..ca53d8c
--- /dev/null
@@ -0,0 +1,393 @@
+/*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(); }
diff --git a/modules/imgproc/test/test_precomp.cpp b/modules/imgproc/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/imgproc/test/test_precomp.hpp b/modules/imgproc/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..f28d167
--- /dev/null
@@ -0,0 +1,11 @@
+#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
diff --git a/modules/imgproc/test/test_pyrsegmentation.cpp b/modules/imgproc/test/test_pyrsegmentation.cpp
new file mode 100644 (file)
index 0000000..89fe46a
--- /dev/null
@@ -0,0 +1,204 @@
+/*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. */
diff --git a/modules/imgproc/test/test_subdivisions.cpp b/modules/imgproc/test/test_subdivisions.cpp
new file mode 100644 (file)
index 0000000..b65b8d2
--- /dev/null
@@ -0,0 +1,341 @@
+/*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. */
+
diff --git a/modules/imgproc/test/test_templmatch.cpp b/modules/imgproc/test/test_templmatch.cpp
new file mode 100644 (file)
index 0000000..1b38e56
--- /dev/null
@@ -0,0 +1,336 @@
+/*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(); }
diff --git a/modules/imgproc/test/test_thresh.cpp b/modules/imgproc/test/test_thresh.cpp
new file mode 100644 (file)
index 0000000..9ef1bf6
--- /dev/null
@@ -0,0 +1,217 @@
+/*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(); }
+
diff --git a/modules/imgproc/test/test_watershed.cpp b/modules/imgproc/test/test_watershed.cpp
new file mode 100644 (file)
index 0000000..7ab8fcb
--- /dev/null
@@ -0,0 +1,133 @@
+/*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(); }
+
diff --git a/modules/ml/test/test_emknearestkmeans.cpp b/modules/ml/test/test_emknearestkmeans.cpp
new file mode 100644 (file)
index 0000000..e1d4360
--- /dev/null
@@ -0,0 +1,327 @@
+/*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(); }
diff --git a/modules/ml/test/test_gbttest.cpp b/modules/ml/test/test_gbttest.cpp
new file mode 100644 (file)
index 0000000..3595189
--- /dev/null
@@ -0,0 +1,275 @@
+
+#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(); }
diff --git a/modules/ml/test/test_main.cpp b/modules/ml/test/test_main.cpp
new file mode 100644 (file)
index 0000000..7384582
--- /dev/null
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("ml")
diff --git a/modules/ml/test/test_mltests.cpp b/modules/ml/test/test_mltests.cpp
new file mode 100644 (file)
index 0000000..fafe4f9
--- /dev/null
@@ -0,0 +1,130 @@
+/*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. */
diff --git a/modules/ml/test/test_mltests2.cpp b/modules/ml/test/test_mltests2.cpp
new file mode 100644 (file)
index 0000000..93c7220
--- /dev/null
@@ -0,0 +1,796 @@
+/*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. */
diff --git a/modules/ml/test/test_precomp.cpp b/modules/ml/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/ml/test/test_precomp.hpp b/modules/ml/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..7a9083d
--- /dev/null
@@ -0,0 +1,80 @@
+#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
diff --git a/modules/ml/test/test_save_load.cpp b/modules/ml/test/test_save_load.cpp
new file mode 100644 (file)
index 0000000..806a6aa
--- /dev/null
@@ -0,0 +1,138 @@
+/*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. */
diff --git a/modules/objdetect/test/test_cascadeandhog.cpp b/modules/objdetect/test/test_cascadeandhog.cpp
new file mode 100644 (file)
index 0000000..dd7f060
--- /dev/null
@@ -0,0 +1,465 @@
+/*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(); }
diff --git a/modules/objdetect/test/test_latentsvmdetector.cpp b/modules/objdetect/test/test_latentsvmdetector.cpp
new file mode 100644 (file)
index 0000000..0e481de
--- /dev/null
@@ -0,0 +1,125 @@
+/*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(); }
diff --git a/modules/objdetect/test/test_main.cpp b/modules/objdetect/test/test_main.cpp
new file mode 100644 (file)
index 0000000..6b24993
--- /dev/null
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/modules/objdetect/test/test_precomp.cpp b/modules/objdetect/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/objdetect/test/test_precomp.hpp b/modules/objdetect/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..67dd004
--- /dev/null
@@ -0,0 +1,10 @@
+#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
diff --git a/modules/python/hdr_parser.pyc b/modules/python/hdr_parser.pyc
new file mode 100755 (executable)
index 0000000..8b63346
Binary files /dev/null and b/modules/python/hdr_parser.pyc differ
index fc36e21..5e5a051 100644 (file)
@@ -257,7 +257,10 @@ CV_EXPORTS_W void calcMotionGradient( const Mat& mhi, CV_OUT Mat& mask,
 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,
index da4f43b..1c94354 100644 (file)
@@ -468,4 +468,19 @@ double cv::calcGlobalOrientation( const Mat& orientation, const Mat& mask,
     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. */
diff --git a/modules/video/test/test_accum.cpp b/modules/video/test/test_accum.cpp
new file mode 100644 (file)
index 0000000..d3cab6c
--- /dev/null
@@ -0,0 +1,247 @@
+/*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(); }
diff --git a/modules/video/test/test_camshift.cpp b/modules/video/test/test_camshift.cpp
new file mode 100644 (file)
index 0000000..b1e8483
--- /dev/null
@@ -0,0 +1,511 @@
+/*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. */
diff --git a/modules/video/test/test_estimaterigid.cpp b/modules/video/test/test_estimaterigid.cpp
new file mode 100644 (file)
index 0000000..c69fbf2
--- /dev/null
@@ -0,0 +1,174 @@
+/*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(); }
diff --git a/modules/video/test/test_kalman.cpp b/modules/video/test/test_kalman.cpp
new file mode 100644 (file)
index 0000000..cf08d23
--- /dev/null
@@ -0,0 +1,124 @@
+/*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. */
diff --git a/modules/video/test/test_main.cpp b/modules/video/test/test_main.cpp
new file mode 100644 (file)
index 0000000..6b24993
--- /dev/null
@@ -0,0 +1,3 @@
+#include "test_precomp.hpp"
+
+CV_TEST_MAIN("cv")
diff --git a/modules/video/test/test_motiontemplates.cpp b/modules/video/test/test_motiontemplates.cpp
new file mode 100644 (file)
index 0000000..452c73b
--- /dev/null
@@ -0,0 +1,497 @@
+/*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(); }
diff --git a/modules/video/test/test_optflow.cpp b/modules/video/test/test_optflow.cpp
new file mode 100644 (file)
index 0000000..38a24a8
--- /dev/null
@@ -0,0 +1,355 @@
+/*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(); }
+
+
diff --git a/modules/video/test/test_optflowpyrlk.cpp b/modules/video/test/test_optflowpyrlk.cpp
new file mode 100644 (file)
index 0000000..b7ed60d
--- /dev/null
@@ -0,0 +1,214 @@
+/*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. */
diff --git a/modules/video/test/test_precomp.cpp b/modules/video/test/test_precomp.cpp
new file mode 100644 (file)
index 0000000..5956e13
--- /dev/null
@@ -0,0 +1 @@
+#include "test_precomp.hpp"
diff --git a/modules/video/test/test_precomp.hpp b/modules/video/test/test_precomp.hpp
new file mode 100644 (file)
index 0000000..71c5e5b
--- /dev/null
@@ -0,0 +1,11 @@
+#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
index 42c840c..3c7bcdf 100644 (file)
@@ -1,9 +1,9 @@
-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")