GTest unit testing framework
Currently covers only small set of functionality.
This commit is contained in:
parent
47ec0394ca
commit
306cbb82ec
@ -109,6 +109,7 @@ enable_testing()
|
|||||||
|
|
||||||
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin CACHE INTERNAL "" FORCE)
|
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin CACHE INTERNAL "" FORCE)
|
||||||
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib CACHE INTERNAL "" FORCE)
|
set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib CACHE INTERNAL "" FORCE)
|
||||||
|
set(TESTS_OUTPUT_DIR ${EXECUTABLE_OUTPUT_PATH}/tests CACHE INTERNAL "" FORCE)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Set default config options
|
# Set default config options
|
||||||
@ -300,6 +301,9 @@ if(CMAKE_COMPILER_IS_GNUCC)
|
|||||||
mark_as_advanced(WITH_GCC_MUDFLAP)
|
mark_as_advanced(WITH_GCC_MUDFLAP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Unit testsing
|
||||||
|
option(WITH_GTESTS "Enable GTest unit testing" OFF)
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
cmake_minimum_required(VERSION 2.8.8)
|
cmake_minimum_required(VERSION 2.8.8)
|
||||||
cmake_policy(VERSION 2.8.8)
|
cmake_policy(VERSION 2.8.8)
|
||||||
@ -2330,10 +2334,17 @@ endif()
|
|||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Libraries
|
# Libraries
|
||||||
|
|
||||||
|
if(WITH_TESTS)
|
||||||
|
include(GTestTesting)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WITH_BLENDER OR WITH_PLAYER)
|
if(WITH_BLENDER OR WITH_PLAYER)
|
||||||
add_subdirectory(source)
|
|
||||||
add_subdirectory(intern)
|
add_subdirectory(intern)
|
||||||
add_subdirectory(extern)
|
add_subdirectory(extern)
|
||||||
|
|
||||||
|
# source after intern and extern to gather all
|
||||||
|
# internal and external library information first, for test linking
|
||||||
|
add_subdirectory(source)
|
||||||
elseif(WITH_CYCLES_STANDALONE)
|
elseif(WITH_CYCLES_STANDALONE)
|
||||||
add_subdirectory(intern/cycles)
|
add_subdirectory(intern/cycles)
|
||||||
if(NOT WITH_SYSTEM_GLEW)
|
if(NOT WITH_SYSTEM_GLEW)
|
||||||
|
47
build_files/cmake/Modules/GTestTesting.cmake
Normal file
47
build_files/cmake/Modules/GTestTesting.cmake
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#=============================================================================
|
||||||
|
# Copyright 2014 Blender Foundation.
|
||||||
|
#
|
||||||
|
# Distributed under the OSI-approved BSD License (the "License");
|
||||||
|
# see accompanying file Copyright.txt for details.
|
||||||
|
#
|
||||||
|
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
# See the License for more information.
|
||||||
|
#
|
||||||
|
# Inspired on the Testing.cmake from Libmv
|
||||||
|
#
|
||||||
|
#=============================================================================
|
||||||
|
|
||||||
|
macro(BLENDER_SRC_GTEST NAME SRC EXTRA_LIBS)
|
||||||
|
if(WITH_TESTS)
|
||||||
|
get_property(_current_include_directories
|
||||||
|
DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
PROPERTY INCLUDE_DIRECTORIES)
|
||||||
|
set(TEST_INC
|
||||||
|
${_current_include_directories}
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/gtests
|
||||||
|
${CMAKE_SOURCE_DIR}/extern/libmv/third_party/glog/src
|
||||||
|
${CMAKE_SOURCE_DIR}/extern/libmv/third_party/gflags
|
||||||
|
${CMAKE_SOURCE_DIR}/extern/gtest/include
|
||||||
|
)
|
||||||
|
unset(_current_include_directories)
|
||||||
|
|
||||||
|
add_executable(${NAME}_test ${SRC})
|
||||||
|
target_link_libraries(${NAME}_test
|
||||||
|
${EXTRA_LIBS}
|
||||||
|
bf_testing_main
|
||||||
|
bf_intern_guardedalloc
|
||||||
|
extern_gtest
|
||||||
|
extern_glog)
|
||||||
|
set_target_properties(${NAME}_test PROPERTIES
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY "${TESTS_OUTPUT_DIR}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${TESTS_OUTPUT_DIR}"
|
||||||
|
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${TESTS_OUTPUT_DIR}"
|
||||||
|
INCLUDE_DIRECTORIES "${TEST_INC}")
|
||||||
|
add_test(${NAME}_test ${TESTS_OUTPUT_DIR}/${NAME}_test)
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
macro(BLENDER_TEST NAME EXTRA_LIBS)
|
||||||
|
BLENDER_SRC_GTEST("${NAME}" "${NAME}_test.cc" "${EXTRA_LIBS}")
|
||||||
|
endmacro()
|
@ -413,6 +413,240 @@ macro(setup_liblinks
|
|||||||
target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
|
target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS})
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
macro(SETUP_BLENDER_SORTED_LIBS)
|
||||||
|
get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS)
|
||||||
|
|
||||||
|
list(APPEND BLENDER_LINK_LIBS
|
||||||
|
bf_windowmanager
|
||||||
|
bf_render
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WITH_MOD_FLUID)
|
||||||
|
list(APPEND BLENDER_LINK_LIBS bf_intern_elbeem)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES)
|
||||||
|
list(APPEND BLENDER_LINK_LIBS
|
||||||
|
cycles_render
|
||||||
|
cycles_bvh
|
||||||
|
cycles_device
|
||||||
|
cycles_kernel
|
||||||
|
cycles_util
|
||||||
|
cycles_subd)
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
list(APPEND BLENDER_LINK_LIBS cycles_kernel_osl)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Sort libraries
|
||||||
|
set(BLENDER_SORTED_LIBS
|
||||||
|
bf_windowmanager
|
||||||
|
|
||||||
|
bf_editor_space_api
|
||||||
|
bf_editor_space_action
|
||||||
|
bf_editor_space_buttons
|
||||||
|
bf_editor_space_console
|
||||||
|
bf_editor_space_file
|
||||||
|
bf_editor_space_graph
|
||||||
|
bf_editor_space_image
|
||||||
|
bf_editor_space_info
|
||||||
|
bf_editor_space_logic
|
||||||
|
bf_editor_space_nla
|
||||||
|
bf_editor_space_node
|
||||||
|
bf_editor_space_outliner
|
||||||
|
bf_editor_space_script
|
||||||
|
bf_editor_space_sequencer
|
||||||
|
bf_editor_space_text
|
||||||
|
bf_editor_space_time
|
||||||
|
bf_editor_space_userpref
|
||||||
|
bf_editor_space_view3d
|
||||||
|
bf_editor_space_clip
|
||||||
|
|
||||||
|
bf_editor_transform
|
||||||
|
bf_editor_util
|
||||||
|
bf_editor_uvedit
|
||||||
|
bf_editor_curve
|
||||||
|
bf_editor_gpencil
|
||||||
|
bf_editor_interface
|
||||||
|
bf_editor_mesh
|
||||||
|
bf_editor_metaball
|
||||||
|
bf_editor_object
|
||||||
|
bf_editor_armature
|
||||||
|
bf_editor_physics
|
||||||
|
bf_editor_render
|
||||||
|
bf_editor_screen
|
||||||
|
bf_editor_sculpt_paint
|
||||||
|
bf_editor_sound
|
||||||
|
bf_editor_animation
|
||||||
|
bf_editor_datafiles
|
||||||
|
bf_editor_mask
|
||||||
|
bf_editor_io
|
||||||
|
|
||||||
|
bf_render
|
||||||
|
bf_python
|
||||||
|
bf_python_ext
|
||||||
|
bf_python_mathutils
|
||||||
|
bf_python_bmesh
|
||||||
|
bf_freestyle
|
||||||
|
bf_ikplugin
|
||||||
|
bf_modifiers
|
||||||
|
bf_bmesh
|
||||||
|
bf_blenkernel
|
||||||
|
bf_nodes
|
||||||
|
bf_gpu
|
||||||
|
bf_blenloader
|
||||||
|
bf_imbuf
|
||||||
|
bf_blenlib
|
||||||
|
bf_intern_ghost
|
||||||
|
bf_intern_string
|
||||||
|
bf_avi
|
||||||
|
bf_imbuf_cineon
|
||||||
|
bf_imbuf_openexr
|
||||||
|
bf_imbuf_openimageio
|
||||||
|
bf_imbuf_dds
|
||||||
|
bf_collada
|
||||||
|
bf_intern_elbeem
|
||||||
|
bf_intern_memutil
|
||||||
|
bf_intern_guardedalloc
|
||||||
|
bf_intern_ctr
|
||||||
|
bf_intern_utfconv
|
||||||
|
ge_blen_routines
|
||||||
|
ge_converter
|
||||||
|
ge_phys_dummy
|
||||||
|
ge_phys_bullet
|
||||||
|
bf_intern_smoke
|
||||||
|
extern_minilzo
|
||||||
|
extern_lzma
|
||||||
|
extern_colamd
|
||||||
|
ge_logic_ketsji
|
||||||
|
extern_recastnavigation
|
||||||
|
ge_logic
|
||||||
|
ge_rasterizer
|
||||||
|
ge_oglrasterizer
|
||||||
|
ge_logic_expressions
|
||||||
|
ge_scenegraph
|
||||||
|
ge_logic_network
|
||||||
|
ge_logic_ngnetwork
|
||||||
|
ge_logic_loopbacknetwork
|
||||||
|
bf_intern_moto
|
||||||
|
extern_openjpeg
|
||||||
|
extern_redcode
|
||||||
|
ge_videotex
|
||||||
|
bf_rna
|
||||||
|
bf_dna
|
||||||
|
bf_blenfont
|
||||||
|
bf_intern_audaspace
|
||||||
|
bf_intern_mikktspace
|
||||||
|
bf_intern_dualcon
|
||||||
|
bf_intern_cycles
|
||||||
|
cycles_render
|
||||||
|
cycles_bvh
|
||||||
|
cycles_device
|
||||||
|
cycles_kernel
|
||||||
|
cycles_util
|
||||||
|
cycles_subd
|
||||||
|
bf_intern_raskter
|
||||||
|
bf_intern_opencolorio
|
||||||
|
extern_rangetree
|
||||||
|
extern_wcwidth
|
||||||
|
extern_libmv
|
||||||
|
extern_glog
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WITH_COMPOSITOR)
|
||||||
|
# added for opencl compositor
|
||||||
|
list_insert_before(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_compositor")
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "bf_compositor" "bf_intern_opencl")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_LIBMV)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_ceres)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_MOD_CLOTH_ELTOPO)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT WITH_SYSTEM_GLEW)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_glew)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BINRELOC)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_binreloc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CXX_GUARDEDALLOC)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_IK_SOLVER)
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "bf_intern_elbeem" "bf_intern_iksolver")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_IK_ITASC)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS bf_intern_itasc)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CODEC_QUICKTIME)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_INPUT_NDOF)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_MOD_BOOLEAN)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_carve)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_GHOST_XDND)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS extern_xdnd)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_CYCLES_OSL)
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "cycles_kernel" "cycles_kernel_osl")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_INTERNATIONAL)
|
||||||
|
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_OPENNL)
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "bf_render" "bf_intern_opennl")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BULLET)
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET)
|
||||||
|
list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
|
||||||
|
set(REMLIB ${SORTLIB})
|
||||||
|
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
|
||||||
|
if(${SEARCHLIB} STREQUAL ${SORTLIB})
|
||||||
|
set(REMLIB "")
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
if(REMLIB)
|
||||||
|
# message(STATUS "Removing library ${REMLIB} from blender linking because: not configured")
|
||||||
|
list(APPEND REM_MSG ${REMLIB})
|
||||||
|
list(REMOVE_ITEM BLENDER_SORTED_LIBS ${REMLIB})
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
if(REM_MSG)
|
||||||
|
list(SORT REM_MSG)
|
||||||
|
message(STATUS "Blender Skipping: (${REM_MSG})")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
unset(SEARCHLIB)
|
||||||
|
unset(SORTLIB)
|
||||||
|
unset(REMLIB)
|
||||||
|
unset(REM_MSG)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
macro(TEST_SSE_SUPPORT
|
macro(TEST_SSE_SUPPORT
|
||||||
_sse_flags
|
_sse_flags
|
||||||
_sse2_flags)
|
_sse2_flags)
|
||||||
|
4
extern/CMakeLists.txt
vendored
4
extern/CMakeLists.txt
vendored
@ -79,3 +79,7 @@ if(WITH_GHOST_XDND)
|
|||||||
add_subdirectory(xdnd)
|
add_subdirectory(xdnd)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_TESTS)
|
||||||
|
add_subdirectory(gtest)
|
||||||
|
endif()
|
||||||
|
64
extern/gtest/CMakeLists.txt
vendored
Normal file
64
extern/gtest/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# The Original Code is Copyright (C) 2014, Blender Foundation
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Sergey Sharybin
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
include
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
src/gtest.cc
|
||||||
|
src/gtest-death-test.cc
|
||||||
|
src/gtest-filepath.cc
|
||||||
|
src/gtest-port.cc
|
||||||
|
src/gtest-printers.cc
|
||||||
|
src/gtest-test-part.cc
|
||||||
|
src/gtest-typed-test.cc
|
||||||
|
|
||||||
|
include/gtest/gtest-death-test.h
|
||||||
|
include/gtest/gtest.h
|
||||||
|
include/gtest/gtest-message.h
|
||||||
|
include/gtest/gtest-param-test.h
|
||||||
|
include/gtest/gtest_pred_impl.h
|
||||||
|
include/gtest/gtest-printers.h
|
||||||
|
include/gtest/gtest_prod.h
|
||||||
|
include/gtest/gtest-spi.h
|
||||||
|
include/gtest/gtest-test-part.h
|
||||||
|
include/gtest/gtest-typed-test.h
|
||||||
|
include/gtest/internal/gtest-death-test-internal.h
|
||||||
|
include/gtest/internal/gtest-filepath.h
|
||||||
|
include/gtest/internal/gtest-internal.h
|
||||||
|
include/gtest/internal/gtest-linked_ptr.h
|
||||||
|
include/gtest/internal/gtest-param-util-generated.h
|
||||||
|
include/gtest/internal/gtest-param-util.h
|
||||||
|
include/gtest/internal/gtest-port.h
|
||||||
|
include/gtest/internal/gtest-string.h
|
||||||
|
include/gtest/internal/gtest-tuple.h
|
||||||
|
include/gtest/internal/gtest-type-util.h
|
||||||
|
)
|
||||||
|
|
||||||
|
blender_add_lib(extern_gtest "${SRC}" "${INC}" "${INC_SYS}")
|
28
extern/gtest/LICENSE
vendored
Normal file
28
extern/gtest/LICENSE
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
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.
|
7
extern/gtest/README
vendored
Normal file
7
extern/gtest/README
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Project: Google C++ Testing Framework
|
||||||
|
URL: http://code.google.com/p/googletest
|
||||||
|
License: New BSD
|
||||||
|
Upstream version: 1.7.0
|
||||||
|
Local modifications:
|
||||||
|
|
||||||
|
None.
|
294
extern/gtest/include/gtest/gtest-death-test.h
vendored
Normal file
294
extern/gtest/include/gtest/gtest-death-test.h
vendored
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
// 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_
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Returns a Boolean value indicating whether the caller is currently
|
||||||
|
// executing in the context of the death test child process. Tools such as
|
||||||
|
// Valgrind heap checkers may need this to modify their behavior in death
|
||||||
|
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||||
|
// implementation of death tests. User code MUST NOT use it.
|
||||||
|
GTEST_API_ bool InDeathTestChild();
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// 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) \
|
||||||
|
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||||
|
|
||||||
|
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||||
|
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||||
|
|
||||||
|
# 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_
|
250
extern/gtest/include/gtest/gtest-message.h
vendored
Normal file
250
extern/gtest/include/gtest/gtest-message.h
vendored
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
// 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>
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
// Ensures that there is at least one operator<< in the global namespace.
|
||||||
|
// See Message& operator<<(...) below for why.
|
||||||
|
void operator<<(const testing::internal::Secret&, int);
|
||||||
|
|
||||||
|
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 stringstream.
|
||||||
|
// 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 stringstream 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.
|
||||||
|
Message();
|
||||||
|
|
||||||
|
// Copy constructor.
|
||||||
|
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
|
||||||
|
*ss_ << msg.GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructs a Message from a C-string.
|
||||||
|
explicit Message(const char* str) : ss_(new ::std::stringstream) {
|
||||||
|
*ss_ << str;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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) {
|
||||||
|
// Some libraries overload << for STL containers. These
|
||||||
|
// overloads are defined in the global namespace instead of ::std.
|
||||||
|
//
|
||||||
|
// 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. With this using declaration,
|
||||||
|
// overloads of << defined in the global namespace and those
|
||||||
|
// visible via Koenig lookup are both exposed in this function.
|
||||||
|
using ::operator <<;
|
||||||
|
*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 {
|
||||||
|
*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);
|
||||||
|
Message& operator <<(wchar_t* 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 an std::string.
|
||||||
|
// Each '\0' character in the buffer is replaced with "\\0".
|
||||||
|
//
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||||
|
std::string GetString() const;
|
||||||
|
|
||||||
|
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 /*is_pointer*/, T* pointer) {
|
||||||
|
if (pointer == NULL) {
|
||||||
|
*ss_ << "(null)";
|
||||||
|
} else {
|
||||||
|
*ss_ << pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
inline void StreamHelper(internal::false_type /*is_pointer*/,
|
||||||
|
const T& value) {
|
||||||
|
// See the comments in Message& operator <<(const T&) above for why
|
||||||
|
// we need this using statement.
|
||||||
|
using ::operator <<;
|
||||||
|
*ss_ << value;
|
||||||
|
}
|
||||||
|
#endif // GTEST_OS_SYMBIAN
|
||||||
|
|
||||||
|
// We'll hold the text streamed to this object here.
|
||||||
|
const internal::scoped_ptr< ::std::stringstream> 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 internal {
|
||||||
|
|
||||||
|
// Converts a streamable value to an std::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".
|
||||||
|
template <typename T>
|
||||||
|
std::string StreamableToString(const T& streamable) {
|
||||||
|
return (Message() << streamable).GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
1421
extern/gtest/include/gtest/gtest-param-test.h
vendored
Normal file
1421
extern/gtest/include/gtest/gtest-param-test.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
855
extern/gtest/include/gtest/gtest-printers.h
vendored
Normal file
855
extern/gtest/include/gtest/gtest-printers.h
vendored
Normal file
@ -0,0 +1,855 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
// Google Test - The Google C++ Testing Framework
|
||||||
|
//
|
||||||
|
// This file implements a universal value printer that can print a
|
||||||
|
// value of any type T:
|
||||||
|
//
|
||||||
|
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||||
|
//
|
||||||
|
// A user can teach this function how to print a class type T by
|
||||||
|
// defining either operator<<() or PrintTo() in the namespace that
|
||||||
|
// defines T. More specifically, the FIRST defined function in the
|
||||||
|
// following list will be used (assuming T is defined in namespace
|
||||||
|
// foo):
|
||||||
|
//
|
||||||
|
// 1. foo::PrintTo(const T&, ostream*)
|
||||||
|
// 2. operator<<(ostream&, const T&) defined in either foo or the
|
||||||
|
// global namespace.
|
||||||
|
//
|
||||||
|
// If none of the above is defined, it will print the debug string of
|
||||||
|
// the value if it is a protocol buffer, or print the raw bytes in the
|
||||||
|
// value otherwise.
|
||||||
|
//
|
||||||
|
// To aid debugging: when T is a reference type, the address of the
|
||||||
|
// value is also printed; when T is a (const) char pointer, both the
|
||||||
|
// pointer value and the NUL-terminated string it points to are
|
||||||
|
// printed.
|
||||||
|
//
|
||||||
|
// We also provide some convenient wrappers:
|
||||||
|
//
|
||||||
|
// // Prints a value to a string. For a (const or not) char
|
||||||
|
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||||
|
// // printed.
|
||||||
|
// std::string ::testing::PrintToString(const T& value);
|
||||||
|
//
|
||||||
|
// // Prints a value tersely: for a reference type, the referenced
|
||||||
|
// // value (but not the address) is printed; for a (const or not) char
|
||||||
|
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||||
|
// // printed.
|
||||||
|
// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
|
||||||
|
//
|
||||||
|
// // Prints value using the type inferred by the compiler. The difference
|
||||||
|
// // from UniversalTersePrint() is that this function prints both the
|
||||||
|
// // pointer and the NUL-terminated string for a (const or not) char pointer.
|
||||||
|
// void ::testing::internal::UniversalPrint(const T& value, ostream*);
|
||||||
|
//
|
||||||
|
// // Prints the fields of a tuple tersely to a string vector, one
|
||||||
|
// // element for each field. Tuple support must be enabled in
|
||||||
|
// // gtest-port.h.
|
||||||
|
// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
|
||||||
|
// const Tuple& value);
|
||||||
|
//
|
||||||
|
// Known limitation:
|
||||||
|
//
|
||||||
|
// The print primitives print the elements of an STL-style container
|
||||||
|
// using the compiler-inferred type of *iter where iter is a
|
||||||
|
// const_iterator of the container. When const_iterator is an input
|
||||||
|
// iterator but not a forward iterator, this inferred type may not
|
||||||
|
// match value_type, and the print output may be incorrect. In
|
||||||
|
// practice, this is rarely a problem as for most containers
|
||||||
|
// const_iterator is a forward iterator. We'll fix this if there's an
|
||||||
|
// actual need for it. Note that this fix cannot rely on value_type
|
||||||
|
// being defined as many user-defined container types don't have
|
||||||
|
// value_type.
|
||||||
|
|
||||||
|
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||||
|
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||||
|
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
// Definitions in the 'internal' and 'internal2' name spaces are
|
||||||
|
// subject to change without notice. DO NOT USE THEM IN USER CODE!
|
||||||
|
namespace internal2 {
|
||||||
|
|
||||||
|
// Prints the given number of bytes in the given object to the given
|
||||||
|
// ostream.
|
||||||
|
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
|
||||||
|
size_t count,
|
||||||
|
::std::ostream* os);
|
||||||
|
|
||||||
|
// For selecting which printer to use when a given type has neither <<
|
||||||
|
// nor PrintTo().
|
||||||
|
enum TypeKind {
|
||||||
|
kProtobuf, // a protobuf type
|
||||||
|
kConvertibleToInteger, // a type implicitly convertible to BiggestInt
|
||||||
|
// (e.g. a named or unnamed enum type)
|
||||||
|
kOtherType // anything else
|
||||||
|
};
|
||||||
|
|
||||||
|
// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
|
||||||
|
// by the universal printer to print a value of type T when neither
|
||||||
|
// operator<< nor PrintTo() is defined for T, where kTypeKind is the
|
||||||
|
// "kind" of T as defined by enum TypeKind.
|
||||||
|
template <typename T, TypeKind kTypeKind>
|
||||||
|
class TypeWithoutFormatter {
|
||||||
|
public:
|
||||||
|
// This default version is called when kTypeKind is kOtherType.
|
||||||
|
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||||
|
PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
|
||||||
|
sizeof(value), os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// We print a protobuf using its ShortDebugString() when the string
|
||||||
|
// doesn't exceed this many characters; otherwise we print it using
|
||||||
|
// DebugString() for better readability.
|
||||||
|
const size_t kProtobufOneLinerMaxLength = 50;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypeWithoutFormatter<T, kProtobuf> {
|
||||||
|
public:
|
||||||
|
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||||
|
const ::testing::internal::string short_str = value.ShortDebugString();
|
||||||
|
const ::testing::internal::string pretty_str =
|
||||||
|
short_str.length() <= kProtobufOneLinerMaxLength ?
|
||||||
|
short_str : ("\n" + value.DebugString());
|
||||||
|
*os << ("<" + pretty_str + ">");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypeWithoutFormatter<T, kConvertibleToInteger> {
|
||||||
|
public:
|
||||||
|
// Since T has no << operator or PrintTo() but can be implicitly
|
||||||
|
// converted to BiggestInt, we print it as a BiggestInt.
|
||||||
|
//
|
||||||
|
// Most likely T is an enum type (either named or unnamed), in which
|
||||||
|
// case printing it as an integer is the desired behavior. In case
|
||||||
|
// T is not an enum, printing it as an integer is the best we can do
|
||||||
|
// given that it has no user-defined printer.
|
||||||
|
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||||
|
const internal::BiggestInt kBigInt = value;
|
||||||
|
*os << kBigInt;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prints the given value to the given ostream. If the value is a
|
||||||
|
// protocol message, its debug string is printed; if it's an enum or
|
||||||
|
// of a type implicitly convertible to BiggestInt, it's printed as an
|
||||||
|
// integer; otherwise the bytes in the value are printed. This is
|
||||||
|
// what UniversalPrinter<T>::Print() does when it knows nothing about
|
||||||
|
// type T and T has neither << operator nor PrintTo().
|
||||||
|
//
|
||||||
|
// A user can override this behavior for a class type Foo by defining
|
||||||
|
// a << operator in the namespace where Foo is defined.
|
||||||
|
//
|
||||||
|
// We put this operator in namespace 'internal2' instead of 'internal'
|
||||||
|
// to simplify the implementation, as much code in 'internal' needs to
|
||||||
|
// use << in STL, which would conflict with our own << were it defined
|
||||||
|
// in 'internal'.
|
||||||
|
//
|
||||||
|
// Note that this operator<< takes a generic std::basic_ostream<Char,
|
||||||
|
// CharTraits> type instead of the more restricted std::ostream. If
|
||||||
|
// we define it to take an std::ostream instead, we'll get an
|
||||||
|
// "ambiguous overloads" compiler error when trying to print a type
|
||||||
|
// Foo that supports streaming to std::basic_ostream<Char,
|
||||||
|
// CharTraits>, as the compiler cannot tell whether
|
||||||
|
// operator<<(std::ostream&, const T&) or
|
||||||
|
// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
|
||||||
|
// specific.
|
||||||
|
template <typename Char, typename CharTraits, typename T>
|
||||||
|
::std::basic_ostream<Char, CharTraits>& operator<<(
|
||||||
|
::std::basic_ostream<Char, CharTraits>& os, const T& x) {
|
||||||
|
TypeWithoutFormatter<T,
|
||||||
|
(internal::IsAProtocolMessage<T>::value ? kProtobuf :
|
||||||
|
internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
|
||||||
|
kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal2
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
|
||||||
|
// magic needed for implementing UniversalPrinter won't work.
|
||||||
|
namespace testing_internal {
|
||||||
|
|
||||||
|
// Used to print a value that is not an STL-style container when the
|
||||||
|
// user doesn't define PrintTo() for it.
|
||||||
|
template <typename T>
|
||||||
|
void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
|
||||||
|
// With the following statement, during unqualified name lookup,
|
||||||
|
// testing::internal2::operator<< appears as if it was declared in
|
||||||
|
// the nearest enclosing namespace that contains both
|
||||||
|
// ::testing_internal and ::testing::internal2, i.e. the global
|
||||||
|
// namespace. For more details, refer to the C++ Standard section
|
||||||
|
// 7.3.4-1 [namespace.udir]. This allows us to fall back onto
|
||||||
|
// testing::internal2::operator<< in case T doesn't come with a <<
|
||||||
|
// operator.
|
||||||
|
//
|
||||||
|
// We cannot write 'using ::testing::internal2::operator<<;', which
|
||||||
|
// gcc 3.3 fails to compile due to a compiler bug.
|
||||||
|
using namespace ::testing::internal2; // NOLINT
|
||||||
|
|
||||||
|
// Assuming T is defined in namespace foo, in the next statement,
|
||||||
|
// the compiler will consider all of:
|
||||||
|
//
|
||||||
|
// 1. foo::operator<< (thanks to Koenig look-up),
|
||||||
|
// 2. ::operator<< (as the current namespace is enclosed in ::),
|
||||||
|
// 3. testing::internal2::operator<< (thanks to the using statement above).
|
||||||
|
//
|
||||||
|
// The operator<< whose type matches T best will be picked.
|
||||||
|
//
|
||||||
|
// We deliberately allow #2 to be a candidate, as sometimes it's
|
||||||
|
// impossible to define #1 (e.g. when foo is ::std, defining
|
||||||
|
// anything in it is undefined behavior unless you are a compiler
|
||||||
|
// vendor.).
|
||||||
|
*os << value;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing_internal
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
|
||||||
|
// value to the given ostream. The caller must ensure that
|
||||||
|
// 'ostream_ptr' is not NULL, or the behavior is undefined.
|
||||||
|
//
|
||||||
|
// We define UniversalPrinter as a class template (as opposed to a
|
||||||
|
// function template), as we need to partially specialize it for
|
||||||
|
// reference types, which cannot be done with function templates.
|
||||||
|
template <typename T>
|
||||||
|
class UniversalPrinter;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void UniversalPrint(const T& value, ::std::ostream* os);
|
||||||
|
|
||||||
|
// Used to print an STL-style container when the user doesn't define
|
||||||
|
// a PrintTo() for it.
|
||||||
|
template <typename C>
|
||||||
|
void DefaultPrintTo(IsContainer /* dummy */,
|
||||||
|
false_type /* is not a pointer */,
|
||||||
|
const C& container, ::std::ostream* os) {
|
||||||
|
const size_t kMaxCount = 32; // The maximum number of elements to print.
|
||||||
|
*os << '{';
|
||||||
|
size_t count = 0;
|
||||||
|
for (typename C::const_iterator it = container.begin();
|
||||||
|
it != container.end(); ++it, ++count) {
|
||||||
|
if (count > 0) {
|
||||||
|
*os << ',';
|
||||||
|
if (count == kMaxCount) { // Enough has been printed.
|
||||||
|
*os << " ...";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*os << ' ';
|
||||||
|
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
|
||||||
|
// handle *it being a native array.
|
||||||
|
internal::UniversalPrint(*it, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > 0) {
|
||||||
|
*os << ' ';
|
||||||
|
}
|
||||||
|
*os << '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to print a pointer that is neither a char pointer nor a member
|
||||||
|
// pointer, when the user doesn't define PrintTo() for it. (A member
|
||||||
|
// variable pointer or member function pointer doesn't really point to
|
||||||
|
// a location in the address space. Their representation is
|
||||||
|
// implementation-defined. Therefore they will be printed as raw
|
||||||
|
// bytes.)
|
||||||
|
template <typename T>
|
||||||
|
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||||
|
true_type /* is a pointer */,
|
||||||
|
T* p, ::std::ostream* os) {
|
||||||
|
if (p == NULL) {
|
||||||
|
*os << "NULL";
|
||||||
|
} else {
|
||||||
|
// C++ doesn't allow casting from a function pointer to any object
|
||||||
|
// pointer.
|
||||||
|
//
|
||||||
|
// IsTrue() silences warnings: "Condition is always true",
|
||||||
|
// "unreachable code".
|
||||||
|
if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
|
||||||
|
// T is not a function type. We just call << to print p,
|
||||||
|
// relying on ADL to pick up user-defined << for their pointer
|
||||||
|
// types, if any.
|
||||||
|
*os << p;
|
||||||
|
} else {
|
||||||
|
// T is a function type, so '*os << p' doesn't do what we want
|
||||||
|
// (it just prints p as bool). We want to print p as a const
|
||||||
|
// void*. However, we cannot cast it to const void* directly,
|
||||||
|
// even using reinterpret_cast, as earlier versions of gcc
|
||||||
|
// (e.g. 3.4.5) cannot compile the cast when p is a function
|
||||||
|
// pointer. Casting to UInt64 first solves the problem.
|
||||||
|
*os << reinterpret_cast<const void*>(
|
||||||
|
reinterpret_cast<internal::UInt64>(p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to print a non-container, non-pointer value when the user
|
||||||
|
// doesn't define PrintTo() for it.
|
||||||
|
template <typename T>
|
||||||
|
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||||
|
false_type /* is not a pointer */,
|
||||||
|
const T& value, ::std::ostream* os) {
|
||||||
|
::testing_internal::DefaultPrintNonContainerTo(value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the given value using the << operator if it has one;
|
||||||
|
// otherwise prints the bytes in it. This is what
|
||||||
|
// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
|
||||||
|
// or overloaded for type T.
|
||||||
|
//
|
||||||
|
// A user can override this behavior for a class type Foo by defining
|
||||||
|
// an overload of PrintTo() in the namespace where Foo is defined. We
|
||||||
|
// give the user this option as sometimes defining a << operator for
|
||||||
|
// Foo is not desirable (e.g. the coding style may prevent doing it,
|
||||||
|
// or there is already a << operator but it doesn't do what the user
|
||||||
|
// wants).
|
||||||
|
template <typename T>
|
||||||
|
void PrintTo(const T& value, ::std::ostream* os) {
|
||||||
|
// DefaultPrintTo() is overloaded. The type of its first two
|
||||||
|
// arguments determine which version will be picked. If T is an
|
||||||
|
// STL-style container, the version for container will be called; if
|
||||||
|
// T is a pointer, the pointer version will be called; otherwise the
|
||||||
|
// generic version will be called.
|
||||||
|
//
|
||||||
|
// Note that we check for container types here, prior to we check
|
||||||
|
// for protocol message types in our operator<<. The rationale is:
|
||||||
|
//
|
||||||
|
// For protocol messages, we want to give people a chance to
|
||||||
|
// override Google Mock's format by defining a PrintTo() or
|
||||||
|
// operator<<. For STL containers, other formats can be
|
||||||
|
// incompatible with Google Mock's format for the container
|
||||||
|
// elements; therefore we check for container types here to ensure
|
||||||
|
// that our format is used.
|
||||||
|
//
|
||||||
|
// The second argument of DefaultPrintTo() is needed to bypass a bug
|
||||||
|
// in Symbian's C++ compiler that prevents it from picking the right
|
||||||
|
// overload between:
|
||||||
|
//
|
||||||
|
// PrintTo(const T& x, ...);
|
||||||
|
// PrintTo(T* x, ...);
|
||||||
|
DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The following list of PrintTo() overloads tells
|
||||||
|
// UniversalPrinter<T>::Print() how to print standard types (built-in
|
||||||
|
// types, strings, plain arrays, and pointers).
|
||||||
|
|
||||||
|
// Overloads for various char types.
|
||||||
|
GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
|
||||||
|
GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
|
||||||
|
inline void PrintTo(char c, ::std::ostream* os) {
|
||||||
|
// When printing a plain char, we always treat it as unsigned. This
|
||||||
|
// way, the output won't be affected by whether the compiler thinks
|
||||||
|
// char is signed or not.
|
||||||
|
PrintTo(static_cast<unsigned char>(c), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloads for other simple built-in types.
|
||||||
|
inline void PrintTo(bool x, ::std::ostream* os) {
|
||||||
|
*os << (x ? "true" : "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overload for wchar_t type.
|
||||||
|
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||||
|
// code otherwise and also as its decimal code (except for L'\0').
|
||||||
|
// The L'\0' char is printed as "L'\\0'". The decimal code is printed
|
||||||
|
// as signed integer when wchar_t is implemented by the compiler
|
||||||
|
// as a signed type and is printed as an unsigned integer when wchar_t
|
||||||
|
// is implemented as an unsigned type.
|
||||||
|
GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
|
||||||
|
|
||||||
|
// Overloads for C strings.
|
||||||
|
GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(char* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const char*>(s), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// signed/unsigned char is often used for representing binary data, so
|
||||||
|
// we print pointers to it as void* to be safe.
|
||||||
|
inline void PrintTo(const signed char* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||||
|
}
|
||||||
|
inline void PrintTo(signed char* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||||
|
}
|
||||||
|
inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||||
|
}
|
||||||
|
inline void PrintTo(unsigned char* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSVC can be configured to define wchar_t as a typedef of unsigned
|
||||||
|
// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
|
||||||
|
// type. When wchar_t is a typedef, defining an overload for const
|
||||||
|
// wchar_t* would cause unsigned short* be printed as a wide string,
|
||||||
|
// possibly causing invalid memory accesses.
|
||||||
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
|
// Overloads for wide C strings
|
||||||
|
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(wchar_t* s, ::std::ostream* os) {
|
||||||
|
PrintTo(ImplicitCast_<const wchar_t*>(s), os);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Overload for C arrays. Multi-dimensional arrays are printed
|
||||||
|
// properly.
|
||||||
|
|
||||||
|
// Prints the given number of elements in an array, without printing
|
||||||
|
// the curly braces.
|
||||||
|
template <typename T>
|
||||||
|
void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
||||||
|
UniversalPrint(a[0], os);
|
||||||
|
for (size_t i = 1; i != count; i++) {
|
||||||
|
*os << ", ";
|
||||||
|
UniversalPrint(a[i], os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloads for ::string and ::std::string.
|
||||||
|
#if GTEST_HAS_GLOBAL_STRING
|
||||||
|
GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(const ::string& s, ::std::ostream* os) {
|
||||||
|
PrintStringTo(s, os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_GLOBAL_STRING
|
||||||
|
|
||||||
|
GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||||
|
PrintStringTo(s, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overloads for ::wstring and ::std::wstring.
|
||||||
|
#if GTEST_HAS_GLOBAL_WSTRING
|
||||||
|
GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
|
||||||
|
PrintWideStringTo(s, os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||||
|
|
||||||
|
#if GTEST_HAS_STD_WSTRING
|
||||||
|
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
|
||||||
|
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||||
|
PrintWideStringTo(s, os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_STD_WSTRING
|
||||||
|
|
||||||
|
#if GTEST_HAS_TR1_TUPLE
|
||||||
|
// Overload for ::std::tr1::tuple. Needed for printing function arguments,
|
||||||
|
// which are packed as tuples.
|
||||||
|
|
||||||
|
// Helper function for printing a tuple. T must be instantiated with
|
||||||
|
// a tuple type.
|
||||||
|
template <typename T>
|
||||||
|
void PrintTupleTo(const T& t, ::std::ostream* os);
|
||||||
|
|
||||||
|
// Overloaded PrintTo() for tuples of various arities. We support
|
||||||
|
// tuples of up-to 10 fields. The following implementation works
|
||||||
|
// regardless of whether tr1::tuple is implemented using the
|
||||||
|
// non-standard variadic template feature or not.
|
||||||
|
|
||||||
|
inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||||
|
typename T6>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||||
|
typename T6, typename T7>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||||
|
typename T6, typename T7, typename T8>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||||
|
typename T6, typename T7, typename T8, typename T9>
|
||||||
|
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||||
|
typename T6, typename T7, typename T8, typename T9, typename T10>
|
||||||
|
void PrintTo(
|
||||||
|
const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
|
||||||
|
::std::ostream* os) {
|
||||||
|
PrintTupleTo(t, os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_TR1_TUPLE
|
||||||
|
|
||||||
|
// Overload for std::pair.
|
||||||
|
template <typename T1, typename T2>
|
||||||
|
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
|
||||||
|
*os << '(';
|
||||||
|
// We cannot use UniversalPrint(value.first, os) here, as T1 may be
|
||||||
|
// a reference type. The same for printing value.second.
|
||||||
|
UniversalPrinter<T1>::Print(value.first, os);
|
||||||
|
*os << ", ";
|
||||||
|
UniversalPrinter<T2>::Print(value.second, os);
|
||||||
|
*os << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Implements printing a non-reference type T by letting the compiler
|
||||||
|
// pick the right overload of PrintTo() for T.
|
||||||
|
template <typename T>
|
||||||
|
class UniversalPrinter {
|
||||||
|
public:
|
||||||
|
// MSVC warns about adding const to a function type, so we want to
|
||||||
|
// disable the warning.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push) // Saves the current warning state.
|
||||||
|
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// Note: we deliberately don't call this PrintTo(), as that name
|
||||||
|
// conflicts with ::testing::internal::PrintTo in the body of the
|
||||||
|
// function.
|
||||||
|
static void Print(const T& value, ::std::ostream* os) {
|
||||||
|
// By default, ::testing::internal::PrintTo() is used for printing
|
||||||
|
// the value.
|
||||||
|
//
|
||||||
|
// Thanks to Koenig look-up, if T is a class and has its own
|
||||||
|
// PrintTo() function defined in its namespace, that function will
|
||||||
|
// be visible here. Since it is more specific than the generic ones
|
||||||
|
// in ::testing::internal, it will be picked by the compiler in the
|
||||||
|
// following statement - exactly what we want.
|
||||||
|
PrintTo(value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop) // Restores the warning state.
|
||||||
|
#endif // _MSC_VER
|
||||||
|
};
|
||||||
|
|
||||||
|
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||||
|
// elements, starting at address 'begin'.
|
||||||
|
template <typename T>
|
||||||
|
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||||
|
if (len == 0) {
|
||||||
|
*os << "{}";
|
||||||
|
} else {
|
||||||
|
*os << "{ ";
|
||||||
|
const size_t kThreshold = 18;
|
||||||
|
const size_t kChunkSize = 8;
|
||||||
|
// If the array has more than kThreshold elements, we'll have to
|
||||||
|
// omit some details by printing only the first and the last
|
||||||
|
// kChunkSize elements.
|
||||||
|
// TODO(wan@google.com): let the user control the threshold using a flag.
|
||||||
|
if (len <= kThreshold) {
|
||||||
|
PrintRawArrayTo(begin, len, os);
|
||||||
|
} else {
|
||||||
|
PrintRawArrayTo(begin, kChunkSize, os);
|
||||||
|
*os << ", ..., ";
|
||||||
|
PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
|
||||||
|
}
|
||||||
|
*os << " }";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This overload prints a (const) char array compactly.
|
||||||
|
GTEST_API_ void UniversalPrintArray(
|
||||||
|
const char* begin, size_t len, ::std::ostream* os);
|
||||||
|
|
||||||
|
// This overload prints a (const) wchar_t array compactly.
|
||||||
|
GTEST_API_ void UniversalPrintArray(
|
||||||
|
const wchar_t* begin, size_t len, ::std::ostream* os);
|
||||||
|
|
||||||
|
// Implements printing an array type T[N].
|
||||||
|
template <typename T, size_t N>
|
||||||
|
class UniversalPrinter<T[N]> {
|
||||||
|
public:
|
||||||
|
// Prints the given array, omitting some elements when there are too
|
||||||
|
// many.
|
||||||
|
static void Print(const T (&a)[N], ::std::ostream* os) {
|
||||||
|
UniversalPrintArray(a, N, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implements printing a reference type T&.
|
||||||
|
template <typename T>
|
||||||
|
class UniversalPrinter<T&> {
|
||||||
|
public:
|
||||||
|
// MSVC warns about adding const to a function type, so we want to
|
||||||
|
// disable the warning.
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(push) // Saves the current warning state.
|
||||||
|
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
static void Print(const T& value, ::std::ostream* os) {
|
||||||
|
// Prints the address of the value. We use reinterpret_cast here
|
||||||
|
// as static_cast doesn't compile when T is a function type.
|
||||||
|
*os << "@" << reinterpret_cast<const void*>(&value) << " ";
|
||||||
|
|
||||||
|
// Then prints the value itself.
|
||||||
|
UniversalPrint(value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# pragma warning(pop) // Restores the warning state.
|
||||||
|
#endif // _MSC_VER
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prints a value tersely: for a reference type, the referenced value
|
||||||
|
// (but not the address) is printed; for a (const) char pointer, the
|
||||||
|
// NUL-terminated string (but not the pointer) is printed.
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class UniversalTersePrinter {
|
||||||
|
public:
|
||||||
|
static void Print(const T& value, ::std::ostream* os) {
|
||||||
|
UniversalPrint(value, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <typename T>
|
||||||
|
class UniversalTersePrinter<T&> {
|
||||||
|
public:
|
||||||
|
static void Print(const T& value, ::std::ostream* os) {
|
||||||
|
UniversalPrint(value, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <typename T, size_t N>
|
||||||
|
class UniversalTersePrinter<T[N]> {
|
||||||
|
public:
|
||||||
|
static void Print(const T (&value)[N], ::std::ostream* os) {
|
||||||
|
UniversalPrinter<T[N]>::Print(value, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
class UniversalTersePrinter<const char*> {
|
||||||
|
public:
|
||||||
|
static void Print(const char* str, ::std::ostream* os) {
|
||||||
|
if (str == NULL) {
|
||||||
|
*os << "NULL";
|
||||||
|
} else {
|
||||||
|
UniversalPrint(string(str), os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
template <>
|
||||||
|
class UniversalTersePrinter<char*> {
|
||||||
|
public:
|
||||||
|
static void Print(char* str, ::std::ostream* os) {
|
||||||
|
UniversalTersePrinter<const char*>::Print(str, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if GTEST_HAS_STD_WSTRING
|
||||||
|
template <>
|
||||||
|
class UniversalTersePrinter<const wchar_t*> {
|
||||||
|
public:
|
||||||
|
static void Print(const wchar_t* str, ::std::ostream* os) {
|
||||||
|
if (str == NULL) {
|
||||||
|
*os << "NULL";
|
||||||
|
} else {
|
||||||
|
UniversalPrint(::std::wstring(str), os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class UniversalTersePrinter<wchar_t*> {
|
||||||
|
public:
|
||||||
|
static void Print(wchar_t* str, ::std::ostream* os) {
|
||||||
|
UniversalTersePrinter<const wchar_t*>::Print(str, os);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void UniversalTersePrint(const T& value, ::std::ostream* os) {
|
||||||
|
UniversalTersePrinter<T>::Print(value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a value using the type inferred by the compiler. The
|
||||||
|
// difference between this and UniversalTersePrint() is that for a
|
||||||
|
// (const) char pointer, this prints both the pointer and the
|
||||||
|
// NUL-terminated string.
|
||||||
|
template <typename T>
|
||||||
|
void UniversalPrint(const T& value, ::std::ostream* os) {
|
||||||
|
// A workarond for the bug in VC++ 7.1 that prevents us from instantiating
|
||||||
|
// UniversalPrinter with T directly.
|
||||||
|
typedef T T1;
|
||||||
|
UniversalPrinter<T1>::Print(value, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if GTEST_HAS_TR1_TUPLE
|
||||||
|
typedef ::std::vector<string> Strings;
|
||||||
|
|
||||||
|
// This helper template allows PrintTo() for tuples and
|
||||||
|
// UniversalTersePrintTupleFieldsToStrings() to be defined by
|
||||||
|
// induction on the number of tuple fields. The idea is that
|
||||||
|
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
|
||||||
|
// fields in tuple t, and can be defined in terms of
|
||||||
|
// TuplePrefixPrinter<N - 1>.
|
||||||
|
|
||||||
|
// The inductive case.
|
||||||
|
template <size_t N>
|
||||||
|
struct TuplePrefixPrinter {
|
||||||
|
// Prints the first N fields of a tuple.
|
||||||
|
template <typename Tuple>
|
||||||
|
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||||
|
TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
|
||||||
|
*os << ", ";
|
||||||
|
UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
|
||||||
|
::Print(::std::tr1::get<N - 1>(t), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tersely prints the first N fields of a tuple to a string vector,
|
||||||
|
// one element for each field.
|
||||||
|
template <typename Tuple>
|
||||||
|
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||||
|
TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
|
||||||
|
::std::stringstream ss;
|
||||||
|
UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
|
||||||
|
strings->push_back(ss.str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base cases.
|
||||||
|
template <>
|
||||||
|
struct TuplePrefixPrinter<0> {
|
||||||
|
template <typename Tuple>
|
||||||
|
static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
|
||||||
|
|
||||||
|
template <typename Tuple>
|
||||||
|
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
|
||||||
|
};
|
||||||
|
// We have to specialize the entire TuplePrefixPrinter<> class
|
||||||
|
// template here, even though the definition of
|
||||||
|
// TersePrintPrefixToStrings() is the same as the generic version, as
|
||||||
|
// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
|
||||||
|
// support specializing a method template of a class template.
|
||||||
|
template <>
|
||||||
|
struct TuplePrefixPrinter<1> {
|
||||||
|
template <typename Tuple>
|
||||||
|
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||||
|
UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
|
||||||
|
Print(::std::tr1::get<0>(t), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Tuple>
|
||||||
|
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||||
|
::std::stringstream ss;
|
||||||
|
UniversalTersePrint(::std::tr1::get<0>(t), &ss);
|
||||||
|
strings->push_back(ss.str());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper function for printing a tuple. T must be instantiated with
|
||||||
|
// a tuple type.
|
||||||
|
template <typename T>
|
||||||
|
void PrintTupleTo(const T& t, ::std::ostream* os) {
|
||||||
|
*os << "(";
|
||||||
|
TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
|
||||||
|
PrintPrefixTo(t, os);
|
||||||
|
*os << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the fields of a tuple tersely to a string vector, one
|
||||||
|
// element for each field. See the comment before
|
||||||
|
// UniversalTersePrint() for how we define "tersely".
|
||||||
|
template <typename Tuple>
|
||||||
|
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
|
||||||
|
Strings result;
|
||||||
|
TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
|
||||||
|
TersePrintPrefixToStrings(value, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_TR1_TUPLE
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
::std::string PrintToString(const T& value) {
|
||||||
|
::std::stringstream ss;
|
||||||
|
internal::UniversalTersePrinter<T>::Print(value, &ss);
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
232
extern/gtest/include/gtest/gtest-spi.h
vendored
Normal file
232
extern/gtest/include/gtest/gtest-spi.h
vendored
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
// 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_
|
||||||
|
|
||||||
|
#include "gtest/gtest.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 string& substr);
|
||||||
|
~SingleFailureChecker();
|
||||||
|
private:
|
||||||
|
const TestPartResultArray* const results_;
|
||||||
|
const TestPartResult::Type type_;
|
||||||
|
const string substr_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
// A set of macros for testing Google Test assertions or code that's expected
|
||||||
|
// to generate Google Test fatal failures. It verifies that the given
|
||||||
|
// statement will cause exactly one fatal Google Test failure with 'substr'
|
||||||
|
// being part of the failure message.
|
||||||
|
//
|
||||||
|
// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
|
||||||
|
// affects and considers failures generated in the current thread and
|
||||||
|
// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||||
|
//
|
||||||
|
// The verification of the assertion is done correctly even when the statement
|
||||||
|
// throws an exception or aborts the current function.
|
||||||
|
//
|
||||||
|
// Known restrictions:
|
||||||
|
// - 'statement' cannot reference local non-static variables or
|
||||||
|
// non-static members of the current object.
|
||||||
|
// - 'statement' cannot return a value.
|
||||||
|
// - You cannot stream a failure message to this macro.
|
||||||
|
//
|
||||||
|
// Note that even though the implementations of the following two
|
||||||
|
// macros are much alike, we cannot refactor them to use a common
|
||||||
|
// helper macro, due to some peculiarity in how the preprocessor
|
||||||
|
// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
|
||||||
|
// gtest_unittest.cc will fail to compile if we do that.
|
||||||
|
#define EXPECT_FATAL_FAILURE(statement, substr) \
|
||||||
|
do { \
|
||||||
|
class GTestExpectFatalFailureHelper {\
|
||||||
|
public:\
|
||||||
|
static void Execute() { statement; }\
|
||||||
|
};\
|
||||||
|
::testing::TestPartResultArray gtest_failures;\
|
||||||
|
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||||
|
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||||
|
{\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter:: \
|
||||||
|
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||||
|
GTestExpectFatalFailureHelper::Execute();\
|
||||||
|
}\
|
||||||
|
} while (::testing::internal::AlwaysFalse())
|
||||||
|
|
||||||
|
#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||||
|
do { \
|
||||||
|
class GTestExpectFatalFailureHelper {\
|
||||||
|
public:\
|
||||||
|
static void Execute() { statement; }\
|
||||||
|
};\
|
||||||
|
::testing::TestPartResultArray gtest_failures;\
|
||||||
|
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||||
|
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||||
|
{\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter:: \
|
||||||
|
INTERCEPT_ALL_THREADS, >est_failures);\
|
||||||
|
GTestExpectFatalFailureHelper::Execute();\
|
||||||
|
}\
|
||||||
|
} while (::testing::internal::AlwaysFalse())
|
||||||
|
|
||||||
|
// A macro for testing Google Test assertions or code that's expected to
|
||||||
|
// generate Google Test non-fatal failures. It asserts that the given
|
||||||
|
// statement will cause exactly one non-fatal Google Test failure with 'substr'
|
||||||
|
// being part of the failure message.
|
||||||
|
//
|
||||||
|
// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
|
||||||
|
// affects and considers failures generated in the current thread and
|
||||||
|
// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||||
|
//
|
||||||
|
// 'statement' is allowed to reference local variables and members of
|
||||||
|
// the current object.
|
||||||
|
//
|
||||||
|
// The verification of the assertion is done correctly even when the statement
|
||||||
|
// throws an exception or aborts the current function.
|
||||||
|
//
|
||||||
|
// Known restrictions:
|
||||||
|
// - You cannot stream a failure message to this macro.
|
||||||
|
//
|
||||||
|
// Note that even though the implementations of the following two
|
||||||
|
// macros are much alike, we cannot refactor them to use a common
|
||||||
|
// helper macro, due to some peculiarity in how the preprocessor
|
||||||
|
// works. If we do that, the code won't compile when the user gives
|
||||||
|
// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
|
||||||
|
// expands to code containing an unprotected comma. The
|
||||||
|
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
|
||||||
|
// catches that.
|
||||||
|
//
|
||||||
|
// For the same reason, we have to write
|
||||||
|
// if (::testing::internal::AlwaysTrue()) { statement; }
|
||||||
|
// instead of
|
||||||
|
// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||||
|
// to avoid an MSVC warning on unreachable code.
|
||||||
|
#define EXPECT_NONFATAL_FAILURE(statement, substr) \
|
||||||
|
do {\
|
||||||
|
::testing::TestPartResultArray gtest_failures;\
|
||||||
|
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||||
|
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||||
|
(substr));\
|
||||||
|
{\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter:: \
|
||||||
|
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||||
|
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||||
|
}\
|
||||||
|
} while (::testing::internal::AlwaysFalse())
|
||||||
|
|
||||||
|
#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||||
|
do {\
|
||||||
|
::testing::TestPartResultArray gtest_failures;\
|
||||||
|
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||||
|
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||||
|
(substr));\
|
||||||
|
{\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||||
|
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
|
||||||
|
>est_failures);\
|
||||||
|
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||||
|
}\
|
||||||
|
} while (::testing::internal::AlwaysFalse())
|
||||||
|
|
||||||
|
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
179
extern/gtest/include/gtest/gtest-test-part.h
vendored
Normal file
179
extern/gtest/include/gtest/gtest-test-part.h
vendored
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
// 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>
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
#include "gtest/internal/gtest-string.h"
|
||||||
|
|
||||||
|
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 == NULL ? "" : 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_.empty() ? NULL : 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 std::string ExtractSummary(const char* message);
|
||||||
|
|
||||||
|
// The name of the source file where the test part took place, or
|
||||||
|
// "" if the source file is unknown.
|
||||||
|
std::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_;
|
||||||
|
std::string summary_; // The test failure summary.
|
||||||
|
std::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_
|
259
extern/gtest/include/gtest/gtest-typed-test.h
vendored
Normal file
259
extern/gtest/include/gtest/gtest-typed-test.h
vendored
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "gtest/internal/gtest-type-util.h"
|
||||||
|
|
||||||
|
// 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_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||||
|
::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_ATTRIBUTE_UNUSED_ = \
|
||||||
|
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 GTEST_ATTRIBUTE_UNUSED_ = \
|
||||||
|
::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_
|
2291
extern/gtest/include/gtest/gtest.h
vendored
Normal file
2291
extern/gtest/include/gtest/gtest.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
358
extern/gtest/include/gtest/gtest_pred_impl.h
vendored
Normal file
358
extern/gtest/include/gtest/gtest_pred_impl.h
vendored
Normal file
@ -0,0 +1,358 @@
|
|||||||
|
// 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/31/2011 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();
|
||||||
|
|
||||||
|
return AssertionFailure() << pred_text << "("
|
||||||
|
<< e1 << ") evaluates to false, where"
|
||||||
|
<< "\n" << e1 << " evaluates to " << v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
return AssertionFailure() << pred_text << "("
|
||||||
|
<< e1 << ", "
|
||||||
|
<< e2 << ") evaluates to false, where"
|
||||||
|
<< "\n" << e1 << " evaluates to " << v1
|
||||||
|
<< "\n" << e2 << " evaluates to " << v2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
return AssertionFailure() << pred_text << "("
|
||||||
|
<< e1 << ", "
|
||||||
|
<< e2 << ", "
|
||||||
|
<< e3 << ") evaluates to false, where"
|
||||||
|
<< "\n" << e1 << " evaluates to " << v1
|
||||||
|
<< "\n" << e2 << " evaluates to " << v2
|
||||||
|
<< "\n" << e3 << " evaluates to " << v3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
return AssertionFailure() << 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
return AssertionFailure() << 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_
|
58
extern/gtest/include/gtest/gtest_prod.h
vendored
Normal file
58
extern/gtest/include/gtest/gtest_prod.h
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// 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_
|
319
extern/gtest/include/gtest/internal/gtest-death-test-internal.h
vendored
Normal file
319
extern/gtest/include/gtest/internal/gtest-death-test-internal.h
vendored
Normal file
@ -0,0 +1,319 @@
|
|||||||
|
// 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_
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
|
||||||
|
#include <stdio.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 three reasons that a test might be aborted.
|
||||||
|
enum AbortReason {
|
||||||
|
TEST_ENCOUNTERED_RETURN_STATEMENT,
|
||||||
|
TEST_THREW_EXCEPTION,
|
||||||
|
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 std::string& message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// A string containing a description of the outcome of the last death test.
|
||||||
|
static std::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);
|
||||||
|
|
||||||
|
// Traps C++ exceptions escaping statement and reports them as test
|
||||||
|
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||||
|
# if GTEST_HAS_EXCEPTIONS
|
||||||
|
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||||
|
try { \
|
||||||
|
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||||
|
} catch (const ::std::exception& gtest_exception) { \
|
||||||
|
fprintf(\
|
||||||
|
stderr, \
|
||||||
|
"\n%s: Caught std::exception-derived exception escaping the " \
|
||||||
|
"death test statement. Exception message: %s\n", \
|
||||||
|
::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
|
||||||
|
gtest_exception.what()); \
|
||||||
|
fflush(stderr); \
|
||||||
|
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||||
|
} catch (...) { \
|
||||||
|
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||||
|
}
|
||||||
|
|
||||||
|
# else
|
||||||
|
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||||
|
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||||
|
|
||||||
|
# endif
|
||||||
|
|
||||||
|
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||||
|
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||||
|
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||||
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
|
if (::testing::internal::AlwaysTrue()) { \
|
||||||
|
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||||
|
::testing::internal::DeathTest* gtest_dt; \
|
||||||
|
if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
|
||||||
|
__FILE__, __LINE__, >est_dt)) { \
|
||||||
|
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||||
|
} \
|
||||||
|
if (gtest_dt != NULL) { \
|
||||||
|
::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
|
||||||
|
gtest_dt_ptr(gtest_dt); \
|
||||||
|
switch (gtest_dt->AssumeRole()) { \
|
||||||
|
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||||
|
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||||
|
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||||
|
} \
|
||||||
|
break; \
|
||||||
|
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||||
|
::testing::internal::DeathTest::ReturnSentinel \
|
||||||
|
gtest_sentinel(gtest_dt); \
|
||||||
|
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||||
|
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||||
|
break; \
|
||||||
|
} \
|
||||||
|
default: \
|
||||||
|
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.
|
||||||
|
|
||||||
|
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
|
||||||
|
// NDEBUG mode. In this case we need the statements to be executed, the regex is
|
||||||
|
// ignored, and the macro must accept a streamed message even though the message
|
||||||
|
// is never printed.
|
||||||
|
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
||||||
|
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||||
|
if (::testing::internal::AlwaysTrue()) { \
|
||||||
|
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||||
|
} else \
|
||||||
|
::testing::Message()
|
||||||
|
|
||||||
|
// 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 std::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_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& file() const { return file_; }
|
||||||
|
int line() const { return line_; }
|
||||||
|
int index() const { return index_; }
|
||||||
|
int write_fd() const { return write_fd_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::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_
|
206
extern/gtest/include/gtest/internal/gtest-filepath.h
vendored
Normal file
206
extern/gtest/include/gtest/internal/gtest-filepath.h
vendored
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
// 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_
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-string.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 std::string& pathname) : pathname_(pathname) {
|
||||||
|
Normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath& operator=(const FilePath& rhs) {
|
||||||
|
Set(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const FilePath& rhs) {
|
||||||
|
pathname_ = rhs.pathname_;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& string() 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 "".
|
||||||
|
bool IsEmpty() const { return pathname_.empty(); }
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
std::string pathname_;
|
||||||
|
}; // class FilePath
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
1158
extern/gtest/include/gtest/internal/gtest-internal.h
vendored
Normal file
1158
extern/gtest/include/gtest/internal/gtest-internal.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
233
extern/gtest/include/gtest/internal/gtest-linked_ptr.h
vendored
Normal file
233
extern/gtest/include/gtest/internal/gtest-linked_ptr.h
vendored
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// 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>
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-port.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.
|
||||||
|
void join(linked_ptr_internal const* ptr)
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||||
|
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.
|
||||||
|
bool depart()
|
||||||
|
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||||
|
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_; }
|
||||||
|
|
||||||
|
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_
|
5143
extern/gtest/include/gtest/internal/gtest-param-util-generated.h
vendored
Normal file
5143
extern/gtest/include/gtest/internal/gtest-param-util-generated.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
619
extern/gtest/include/gtest/internal/gtest-param-util.h
vendored
Normal file
619
extern/gtest/include/gtest/internal/gtest-param-util.h
vendored
Normal file
@ -0,0 +1,619 @@
|
|||||||
|
// 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.
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
#include "gtest/internal/gtest-linked_ptr.h"
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
#include "gtest/gtest-printers.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:
|
||||||
|
linked_ptr<const ParamGeneratorInterface<T> > impl_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generates values from a range of two comparable values. Can be used to
|
||||||
|
// generate sequences of user-defined types that implement operator+() and
|
||||||
|
// operator<().
|
||||||
|
// This class is used in the Range() function.
|
||||||
|
template <typename T, typename IncrementT>
|
||||||
|
class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
|
public:
|
||||||
|
RangeGenerator(T begin, T end, IncrementT step)
|
||||||
|
: begin_(begin), end_(end),
|
||||||
|
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
||||||
|
virtual ~RangeGenerator() {}
|
||||||
|
|
||||||
|
virtual ParamIteratorInterface<T>* Begin() const {
|
||||||
|
return new Iterator(this, begin_, 0, step_);
|
||||||
|
}
|
||||||
|
virtual ParamIteratorInterface<T>* End() const {
|
||||||
|
return new Iterator(this, end_, end_index_, step_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Iterator : public ParamIteratorInterface<T> {
|
||||||
|
public:
|
||||||
|
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
||||||
|
IncrementT step)
|
||||||
|
: base_(base), value_(value), index_(index), step_(step) {}
|
||||||
|
virtual ~Iterator() {}
|
||||||
|
|
||||||
|
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||||
|
return base_;
|
||||||
|
}
|
||||||
|
virtual void Advance() {
|
||||||
|
value_ = value_ + step_;
|
||||||
|
index_++;
|
||||||
|
}
|
||||||
|
virtual ParamIteratorInterface<T>* Clone() const {
|
||||||
|
return new Iterator(*this);
|
||||||
|
}
|
||||||
|
virtual const T* Current() const { return &value_; }
|
||||||
|
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||||
|
// Having the same base generator guarantees that the other
|
||||||
|
// iterator is of the same type and we can downcast.
|
||||||
|
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||||
|
<< "The program attempted to compare iterators "
|
||||||
|
<< "from different generators." << std::endl;
|
||||||
|
const int other_index =
|
||||||
|
CheckedDowncastToActualType<const Iterator>(&other)->index_;
|
||||||
|
return index_ == other_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator(const Iterator& other)
|
||||||
|
: ParamIteratorInterface<T>(),
|
||||||
|
base_(other.base_), value_(other.value_), index_(other.index_),
|
||||||
|
step_(other.step_) {}
|
||||||
|
|
||||||
|
// No implementation - assignment is unsupported.
|
||||||
|
void operator=(const Iterator& other);
|
||||||
|
|
||||||
|
const ParamGeneratorInterface<T>* const base_;
|
||||||
|
T value_;
|
||||||
|
int index_;
|
||||||
|
const IncrementT step_;
|
||||||
|
}; // class RangeGenerator::Iterator
|
||||||
|
|
||||||
|
static int CalculateEndIndex(const T& begin,
|
||||||
|
const T& end,
|
||||||
|
const IncrementT& step) {
|
||||||
|
int end_index = 0;
|
||||||
|
for (T i = begin; i < end; i = i + step)
|
||||||
|
end_index++;
|
||||||
|
return end_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No implementation - assignment is unsupported.
|
||||||
|
void operator=(const RangeGenerator& other);
|
||||||
|
|
||||||
|
const T begin_;
|
||||||
|
const T end_;
|
||||||
|
const IncrementT step_;
|
||||||
|
// The index for the end() iterator. All the elements in the generated
|
||||||
|
// sequence are indexed (0-based) to aid iterator comparison.
|
||||||
|
const int end_index_;
|
||||||
|
}; // class RangeGenerator
|
||||||
|
|
||||||
|
|
||||||
|
// Generates values from a pair of STL-style iterators. Used in the
|
||||||
|
// ValuesIn() function. The elements are copied from the source range
|
||||||
|
// since the source can be located on the stack, and the generator
|
||||||
|
// is likely to persist beyond that stack frame.
|
||||||
|
template <typename T>
|
||||||
|
class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||||
|
public:
|
||||||
|
template <typename ForwardIterator>
|
||||||
|
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
||||||
|
: container_(begin, end) {}
|
||||||
|
virtual ~ValuesInIteratorRangeGenerator() {}
|
||||||
|
|
||||||
|
virtual ParamIteratorInterface<T>* Begin() const {
|
||||||
|
return new Iterator(this, container_.begin());
|
||||||
|
}
|
||||||
|
virtual ParamIteratorInterface<T>* End() const {
|
||||||
|
return new Iterator(this, container_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef typename ::std::vector<T> ContainerType;
|
||||||
|
|
||||||
|
class Iterator : public ParamIteratorInterface<T> {
|
||||||
|
public:
|
||||||
|
Iterator(const ParamGeneratorInterface<T>* base,
|
||||||
|
typename ContainerType::const_iterator iterator)
|
||||||
|
: base_(base), iterator_(iterator) {}
|
||||||
|
virtual ~Iterator() {}
|
||||||
|
|
||||||
|
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||||
|
return base_;
|
||||||
|
}
|
||||||
|
virtual void Advance() {
|
||||||
|
++iterator_;
|
||||||
|
value_.reset();
|
||||||
|
}
|
||||||
|
virtual ParamIteratorInterface<T>* Clone() const {
|
||||||
|
return new Iterator(*this);
|
||||||
|
}
|
||||||
|
// We need to use cached value referenced by iterator_ because *iterator_
|
||||||
|
// can return a temporary object (and of type other then T), so just
|
||||||
|
// having "return &*iterator_;" doesn't work.
|
||||||
|
// value_ is updated here and not in Advance() because Advance()
|
||||||
|
// can advance iterator_ beyond the end of the range, and we cannot
|
||||||
|
// detect that fact. The client code, on the other hand, is
|
||||||
|
// responsible for not calling Current() on an out-of-range iterator.
|
||||||
|
virtual const T* Current() const {
|
||||||
|
if (value_.get() == NULL)
|
||||||
|
value_.reset(new T(*iterator_));
|
||||||
|
return value_.get();
|
||||||
|
}
|
||||||
|
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||||
|
// Having the same base generator guarantees that the other
|
||||||
|
// iterator is of the same type and we can downcast.
|
||||||
|
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||||
|
<< "The program attempted to compare iterators "
|
||||||
|
<< "from different generators." << std::endl;
|
||||||
|
return iterator_ ==
|
||||||
|
CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator(const Iterator& other)
|
||||||
|
// The explicit constructor call suppresses a false warning
|
||||||
|
// emitted by gcc when supplied with the -Wextra option.
|
||||||
|
: ParamIteratorInterface<T>(),
|
||||||
|
base_(other.base_),
|
||||||
|
iterator_(other.iterator_) {}
|
||||||
|
|
||||||
|
const ParamGeneratorInterface<T>* const base_;
|
||||||
|
typename ContainerType::const_iterator iterator_;
|
||||||
|
// A cached value of *iterator_. We keep it here to allow access by
|
||||||
|
// pointer in the wrapping iterator's operator->().
|
||||||
|
// value_ needs to be mutable to be accessed in Current().
|
||||||
|
// Use of scoped_ptr helps manage cached value's lifetime,
|
||||||
|
// which is bound by the lifespan of the iterator itself.
|
||||||
|
mutable scoped_ptr<const T> value_;
|
||||||
|
}; // class ValuesInIteratorRangeGenerator::Iterator
|
||||||
|
|
||||||
|
// No implementation - assignment is unsupported.
|
||||||
|
void operator=(const ValuesInIteratorRangeGenerator& other);
|
||||||
|
|
||||||
|
const ContainerType container_;
|
||||||
|
}; // class ValuesInIteratorRangeGenerator
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// Stores a parameter value and later creates tests parameterized with that
|
||||||
|
// value.
|
||||||
|
template <class TestClass>
|
||||||
|
class ParameterizedTestFactory : public TestFactoryBase {
|
||||||
|
public:
|
||||||
|
typedef typename TestClass::ParamType ParamType;
|
||||||
|
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||||
|
parameter_(parameter) {}
|
||||||
|
virtual Test* CreateTest() {
|
||||||
|
TestClass::SetParam(¶meter_);
|
||||||
|
return new TestClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const ParamType parameter_;
|
||||||
|
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
|
||||||
|
};
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// TestMetaFactoryBase is a base class for meta-factories that create
|
||||||
|
// test factories for passing into MakeAndRegisterTestInfo function.
|
||||||
|
template <class ParamType>
|
||||||
|
class TestMetaFactoryBase {
|
||||||
|
public:
|
||||||
|
virtual ~TestMetaFactoryBase() {}
|
||||||
|
|
||||||
|
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// TestMetaFactory creates test factories for passing into
|
||||||
|
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
||||||
|
// ownership of test factory pointer, same factory object cannot be passed
|
||||||
|
// into that method twice. But ParameterizedTestCaseInfo is going to call
|
||||||
|
// it for each Test/Parameter value combination. Thus it needs meta factory
|
||||||
|
// creator class.
|
||||||
|
template <class TestCase>
|
||||||
|
class TestMetaFactory
|
||||||
|
: public TestMetaFactoryBase<typename TestCase::ParamType> {
|
||||||
|
public:
|
||||||
|
typedef typename TestCase::ParamType ParamType;
|
||||||
|
|
||||||
|
TestMetaFactory() {}
|
||||||
|
|
||||||
|
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
|
||||||
|
return new ParameterizedTestFactory<TestCase>(parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
|
||||||
|
};
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// ParameterizedTestCaseInfoBase is a generic interface
|
||||||
|
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
|
||||||
|
// accumulates test information provided by TEST_P macro invocations
|
||||||
|
// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
|
||||||
|
// and uses that information to register all resulting test instances
|
||||||
|
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
|
||||||
|
// a collection of pointers to the ParameterizedTestCaseInfo objects
|
||||||
|
// and calls RegisterTests() on each of them when asked.
|
||||||
|
class ParameterizedTestCaseInfoBase {
|
||||||
|
public:
|
||||||
|
virtual ~ParameterizedTestCaseInfoBase() {}
|
||||||
|
|
||||||
|
// Base part of test case name for display purposes.
|
||||||
|
virtual const string& GetTestCaseName() const = 0;
|
||||||
|
// Test case id to verify identity.
|
||||||
|
virtual TypeId GetTestCaseTypeId() const = 0;
|
||||||
|
// UnitTest class invokes this method to register tests in this
|
||||||
|
// test case right before running them in RUN_ALL_TESTS macro.
|
||||||
|
// This method should not be called more then once on any single
|
||||||
|
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||||
|
virtual void RegisterTests() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ParameterizedTestCaseInfoBase() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
|
||||||
|
};
|
||||||
|
|
||||||
|
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||||
|
//
|
||||||
|
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
|
||||||
|
// macro invocations for a particular test case and generators
|
||||||
|
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
|
||||||
|
// test case. It registers tests with all values generated by all
|
||||||
|
// generators when asked.
|
||||||
|
template <class TestCase>
|
||||||
|
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||||
|
public:
|
||||||
|
// ParamType and GeneratorCreationFunc are private types but are required
|
||||||
|
// for declarations of public methods AddTestPattern() and
|
||||||
|
// AddTestCaseInstantiation().
|
||||||
|
typedef typename TestCase::ParamType ParamType;
|
||||||
|
// A function that returns an instance of appropriate generator type.
|
||||||
|
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
||||||
|
|
||||||
|
explicit ParameterizedTestCaseInfo(const char* name)
|
||||||
|
: test_case_name_(name) {}
|
||||||
|
|
||||||
|
// Test case base name for display purposes.
|
||||||
|
virtual const string& GetTestCaseName() const { return test_case_name_; }
|
||||||
|
// Test case id to verify identity.
|
||||||
|
virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
|
||||||
|
// TEST_P macro uses AddTestPattern() to record information
|
||||||
|
// about a single test in a LocalTestInfo structure.
|
||||||
|
// test_case_name is the base name of the test case (without invocation
|
||||||
|
// prefix). test_base_name is the name of an individual test without
|
||||||
|
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||||
|
// test case base name and DoBar is test base name.
|
||||||
|
void AddTestPattern(const char* test_case_name,
|
||||||
|
const char* test_base_name,
|
||||||
|
TestMetaFactoryBase<ParamType>* meta_factory) {
|
||||||
|
tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
|
||||||
|
test_base_name,
|
||||||
|
meta_factory)));
|
||||||
|
}
|
||||||
|
// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
|
||||||
|
// about a generator.
|
||||||
|
int AddTestCaseInstantiation(const string& 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)());
|
||||||
|
|
||||||
|
string test_case_name;
|
||||||
|
if ( !instantiation_name.empty() )
|
||||||
|
test_case_name = instantiation_name + "/";
|
||||||
|
test_case_name += test_info->test_case_base_name;
|
||||||
|
|
||||||
|
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 << "/" << i;
|
||||||
|
MakeAndRegisterTestInfo(
|
||||||
|
test_case_name.c_str(),
|
||||||
|
test_name_stream.GetString().c_str(),
|
||||||
|
NULL, // No type parameter.
|
||||||
|
PrintToString(*param_it).c_str(),
|
||||||
|
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);
|
||||||
|
posix::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_
|
1947
extern/gtest/include/gtest/internal/gtest-port.h
vendored
Normal file
1947
extern/gtest/include/gtest/internal/gtest-port.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
167
extern/gtest/include/gtest/internal/gtest-string.h
vendored
Normal file
167
extern/gtest/include/gtest/internal/gtest-string.h
vendored
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
// 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>
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// String - an abstract class holding static string utilities.
|
||||||
|
class GTEST_API_ String {
|
||||||
|
public:
|
||||||
|
// Static utility methods
|
||||||
|
|
||||||
|
// 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 std::string ShowWideCString(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);
|
||||||
|
|
||||||
|
// Returns true iff the given string ends with the given suffix, ignoring
|
||||||
|
// case. Any string is considered to end with an empty suffix.
|
||||||
|
static bool EndsWithCaseInsensitive(
|
||||||
|
const std::string& str, const std::string& suffix);
|
||||||
|
|
||||||
|
// Formats an int value as "%02d".
|
||||||
|
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
||||||
|
|
||||||
|
// Formats an int value as "%X".
|
||||||
|
static std::string FormatHexInt(int value);
|
||||||
|
|
||||||
|
// Formats a byte as "%02X".
|
||||||
|
static std::string FormatByte(unsigned char value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
String(); // Not meant to be instantiated.
|
||||||
|
}; // class String
|
||||||
|
|
||||||
|
// Gets the content of the stringstream's buffer as an std::string. Each '\0'
|
||||||
|
// character in the buffer is replaced with "\\0".
|
||||||
|
GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
} // namespace testing
|
||||||
|
|
||||||
|
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
1012
extern/gtest/include/gtest/internal/gtest-tuple.h
vendored
Normal file
1012
extern/gtest/include/gtest/internal/gtest-tuple.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3331
extern/gtest/include/gtest/internal/gtest-type-util.h
vendored
Normal file
3331
extern/gtest/include/gtest/internal/gtest-type-util.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
48
extern/gtest/src/gtest-all.cc
vendored
Normal file
48
extern/gtest/src/gtest-all.cc
vendored
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// 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 "gtest/gtest.h"
|
||||||
|
|
||||||
|
// The following lines pull in the real gtest *.cc files.
|
||||||
|
#include "src/gtest.cc"
|
||||||
|
#include "src/gtest-death-test.cc"
|
||||||
|
#include "src/gtest-filepath.cc"
|
||||||
|
#include "src/gtest-port.cc"
|
||||||
|
#include "src/gtest-printers.cc"
|
||||||
|
#include "src/gtest-test-part.cc"
|
||||||
|
#include "src/gtest-typed-test.cc"
|
1344
extern/gtest/src/gtest-death-test.cc
vendored
Normal file
1344
extern/gtest/src/gtest-death-test.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
382
extern/gtest/src/gtest-filepath.cc
vendored
Normal file
382
extern/gtest/src/gtest-filepath.cc
vendored
Normal file
@ -0,0 +1,382 @@
|
|||||||
|
// 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 "gtest/gtest-message.h"
|
||||||
|
#include "gtest/internal/gtest-filepath.h"
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
#include "gtest/internal/gtest-string.h"
|
||||||
|
|
||||||
|
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 {
|
||||||
|
const std::string dot_extension = std::string(".") + extension;
|
||||||
|
if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) {
|
||||||
|
return FilePath(pathname_.substr(
|
||||||
|
0, pathname_.length() - dot_extension.length()));
|
||||||
|
}
|
||||||
|
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(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();
|
||||||
|
std::string dir;
|
||||||
|
if (last_sep) {
|
||||||
|
dir = std::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) {
|
||||||
|
std::string file;
|
||||||
|
if (number == 0) {
|
||||||
|
file = base_name.string() + "." + extension;
|
||||||
|
} else {
|
||||||
|
file = base_name.string() + "_" + StreamableToString(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(dir.string() + kPathSeparator + relative_path.string());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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(pathname_.substr(0, 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
|
1218
extern/gtest/src/gtest-internal-inl.h
vendored
Normal file
1218
extern/gtest/src/gtest-internal-inl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
805
extern/gtest/src/gtest-port.cc
vendored
Normal file
805
extern/gtest/src/gtest-port.cc
vendored
Normal file
@ -0,0 +1,805 @@
|
|||||||
|
// 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 "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.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
|
||||||
|
|
||||||
|
#if GTEST_OS_QNX
|
||||||
|
# include <devctl.h>
|
||||||
|
# include <sys/procfs.h>
|
||||||
|
#endif // GTEST_OS_QNX
|
||||||
|
|
||||||
|
#include "gtest/gtest-spi.h"
|
||||||
|
#include "gtest/gtest-message.h"
|
||||||
|
#include "gtest/internal/gtest-internal.h"
|
||||||
|
#include "gtest/internal/gtest-string.h"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
#include "src/gtest-internal-inl.h"
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif GTEST_OS_QNX
|
||||||
|
|
||||||
|
// Returns the number of threads running in the process, or 0 to indicate that
|
||||||
|
// we cannot detect it.
|
||||||
|
size_t GetThreadCount() {
|
||||||
|
const int fd = open("/proc/self/as", O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
procfs_info process_info;
|
||||||
|
const int status =
|
||||||
|
devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL);
|
||||||
|
close(fd);
|
||||||
|
if (status == EOK) {
|
||||||
|
return static_cast<size_t>(process_info.num_threads);
|
||||||
|
} 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 IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; }
|
||||||
|
bool IsAsciiPunct(char ch) {
|
||||||
|
return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~");
|
||||||
|
}
|
||||||
|
bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); }
|
||||||
|
bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); }
|
||||||
|
bool IsAsciiWordChar(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 (IsAsciiPunct(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 IsAsciiDigit(ch);
|
||||||
|
case 'D': return !IsAsciiDigit(ch);
|
||||||
|
case 'f': return ch == '\f';
|
||||||
|
case 'n': return ch == '\n';
|
||||||
|
case 'r': return ch == '\r';
|
||||||
|
case 's': return IsAsciiWhiteSpace(ch);
|
||||||
|
case 'S': return !IsAsciiWhiteSpace(ch);
|
||||||
|
case 't': return ch == '\t';
|
||||||
|
case 'v': return ch == '\v';
|
||||||
|
case 'w': return IsAsciiWordChar(ch);
|
||||||
|
case 'W': return !IsAsciiWordChar(ch);
|
||||||
|
}
|
||||||
|
return IsAsciiPunct(pattern_char) && pattern_char == ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (pattern_char == '.' && ch != '\n') || pattern_char == ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function used by ValidateRegex() to format error messages.
|
||||||
|
std::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
|
||||||
|
|
||||||
|
const char kUnknownFile[] = "unknown file";
|
||||||
|
|
||||||
|
// Formats a source file path and a line number as they would appear
|
||||||
|
// in an error message from the compiler used to compile this code.
|
||||||
|
GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) {
|
||||||
|
const std::string file_name(file == NULL ? kUnknownFile : file);
|
||||||
|
|
||||||
|
if (line < 0) {
|
||||||
|
return file_name + ":";
|
||||||
|
}
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
return file_name + "(" + StreamableToString(line) + "):";
|
||||||
|
#else
|
||||||
|
return file_name + ":" + StreamableToString(line) + ":";
|
||||||
|
#endif // _MSC_VER
|
||||||
|
}
|
||||||
|
|
||||||
|
// Formats a file location for compiler-independent XML output.
|
||||||
|
// Although this function is not platform dependent, we put it next to
|
||||||
|
// FormatFileLocation in order to contrast the two functions.
|
||||||
|
// Note that FormatCompilerIndependentFileLocation() does NOT append colon
|
||||||
|
// to the file location it produces, unlike FormatFileLocation().
|
||||||
|
GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(
|
||||||
|
const char* file, int line) {
|
||||||
|
const std::string file_name(file == NULL ? kUnknownFile : file);
|
||||||
|
|
||||||
|
if (line < 0)
|
||||||
|
return file_name;
|
||||||
|
else
|
||||||
|
return file_name + ":" + StreamableToString(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
explicit 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. We use /tmp on most systems, and /sdcard on Android.
|
||||||
|
// That's because Android doesn't have /tmp.
|
||||||
|
# if GTEST_OS_LINUX_ANDROID
|
||||||
|
// Note: Android applications are expected to call the framework's
|
||||||
|
// Context.getExternalStorageDirectory() method through JNI to get
|
||||||
|
// the location of the world-writable SD Card directory. However,
|
||||||
|
// this requires a Context handle, which cannot be retrieved
|
||||||
|
// globally from native code. Doing so also precludes running the
|
||||||
|
// code as part of a regular standalone executable, which doesn't
|
||||||
|
// run in a Dalvik process (e.g. when running it through 'adb shell').
|
||||||
|
//
|
||||||
|
// The location /sdcard is directly accessible from native code
|
||||||
|
// and is the only location (unofficially) supported by the Android
|
||||||
|
// team. It's generally a symlink to the real SD Card mount point
|
||||||
|
// which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or
|
||||||
|
// other OEM-customized locations. Never rely on these, and always
|
||||||
|
// use /sdcard.
|
||||||
|
char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX";
|
||||||
|
# else
|
||||||
|
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
||||||
|
# endif // GTEST_OS_LINUX_ANDROID
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::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 std::string content = ReadEntireFile(file);
|
||||||
|
posix::FClose(file);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Reads the entire content of a file as an std::string.
|
||||||
|
static std::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.
|
||||||
|
std::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 std::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.
|
||||||
|
std::string GetCapturedStream(CapturedStream** captured_stream) {
|
||||||
|
const std::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.
|
||||||
|
std::string GetCapturedStdout() {
|
||||||
|
return GetCapturedStream(&g_captured_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops capturing stderr and returns the captured string.
|
||||||
|
std::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<testing::internal::string> g_argvs;
|
||||||
|
|
||||||
|
static const ::std::vector<testing::internal::string>* g_injected_test_argvs =
|
||||||
|
NULL; // Owned.
|
||||||
|
|
||||||
|
void SetInjectableArgvs(const ::std::vector<testing::internal::string>* argvs) {
|
||||||
|
if (g_injected_test_argvs != argvs)
|
||||||
|
delete g_injected_test_argvs;
|
||||||
|
g_injected_test_argvs = argvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ::std::vector<testing::internal::string>& GetInjectableArgvs() {
|
||||||
|
if (g_injected_test_argvs != NULL) {
|
||||||
|
return *g_injected_test_argvs;
|
||||||
|
}
|
||||||
|
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 std::string FlagToEnvVar(const char* flag) {
|
||||||
|
const std::string full_flag =
|
||||||
|
(Message() << GTEST_FLAG_PREFIX_ << flag).GetString();
|
||||||
|
|
||||||
|
Message env_var;
|
||||||
|
for (size_t i = 0; i != full_flag.length(); i++) {
|
||||||
|
env_var << 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 std::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 std::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 std::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
|
363
extern/gtest/src/gtest-printers.cc
vendored
Normal file
363
extern/gtest/src/gtest-printers.cc
vendored
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
// Google Test - The Google C++ Testing Framework
|
||||||
|
//
|
||||||
|
// This file implements a universal value printer that can print a
|
||||||
|
// value of any type T:
|
||||||
|
//
|
||||||
|
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||||
|
//
|
||||||
|
// It uses the << operator when possible, and prints the bytes in the
|
||||||
|
// object otherwise. A user can override its behavior for a class
|
||||||
|
// type Foo by defining either operator<<(::std::ostream&, const Foo&)
|
||||||
|
// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that
|
||||||
|
// defines Foo.
|
||||||
|
|
||||||
|
#include "gtest/gtest-printers.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ostream> // NOLINT
|
||||||
|
#include <string>
|
||||||
|
#include "gtest/internal/gtest-port.h"
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using ::std::ostream;
|
||||||
|
|
||||||
|
// Prints a segment of bytes in the given object.
|
||||||
|
void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start,
|
||||||
|
size_t count, ostream* os) {
|
||||||
|
char text[5] = "";
|
||||||
|
for (size_t i = 0; i != count; i++) {
|
||||||
|
const size_t j = start + i;
|
||||||
|
if (i != 0) {
|
||||||
|
// Organizes the bytes into groups of 2 for easy parsing by
|
||||||
|
// human.
|
||||||
|
if ((j % 2) == 0)
|
||||||
|
*os << ' ';
|
||||||
|
else
|
||||||
|
*os << '-';
|
||||||
|
}
|
||||||
|
GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]);
|
||||||
|
*os << text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the bytes in the given value to the given ostream.
|
||||||
|
void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count,
|
||||||
|
ostream* os) {
|
||||||
|
// Tells the user how big the object is.
|
||||||
|
*os << count << "-byte object <";
|
||||||
|
|
||||||
|
const size_t kThreshold = 132;
|
||||||
|
const size_t kChunkSize = 64;
|
||||||
|
// If the object size is bigger than kThreshold, we'll have to omit
|
||||||
|
// some details by printing only the first and the last kChunkSize
|
||||||
|
// bytes.
|
||||||
|
// TODO(wan): let the user control the threshold using a flag.
|
||||||
|
if (count < kThreshold) {
|
||||||
|
PrintByteSegmentInObjectTo(obj_bytes, 0, count, os);
|
||||||
|
} else {
|
||||||
|
PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os);
|
||||||
|
*os << " ... ";
|
||||||
|
// Rounds up to 2-byte boundary.
|
||||||
|
const size_t resume_pos = (count - kChunkSize + 1)/2*2;
|
||||||
|
PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os);
|
||||||
|
}
|
||||||
|
*os << ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace internal2 {
|
||||||
|
|
||||||
|
// Delegates to PrintBytesInObjectToImpl() to print the bytes in the
|
||||||
|
// given object. The delegation simplifies the implementation, which
|
||||||
|
// uses the << operator and thus is easier done outside of the
|
||||||
|
// ::testing::internal namespace, which contains a << operator that
|
||||||
|
// sometimes conflicts with the one in STL.
|
||||||
|
void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count,
|
||||||
|
ostream* os) {
|
||||||
|
PrintBytesInObjectToImpl(obj_bytes, count, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal2
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Depending on the value of a char (or wchar_t), we print it in one
|
||||||
|
// of three formats:
|
||||||
|
// - as is if it's a printable ASCII (e.g. 'a', '2', ' '),
|
||||||
|
// - as a hexidecimal escape sequence (e.g. '\x7F'), or
|
||||||
|
// - as a special escape sequence (e.g. '\r', '\n').
|
||||||
|
enum CharFormat {
|
||||||
|
kAsIs,
|
||||||
|
kHexEscape,
|
||||||
|
kSpecialEscape
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns true if c is a printable ASCII character. We test the
|
||||||
|
// value of c directly instead of calling isprint(), which is buggy on
|
||||||
|
// Windows Mobile.
|
||||||
|
inline bool IsPrintableAscii(wchar_t c) {
|
||||||
|
return 0x20 <= c && c <= 0x7E;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a wide or narrow char c as a character literal without the
|
||||||
|
// quotes, escaping it when necessary; returns how c was formatted.
|
||||||
|
// The template argument UnsignedChar is the unsigned version of Char,
|
||||||
|
// which is the type of c.
|
||||||
|
template <typename UnsignedChar, typename Char>
|
||||||
|
static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) {
|
||||||
|
switch (static_cast<wchar_t>(c)) {
|
||||||
|
case L'\0':
|
||||||
|
*os << "\\0";
|
||||||
|
break;
|
||||||
|
case L'\'':
|
||||||
|
*os << "\\'";
|
||||||
|
break;
|
||||||
|
case L'\\':
|
||||||
|
*os << "\\\\";
|
||||||
|
break;
|
||||||
|
case L'\a':
|
||||||
|
*os << "\\a";
|
||||||
|
break;
|
||||||
|
case L'\b':
|
||||||
|
*os << "\\b";
|
||||||
|
break;
|
||||||
|
case L'\f':
|
||||||
|
*os << "\\f";
|
||||||
|
break;
|
||||||
|
case L'\n':
|
||||||
|
*os << "\\n";
|
||||||
|
break;
|
||||||
|
case L'\r':
|
||||||
|
*os << "\\r";
|
||||||
|
break;
|
||||||
|
case L'\t':
|
||||||
|
*os << "\\t";
|
||||||
|
break;
|
||||||
|
case L'\v':
|
||||||
|
*os << "\\v";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (IsPrintableAscii(c)) {
|
||||||
|
*os << static_cast<char>(c);
|
||||||
|
return kAsIs;
|
||||||
|
} else {
|
||||||
|
*os << "\\x" + String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||||
|
return kHexEscape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kSpecialEscape;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a wchar_t c as if it's part of a string literal, escaping it when
|
||||||
|
// necessary; returns how c was formatted.
|
||||||
|
static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) {
|
||||||
|
switch (c) {
|
||||||
|
case L'\'':
|
||||||
|
*os << "'";
|
||||||
|
return kAsIs;
|
||||||
|
case L'"':
|
||||||
|
*os << "\\\"";
|
||||||
|
return kSpecialEscape;
|
||||||
|
default:
|
||||||
|
return PrintAsCharLiteralTo<wchar_t>(c, os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a char c as if it's part of a string literal, escaping it when
|
||||||
|
// necessary; returns how c was formatted.
|
||||||
|
static CharFormat PrintAsStringLiteralTo(char c, ostream* os) {
|
||||||
|
return PrintAsStringLiteralTo(
|
||||||
|
static_cast<wchar_t>(static_cast<unsigned char>(c)), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a wide or narrow character c and its code. '\0' is printed
|
||||||
|
// as "'\\0'", other unprintable characters are also properly escaped
|
||||||
|
// using the standard C++ escape sequence. The template argument
|
||||||
|
// UnsignedChar is the unsigned version of Char, which is the type of c.
|
||||||
|
template <typename UnsignedChar, typename Char>
|
||||||
|
void PrintCharAndCodeTo(Char c, ostream* os) {
|
||||||
|
// First, print c as a literal in the most readable form we can find.
|
||||||
|
*os << ((sizeof(c) > 1) ? "L'" : "'");
|
||||||
|
const CharFormat format = PrintAsCharLiteralTo<UnsignedChar>(c, os);
|
||||||
|
*os << "'";
|
||||||
|
|
||||||
|
// To aid user debugging, we also print c's code in decimal, unless
|
||||||
|
// it's 0 (in which case c was printed as '\\0', making the code
|
||||||
|
// obvious).
|
||||||
|
if (c == 0)
|
||||||
|
return;
|
||||||
|
*os << " (" << static_cast<int>(c);
|
||||||
|
|
||||||
|
// For more convenience, we print c's code again in hexidecimal,
|
||||||
|
// unless c was already printed in the form '\x##' or the code is in
|
||||||
|
// [1, 9].
|
||||||
|
if (format == kHexEscape || (1 <= c && c <= 9)) {
|
||||||
|
// Do nothing.
|
||||||
|
} else {
|
||||||
|
*os << ", 0x" << String::FormatHexInt(static_cast<UnsignedChar>(c));
|
||||||
|
}
|
||||||
|
*os << ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintTo(unsigned char c, ::std::ostream* os) {
|
||||||
|
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||||
|
}
|
||||||
|
void PrintTo(signed char c, ::std::ostream* os) {
|
||||||
|
PrintCharAndCodeTo<unsigned char>(c, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||||
|
// code otherwise and also as its code. L'\0' is printed as "L'\\0'".
|
||||||
|
void PrintTo(wchar_t wc, ostream* os) {
|
||||||
|
PrintCharAndCodeTo<wchar_t>(wc, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the given array of characters to the ostream. CharType must be either
|
||||||
|
// char or wchar_t.
|
||||||
|
// The array starts at begin, the length is len, it may include '\0' characters
|
||||||
|
// and may not be NUL-terminated.
|
||||||
|
template <typename CharType>
|
||||||
|
static void PrintCharsAsStringTo(
|
||||||
|
const CharType* begin, size_t len, ostream* os) {
|
||||||
|
const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\"";
|
||||||
|
*os << kQuoteBegin;
|
||||||
|
bool is_previous_hex = false;
|
||||||
|
for (size_t index = 0; index < len; ++index) {
|
||||||
|
const CharType cur = begin[index];
|
||||||
|
if (is_previous_hex && IsXDigit(cur)) {
|
||||||
|
// Previous character is of '\x..' form and this character can be
|
||||||
|
// interpreted as another hexadecimal digit in its number. Break string to
|
||||||
|
// disambiguate.
|
||||||
|
*os << "\" " << kQuoteBegin;
|
||||||
|
}
|
||||||
|
is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape;
|
||||||
|
}
|
||||||
|
*os << "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a (const) char/wchar_t array of 'len' elements, starting at address
|
||||||
|
// 'begin'. CharType must be either char or wchar_t.
|
||||||
|
template <typename CharType>
|
||||||
|
static void UniversalPrintCharArray(
|
||||||
|
const CharType* begin, size_t len, ostream* os) {
|
||||||
|
// The code
|
||||||
|
// const char kFoo[] = "foo";
|
||||||
|
// generates an array of 4, not 3, elements, with the last one being '\0'.
|
||||||
|
//
|
||||||
|
// Therefore when printing a char array, we don't print the last element if
|
||||||
|
// it's '\0', such that the output matches the string literal as it's
|
||||||
|
// written in the source code.
|
||||||
|
if (len > 0 && begin[len - 1] == '\0') {
|
||||||
|
PrintCharsAsStringTo(begin, len - 1, os);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If, however, the last element in the array is not '\0', e.g.
|
||||||
|
// const char kFoo[] = { 'f', 'o', 'o' };
|
||||||
|
// we must print the entire array. We also print a message to indicate
|
||||||
|
// that the array is not NUL-terminated.
|
||||||
|
PrintCharsAsStringTo(begin, len, os);
|
||||||
|
*os << " (no terminating NUL)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a (const) char array of 'len' elements, starting at address 'begin'.
|
||||||
|
void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
|
||||||
|
UniversalPrintCharArray(begin, len, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a (const) wchar_t array of 'len' elements, starting at address
|
||||||
|
// 'begin'.
|
||||||
|
void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) {
|
||||||
|
UniversalPrintCharArray(begin, len, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints the given C string to the ostream.
|
||||||
|
void PrintTo(const char* s, ostream* os) {
|
||||||
|
if (s == NULL) {
|
||||||
|
*os << "NULL";
|
||||||
|
} else {
|
||||||
|
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||||
|
PrintCharsAsStringTo(s, strlen(s), os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSVC compiler can be configured to define whar_t as a typedef
|
||||||
|
// of unsigned short. Defining an overload for const wchar_t* in that case
|
||||||
|
// would cause pointers to unsigned shorts be printed as wide strings,
|
||||||
|
// possibly accessing more memory than intended and causing invalid
|
||||||
|
// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when
|
||||||
|
// wchar_t is implemented as a native type.
|
||||||
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
|
// Prints the given wide C string to the ostream.
|
||||||
|
void PrintTo(const wchar_t* s, ostream* os) {
|
||||||
|
if (s == NULL) {
|
||||||
|
*os << "NULL";
|
||||||
|
} else {
|
||||||
|
*os << ImplicitCast_<const void*>(s) << " pointing to ";
|
||||||
|
PrintCharsAsStringTo(s, wcslen(s), os);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // wchar_t is native
|
||||||
|
|
||||||
|
// Prints a ::string object.
|
||||||
|
#if GTEST_HAS_GLOBAL_STRING
|
||||||
|
void PrintStringTo(const ::string& s, ostream* os) {
|
||||||
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_GLOBAL_STRING
|
||||||
|
|
||||||
|
void PrintStringTo(const ::std::string& s, ostream* os) {
|
||||||
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prints a ::wstring object.
|
||||||
|
#if GTEST_HAS_GLOBAL_WSTRING
|
||||||
|
void PrintWideStringTo(const ::wstring& s, ostream* os) {
|
||||||
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||||
|
|
||||||
|
#if GTEST_HAS_STD_WSTRING
|
||||||
|
void PrintWideStringTo(const ::std::wstring& s, ostream* os) {
|
||||||
|
PrintCharsAsStringTo(s.data(), s.size(), os);
|
||||||
|
}
|
||||||
|
#endif // GTEST_HAS_STD_WSTRING
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
} // namespace testing
|
110
extern/gtest/src/gtest-test-part.cc
vendored
Normal file
110
extern/gtest/src/gtest-test-part.cc
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// 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)
|
||||||
|
|
||||||
|
#include "gtest/gtest-test-part.h"
|
||||||
|
|
||||||
|
// 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
|
||||||
|
#include "src/gtest-internal-inl.h"
|
||||||
|
#undef GTEST_IMPLEMENTATION_
|
||||||
|
|
||||||
|
namespace testing {
|
||||||
|
|
||||||
|
using internal::GetUnitTestImpl;
|
||||||
|
|
||||||
|
// Gets the summary of the failure message by omitting the stack trace
|
||||||
|
// in it.
|
||||||
|
std::string TestPartResult::ExtractSummary(const char* message) {
|
||||||
|
const char* const stack_trace = strstr(message, internal::kStackTraceMarker);
|
||||||
|
return stack_trace == NULL ? message :
|
||||||
|
std::string(message, stack_trace);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
110
extern/gtest/src/gtest-typed-test.cc
vendored
Normal file
110
extern/gtest/src/gtest-typed-test.cc
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// 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 "gtest/gtest-typed-test.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
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<std::string> tests;
|
||||||
|
for (const char* names = registered_tests; names != NULL;
|
||||||
|
names = SkipComma(names)) {
|
||||||
|
const std::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 std::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
|
5015
extern/gtest/src/gtest.cc
vendored
Normal file
5015
extern/gtest/src/gtest.cc
vendored
Normal file
File diff suppressed because it is too large
Load Diff
38
extern/gtest/src/gtest_main.cc
vendored
Normal file
38
extern/gtest/src/gtest_main.cc
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
GTEST_API_ int main(int argc, char **argv) {
|
||||||
|
printf("Running main() from gtest_main.cc\n");
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
112
extern/libmv/CMakeLists.txt
vendored
112
extern/libmv/CMakeLists.txt
vendored
@ -30,6 +30,9 @@ set(INC
|
|||||||
.
|
.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
)
|
||||||
|
|
||||||
set(SRC
|
set(SRC
|
||||||
libmv-capi.h
|
libmv-capi.h
|
||||||
libmv-capi_intern.h
|
libmv-capi_intern.h
|
||||||
@ -67,6 +70,7 @@ if(WITH_LIBMV)
|
|||||||
libmv/multiview/fundamental.cc
|
libmv/multiview/fundamental.cc
|
||||||
libmv/multiview/homography.cc
|
libmv/multiview/homography.cc
|
||||||
libmv/multiview/panography.cc
|
libmv/multiview/panography.cc
|
||||||
|
libmv/multiview/panography_kernel.cc
|
||||||
libmv/multiview/projection.cc
|
libmv/multiview/projection.cc
|
||||||
libmv/multiview/triangulation.cc
|
libmv/multiview/triangulation.cc
|
||||||
libmv/numeric/numeric.cc
|
libmv/numeric/numeric.cc
|
||||||
@ -92,10 +96,6 @@ if(WITH_LIBMV)
|
|||||||
libmv/tracking/track_region.cc
|
libmv/tracking/track_region.cc
|
||||||
libmv/tracking/trklt_region_tracker.cc
|
libmv/tracking/trklt_region_tracker.cc
|
||||||
|
|
||||||
third_party/gflags/gflags.cc
|
|
||||||
third_party/gflags/gflags_completions.cc
|
|
||||||
third_party/gflags/gflags_reporting.cc
|
|
||||||
|
|
||||||
libmv-util.h
|
libmv-util.h
|
||||||
libmv/base/aligned_malloc.h
|
libmv/base/aligned_malloc.h
|
||||||
libmv/base/id_generator.h
|
libmv/base/id_generator.h
|
||||||
@ -106,6 +106,7 @@ if(WITH_LIBMV)
|
|||||||
libmv/image/convolve.h
|
libmv/image/convolve.h
|
||||||
libmv/image/correlation.h
|
libmv/image/correlation.h
|
||||||
libmv/image/image_converter.h
|
libmv/image/image_converter.h
|
||||||
|
libmv/image/image_drawing.h
|
||||||
libmv/image/image.h
|
libmv/image/image.h
|
||||||
libmv/image/sample.h
|
libmv/image/sample.h
|
||||||
libmv/image/tuple.h
|
libmv/image/tuple.h
|
||||||
@ -113,13 +114,16 @@ if(WITH_LIBMV)
|
|||||||
libmv/multiview/conditioning.h
|
libmv/multiview/conditioning.h
|
||||||
libmv/multiview/euclidean_resection.h
|
libmv/multiview/euclidean_resection.h
|
||||||
libmv/multiview/fundamental.h
|
libmv/multiview/fundamental.h
|
||||||
|
libmv/multiview/homography_error.h
|
||||||
libmv/multiview/homography.h
|
libmv/multiview/homography.h
|
||||||
libmv/multiview/homography_parameterization.h
|
libmv/multiview/homography_parameterization.h
|
||||||
libmv/multiview/nviewtriangulation.h
|
libmv/multiview/nviewtriangulation.h
|
||||||
libmv/multiview/panography.h
|
libmv/multiview/panography.h
|
||||||
|
libmv/multiview/panography_kernel.h
|
||||||
libmv/multiview/projection.h
|
libmv/multiview/projection.h
|
||||||
libmv/multiview/resection.h
|
libmv/multiview/resection.h
|
||||||
libmv/multiview/triangulation.h
|
libmv/multiview/triangulation.h
|
||||||
|
libmv/multiview/two_view_kernel.h
|
||||||
libmv/numeric/dogleg.h
|
libmv/numeric/dogleg.h
|
||||||
libmv/numeric/function_derivative.h
|
libmv/numeric/function_derivative.h
|
||||||
libmv/numeric/levenberg_marquardt.h
|
libmv/numeric/levenberg_marquardt.h
|
||||||
@ -149,18 +153,86 @@ if(WITH_LIBMV)
|
|||||||
libmv/tracking/track_region.h
|
libmv/tracking/track_region.h
|
||||||
libmv/tracking/trklt_region_tracker.h
|
libmv/tracking/trklt_region_tracker.h
|
||||||
|
|
||||||
|
third_party/msinttypes/inttypes.h
|
||||||
|
third_party/msinttypes/stdint.h
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/glog/src/windows
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MINGW)
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/msinttypes
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_TESTS)
|
||||||
|
blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "" "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
BLENDER_SRC_GTEST("libmv_scoped_ptr" "./libmv/base/scoped_ptr_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_vector" "./libmv/base/vector_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_array_nd" "./libmv/image/array_nd_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_convolve" "./libmv/image/convolve_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_image" "./libmv/image/image_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_sample" "./libmv/image/sample_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_tuple" "./libmv/image/tuple_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_euclidean_resection" "./libmv/multiview/euclidean_resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_fundamental" "./libmv/multiview/fundamental_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_homography" "./libmv/multiview/homography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_nviewtriangulation" "./libmv/multiview/nviewtriangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_panography" "./libmv/multiview/panography_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_projection" "./libmv/multiview/projection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_resection" "./libmv/multiview/resection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_triangulation" "./libmv/multiview/triangulation_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_dogleg" "./libmv/numeric/dogleg_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_function_derivative" "./libmv/numeric/function_derivative_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_levenberg_marquardt" "./libmv/numeric/levenberg_marquardt_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_numeric" "./libmv/numeric/numeric_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_poly" "./libmv/numeric/poly_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_camera_intrinsics" "./libmv/simple_pipeline/camera_intrinsics_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_detect" "./libmv/simple_pipeline/detect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_intersect" "./libmv/simple_pipeline/intersect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_keyframe_selection" "./libmv/simple_pipeline/keyframe_selection_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_modal_solver" "./libmv/simple_pipeline/modal_solver_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_resect" "./libmv/simple_pipeline/resect_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_brute_region_tracker" "./libmv/tracking/brute_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_klt_region_tracker" "./libmv/tracking/klt_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
BLENDER_SRC_GTEST("libmv_pyramid_region_tracker" "./libmv/tracking/pyramid_region_tracker_test.cc" "libmv_test_dataset;extern_libmv;extern_ceres")
|
||||||
|
else()
|
||||||
|
list(APPEND SRC
|
||||||
|
libmv-capi_stub.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
|
||||||
|
|
||||||
|
if(WITH_LIBMV)
|
||||||
|
add_subdirectory(third_party)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# make GLog a separate target, so it can be used for gtest as well.
|
||||||
|
if(WITH_LIBMV OR WITH_TESTS)
|
||||||
|
# We compile GLog together with GFlag so we don't worry about
|
||||||
|
# adding extra lib to linker.
|
||||||
|
set(GLOG_SRC
|
||||||
|
third_party/gflags/gflags.cc
|
||||||
|
third_party/gflags/gflags_completions.cc
|
||||||
|
third_party/gflags/gflags_reporting.cc
|
||||||
|
|
||||||
third_party/gflags/config.h
|
third_party/gflags/config.h
|
||||||
third_party/gflags/gflags/gflags_completions.h
|
third_party/gflags/gflags/gflags_completions.h
|
||||||
third_party/gflags/gflags/gflags_declare.h
|
third_party/gflags/gflags/gflags_declare.h
|
||||||
third_party/gflags/gflags/gflags.h
|
third_party/gflags/gflags/gflags.h
|
||||||
third_party/gflags/mutex.h
|
third_party/gflags/mutex.h
|
||||||
third_party/gflags/util.h
|
third_party/gflags/util.h
|
||||||
third_party/msinttypes/inttypes.h
|
|
||||||
third_party/msinttypes/stdint.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND SRC
|
list(APPEND GLOG_SRC
|
||||||
third_party/glog/src/logging.cc
|
third_party/glog/src/logging.cc
|
||||||
third_party/glog/src/raw_logging.cc
|
third_party/glog/src/raw_logging.cc
|
||||||
third_party/glog/src/utilities.cc
|
third_party/glog/src/utilities.cc
|
||||||
@ -185,18 +257,8 @@ if(WITH_LIBMV)
|
|||||||
third_party/glog/src/windows/port.h
|
third_party/glog/src/windows/port.h
|
||||||
third_party/glog/src/windows/config.h
|
third_party/glog/src/windows/config.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND INC
|
|
||||||
third_party/glog/src/windows
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT MINGW)
|
|
||||||
list(APPEND INC
|
|
||||||
third_party/msinttypes
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
list(APPEND SRC
|
list(APPEND GLOG_SRC
|
||||||
third_party/glog/src/demangle.cc
|
third_party/glog/src/demangle.cc
|
||||||
third_party/glog/src/logging.cc
|
third_party/glog/src/logging.cc
|
||||||
third_party/glog/src/raw_logging.cc
|
third_party/glog/src/raw_logging.cc
|
||||||
@ -228,14 +290,14 @@ if(WITH_LIBMV)
|
|||||||
third_party/glog/src/utilities.h
|
third_party/glog/src/utilities.h
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
|
||||||
list(APPEND SRC
|
set(GLOG_INC
|
||||||
libmv-capi_stub.cc
|
third_party/gflags
|
||||||
|
third_party/glog/src
|
||||||
)
|
)
|
||||||
endif()
|
|
||||||
|
|
||||||
blender_add_lib(extern_libmv "${SRC}" "${INC}" "${INC_SYS}")
|
set(GLOG_INC_SYS
|
||||||
|
)
|
||||||
|
|
||||||
if(WITH_LIBMV)
|
blender_add_lib(extern_glog "${GLOG_SRC}" "${GLOG_INC}" "${GLOG_INC_SYS}")
|
||||||
add_subdirectory(third_party)
|
|
||||||
endif()
|
endif()
|
||||||
|
2
extern/libmv/SConscript
vendored
2
extern/libmv/SConscript
vendored
@ -44,6 +44,8 @@ if env['WITH_BF_LIBMV']:
|
|||||||
else:
|
else:
|
||||||
src = env.Glob("libmv-capi_stub.cc")
|
src = env.Glob("libmv-capi_stub.cc")
|
||||||
|
|
||||||
|
src = [src for src in src if src.find('_test.cc') == -1]
|
||||||
|
|
||||||
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
|
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
|
||||||
|
|
||||||
if env['WITH_BF_LIBMV']:
|
if env['WITH_BF_LIBMV']:
|
||||||
|
87
extern/libmv/bundle.sh
vendored
87
extern/libmv/bundle.sh
vendored
@ -30,15 +30,20 @@ rm -rf $tmp
|
|||||||
|
|
||||||
chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
|
chmod 664 ./third_party/glog/src/windows/*.cc ./third_party/glog/src/windows/*.h ./third_party/glog/src/windows/glog/*.h
|
||||||
|
|
||||||
sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | sed -r 's/^\.\//\t\t/' | sort -d`
|
sources=`find ./libmv -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v _test.cc | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
headers=`find ./libmv -type f -iname '*.h' | sed -r 's/^\.\//\t\t/' | sort -d`
|
headers=`find ./libmv -type f -iname '*.h' | grep -v test_data_sets | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
|
|
||||||
third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
|
third_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep -v glog | grep -v gflags | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
|
third_headers=`find ./third_party -type f -iname '*.h' | grep -v glog | grep -v gflags | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
|
|
||||||
third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
|
third_glog_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
|
||||||
third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
|
third_glog_headers=`find ./third_party -type f -iname '*.h' | grep glog | grep -v windows | sed -r 's/^\.\//\t\t\t/' | sort -d`
|
||||||
|
|
||||||
|
third_gflags_sources=`find ./third_party -type f -iname '*.cc' -or -iname '*.cpp' -or -iname '*.c' | grep gflags | grep -v windows | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
|
third_gflags_headers=`find ./third_party -type f -iname '*.h' | grep gflags | grep -v windows | sed -r 's/^\.\//\t\t/' | sort -d`
|
||||||
|
|
||||||
|
tests=`find ./libmv -type f -iname '*_test.cc' | sort -d | awk ' { name=gensub(".*/([A-Za-z_]+)_test.cc", "\\\\1", $1); printf("\tBLENDER_SRC_GTEST(\"libmv_%s\" \"%s\" \"libmv_test_dataset;extern_libmv;extern_ceres\")\n", name, $1) } '`
|
||||||
|
|
||||||
src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
|
src_dir=`find ./libmv -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
|
||||||
src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
|
src_third_dir=`find ./third_party -type f -iname '*.cc' -exec dirname {} \; -or -iname '*.cpp' -exec dirname {} \; -or -iname '*.c' -exec dirname {} \; | grep -v ceres | sed -r 's/^\.\//\t\t/' | sort -d | uniq`
|
||||||
src=""
|
src=""
|
||||||
@ -118,6 +123,9 @@ set(INC
|
|||||||
.
|
.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
)
|
||||||
|
|
||||||
set(SRC
|
set(SRC
|
||||||
libmv-capi.h
|
libmv-capi.h
|
||||||
libmv-capi_intern.h
|
libmv-capi_intern.h
|
||||||
@ -148,9 +156,7 @@ if(WITH_LIBMV)
|
|||||||
libmv-capi.cc
|
libmv-capi.cc
|
||||||
libmv-util.cc
|
libmv-util.cc
|
||||||
${sources}
|
${sources}
|
||||||
|
|
||||||
${third_sources}
|
${third_sources}
|
||||||
|
|
||||||
libmv-util.h
|
libmv-util.h
|
||||||
${headers}
|
${headers}
|
||||||
|
|
||||||
@ -158,7 +164,46 @@ ${third_headers}
|
|||||||
)
|
)
|
||||||
|
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
list(APPEND SRC
|
list(APPEND INC
|
||||||
|
third_party/glog/src/windows
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT MINGW)
|
||||||
|
list(APPEND INC
|
||||||
|
third_party/msinttypes
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WITH_TESTS)
|
||||||
|
blender_add_lib(libmv_test_dataset "./libmv/multiview/test_data_sets.cc" "${INC}" "${INC_SYS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
${tests}
|
||||||
|
else()
|
||||||
|
list(APPEND SRC
|
||||||
|
libmv-capi_stub.cc
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
|
||||||
|
|
||||||
|
if(WITH_LIBMV)
|
||||||
|
add_subdirectory(third_party)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# make GLog a separate target, so it can be used for gtest as well.
|
||||||
|
if(WITH_LIBMV OR WITH_TESTS)
|
||||||
|
# We compile GLog together with GFlag so we don't worry about
|
||||||
|
# adding extra lib to linker.
|
||||||
|
set(GLOG_SRC
|
||||||
|
${third_gflags_sources}
|
||||||
|
|
||||||
|
${third_gflags_headers}
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND GLOG_SRC
|
||||||
third_party/glog/src/logging.cc
|
third_party/glog/src/logging.cc
|
||||||
third_party/glog/src/raw_logging.cc
|
third_party/glog/src/raw_logging.cc
|
||||||
third_party/glog/src/utilities.cc
|
third_party/glog/src/utilities.cc
|
||||||
@ -183,33 +228,23 @@ ${third_headers}
|
|||||||
third_party/glog/src/windows/port.h
|
third_party/glog/src/windows/port.h
|
||||||
third_party/glog/src/windows/config.h
|
third_party/glog/src/windows/config.h
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND INC
|
|
||||||
third_party/glog/src/windows
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT MINGW)
|
|
||||||
list(APPEND INC
|
|
||||||
third_party/msinttypes
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
else()
|
else()
|
||||||
list(APPEND SRC
|
list(APPEND GLOG_SRC
|
||||||
${third_glog_sources}
|
${third_glog_sources}
|
||||||
|
|
||||||
${third_glog_headers}
|
${third_glog_headers}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
|
||||||
list(APPEND SRC
|
set(GLOG_INC
|
||||||
libmv-capi_stub.cc
|
third_party/gflags
|
||||||
|
third_party/glog/src
|
||||||
)
|
)
|
||||||
endif()
|
|
||||||
|
|
||||||
blender_add_lib(extern_libmv "\${SRC}" "\${INC}" "\${INC_SYS}")
|
set(GLOG_INC_SYS
|
||||||
|
)
|
||||||
|
|
||||||
if(WITH_LIBMV)
|
blender_add_lib(extern_glog "\${GLOG_SRC}" "\${GLOG_INC}" "\${GLOG_INC_SYS}")
|
||||||
add_subdirectory(third_party)
|
|
||||||
endif()
|
endif()
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
@ -254,6 +289,8 @@ ${win_src}
|
|||||||
else:
|
else:
|
||||||
src = env.Glob("libmv-capi_stub.cc")
|
src = env.Glob("libmv-capi_stub.cc")
|
||||||
|
|
||||||
|
src = [src for src in src if src.find('_test.cc') == -1]
|
||||||
|
|
||||||
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
|
env.BlenderLib ( libname = 'extern_libmv', sources=src, includes=Split(incs), defines=defs, libtype=['extern', 'player'], priority=[20,137] )
|
||||||
|
|
||||||
if env['WITH_BF_LIBMV']:
|
if env['WITH_BF_LIBMV']:
|
||||||
|
36
extern/libmv/files.txt
vendored
36
extern/libmv/files.txt
vendored
@ -2,60 +2,92 @@ libmv/base/aligned_malloc.cc
|
|||||||
libmv/base/aligned_malloc.h
|
libmv/base/aligned_malloc.h
|
||||||
libmv/base/id_generator.h
|
libmv/base/id_generator.h
|
||||||
libmv/base/scoped_ptr.h
|
libmv/base/scoped_ptr.h
|
||||||
|
libmv/base/scoped_ptr_test.cc
|
||||||
libmv/base/vector.h
|
libmv/base/vector.h
|
||||||
|
libmv/base/vector_test.cc
|
||||||
libmv/base/vector_utils.h
|
libmv/base/vector_utils.h
|
||||||
libmv/image/array_nd.cc
|
libmv/image/array_nd.cc
|
||||||
libmv/image/array_nd.h
|
libmv/image/array_nd.h
|
||||||
|
libmv/image/array_nd_test.cc
|
||||||
libmv/image/convolve.cc
|
libmv/image/convolve.cc
|
||||||
libmv/image/convolve.h
|
libmv/image/convolve.h
|
||||||
|
libmv/image/convolve_test.cc
|
||||||
libmv/image/correlation.h
|
libmv/image/correlation.h
|
||||||
libmv/image/image_converter.h
|
libmv/image/image_converter.h
|
||||||
|
libmv/image/image_drawing.h
|
||||||
libmv/image/image.h
|
libmv/image/image.h
|
||||||
|
libmv/image/image_test.cc
|
||||||
libmv/image/sample.h
|
libmv/image/sample.h
|
||||||
|
libmv/image/sample_test.cc
|
||||||
libmv/image/tuple.h
|
libmv/image/tuple.h
|
||||||
|
libmv/image/tuple_test.cc
|
||||||
libmv/logging/logging.h
|
libmv/logging/logging.h
|
||||||
libmv/multiview/conditioning.cc
|
libmv/multiview/conditioning.cc
|
||||||
libmv/multiview/conditioning.h
|
libmv/multiview/conditioning.h
|
||||||
libmv/multiview/euclidean_resection.cc
|
libmv/multiview/euclidean_resection.cc
|
||||||
libmv/multiview/euclidean_resection.h
|
libmv/multiview/euclidean_resection.h
|
||||||
|
libmv/multiview/euclidean_resection_test.cc
|
||||||
libmv/multiview/fundamental.cc
|
libmv/multiview/fundamental.cc
|
||||||
libmv/multiview/fundamental.h
|
libmv/multiview/fundamental.h
|
||||||
|
libmv/multiview/fundamental_test.cc
|
||||||
libmv/multiview/homography.cc
|
libmv/multiview/homography.cc
|
||||||
|
libmv/multiview/homography_error.h
|
||||||
libmv/multiview/homography.h
|
libmv/multiview/homography.h
|
||||||
libmv/multiview/homography_parameterization.h
|
libmv/multiview/homography_parameterization.h
|
||||||
|
libmv/multiview/homography_test.cc
|
||||||
libmv/multiview/nviewtriangulation.h
|
libmv/multiview/nviewtriangulation.h
|
||||||
|
libmv/multiview/nviewtriangulation_test.cc
|
||||||
libmv/multiview/panography.cc
|
libmv/multiview/panography.cc
|
||||||
libmv/multiview/panography.h
|
libmv/multiview/panography.h
|
||||||
|
libmv/multiview/panography_kernel.cc
|
||||||
|
libmv/multiview/panography_kernel.h
|
||||||
|
libmv/multiview/panography_test.cc
|
||||||
libmv/multiview/projection.cc
|
libmv/multiview/projection.cc
|
||||||
libmv/multiview/projection.h
|
libmv/multiview/projection.h
|
||||||
|
libmv/multiview/projection_test.cc
|
||||||
libmv/multiview/resection.h
|
libmv/multiview/resection.h
|
||||||
|
libmv/multiview/resection_test.cc
|
||||||
|
libmv/multiview/test_data_sets.cc
|
||||||
|
libmv/multiview/test_data_sets.h
|
||||||
libmv/multiview/triangulation.cc
|
libmv/multiview/triangulation.cc
|
||||||
libmv/multiview/triangulation.h
|
libmv/multiview/triangulation.h
|
||||||
|
libmv/multiview/triangulation_test.cc
|
||||||
|
libmv/multiview/two_view_kernel.h
|
||||||
libmv/numeric/dogleg.h
|
libmv/numeric/dogleg.h
|
||||||
|
libmv/numeric/dogleg_test.cc
|
||||||
libmv/numeric/function_derivative.h
|
libmv/numeric/function_derivative.h
|
||||||
|
libmv/numeric/function_derivative_test.cc
|
||||||
libmv/numeric/levenberg_marquardt.h
|
libmv/numeric/levenberg_marquardt.h
|
||||||
|
libmv/numeric/levenberg_marquardt_test.cc
|
||||||
libmv/numeric/numeric.cc
|
libmv/numeric/numeric.cc
|
||||||
libmv/numeric/numeric.h
|
libmv/numeric/numeric.h
|
||||||
|
libmv/numeric/numeric_test.cc
|
||||||
libmv/numeric/poly.cc
|
libmv/numeric/poly.cc
|
||||||
libmv/numeric/poly.h
|
libmv/numeric/poly.h
|
||||||
|
libmv/numeric/poly_test.cc
|
||||||
libmv/simple_pipeline/bundle.cc
|
libmv/simple_pipeline/bundle.cc
|
||||||
libmv/simple_pipeline/bundle.h
|
libmv/simple_pipeline/bundle.h
|
||||||
libmv/simple_pipeline/callbacks.h
|
libmv/simple_pipeline/callbacks.h
|
||||||
libmv/simple_pipeline/camera_intrinsics.cc
|
libmv/simple_pipeline/camera_intrinsics.cc
|
||||||
libmv/simple_pipeline/camera_intrinsics.h
|
libmv/simple_pipeline/camera_intrinsics.h
|
||||||
libmv/simple_pipeline/camera_intrinsics_impl.h
|
libmv/simple_pipeline/camera_intrinsics_impl.h
|
||||||
|
libmv/simple_pipeline/camera_intrinsics_test.cc
|
||||||
libmv/simple_pipeline/detect.cc
|
libmv/simple_pipeline/detect.cc
|
||||||
libmv/simple_pipeline/detect.h
|
libmv/simple_pipeline/detect.h
|
||||||
|
libmv/simple_pipeline/detect_test.cc
|
||||||
libmv/simple_pipeline/distortion_models.cc
|
libmv/simple_pipeline/distortion_models.cc
|
||||||
libmv/simple_pipeline/distortion_models.h
|
libmv/simple_pipeline/distortion_models.h
|
||||||
libmv/simple_pipeline/initialize_reconstruction.cc
|
libmv/simple_pipeline/initialize_reconstruction.cc
|
||||||
libmv/simple_pipeline/initialize_reconstruction.h
|
libmv/simple_pipeline/initialize_reconstruction.h
|
||||||
libmv/simple_pipeline/intersect.cc
|
libmv/simple_pipeline/intersect.cc
|
||||||
libmv/simple_pipeline/intersect.h
|
libmv/simple_pipeline/intersect.h
|
||||||
|
libmv/simple_pipeline/intersect_test.cc
|
||||||
libmv/simple_pipeline/keyframe_selection.cc
|
libmv/simple_pipeline/keyframe_selection.cc
|
||||||
libmv/simple_pipeline/keyframe_selection.h
|
libmv/simple_pipeline/keyframe_selection.h
|
||||||
|
libmv/simple_pipeline/keyframe_selection_test.cc
|
||||||
libmv/simple_pipeline/modal_solver.cc
|
libmv/simple_pipeline/modal_solver.cc
|
||||||
libmv/simple_pipeline/modal_solver.h
|
libmv/simple_pipeline/modal_solver.h
|
||||||
|
libmv/simple_pipeline/modal_solver_test.cc
|
||||||
libmv/simple_pipeline/pipeline.cc
|
libmv/simple_pipeline/pipeline.cc
|
||||||
libmv/simple_pipeline/pipeline.h
|
libmv/simple_pipeline/pipeline.h
|
||||||
libmv/simple_pipeline/reconstruction.cc
|
libmv/simple_pipeline/reconstruction.cc
|
||||||
@ -64,16 +96,20 @@ libmv/simple_pipeline/reconstruction_scale.cc
|
|||||||
libmv/simple_pipeline/reconstruction_scale.h
|
libmv/simple_pipeline/reconstruction_scale.h
|
||||||
libmv/simple_pipeline/resect.cc
|
libmv/simple_pipeline/resect.cc
|
||||||
libmv/simple_pipeline/resect.h
|
libmv/simple_pipeline/resect.h
|
||||||
|
libmv/simple_pipeline/resect_test.cc
|
||||||
libmv/simple_pipeline/tracks.cc
|
libmv/simple_pipeline/tracks.cc
|
||||||
libmv/simple_pipeline/tracks.h
|
libmv/simple_pipeline/tracks.h
|
||||||
libmv/tracking/brute_region_tracker.cc
|
libmv/tracking/brute_region_tracker.cc
|
||||||
libmv/tracking/brute_region_tracker.h
|
libmv/tracking/brute_region_tracker.h
|
||||||
|
libmv/tracking/brute_region_tracker_test.cc
|
||||||
libmv/tracking/hybrid_region_tracker.cc
|
libmv/tracking/hybrid_region_tracker.cc
|
||||||
libmv/tracking/hybrid_region_tracker.h
|
libmv/tracking/hybrid_region_tracker.h
|
||||||
libmv/tracking/klt_region_tracker.cc
|
libmv/tracking/klt_region_tracker.cc
|
||||||
libmv/tracking/klt_region_tracker.h
|
libmv/tracking/klt_region_tracker.h
|
||||||
|
libmv/tracking/klt_region_tracker_test.cc
|
||||||
libmv/tracking/pyramid_region_tracker.cc
|
libmv/tracking/pyramid_region_tracker.cc
|
||||||
libmv/tracking/pyramid_region_tracker.h
|
libmv/tracking/pyramid_region_tracker.h
|
||||||
|
libmv/tracking/pyramid_region_tracker_test.cc
|
||||||
libmv/tracking/region_tracker.h
|
libmv/tracking/region_tracker.h
|
||||||
libmv/tracking/retrack_region_tracker.cc
|
libmv/tracking/retrack_region_tracker.cc
|
||||||
libmv/tracking/retrack_region_tracker.h
|
libmv/tracking/retrack_region_tracker.h
|
||||||
|
79
extern/libmv/libmv/base/scoped_ptr_test.cc
vendored
Normal file
79
extern/libmv/libmv/base/scoped_ptr_test.cc
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/base/scoped_ptr.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct FreeMe {
|
||||||
|
FreeMe(int *freed) : freed(freed) {}
|
||||||
|
~FreeMe() { (*freed)++; }
|
||||||
|
int *freed;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(ScopedPtr, NullDoesNothing) {
|
||||||
|
scoped_ptr<FreeMe> x(NULL);
|
||||||
|
// Does nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopedPtr, FreesWhenOutOfScope) {
|
||||||
|
int frees = 0;
|
||||||
|
{
|
||||||
|
scoped_ptr<FreeMe> scoped(new FreeMe(&frees));
|
||||||
|
EXPECT_EQ(0, frees);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(1, frees);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopedPtr, Operators) {
|
||||||
|
int tag = 123;
|
||||||
|
scoped_ptr<FreeMe> scoped(new FreeMe(&tag));
|
||||||
|
EXPECT_EQ(123, *(scoped->freed));
|
||||||
|
EXPECT_EQ(123, *((*scoped).freed));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopedPtr, Reset) {
|
||||||
|
int frees = 0;
|
||||||
|
scoped_ptr<FreeMe> scoped(new FreeMe(&frees));
|
||||||
|
EXPECT_EQ(0, frees);
|
||||||
|
scoped.reset(new FreeMe(&frees));
|
||||||
|
EXPECT_EQ(1, frees);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ScopedPtr, ReleaseAndGet) {
|
||||||
|
int frees = 0;
|
||||||
|
FreeMe *allocated = new FreeMe(&frees);
|
||||||
|
FreeMe *released = NULL;
|
||||||
|
{
|
||||||
|
scoped_ptr<FreeMe> scoped(allocated);
|
||||||
|
EXPECT_EQ(0, frees);
|
||||||
|
EXPECT_EQ(allocated, scoped.get());
|
||||||
|
released = scoped.release();
|
||||||
|
EXPECT_EQ(0, frees);
|
||||||
|
EXPECT_EQ(released, allocated);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, frees);
|
||||||
|
delete released;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace libmv
|
223
extern/libmv/libmv/base/vector_test.cc
vendored
Normal file
223
extern/libmv/libmv/base/vector_test.cc
vendored
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
// This uses a Vec2d which is a fixed-size vectorizable Eigen type. It is
|
||||||
|
// necessary to test vectorizable types to ensure that the alignment asserts
|
||||||
|
// trigger if the alignment is not correct.
|
||||||
|
TEST(VectorAlignmentTest, PushBack) {
|
||||||
|
Vec2 x1, x2;
|
||||||
|
x1 << 1, 2;
|
||||||
|
x2 << 3, 4;
|
||||||
|
|
||||||
|
vector<Vec2> vs;
|
||||||
|
vs.push_back(x1);
|
||||||
|
EXPECT_EQ(1, vs.size());
|
||||||
|
EXPECT_EQ(1, vs.capacity());
|
||||||
|
|
||||||
|
vs.push_back(x2);
|
||||||
|
EXPECT_EQ(2, vs.size());
|
||||||
|
EXPECT_EQ(2, vs.capacity());
|
||||||
|
|
||||||
|
// The following is necessary because of some bug in gtest; the expected
|
||||||
|
// parameter can't be a fixed size vectorizable type with alignment
|
||||||
|
// requirements.
|
||||||
|
Vec x1r = x1;
|
||||||
|
Vec x2r = x2;
|
||||||
|
EXPECT_EQ(x1r, vs[0]);
|
||||||
|
EXPECT_EQ(x2r, vs[1]);
|
||||||
|
|
||||||
|
vs.push_back(x2);
|
||||||
|
vs.push_back(x2);
|
||||||
|
vs.push_back(x2);
|
||||||
|
EXPECT_EQ(5, vs.size());
|
||||||
|
EXPECT_EQ(8, vs.capacity());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count the number of destruct calls to test that the destructor gets called.
|
||||||
|
int foo_construct_calls = 0;
|
||||||
|
int foo_destruct_calls = 0;
|
||||||
|
|
||||||
|
struct Foo {
|
||||||
|
public:
|
||||||
|
Foo() : value(5) { foo_construct_calls++; }
|
||||||
|
~Foo() { foo_destruct_calls++; }
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VectorTest : public testing::Test {
|
||||||
|
VectorTest() {
|
||||||
|
foo_construct_calls = 0;
|
||||||
|
foo_destruct_calls = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(VectorTest, EmptyVectorDoesNotConstruct) {
|
||||||
|
{
|
||||||
|
vector<Foo> v;
|
||||||
|
EXPECT_EQ(0, v.size());
|
||||||
|
EXPECT_EQ(0, v.capacity());
|
||||||
|
}
|
||||||
|
EXPECT_EQ(0, foo_construct_calls);
|
||||||
|
EXPECT_EQ(0, foo_destruct_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, DestructorGetsCalled) {
|
||||||
|
{
|
||||||
|
vector<Foo> v;
|
||||||
|
v.resize(5);
|
||||||
|
}
|
||||||
|
EXPECT_EQ(5, foo_construct_calls);
|
||||||
|
EXPECT_EQ(5, foo_destruct_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, ReserveDoesNotCallConstructorsOrDestructors) {
|
||||||
|
vector<Foo> v;
|
||||||
|
EXPECT_EQ(0, v.size());
|
||||||
|
EXPECT_EQ(0, v.capacity());
|
||||||
|
EXPECT_EQ(0, foo_construct_calls);
|
||||||
|
EXPECT_EQ(0, foo_destruct_calls);
|
||||||
|
|
||||||
|
v.reserve(5);
|
||||||
|
EXPECT_EQ(0, v.size());
|
||||||
|
EXPECT_EQ(5, v.capacity());
|
||||||
|
EXPECT_EQ(0, foo_construct_calls);
|
||||||
|
EXPECT_EQ(0, foo_destruct_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, ResizeConstructsAndDestructsAsExpected) {
|
||||||
|
vector<Foo> v;
|
||||||
|
|
||||||
|
// Create one object.
|
||||||
|
v.resize(1);
|
||||||
|
EXPECT_EQ(1, v.size());
|
||||||
|
EXPECT_EQ(1, v.capacity());
|
||||||
|
EXPECT_EQ(1, foo_construct_calls);
|
||||||
|
EXPECT_EQ(0, foo_destruct_calls);
|
||||||
|
EXPECT_EQ(5, v[0].value);
|
||||||
|
|
||||||
|
// Create two more.
|
||||||
|
v.resize(3);
|
||||||
|
EXPECT_EQ(3, v.size());
|
||||||
|
EXPECT_EQ(3, v.capacity());
|
||||||
|
EXPECT_EQ(3, foo_construct_calls);
|
||||||
|
EXPECT_EQ(0, foo_destruct_calls);
|
||||||
|
|
||||||
|
// Delete the last one.
|
||||||
|
v.resize(2);
|
||||||
|
EXPECT_EQ(2, v.size());
|
||||||
|
EXPECT_EQ(3, v.capacity());
|
||||||
|
EXPECT_EQ(3, foo_construct_calls);
|
||||||
|
EXPECT_EQ(1, foo_destruct_calls);
|
||||||
|
|
||||||
|
// Delete the remaining two.
|
||||||
|
v.resize(0);
|
||||||
|
EXPECT_EQ(0, v.size());
|
||||||
|
EXPECT_EQ(3, v.capacity());
|
||||||
|
EXPECT_EQ(3, foo_construct_calls);
|
||||||
|
EXPECT_EQ(3, foo_destruct_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, PushPopBack) {
|
||||||
|
vector<Foo> v;
|
||||||
|
|
||||||
|
Foo foo;
|
||||||
|
foo.value = 10;
|
||||||
|
v.push_back(foo);
|
||||||
|
EXPECT_EQ(1, v.size());
|
||||||
|
EXPECT_EQ(10, v.back().value);
|
||||||
|
|
||||||
|
v.pop_back();
|
||||||
|
EXPECT_EQ(0, v.size());
|
||||||
|
EXPECT_EQ(1, foo_construct_calls);
|
||||||
|
EXPECT_EQ(1, foo_destruct_calls);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, CopyConstructor) {
|
||||||
|
vector<int> a;
|
||||||
|
a.push_back(1);
|
||||||
|
a.push_back(5);
|
||||||
|
a.push_back(3);
|
||||||
|
|
||||||
|
vector<int> b(a);
|
||||||
|
EXPECT_EQ(a.size(), b.size());
|
||||||
|
//EXPECT_EQ(a.capacity(), b.capacity());
|
||||||
|
for (int i = 0; i < a.size(); ++i) {
|
||||||
|
EXPECT_EQ(a[i], b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, OperatorEquals) {
|
||||||
|
vector<int> a, b;
|
||||||
|
a.push_back(1);
|
||||||
|
a.push_back(5);
|
||||||
|
a.push_back(3);
|
||||||
|
|
||||||
|
b = a;
|
||||||
|
|
||||||
|
EXPECT_EQ(a.size(), b.size());
|
||||||
|
//EXPECT_EQ(a.capacity(), b.capacity());
|
||||||
|
for (int i = 0; i < a.size(); ++i) {
|
||||||
|
EXPECT_EQ(a[i], b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorTest, STLFind) {
|
||||||
|
vector<int> a;
|
||||||
|
a.push_back(1);
|
||||||
|
a.push_back(5);
|
||||||
|
a.push_back(3);
|
||||||
|
|
||||||
|
// Find return an int *
|
||||||
|
EXPECT_EQ(std::find(&a[0], &a[2], 1) == &a[0], true);
|
||||||
|
EXPECT_EQ(std::find(&a[0], &a[2], 5) == &a[1], true);
|
||||||
|
EXPECT_EQ(std::find(&a[0], &a[2], 3) == &a[2], true);
|
||||||
|
|
||||||
|
// Find return a const int *
|
||||||
|
EXPECT_EQ(std::find(a.begin(), a.end(), 1) == &a[0], true);
|
||||||
|
EXPECT_EQ(std::find(a.begin(), a.end(), 5) == &a[1], true);
|
||||||
|
EXPECT_EQ(std::find(a.begin(), a.end(), 3) == &a[2], true);
|
||||||
|
|
||||||
|
// Search value that are not in the vector
|
||||||
|
EXPECT_EQ(std::find(a.begin(), a.end(), 0) == a.end(), true);
|
||||||
|
EXPECT_EQ(std::find(a.begin(), a.end(), 52) == a.end(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Vector, swap) {
|
||||||
|
vector<int> a, b;
|
||||||
|
a.push_back(1);
|
||||||
|
a.push_back(2);
|
||||||
|
b.push_back(3);
|
||||||
|
a.swap(b);
|
||||||
|
EXPECT_EQ(1, a.size());
|
||||||
|
EXPECT_EQ(3, a[0]);
|
||||||
|
EXPECT_EQ(2, b.size());
|
||||||
|
EXPECT_EQ(1, b[0]);
|
||||||
|
EXPECT_EQ(2, b[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
324
extern/libmv/libmv/image/array_nd_test.cc
vendored
Normal file
324
extern/libmv/libmv/image/array_nd_test.cc
vendored
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/image/array_nd.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using libmv::ArrayND;
|
||||||
|
using libmv::Array3D;
|
||||||
|
using libmv::Array3Df;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(ArrayND, EmptyConstructor) {
|
||||||
|
ArrayND<int, 2> a;
|
||||||
|
|
||||||
|
EXPECT_EQ(0, a.Shape(0));
|
||||||
|
EXPECT_EQ(0, a.Shape(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, IndexConstructor) {
|
||||||
|
int s[] = {1, 2, 3};
|
||||||
|
ArrayND<int, 3>::Index shape(s);
|
||||||
|
ArrayND<int, 3> a(shape);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a.Shape(0));
|
||||||
|
EXPECT_EQ(2, a.Shape(1));
|
||||||
|
EXPECT_EQ(3, a.Shape(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, PointerConstructor) {
|
||||||
|
int s[] = {1, 2, 3};
|
||||||
|
ArrayND<int, 3> a(s);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a.Shape(0));
|
||||||
|
EXPECT_EQ(2, a.Shape(1));
|
||||||
|
EXPECT_EQ(3, a.Shape(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, CopyConstructor) {
|
||||||
|
int s[] = {1, 2, 3};
|
||||||
|
ArrayND<int, 3> a(s);
|
||||||
|
a(0, 1, 1) = 3;
|
||||||
|
a(0, 1, 2) = 3;
|
||||||
|
ArrayND<int, 3> b(a);
|
||||||
|
EXPECT_EQ(1, b.Shape(0));
|
||||||
|
EXPECT_EQ(2, b.Shape(1));
|
||||||
|
EXPECT_EQ(3, b.Shape(2));
|
||||||
|
EXPECT_EQ(3, b(0, 1, 1));
|
||||||
|
b(0, 1, 2) = 2;
|
||||||
|
EXPECT_EQ(3, a(0, 1, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, Assignation) {
|
||||||
|
int s[] = {1, 2, 3};
|
||||||
|
ArrayND<int, 3> a(s);
|
||||||
|
a(0, 1, 1) = 3;
|
||||||
|
a(0, 1, 2) = 3;
|
||||||
|
ArrayND<int, 3> b;
|
||||||
|
b = a;
|
||||||
|
EXPECT_EQ(1, b.Shape(0));
|
||||||
|
EXPECT_EQ(2, b.Shape(1));
|
||||||
|
EXPECT_EQ(3, b.Shape(2));
|
||||||
|
EXPECT_EQ(3, b(0, 1, 1));
|
||||||
|
b(0, 1, 2) = 2;
|
||||||
|
EXPECT_EQ(3, a(0, 1, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, Fill) {
|
||||||
|
int s[] = {2, 2};
|
||||||
|
ArrayND<int, 2> a(s);
|
||||||
|
a.Fill(42);
|
||||||
|
EXPECT_EQ(42, a(0, 0));
|
||||||
|
EXPECT_EQ(42, a(0, 1));
|
||||||
|
EXPECT_EQ(42, a(1, 0));
|
||||||
|
EXPECT_EQ(42, a(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, Size) {
|
||||||
|
int s[] = {1, 2, 3};
|
||||||
|
ArrayND<int, 3>::Index shape(s);
|
||||||
|
ArrayND<int, 3> a(shape);
|
||||||
|
|
||||||
|
int l[] = {0, 1, 2};
|
||||||
|
ArrayND<int, 3>::Index last(l);
|
||||||
|
|
||||||
|
EXPECT_EQ(a.Size(), a.Offset(last)+1);
|
||||||
|
EXPECT_TRUE(a.Contains(last));
|
||||||
|
EXPECT_FALSE(a.Contains(shape));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, MemorySizeInBytes) {
|
||||||
|
int s[] = {2, 3};
|
||||||
|
ArrayND<int, 2>::Index shape(s);
|
||||||
|
ArrayND<int, 2> a(shape);
|
||||||
|
|
||||||
|
int size = 24 + sizeof(a);
|
||||||
|
EXPECT_EQ(size, a.MemorySizeInBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, Parenthesis) {
|
||||||
|
typedef ArrayND<int, 2>::Index Index;
|
||||||
|
|
||||||
|
int s[] = {3, 3};
|
||||||
|
ArrayND<int, 2> a(s);
|
||||||
|
|
||||||
|
*(a.Data()+0) = 0;
|
||||||
|
*(a.Data()+5) = 5;
|
||||||
|
|
||||||
|
int i1[] = {0, 0};
|
||||||
|
EXPECT_EQ(0, a(Index(i1)));
|
||||||
|
int i2[] = {1, 2};
|
||||||
|
EXPECT_EQ(5, a(Index(i2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 1DConstructor) {
|
||||||
|
ArrayND<int, 1> a(3);
|
||||||
|
|
||||||
|
EXPECT_EQ(3, a.Shape(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 2DConstructor) {
|
||||||
|
ArrayND<int, 2> a(1, 2);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a.Shape(0));
|
||||||
|
EXPECT_EQ(2, a.Shape(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 3DConstructor) {
|
||||||
|
ArrayND<int, 3> a(1, 2, 3);
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a.Shape(0));
|
||||||
|
EXPECT_EQ(2, a.Shape(1));
|
||||||
|
EXPECT_EQ(3, a.Shape(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 1DAccessor) {
|
||||||
|
ArrayND<int, 1> a(3);
|
||||||
|
a(0) = 1;
|
||||||
|
a(1) = 2;
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a(0));
|
||||||
|
EXPECT_EQ(2, a(1));
|
||||||
|
EXPECT_EQ(1, *(a.Data()));
|
||||||
|
EXPECT_EQ(2, *(a.Data() + a.Stride(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 2DAccessor) {
|
||||||
|
ArrayND<int, 2> a(3, 3);
|
||||||
|
a(0, 0) = 1;
|
||||||
|
a(1, 1) = 2;
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a(0, 0));
|
||||||
|
EXPECT_EQ(2, a(1, 1));
|
||||||
|
EXPECT_EQ(1, *(a.Data()));
|
||||||
|
EXPECT_EQ(2, *(a.Data() + a.Stride(0) + a.Stride(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, 3DAccessor) {
|
||||||
|
ArrayND<int, 3> a(3, 3, 3);
|
||||||
|
a(0, 0, 0) = 1;
|
||||||
|
a(1, 1, 1) = 2;
|
||||||
|
|
||||||
|
EXPECT_EQ(1, a(0, 0, 0));
|
||||||
|
EXPECT_EQ(2, a(1, 1, 1));
|
||||||
|
EXPECT_EQ(1, *(a.Data()));
|
||||||
|
EXPECT_EQ(2, *(a.Data() + a.Stride(0) + a.Stride(1) + a.Stride(2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, CopyFrom) {
|
||||||
|
ArrayND<int, 3> a(2, 2, 1);
|
||||||
|
a(0, 0, 0) = 1;
|
||||||
|
a(0, 1, 0) = 2;
|
||||||
|
a(1, 0, 0) = 3;
|
||||||
|
a(1, 1, 0) = 4;
|
||||||
|
ArrayND<float, 3> b;
|
||||||
|
b.CopyFrom(a);
|
||||||
|
EXPECT_FLOAT_EQ(1.f, b(0, 0, 0));
|
||||||
|
EXPECT_FLOAT_EQ(2.f, b(0, 1, 0));
|
||||||
|
EXPECT_FLOAT_EQ(3.f, b(1, 0, 0));
|
||||||
|
EXPECT_FLOAT_EQ(4.f, b(1, 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, MultiplyElements) {
|
||||||
|
ArrayND<int, 3> a(2, 2, 1);
|
||||||
|
a(0, 0, 0) = 1;
|
||||||
|
a(0, 1, 0) = 2;
|
||||||
|
a(1, 0, 0) = 3;
|
||||||
|
a(1, 1, 0) = 4;
|
||||||
|
ArrayND<int, 3> b(2, 2, 1);
|
||||||
|
b(0, 0, 0) = 6;
|
||||||
|
b(0, 1, 0) = 5;
|
||||||
|
b(1, 0, 0) = 4;
|
||||||
|
b(1, 1, 0) = 3;
|
||||||
|
ArrayND<int, 3> c;
|
||||||
|
MultiplyElements(a, b, &c);
|
||||||
|
EXPECT_FLOAT_EQ(6, c(0, 0, 0));
|
||||||
|
EXPECT_FLOAT_EQ(10, c(0, 1, 0));
|
||||||
|
EXPECT_FLOAT_EQ(12, c(1, 0, 0));
|
||||||
|
EXPECT_FLOAT_EQ(12, c(1, 1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, IsEqualOperator) {
|
||||||
|
ArrayND<int, 3> a(2, 2, 1);
|
||||||
|
a(0, 0, 0) = 1;
|
||||||
|
a(0, 1, 0) = 2;
|
||||||
|
a(1, 0, 0) = 3;
|
||||||
|
a(1, 1, 0) = 4;
|
||||||
|
ArrayND<int, 3> b(2, 2, 1);
|
||||||
|
b(0, 0, 0) = 1;
|
||||||
|
b(0, 1, 0) = 2;
|
||||||
|
b(1, 0, 0) = 3;
|
||||||
|
b(1, 1, 0) = 4;
|
||||||
|
EXPECT_TRUE(a == b);
|
||||||
|
EXPECT_FALSE(a != b);
|
||||||
|
b(1, 1, 0) = 5;
|
||||||
|
EXPECT_TRUE(a != b);
|
||||||
|
EXPECT_FALSE(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Array3D, Sizes) {
|
||||||
|
Array3D<int> array;
|
||||||
|
EXPECT_EQ(array.Height(), 0);
|
||||||
|
EXPECT_EQ(array.Width(), 0);
|
||||||
|
EXPECT_EQ(array.Depth(), 0);
|
||||||
|
EXPECT_EQ(array.Shape(0), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Array3D, CopyConstructor) {
|
||||||
|
Array3D<int> array(10, 10);
|
||||||
|
array(0, 0) = 1;
|
||||||
|
array(0, 1) = 1;
|
||||||
|
Array3D<int> copy(array);
|
||||||
|
EXPECT_EQ(copy.Height(), 10);
|
||||||
|
EXPECT_EQ(copy.Width(), 10);
|
||||||
|
EXPECT_EQ(copy.Depth(), 1);
|
||||||
|
EXPECT_EQ(copy(0, 0), 1);
|
||||||
|
copy(0, 1) = 2;
|
||||||
|
EXPECT_EQ(array(0, 1), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Array3D, Assignation) {
|
||||||
|
Array3D<int> array(10, 10);
|
||||||
|
array(0, 0) = 1;
|
||||||
|
array(0, 1) = 1;
|
||||||
|
Array3D<int> copy;
|
||||||
|
copy = array;
|
||||||
|
EXPECT_EQ(copy.Height(), 10);
|
||||||
|
EXPECT_EQ(copy.Width(), 10);
|
||||||
|
EXPECT_EQ(copy.Depth(), 1);
|
||||||
|
EXPECT_EQ(copy(0, 0), 1);
|
||||||
|
copy(0, 1) = 2;
|
||||||
|
EXPECT_EQ(array(0, 1), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Array3D, Parenthesis) {
|
||||||
|
Array3D<int> array(1, 2, 3);
|
||||||
|
array(0, 1, 0) = 3;
|
||||||
|
EXPECT_EQ(array(0, 1), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Array3Df, SplitChannels) {
|
||||||
|
Array3Df array(1, 2, 3);
|
||||||
|
array(0, 0, 0) = 1;
|
||||||
|
array(0, 1, 0) = 1;
|
||||||
|
array(0, 0, 1) = 2;
|
||||||
|
array(0, 1, 1) = 2;
|
||||||
|
array(0, 0, 2) = 3;
|
||||||
|
array(0, 1, 2) = 3;
|
||||||
|
Array3Df c0, c1, c2;
|
||||||
|
SplitChannels(array, &c0, &c1, &c2);
|
||||||
|
for (int row = 0; row < 1; ++row) {
|
||||||
|
for (int column = 0; column < 2; ++column) {
|
||||||
|
EXPECT_EQ(array(row, column, 0), c0(row, column));
|
||||||
|
EXPECT_EQ(array(row, column, 1), c1(row, column));
|
||||||
|
EXPECT_EQ(array(row, column, 2), c2(row, column));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ArrayND, MultiplyElementsGeneric) {
|
||||||
|
ArrayND<double, 5> A;
|
||||||
|
ArrayND<int, 5> B;
|
||||||
|
ArrayND<double, 5> C;
|
||||||
|
int shape[] = {1, 3, 5, 7, 1};
|
||||||
|
A.Resize(shape);
|
||||||
|
B.Resize(shape);
|
||||||
|
|
||||||
|
A.Fill(1.1);
|
||||||
|
B.Fill(2);
|
||||||
|
MultiplyElements(A, B, &C);
|
||||||
|
|
||||||
|
ArrayND<double, 5>::Index cIndex;
|
||||||
|
for (int d0 = 0; d0 < shape[0]; ++d0)
|
||||||
|
for (int d1 = 0; d1 < shape[1]; ++d1)
|
||||||
|
for (int d2 = 0; d2 < shape[2]; ++d2)
|
||||||
|
for (int d3 = 0; d3 < shape[3]; ++d3)
|
||||||
|
for (int d4 = 0; d4 < shape[4]; ++d4) {
|
||||||
|
cIndex(0) = d0;
|
||||||
|
cIndex(1) = d1;
|
||||||
|
cIndex(2) = d2;
|
||||||
|
cIndex(3) = d3;
|
||||||
|
cIndex(4) = d4;
|
||||||
|
EXPECT_EQ(2.2, C(cIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
110
extern/libmv/libmv/image/convolve_test.cc
vendored
Normal file
110
extern/libmv/libmv/image/convolve_test.cc
vendored
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/image/convolve.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Convolve, ComputeGaussianKernel) {
|
||||||
|
Vec kernel, derivative;
|
||||||
|
ComputeGaussianKernel(1, &kernel, &derivative);
|
||||||
|
EXPECT_EQ(7, kernel.size());
|
||||||
|
// TODO(keir): Put in a more thorough test here!
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, ConvolveGaussian) {
|
||||||
|
FloatImage im(10, 10);
|
||||||
|
im.Fill(1);
|
||||||
|
FloatImage blured;
|
||||||
|
ConvolveGaussian(im, 3, &blured);
|
||||||
|
EXPECT_NEAR(im(5, 5), 1, 1e-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, BoxFilterHorizontal) {
|
||||||
|
FloatImage im(10, 10), convolved, filtered;
|
||||||
|
im.Fill(1);
|
||||||
|
BoxFilterHorizontal(im, 3, &filtered);
|
||||||
|
Vec kernel(3);
|
||||||
|
kernel.setConstant(1.);
|
||||||
|
ConvolveHorizontal(im, kernel, &convolved);
|
||||||
|
EXPECT_EQ(filtered(5, 5), 3);
|
||||||
|
EXPECT_TRUE(filtered == convolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, BoxFilter) {
|
||||||
|
FloatImage image(5, 5), filtered;
|
||||||
|
// A single 1.0 inside a 5x5 image should expand to a 3x3 square.
|
||||||
|
image.Fill(0);
|
||||||
|
image(2, 2) = 1.0;
|
||||||
|
BoxFilter(image, 3, &filtered);
|
||||||
|
for (int j = 0; j < 5; j++) {
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
if (i == 0 || i == 4 || j == 0 || j == 4) {
|
||||||
|
EXPECT_EQ(0.0, filtered(j, i));
|
||||||
|
} else {
|
||||||
|
EXPECT_EQ(1.0, filtered(j, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, BlurredImageAndDerivativesChannelsFlat) {
|
||||||
|
FloatImage im(10, 10), blurred_and_derivatives;
|
||||||
|
im.Fill(1);
|
||||||
|
BlurredImageAndDerivativesChannels(im, 1.0, &blurred_and_derivatives);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 1.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, BlurredImageAndDerivativesChannelsHorizontalSlope) {
|
||||||
|
FloatImage image(10, 10), blurred_and_derivatives;
|
||||||
|
for (int j = 0; j < 10; ++j) {
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
image(j, i) = 2*i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 2.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 0.0, 1e-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Convolve, BlurredImageAndDerivativesChannelsVerticalSlope) {
|
||||||
|
FloatImage image(10, 10), blurred_and_derivatives;
|
||||||
|
for (int j = 0; j < 10; ++j) {
|
||||||
|
for (int i = 0; i < 10; ++i) {
|
||||||
|
image(j, i) = 2*j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlurredImageAndDerivativesChannels(image, 0.9, &blurred_and_derivatives);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 0), 10.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 1), 0.0, 1e-7);
|
||||||
|
EXPECT_NEAR(blurred_and_derivatives(5, 5, 2), 2.0, 1e-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
285
extern/libmv/libmv/image/image_drawing.h
vendored
Normal file
285
extern/libmv/libmv/image/image_drawing.h
vendored
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
// Generic Image Processing Algorithm (GIPA)
|
||||||
|
// Use an ImageModel class that must implement the following :
|
||||||
|
//
|
||||||
|
// ::Contains(int y, int x) <= Tell if a point is inside or not the image
|
||||||
|
// ::operator(int y,int x) <= Modification accessor over the pixel (y,x)
|
||||||
|
// ::Width()
|
||||||
|
// ::Height()
|
||||||
|
|
||||||
|
#ifndef LIBMV_IMAGE_IMAGE_DRAWING_H
|
||||||
|
#define LIBMV_IMAGE_IMAGE_DRAWING_H
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
/// Put the pixel in the image to the given color only if the point (xc,yc)
|
||||||
|
/// is inside the image.
|
||||||
|
template <class Image, class Color>
|
||||||
|
inline void safePutPixel(int yc, int xc, const Color & col, Image *pim) {
|
||||||
|
if (!pim)
|
||||||
|
return;
|
||||||
|
if (pim->Contains(yc, xc)) {
|
||||||
|
(*pim)(yc, xc) = col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Put the pixel in the image to the given color only if the point (xc,yc)
|
||||||
|
/// is inside the image. This function support multi-channel color
|
||||||
|
/// \note The color pointer col must have size as the image depth
|
||||||
|
template <class Image, class Color>
|
||||||
|
inline void safePutPixel(int yc, int xc, const Color *col, Image *pim) {
|
||||||
|
if (!pim)
|
||||||
|
return;
|
||||||
|
if (pim->Contains(yc, xc)) {
|
||||||
|
for (int i = 0; i < pim->Depth(); ++i)
|
||||||
|
(*pim)(yc, xc, i) = *(col + i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham approach to draw ellipse.
|
||||||
|
// http://raphaello.univ-fcomte.fr/ig/algorithme/ExemplesGLUt/BresenhamEllipse.htm
|
||||||
|
// Add the rotation of the ellipse.
|
||||||
|
// As the algo. use symmetry we must use 4 rotations.
|
||||||
|
template <class Image, class Color>
|
||||||
|
void DrawEllipse(int xc, int yc, int radiusA, int radiusB,
|
||||||
|
const Color &col, Image *pim, double angle = 0.0) {
|
||||||
|
int a = radiusA;
|
||||||
|
int b = radiusB;
|
||||||
|
|
||||||
|
// Counter Clockwise rotation matrix.
|
||||||
|
double matXY[4] = { cos(angle), sin(angle),
|
||||||
|
-sin(angle), cos(angle)};
|
||||||
|
int x, y;
|
||||||
|
double d1, d2;
|
||||||
|
x = 0;
|
||||||
|
y = b;
|
||||||
|
d1 = b*b - a*a*b + a*a/4;
|
||||||
|
|
||||||
|
float rotX = (matXY[0] * x + matXY[1] * y);
|
||||||
|
float rotY = (matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x + matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
|
||||||
|
while (a*a*(y-.5) > b*b*(x+1)) {
|
||||||
|
if (d1 < 0) {
|
||||||
|
d1 += b*b*(2*x+3);
|
||||||
|
++x;
|
||||||
|
} else {
|
||||||
|
d1 += b*b*(2*x+3) + a*a*(-2*y+2);
|
||||||
|
++x;
|
||||||
|
--y;
|
||||||
|
}
|
||||||
|
rotX = (matXY[0] * x + matXY[1] * y);
|
||||||
|
rotY = (matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x + matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
}
|
||||||
|
d2 = b*b*(x+.5)*(x+.5) + a*a*(y-1)*(y-1) - a*a*b*b;
|
||||||
|
while (y > 0) {
|
||||||
|
if (d2 < 0) {
|
||||||
|
d2 += b*b*(2*x+2) + a*a*(-2*y+3);
|
||||||
|
--y;
|
||||||
|
++x;
|
||||||
|
} else {
|
||||||
|
d2 += a*a*(-2*y+3);
|
||||||
|
--y;
|
||||||
|
}
|
||||||
|
rotX = (matXY[0] * x + matXY[1] * y);
|
||||||
|
rotY = (matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x - matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x - matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
rotX = (-matXY[0] * x + matXY[1] * y);
|
||||||
|
rotY = (-matXY[2] * x + matXY[3] * y);
|
||||||
|
safePutPixel(yc + rotY, xc + rotX, col, pim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham approach do not allow to draw concentric circle without holes.
|
||||||
|
// So it's better the use the Andres method.
|
||||||
|
// http://fr.wikipedia.org/wiki/Algorithme_de_tracé_de_cercle_d'Andres.
|
||||||
|
template <class Image, class Color>
|
||||||
|
void DrawCircle(int x, int y, int radius, const Color &col, Image *pim) {
|
||||||
|
Image &im = *pim;
|
||||||
|
if ( im.Contains(y + radius, x + radius)
|
||||||
|
|| im.Contains(y + radius, x - radius)
|
||||||
|
|| im.Contains(y - radius, x + radius)
|
||||||
|
|| im.Contains(y - radius, x - radius)) {
|
||||||
|
int x1 = 0;
|
||||||
|
int y1 = radius;
|
||||||
|
int d = radius - 1;
|
||||||
|
while (y1 >= x1) {
|
||||||
|
// Draw the point for each octant.
|
||||||
|
safePutPixel( y1 + y, x1 + x, col, pim);
|
||||||
|
safePutPixel( x1 + y, y1 + x, col, pim);
|
||||||
|
safePutPixel( y1 + y, -x1 + x, col, pim);
|
||||||
|
safePutPixel( x1 + y, -y1 + x, col, pim);
|
||||||
|
safePutPixel(-y1 + y, x1 + x, col, pim);
|
||||||
|
safePutPixel(-x1 + y, y1 + x, col, pim);
|
||||||
|
safePutPixel(-y1 + y, -x1 + x, col, pim);
|
||||||
|
safePutPixel(-x1 + y, -y1 + x, col, pim);
|
||||||
|
if (d >= 2 * x1) {
|
||||||
|
d = d - 2 * x1 - 1;
|
||||||
|
x1 += 1;
|
||||||
|
} else {
|
||||||
|
if (d <= 2 * (radius - y1)) {
|
||||||
|
d = d + 2 * y1 - 1;
|
||||||
|
y1 -= 1;
|
||||||
|
} else {
|
||||||
|
d = d + 2 * (y1 - x1 - 1);
|
||||||
|
y1 -= 1;
|
||||||
|
x1 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham algorithm
|
||||||
|
template <class Image, class Color>
|
||||||
|
void DrawLine(int xa, int ya, int xb, int yb, const Color &col, Image *pim) {
|
||||||
|
Image &im = *pim;
|
||||||
|
|
||||||
|
// If one point is outside the image
|
||||||
|
// Replace the outside point by the intersection of the line and
|
||||||
|
// the limit (either x=width or y=height).
|
||||||
|
if (!im.Contains(ya, xa) || !im.Contains(yb, xb)) {
|
||||||
|
int width = pim->Width();
|
||||||
|
int height = pim->Height();
|
||||||
|
const bool xdir = xa < xb, ydir = ya < yb;
|
||||||
|
float nx0 = xa, nx1 = xb, ny0 = ya, ny1 = yb,
|
||||||
|
&xleft = xdir?nx0:nx1, &yleft = xdir?ny0:ny1,
|
||||||
|
&xright = xdir?nx1:nx0, &yright = xdir?ny1:ny0,
|
||||||
|
&xup = ydir?nx0:nx1, &yup = ydir?ny0:ny1,
|
||||||
|
&xdown = ydir?nx1:nx0, &ydown = ydir?ny1:ny0;
|
||||||
|
|
||||||
|
if (xright < 0 || xleft >= width) return;
|
||||||
|
if (xleft < 0) {
|
||||||
|
yleft -= xleft*(yright - yleft)/(xright - xleft);
|
||||||
|
xleft = 0;
|
||||||
|
}
|
||||||
|
if (xright >= width) {
|
||||||
|
yright -= (xright - width)*(yright - yleft)/(xright - xleft);
|
||||||
|
xright = width - 1;
|
||||||
|
}
|
||||||
|
if (ydown < 0 || yup >= height) return;
|
||||||
|
if (yup < 0) {
|
||||||
|
xup -= yup*(xdown - xup)/(ydown - yup);
|
||||||
|
yup = 0;
|
||||||
|
}
|
||||||
|
if (ydown >= height) {
|
||||||
|
xdown -= (ydown - height)*(xdown - xup)/(ydown - yup);
|
||||||
|
ydown = height - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
xa = (int) xleft;
|
||||||
|
xb = (int) xright;
|
||||||
|
ya = (int) yleft;
|
||||||
|
yb = (int) yright;
|
||||||
|
}
|
||||||
|
|
||||||
|
int xbas, xhaut, ybas, yhaut;
|
||||||
|
// Check the condition ybas < yhaut.
|
||||||
|
if (ya <= yb) {
|
||||||
|
xbas = xa;
|
||||||
|
ybas = ya;
|
||||||
|
xhaut = xb;
|
||||||
|
yhaut = yb;
|
||||||
|
} else {
|
||||||
|
xbas = xb;
|
||||||
|
ybas = yb;
|
||||||
|
xhaut = xa;
|
||||||
|
yhaut = ya;
|
||||||
|
}
|
||||||
|
// Initialize slope.
|
||||||
|
int x, y, dx, dy, incrmX, incrmY, dp, N, S;
|
||||||
|
dx = xhaut - xbas;
|
||||||
|
dy = yhaut - ybas;
|
||||||
|
if (dx > 0) { // If xhaut > xbas we will increment X.
|
||||||
|
incrmX = 1;
|
||||||
|
} else {
|
||||||
|
incrmX = -1; // else we will decrement X.
|
||||||
|
dx *= -1;
|
||||||
|
}
|
||||||
|
if (dy > 0) { // Positive slope will increment X.
|
||||||
|
incrmY = 1;
|
||||||
|
} else { // Negative slope.
|
||||||
|
incrmY = -1;
|
||||||
|
}
|
||||||
|
if (dx >= dy) {
|
||||||
|
dp = 2 * dy - dx;
|
||||||
|
S = 2 * dy;
|
||||||
|
N = 2 * (dy - dx);
|
||||||
|
y = ybas;
|
||||||
|
x = xbas;
|
||||||
|
while (x != xhaut) {
|
||||||
|
safePutPixel(y, x, col, pim);
|
||||||
|
x += incrmX;
|
||||||
|
if (dp <= 0) { // Go in direction of the South Pixel.
|
||||||
|
dp += S;
|
||||||
|
} else { // Go to the North.
|
||||||
|
dp += N;
|
||||||
|
y+=incrmY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dp = 2 * dx - dy;
|
||||||
|
S = 2 * dx;
|
||||||
|
N = 2 * (dx - dy);
|
||||||
|
x = xbas;
|
||||||
|
y = ybas;
|
||||||
|
while (y < yhaut) {
|
||||||
|
safePutPixel(y, x, col, pim);
|
||||||
|
y += incrmY;
|
||||||
|
if (dp <= 0) { // Go in direction of the South Pixel.
|
||||||
|
dp += S;
|
||||||
|
} else { // Go to the North.
|
||||||
|
dp += N;
|
||||||
|
x += incrmX;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
safePutPixel(y, x, col, pim);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_IMAGE_IMAGE_DRAWING_H
|
45
extern/libmv/libmv/image/image_test.cc
vendored
Normal file
45
extern/libmv/libmv/image/image_test.cc
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using libmv::Image;
|
||||||
|
using libmv::Array3Df;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Image, SimpleImageAccessors) {
|
||||||
|
Array3Df *array = new Array3Df(2, 3);
|
||||||
|
Image image(array);
|
||||||
|
EXPECT_EQ(array, image.AsArray3Df());
|
||||||
|
EXPECT_TRUE(NULL == image.AsArray3Du());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Image, MemorySizeInBytes) {
|
||||||
|
Array3Df *array = new Array3Df(2, 3);
|
||||||
|
Image image(array);
|
||||||
|
int size = sizeof(image) + array->MemorySizeInBytes();
|
||||||
|
EXPECT_EQ(size, image.MemorySizeInBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
89
extern/libmv/libmv/image/sample_test.cc
vendored
Normal file
89
extern/libmv/libmv/image/sample_test.cc
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/image/sample.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Image, Nearest) {
|
||||||
|
Array3Du image(2, 2);
|
||||||
|
image(0, 0) = 0;
|
||||||
|
image(0, 1) = 1;
|
||||||
|
image(1, 0) = 2;
|
||||||
|
image(1, 1) = 3;
|
||||||
|
EXPECT_EQ(0, SampleNearest(image, -0.4f, -0.4f));
|
||||||
|
EXPECT_EQ(0, SampleNearest(image, 0.4f, 0.4f));
|
||||||
|
EXPECT_EQ(3, SampleNearest(image, 0.6f, 0.6f));
|
||||||
|
EXPECT_EQ(3, SampleNearest(image, 1.4f, 1.4f));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Image, Linear) {
|
||||||
|
Array3Df image(2, 2);
|
||||||
|
image(0, 0) = 0;
|
||||||
|
image(0, 1) = 1;
|
||||||
|
image(1, 0) = 2;
|
||||||
|
image(1, 1) = 3;
|
||||||
|
EXPECT_EQ(1.5, SampleLinear(image, 0.5, 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Image, DownsampleBy2) {
|
||||||
|
Array3Df image(2, 2);
|
||||||
|
image(0, 0) = 0;
|
||||||
|
image(0, 1) = 1;
|
||||||
|
image(1, 0) = 2;
|
||||||
|
image(1, 1) = 3;
|
||||||
|
Array3Df resampled_image;
|
||||||
|
DownsampleChannelsBy2(image, &resampled_image);
|
||||||
|
ASSERT_EQ(1, resampled_image.Height());
|
||||||
|
ASSERT_EQ(1, resampled_image.Width());
|
||||||
|
ASSERT_EQ(1, resampled_image.Depth());
|
||||||
|
EXPECT_FLOAT_EQ(6./4., resampled_image(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Image, DownsampleBy2MultiChannel) {
|
||||||
|
Array3Df image(2, 2, 3);
|
||||||
|
image(0, 0, 0) = 0;
|
||||||
|
image(0, 1, 0) = 1;
|
||||||
|
image(1, 0, 0) = 2;
|
||||||
|
image(1, 1, 0) = 3;
|
||||||
|
|
||||||
|
image(0, 0, 1) = 5;
|
||||||
|
image(0, 1, 1) = 6;
|
||||||
|
image(1, 0, 1) = 7;
|
||||||
|
image(1, 1, 1) = 8;
|
||||||
|
|
||||||
|
image(0, 0, 2) = 9;
|
||||||
|
image(0, 1, 2) = 10;
|
||||||
|
image(1, 0, 2) = 11;
|
||||||
|
image(1, 1, 2) = 12;
|
||||||
|
|
||||||
|
Array3Df resampled_image;
|
||||||
|
DownsampleChannelsBy2(image, &resampled_image);
|
||||||
|
ASSERT_EQ(1, resampled_image.Height());
|
||||||
|
ASSERT_EQ(1, resampled_image.Width());
|
||||||
|
ASSERT_EQ(3, resampled_image.Depth());
|
||||||
|
EXPECT_FLOAT_EQ((0+1+2+3)/4., resampled_image(0, 0, 0));
|
||||||
|
EXPECT_FLOAT_EQ((5+6+7+8)/4., resampled_image(0, 0, 1));
|
||||||
|
EXPECT_FLOAT_EQ((9+10+11+12)/4., resampled_image(0, 0, 2));
|
||||||
|
}
|
||||||
|
} // namespace
|
83
extern/libmv/libmv/image/tuple_test.cc
vendored
Normal file
83
extern/libmv/libmv/image/tuple_test.cc
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/image/tuple.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
using libmv::Tuple;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Tuple, InitConstantValue) {
|
||||||
|
Tuple<int, 3> t(5);
|
||||||
|
EXPECT_EQ(t(0), 5);
|
||||||
|
EXPECT_EQ(t(0), 5);
|
||||||
|
EXPECT_EQ(t(0), 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Tuple, InitFromPointer) {
|
||||||
|
float vals[3] = {1.0f, 2.0f, 3.0f};
|
||||||
|
|
||||||
|
Tuple<float, 3> t(vals);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
EXPECT_EQ(t(i), vals[i]);
|
||||||
|
|
||||||
|
Tuple<int, 3> b(t);
|
||||||
|
EXPECT_EQ(b(0), int(vals[0]));
|
||||||
|
EXPECT_EQ(b(1), int(vals[1]));
|
||||||
|
EXPECT_EQ(b(2), int(vals[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Tuple, Swap) {
|
||||||
|
unsigned char vala[3] = {1, 2, 3};
|
||||||
|
unsigned char valb[3] = {4, 5, 6};
|
||||||
|
|
||||||
|
Tuple<unsigned char, 3> a(vala);
|
||||||
|
Tuple<unsigned char, 3> b(valb);
|
||||||
|
|
||||||
|
std::swap(a, b);
|
||||||
|
|
||||||
|
EXPECT_EQ(a(0), int(valb[0]));
|
||||||
|
EXPECT_EQ(a(1), int(valb[1]));
|
||||||
|
EXPECT_EQ(a(2), int(valb[2]));
|
||||||
|
EXPECT_EQ(b(0), int(vala[0]));
|
||||||
|
EXPECT_EQ(b(1), int(vala[1]));
|
||||||
|
EXPECT_EQ(b(2), int(vala[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Tuple, IsEqualOperator) {
|
||||||
|
Tuple<int, 3> a;
|
||||||
|
a(0) = 1;
|
||||||
|
a(1) = 2;
|
||||||
|
a(2) = 3;
|
||||||
|
Tuple<int, 3> b;
|
||||||
|
b(0) = 1;
|
||||||
|
b(1) = 2;
|
||||||
|
b(2) = 3;
|
||||||
|
EXPECT_TRUE(a == b);
|
||||||
|
EXPECT_FALSE(a != b);
|
||||||
|
b(1) = 5;
|
||||||
|
EXPECT_TRUE(a != b);
|
||||||
|
EXPECT_FALSE(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
237
extern/libmv/libmv/multiview/euclidean_resection_test.cc
vendored
Normal file
237
extern/libmv/libmv/multiview/euclidean_resection_test.cc
vendored
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/multiview/euclidean_resection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using namespace libmv::euclidean_resection;
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
// Generates all necessary inputs and expected outputs for EuclideanResection.
|
||||||
|
void CreateCameraSystem(const Mat3& KK,
|
||||||
|
const Mat3X& x_image,
|
||||||
|
const Vec& X_distances,
|
||||||
|
const Mat3& R_input,
|
||||||
|
const Vec3& T_input,
|
||||||
|
Mat2X *x_camera,
|
||||||
|
Mat3X *X_world,
|
||||||
|
Mat3 *R_expected,
|
||||||
|
Vec3 *T_expected) {
|
||||||
|
int num_points = x_image.cols();
|
||||||
|
|
||||||
|
Mat3X x_unit_cam(3, num_points);
|
||||||
|
x_unit_cam = KK.inverse() * x_image;
|
||||||
|
|
||||||
|
// Create normalized camera coordinates to be used as an input to the PnP
|
||||||
|
// function, instead of using NormalizeColumnVectors(&x_unit_cam).
|
||||||
|
*x_camera = x_unit_cam.block(0, 0, 2, num_points);
|
||||||
|
for (int i = 0; i < num_points; ++i) {
|
||||||
|
x_unit_cam.col(i).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the 3D points in the camera system.
|
||||||
|
Mat X_camera(3, num_points);
|
||||||
|
for (int i = 0; i < num_points; ++i) {
|
||||||
|
X_camera.col(i) = X_distances(i) * x_unit_cam.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the transformation to the camera 3D points
|
||||||
|
Mat translation_matrix(3, num_points);
|
||||||
|
translation_matrix.row(0).setConstant(T_input(0));
|
||||||
|
translation_matrix.row(1).setConstant(T_input(1));
|
||||||
|
translation_matrix.row(2).setConstant(T_input(2));
|
||||||
|
|
||||||
|
*X_world = R_input * X_camera + translation_matrix;
|
||||||
|
|
||||||
|
// Create the expected result for comparison.
|
||||||
|
*R_expected = R_input.transpose();
|
||||||
|
*T_expected = *R_expected * (-T_input);
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(AbsoluteOrientation, QuaternionSolution) {
|
||||||
|
int num_points = 4;
|
||||||
|
Mat X;
|
||||||
|
Mat Xp;
|
||||||
|
X = 100 * Mat::Random(3, num_points);
|
||||||
|
|
||||||
|
// Create a random translation and rotation.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 t_input;
|
||||||
|
t_input.setRandom();
|
||||||
|
t_input = 100 * t_input;
|
||||||
|
|
||||||
|
Mat translation_matrix(3, num_points);
|
||||||
|
translation_matrix.row(0).setConstant(t_input(0));
|
||||||
|
translation_matrix.row(1).setConstant(t_input(1));
|
||||||
|
translation_matrix.row(2).setConstant(t_input(2));
|
||||||
|
|
||||||
|
// Create the transformed 3D points Xp as Xp = R * X + t.
|
||||||
|
Xp = R_input * X + translation_matrix;
|
||||||
|
|
||||||
|
// Output variables.
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
|
||||||
|
AbsoluteOrientation(X, Xp, &R, &t);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(t, t_input, 1e-6);
|
||||||
|
EXPECT_MATRIX_NEAR(R, R_input, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
|
||||||
|
// In this test only the translation and rotation are random. The image
|
||||||
|
// points are selected from a real case and are well conditioned.
|
||||||
|
Vec2i image_dimensions;
|
||||||
|
image_dimensions << 1600, 1200;
|
||||||
|
|
||||||
|
Mat3 KK;
|
||||||
|
KK << 2796, 0, 804,
|
||||||
|
0 , 2796, 641,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
// The real image points.
|
||||||
|
int num_points = 4;
|
||||||
|
Mat3X x_image(3, num_points);
|
||||||
|
x_image << 1164.06, 734.948, 749.599, 430.727,
|
||||||
|
681.386, 844.59, 496.315, 580.775,
|
||||||
|
1, 1, 1, 1;
|
||||||
|
|
||||||
|
|
||||||
|
// A vector of the 4 distances to the 3D points.
|
||||||
|
Vec X_distances = 100 * Vec::Random(num_points).array().abs();
|
||||||
|
|
||||||
|
// Create the random camera motion R and t that resection should recover.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 T_input;
|
||||||
|
T_input.setRandom();
|
||||||
|
T_input = 100 * T_input;
|
||||||
|
|
||||||
|
// Create the camera system, also getting the expected result of the
|
||||||
|
// transformation.
|
||||||
|
Mat3 R_expected;
|
||||||
|
Vec3 T_expected;
|
||||||
|
Mat3X X_world;
|
||||||
|
Mat2X x_camera;
|
||||||
|
CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
|
||||||
|
&x_camera, &X_world, &R_expected, &T_expected);
|
||||||
|
|
||||||
|
// Finally, run the code under test.
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_ANSAR_DANIILIDIS);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
|
||||||
|
// For now, the EPnP doesn't have a non-linear optimization step and so is
|
||||||
|
// not precise enough with only 4 points.
|
||||||
|
//
|
||||||
|
// TODO(jmichot): Reenable this test when there is nonlinear refinement.
|
||||||
|
#if 0
|
||||||
|
R_output.setIdentity();
|
||||||
|
T_output.setZero();
|
||||||
|
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_EPNP);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jmichot): Reduce the code duplication here with the code above.
|
||||||
|
TEST(EuclideanResection, Points6AllRandomInput) {
|
||||||
|
Mat3 KK;
|
||||||
|
KK << 2796, 0, 804,
|
||||||
|
0 , 2796, 641,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
// Create random image points for a 1600x1200 image.
|
||||||
|
int w = 1600;
|
||||||
|
int h = 1200;
|
||||||
|
int num_points = 6;
|
||||||
|
Mat3X x_image(3, num_points);
|
||||||
|
x_image.row(0) = w * Vec::Random(num_points).array().abs();
|
||||||
|
x_image.row(1) = h * Vec::Random(num_points).array().abs();
|
||||||
|
x_image.row(2).setOnes();
|
||||||
|
|
||||||
|
// Normalized camera coordinates to be used as an input to the PnP function.
|
||||||
|
Mat2X x_camera;
|
||||||
|
Vec X_distances = 100 * Vec::Random(num_points).array().abs();
|
||||||
|
|
||||||
|
// Create the random camera motion R and t that resection should recover.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 T_input;
|
||||||
|
T_input.setRandom();
|
||||||
|
T_input = 100 * T_input;
|
||||||
|
|
||||||
|
// Create the camera system.
|
||||||
|
Mat3 R_expected;
|
||||||
|
Vec3 T_expected;
|
||||||
|
Mat3X X_world;
|
||||||
|
CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
|
||||||
|
&x_camera, &X_world, &R_expected, &T_expected);
|
||||||
|
|
||||||
|
// Test each of the resection methods.
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_ANSAR_DANIILIDIS);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_EPNP);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_image, X_world, KK,
|
||||||
|
&R_output, &T_output);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
}
|
162
extern/libmv/libmv/multiview/fundamental_test.cc
vendored
Normal file
162
extern/libmv/libmv/multiview/fundamental_test.cc
vendored
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/conditioning.h"
|
||||||
|
#include "libmv/multiview/fundamental.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/test_data_sets.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
TEST(Fundamental, FundamentalFromProjections) {
|
||||||
|
Mat34 P1_gt, P2_gt;
|
||||||
|
P1_gt << 1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
P2_gt << 1, 1, 1, 3,
|
||||||
|
0, 2, 0, 3,
|
||||||
|
0, 1, 1, 0;
|
||||||
|
Mat3 F_gt;
|
||||||
|
FundamentalFromProjections(P1_gt, P2_gt, &F_gt);
|
||||||
|
|
||||||
|
Mat34 P1, P2;
|
||||||
|
ProjectionsFromFundamental(F_gt, &P1, &P2);
|
||||||
|
|
||||||
|
Mat3 F;
|
||||||
|
FundamentalFromProjections(P1, P2, &F);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_PROP(F_gt, F, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Fundamental, PreconditionerFromPoints) {
|
||||||
|
int n = 4;
|
||||||
|
Mat points(2, n);
|
||||||
|
points << 0, 0, 1, 1,
|
||||||
|
0, 2, 1, 3;
|
||||||
|
|
||||||
|
Mat3 T;
|
||||||
|
PreconditionerFromPoints(points, &T);
|
||||||
|
|
||||||
|
Mat normalized_points;
|
||||||
|
ApplyTransformationToPoints(points, T, &normalized_points);
|
||||||
|
|
||||||
|
Vec mean, variance;
|
||||||
|
MeanAndVarianceAlongRows(normalized_points, &mean, &variance);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0, mean(0), 1e-8);
|
||||||
|
EXPECT_NEAR(0, mean(1), 1e-8);
|
||||||
|
EXPECT_NEAR(2, variance(0), 1e-8);
|
||||||
|
EXPECT_NEAR(2, variance(1), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Fundamental, EssentialFromFundamental) {
|
||||||
|
TwoViewDataSet d = TwoRealisticCameras();
|
||||||
|
|
||||||
|
Mat3 E_from_Rt;
|
||||||
|
EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E_from_Rt);
|
||||||
|
|
||||||
|
Mat3 E_from_F;
|
||||||
|
EssentialFromFundamental(d.F, d.K1, d.K2, &E_from_F);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_PROP(E_from_Rt, E_from_F, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Fundamental, MotionFromEssential) {
|
||||||
|
TwoViewDataSet d = TwoRealisticCameras();
|
||||||
|
|
||||||
|
Mat3 E;
|
||||||
|
EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E);
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t);
|
||||||
|
NormalizeL2(&t);
|
||||||
|
|
||||||
|
std::vector<Mat3> Rs;
|
||||||
|
std::vector<Vec3> ts;
|
||||||
|
MotionFromEssential(E, &Rs, &ts);
|
||||||
|
bool one_solution_is_correct = false;
|
||||||
|
for (size_t i = 0; i < Rs.size(); ++i) {
|
||||||
|
if (FrobeniusDistance(Rs[i], R) < 1e-8 && DistanceL2(ts[i], t) < 1e-8) {
|
||||||
|
one_solution_is_correct = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(one_solution_is_correct);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Fundamental, MotionFromEssentialChooseSolution) {
|
||||||
|
TwoViewDataSet d = TwoRealisticCameras();
|
||||||
|
|
||||||
|
Mat3 E;
|
||||||
|
EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E);
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t);
|
||||||
|
NormalizeL2(&t);
|
||||||
|
|
||||||
|
std::vector<Mat3> Rs;
|
||||||
|
std::vector<Vec3> ts;
|
||||||
|
MotionFromEssential(E, &Rs, &ts);
|
||||||
|
|
||||||
|
Vec2 x1, x2;
|
||||||
|
MatrixColumn(d.x1, 0, &x1);
|
||||||
|
MatrixColumn(d.x2, 0, &x2);
|
||||||
|
int solution = MotionFromEssentialChooseSolution(Rs, ts, d.K1, x1, d.K2, x2);
|
||||||
|
|
||||||
|
EXPECT_LE(0, solution);
|
||||||
|
EXPECT_LE(solution, 3);
|
||||||
|
EXPECT_LE(FrobeniusDistance(Rs[solution], R), 1e-8);
|
||||||
|
EXPECT_LE(DistanceL2(ts[solution], t), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Fundamental, MotionFromEssentialAndCorrespondence) {
|
||||||
|
TwoViewDataSet d = TwoRealisticCameras();
|
||||||
|
|
||||||
|
Mat3 E;
|
||||||
|
EssentialFromRt(d.R1, d.t1, d.R2, d.t2, &E);
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
RelativeCameraMotion(d.R1, d.t1, d.R2, d.t2, &R, &t);
|
||||||
|
NormalizeL2(&t);
|
||||||
|
|
||||||
|
Vec2 x1, x2;
|
||||||
|
MatrixColumn(d.x1, 0, &x1);
|
||||||
|
MatrixColumn(d.x2, 0, &x2);
|
||||||
|
|
||||||
|
Mat3 R_estimated;
|
||||||
|
Vec3 t_estimated;
|
||||||
|
MotionFromEssentialAndCorrespondence(E, d.K1, x1, d.K2, x2,
|
||||||
|
&R_estimated, &t_estimated);
|
||||||
|
|
||||||
|
EXPECT_LE(FrobeniusDistance(R_estimated, R), 1e-8);
|
||||||
|
EXPECT_LE(DistanceL2(t_estimated, t), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
248
extern/libmv/libmv/multiview/homography_error.h
vendored
Normal file
248
extern/libmv/libmv/multiview/homography_error.h
vendored
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_
|
||||||
|
#define LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_
|
||||||
|
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace homography {
|
||||||
|
namespace homography2D {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for estimating the asymmetric error between a vector x2 and the
|
||||||
|
* transformed x1 such that
|
||||||
|
* Error = ||x2 - Psi(H * x1)||^2
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
* \note It should be distributed as Chi-squared with k = 2.
|
||||||
|
*/
|
||||||
|
struct AsymmetricError {
|
||||||
|
/**
|
||||||
|
* Computes the asymmetric residuals between a set of 2D points x2 and the
|
||||||
|
* transformed 2D point set x1 such that
|
||||||
|
* Residuals_i = x2_i - Psi(H * x1_i)
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[out] dx A 2xN matrix of column vectors of residuals errors
|
||||||
|
*/
|
||||||
|
static void Residuals(const Mat &H, const Mat &x1,
|
||||||
|
const Mat &x2, Mat2X *dx) {
|
||||||
|
dx->resize(2, x1.cols());
|
||||||
|
Mat3X x2h_est;
|
||||||
|
if (x1.rows() == 2)
|
||||||
|
x2h_est = H * EuclideanToHomogeneous(static_cast<Mat2X>(x1));
|
||||||
|
else
|
||||||
|
x2h_est = H * x1;
|
||||||
|
dx->row(0) = x2h_est.row(0).array() / x2h_est.row(2).array();
|
||||||
|
dx->row(1) = x2h_est.row(1).array() / x2h_est.row(2).array();
|
||||||
|
if (x2.rows() == 2)
|
||||||
|
*dx = x2 - *dx;
|
||||||
|
else
|
||||||
|
*dx = HomogeneousToEuclidean(static_cast<Mat3X>(x2)) - *dx;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the asymmetric residuals between a 2D point x2 and the transformed
|
||||||
|
* 2D point x1 such that
|
||||||
|
* Residuals = x2 - Psi(H * x1)
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[out] dx A vector of size 2 of the residual error
|
||||||
|
*/
|
||||||
|
static void Residuals(const Mat &H, const Vec &x1,
|
||||||
|
const Vec &x2, Vec2 *dx) {
|
||||||
|
Vec3 x2h_est;
|
||||||
|
if (x1.rows() == 2)
|
||||||
|
x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1));
|
||||||
|
else
|
||||||
|
x2h_est = H * x1;
|
||||||
|
if (x2.rows() == 2)
|
||||||
|
*dx = x2 - x2h_est.head<2>() / x2h_est[2];
|
||||||
|
else
|
||||||
|
*dx = HomogeneousToEuclidean(static_cast<Vec3>(x2)) -
|
||||||
|
x2h_est.head<2>() / x2h_est[2];
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the squared norm of the residuals between a set of 2D points x2
|
||||||
|
* and the transformed 2D point set x1 such that
|
||||||
|
* Error = || x2 - Psi(H * x1) ||^2
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \return The squared norm of the asymmetric residuals errors
|
||||||
|
*/
|
||||||
|
static double Error(const Mat &H, const Mat &x1, const Mat &x2) {
|
||||||
|
Mat2X dx;
|
||||||
|
Residuals(H, x1, x2, &dx);
|
||||||
|
return dx.squaredNorm();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the squared norm of the residuals between a 2D point x2 and the
|
||||||
|
* transformed 2D point x1 such that rms = || x2 - Psi(H * x1) ||^2
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \return The squared norm of the asymmetric residual error
|
||||||
|
*/
|
||||||
|
static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
|
||||||
|
Vec2 dx;
|
||||||
|
Residuals(H, x1, x2, &dx);
|
||||||
|
return dx.squaredNorm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure for estimating the symmetric error
|
||||||
|
* between a vector x2 and the transformed x1 such that
|
||||||
|
* Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
* \note It should be distributed as Chi-squared with k = 4.
|
||||||
|
*/
|
||||||
|
struct SymmetricError {
|
||||||
|
/**
|
||||||
|
* Computes the squared norm of the residuals between x2 and the
|
||||||
|
* transformed x1 such that
|
||||||
|
* Error = ||x2 - Psi(H * x1)||^2 + ||x1 - Psi(H^-1 * x2)||^2
|
||||||
|
* where Psi is the function that transforms homogeneous to euclidean coords.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \return The squared norm of the symmetric residuals errors
|
||||||
|
*/
|
||||||
|
static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
|
||||||
|
// TODO(keir): This is awesomely inefficient because it does a 3x3
|
||||||
|
// inversion for each evaluation.
|
||||||
|
Mat3 Hinv = H.inverse();
|
||||||
|
return AsymmetricError::Error(H, x1, x2) +
|
||||||
|
AsymmetricError::Error(Hinv, x2, x1);
|
||||||
|
}
|
||||||
|
// TODO(julien) Add residuals function \see AsymmetricError
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* Structure for estimating the algebraic error (cross product)
|
||||||
|
* between a vector x2 and the transformed x1 such that
|
||||||
|
* Error = ||[x2] * H * x1||^^2
|
||||||
|
* where [x2] is the skew matrix of x2.
|
||||||
|
*/
|
||||||
|
struct AlgebraicError {
|
||||||
|
// TODO(julien) Make an AlgebraicError2Rows and AlgebraicError3Rows
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the algebraic residuals (cross product) between a set of 2D
|
||||||
|
* points x2 and the transformed 2D point set x1 such that
|
||||||
|
* [x2] * H * x1 where [x2] is the skew matrix of x2.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[out] dx A 3xN matrix of column vectors of residuals errors
|
||||||
|
*/
|
||||||
|
static void Residuals(const Mat &H, const Mat &x1,
|
||||||
|
const Mat &x2, Mat3X *dx) {
|
||||||
|
dx->resize(3, x1.cols());
|
||||||
|
Vec3 col;
|
||||||
|
for (int i = 0; i < x1.cols(); ++i) {
|
||||||
|
Residuals(H, x1.col(i), x2.col(i), &col);
|
||||||
|
dx->col(i) = col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the algebraic residuals (cross product) between a 2D point x2
|
||||||
|
* and the transformed 2D point x1 such that
|
||||||
|
* [x2] * H * x1 where [x2] is the skew matrix of x2.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[out] dx A vector of size 3 of the residual error
|
||||||
|
*/
|
||||||
|
static void Residuals(const Mat &H, const Vec &x1,
|
||||||
|
const Vec &x2, Vec3 *dx) {
|
||||||
|
Vec3 x2h_est;
|
||||||
|
if (x1.rows() == 2)
|
||||||
|
x2h_est = H * EuclideanToHomogeneous(static_cast<Vec2>(x1));
|
||||||
|
else
|
||||||
|
x2h_est = H * x1;
|
||||||
|
if (x2.rows() == 2)
|
||||||
|
*dx = SkewMat(EuclideanToHomogeneous(static_cast<Vec2>(x2))) * x2h_est;
|
||||||
|
else
|
||||||
|
*dx = SkewMat(x2) * x2h_est;
|
||||||
|
// TODO(julien) This is inefficient since it creates an
|
||||||
|
// identical 3x3 skew matrix for each evaluation.
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the squared norm of the algebraic residuals between a set of 2D
|
||||||
|
* points x2 and the transformed 2D point set x1 such that
|
||||||
|
* [x2] * H * x1 where [x2] is the skew matrix of x2.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \param[in] x2 A set of 2D points (2xN or 3xN matrix of column vectors).
|
||||||
|
* \return The squared norm of the asymmetric residuals errors
|
||||||
|
*/
|
||||||
|
static double Error(const Mat &H, const Mat &x1, const Mat &x2) {
|
||||||
|
Mat3X dx;
|
||||||
|
Residuals(H, x1, x2, &dx);
|
||||||
|
return dx.squaredNorm();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Computes the squared norm of the algebraic residuals between a 2D point x2
|
||||||
|
* and the transformed 2D point x1 such that
|
||||||
|
* [x2] * H * x1 where [x2] is the skew matrix of x2.
|
||||||
|
*
|
||||||
|
* \param[in] H The 3x3 homography matrix.
|
||||||
|
* The estimated homography should approximatelly hold the condition y = H x.
|
||||||
|
* \param[in] x1 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \param[in] x2 A 2D point (vector of size 2 or 3 (euclidean/homogeneous))
|
||||||
|
* \return The squared norm of the asymmetric residual error
|
||||||
|
*/
|
||||||
|
static double Error(const Mat &H, const Vec &x1, const Vec &x2) {
|
||||||
|
Vec3 dx;
|
||||||
|
Residuals(H, x1, x2, &dx);
|
||||||
|
return dx.squaredNorm();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// TODO(keir): Add error based on ideal points.
|
||||||
|
|
||||||
|
} // namespace homography2D
|
||||||
|
// TODO(julien) add homography3D errors
|
||||||
|
} // namespace homography
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_MULTIVIEW_HOMOGRAPHY_ERRORS_H_
|
261
extern/libmv/libmv/multiview/homography_test.cc
vendored
Normal file
261
extern/libmv/libmv/multiview/homography_test.cc
vendored
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/homography.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Check whether homography transform M actually transforms
|
||||||
|
// given vectors x1 to x2. Used to check validness of a reconstructed
|
||||||
|
// homography matrix.
|
||||||
|
// TODO(sergey): Consider using this in all tests since possible homography
|
||||||
|
// matrix is not fixed to a single value and different-looking matrices
|
||||||
|
// might actually crrespond to the same exact transform.
|
||||||
|
void CheckHomography2DTransform(const Mat3 &H,
|
||||||
|
const Mat &x1,
|
||||||
|
const Mat &x2) {
|
||||||
|
for (int i = 0; i < x2.cols(); ++i) {
|
||||||
|
Vec3 x2_expected = x2.col(i);
|
||||||
|
Vec3 x2_observed = H * x1.col(i);
|
||||||
|
x2_observed /= x2_observed(2);
|
||||||
|
EXPECT_MATRIX_NEAR(x2_expected, x2_observed, 1e-8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
TEST(Homography2DTest, Rotation45AndTranslationXY) {
|
||||||
|
Mat x1(3, 4);
|
||||||
|
x1 << 0, 1, 0, 5,
|
||||||
|
0, 0, 2, 3,
|
||||||
|
1, 1, 1, 1;
|
||||||
|
|
||||||
|
double angle = 45.0;
|
||||||
|
Mat3 m;
|
||||||
|
m << cos(angle), -sin(angle), -2,
|
||||||
|
sin(angle), cos(angle), 5,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
// Transform point from ground truth matrix
|
||||||
|
for (int i = 0; i < x2.cols(); ++i)
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
|
||||||
|
Mat3 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
VLOG(1) << "Mat Homography2D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
VLOG(1) << "Mat GT ";
|
||||||
|
VLOG(1) << m;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography2DTest, AffineGeneral4) {
|
||||||
|
// TODO(julien) find why it doesn't work with 4 points!!!
|
||||||
|
Mat x1(3, 4);
|
||||||
|
x1 << 0, 1, 0, 2,
|
||||||
|
0, 0, 1, 2,
|
||||||
|
1, 1, 1, 1;
|
||||||
|
Mat3 m;
|
||||||
|
m << 3, -1, 4,
|
||||||
|
6, -2, -3,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i) {
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat3 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
VLOG(1) << "Mat Homography2D";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
CheckHomography2DTransform(homography_mat, x1, x2);
|
||||||
|
|
||||||
|
// Test with euclidean coordinates
|
||||||
|
Mat eX1, eX2;
|
||||||
|
HomogeneousToEuclidean(x1, &eX1);
|
||||||
|
HomogeneousToEuclidean(x2, &eX2);
|
||||||
|
homography_mat.setIdentity();
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(eX1, eX2, &homography_mat));
|
||||||
|
|
||||||
|
VLOG(1) << "Mat Homography2D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
CheckHomography2DTransform(homography_mat, x1, x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography2DTest, AffineGeneral5) {
|
||||||
|
Mat x1(3, 5);
|
||||||
|
x1 << 0, 1, 0, 2, 5,
|
||||||
|
0, 0, 1, 2, 2,
|
||||||
|
1, 1, 1, 1, 1;
|
||||||
|
Mat3 m;
|
||||||
|
m << 3, -1, 4,
|
||||||
|
6, -2, -3,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i)
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
|
||||||
|
Mat3 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
|
||||||
|
VLOG(1) << "Mat Homography2D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
|
||||||
|
// Test with euclidean coordinates
|
||||||
|
Mat eX1, eX2;
|
||||||
|
HomogeneousToEuclidean(x1, &eX1);
|
||||||
|
HomogeneousToEuclidean(x2, &eX2);
|
||||||
|
homography_mat.setIdentity();
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(eX1, eX2, &homography_mat));
|
||||||
|
|
||||||
|
VLOG(1) << "Mat Homography2D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography2DTest, HomographyGeneral) {
|
||||||
|
Mat x1(3, 4);
|
||||||
|
x1 << 0, 1, 0, 5,
|
||||||
|
0, 0, 2, 3,
|
||||||
|
1, 1, 1, 1;
|
||||||
|
Mat3 m;
|
||||||
|
m << 3, -1, 4,
|
||||||
|
6, -2, -3,
|
||||||
|
1, -3, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i)
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
|
||||||
|
Mat3 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography2DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
|
||||||
|
VLOG(1) << "Mat Homography2D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography3DTest, RotationAndTranslationXYZ) {
|
||||||
|
Mat x1(4, 5);
|
||||||
|
x1 << 0, 0, 1, 5, 2,
|
||||||
|
0, 1, 2, 3, 5,
|
||||||
|
0, 2, 0, 1, 5,
|
||||||
|
1, 1, 1, 1, 1;
|
||||||
|
Mat4 M;
|
||||||
|
M.setIdentity();
|
||||||
|
/*
|
||||||
|
M = AngleAxisd(45.0, Vector3f::UnitZ())
|
||||||
|
* AngleAxisd(25.0, Vector3f::UnitX())
|
||||||
|
* AngleAxisd(5.0, Vector3f::UnitZ());*/
|
||||||
|
|
||||||
|
// Rotation on x + translation
|
||||||
|
double angle = 45.0;
|
||||||
|
Mat4 rot;
|
||||||
|
rot << 1, 0, 0, 1,
|
||||||
|
0, cos(angle), -sin(angle), 3,
|
||||||
|
0, sin(angle), cos(angle), -2,
|
||||||
|
0, 0, 0, 1;
|
||||||
|
M *= rot;
|
||||||
|
// Rotation on y
|
||||||
|
angle = 25.0;
|
||||||
|
rot << cos(angle), 0, sin(angle), 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
-sin(angle), 0, cos(angle), 0,
|
||||||
|
0, 0, 0, 1;
|
||||||
|
M *= rot;
|
||||||
|
// Rotation on z
|
||||||
|
angle = 5.0;
|
||||||
|
rot << cos(angle), -sin(angle), 0, 0,
|
||||||
|
sin(angle), cos(angle), 0, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1;
|
||||||
|
M *= rot;
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i) {
|
||||||
|
x2.col(i) = M * x1.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
|
||||||
|
VLOG(1) << "Mat Homography3D " << homography_mat;
|
||||||
|
VLOG(1) << "Mat GT " << M;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, M, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography3DTest, AffineGeneral) {
|
||||||
|
Mat x1(4, 5);
|
||||||
|
x1 << 0, 0, 1, 5, 2,
|
||||||
|
0, 1, 2, 3, 5,
|
||||||
|
0, 2, 0, 1, 5,
|
||||||
|
1, 1, 1, 1, 1;
|
||||||
|
Mat4 m;
|
||||||
|
m << 3, -1, 4, 1,
|
||||||
|
6, -2, -3, -6,
|
||||||
|
1, 0, 1, 2,
|
||||||
|
0, 0, 0, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i) {
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
VLOG(1) << "Mat Homography3D ";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Homography3DTest, HomographyGeneral) {
|
||||||
|
Mat x1(4, 5);
|
||||||
|
x1 << 0, 0, 1, 5, 2,
|
||||||
|
0, 1, 2, 3, 5,
|
||||||
|
0, 2, 0, 1, 5,
|
||||||
|
1, 1, 1, 1, 1;
|
||||||
|
Mat4 m;
|
||||||
|
m << 3, -1, 4, 1,
|
||||||
|
6, -2, -3, -6,
|
||||||
|
1, 0, 1, 2,
|
||||||
|
-3, 1, 0, 1;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
for (int i = 0; i < x2.cols(); ++i) {
|
||||||
|
x2.col(i) = m * x1.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4 homography_mat;
|
||||||
|
EXPECT_TRUE(Homography3DFromCorrespondencesLinear(x1, x2, &homography_mat));
|
||||||
|
VLOG(1) << "Mat Homography3D";
|
||||||
|
VLOG(1) << homography_mat;
|
||||||
|
EXPECT_MATRIX_NEAR(homography_mat, m, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
94
extern/libmv/libmv/multiview/nviewtriangulation_test.cc
vendored
Normal file
94
extern/libmv/libmv/multiview/nviewtriangulation_test.cc
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/nviewtriangulation.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/test_data_sets.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
TEST(NViewTriangulate, FiveViews) {
|
||||||
|
int nviews = 5;
|
||||||
|
int npoints = 6;
|
||||||
|
NViewDataSet d = NRealisticCamerasFull(nviews, npoints);
|
||||||
|
|
||||||
|
// Collect P matrices together.
|
||||||
|
vector<Mat34> Ps(nviews);
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
Ps[j] = d.P(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < npoints; ++i) {
|
||||||
|
// Collect the image of point i in each frame.
|
||||||
|
Mat2X xs(2, nviews);
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
xs.col(j) = d.x[j].col(i);
|
||||||
|
}
|
||||||
|
Vec4 X;
|
||||||
|
NViewTriangulate(xs, Ps, &X);
|
||||||
|
|
||||||
|
// Check reprojection error. Should be nearly zero.
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
Vec3 x_reprojected = Ps[j]*X;
|
||||||
|
x_reprojected /= x_reprojected(2);
|
||||||
|
double error = (x_reprojected.head(2) - xs.col(j)).norm();
|
||||||
|
EXPECT_NEAR(error, 0.0, 1e-9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NViewTriangulateAlgebraic, FiveViews) {
|
||||||
|
int nviews = 5;
|
||||||
|
int npoints = 6;
|
||||||
|
NViewDataSet d = NRealisticCamerasFull(nviews, npoints);
|
||||||
|
|
||||||
|
// Collect P matrices together.
|
||||||
|
vector<Mat34> Ps(nviews);
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
Ps[j] = d.P(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < npoints; ++i) {
|
||||||
|
// Collect the image of point i in each frame.
|
||||||
|
Mat2X xs(2, nviews);
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
xs.col(j) = d.x[j].col(i);
|
||||||
|
}
|
||||||
|
Vec4 X;
|
||||||
|
NViewTriangulate(xs, Ps, &X);
|
||||||
|
|
||||||
|
// Check reprojection error. Should be nearly zero.
|
||||||
|
for (int j = 0; j < nviews; ++j) {
|
||||||
|
Vec3 x_reprojected = Ps[j]*X;
|
||||||
|
x_reprojected /= x_reprojected(2);
|
||||||
|
double error = (x_reprojected.head<2>() - xs.col(j)).norm();
|
||||||
|
EXPECT_NEAR(error, 0.0, 1e-9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
51
extern/libmv/libmv/multiview/panography_kernel.cc
vendored
Normal file
51
extern/libmv/libmv/multiview/panography_kernel.cc
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2008, 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/multiview/panography_kernel.h"
|
||||||
|
#include "libmv/multiview/panography.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace panography {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
void TwoPointSolver::Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs) {
|
||||||
|
// Solve for the focal lengths.
|
||||||
|
vector<double> fs;
|
||||||
|
F_FromCorrespondance_2points(x1, x2, &fs);
|
||||||
|
|
||||||
|
// Then solve for the rotations and homographies.
|
||||||
|
Mat x1h, x2h;
|
||||||
|
EuclideanToHomogeneous(x1, &x1h);
|
||||||
|
EuclideanToHomogeneous(x2, &x2h);
|
||||||
|
for (int i = 0; i < fs.size(); ++i) {
|
||||||
|
Mat3 K1 = Mat3::Identity() * fs[i];
|
||||||
|
K1(2, 2) = 1.0;
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
GetR_FixedCameraCenter(x1h, x2h, fs[i], &R);
|
||||||
|
R /= R(2, 2);
|
||||||
|
|
||||||
|
(*Hs).push_back(K1 * R * K1.inverse());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace panography
|
||||||
|
} // namespace libmv
|
54
extern/libmv/libmv/multiview/panography_kernel.h
vendored
Normal file
54
extern/libmv/libmv/multiview/panography_kernel.h
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H
|
||||||
|
#define LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/multiview/conditioning.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/two_view_kernel.h"
|
||||||
|
#include "libmv/multiview/homography_error.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace panography {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
struct TwoPointSolver {
|
||||||
|
enum { MINIMUM_SAMPLES = 2 };
|
||||||
|
static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *Hs);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef two_view::kernel::Kernel<
|
||||||
|
TwoPointSolver, homography::homography2D::AsymmetricError, Mat3>
|
||||||
|
UnnormalizedKernel;
|
||||||
|
|
||||||
|
typedef two_view::kernel::Kernel<
|
||||||
|
two_view::kernel::NormalizedSolver<TwoPointSolver, UnnormalizerI>,
|
||||||
|
homography::homography2D::AsymmetricError,
|
||||||
|
Mat3>
|
||||||
|
Kernel;
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace panography
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_MULTIVIEW_PANOGRAPHY_KERNEL_H
|
144
extern/libmv/libmv/multiview/panography_test.cc
vendored
Normal file
144
extern/libmv/libmv/multiview/panography_test.cc
vendored
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/panography.h"
|
||||||
|
#include "libmv/multiview/panography_kernel.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Panography, PrintSomeSharedFocalEstimationValues) {
|
||||||
|
Mat x1(2, 2), x2(2, 2);
|
||||||
|
x1<< 158, 78,
|
||||||
|
124, 113;
|
||||||
|
x2<< 300, 214,
|
||||||
|
125, 114;
|
||||||
|
|
||||||
|
// Normalize data (set principal point 0,0 and image border to 1.0).
|
||||||
|
x1.block<1, 2>(0, 0) /= 320;
|
||||||
|
x1.block<1, 2>(1, 0) /= 240;
|
||||||
|
x2.block<1, 2>(0, 0) /= 320;
|
||||||
|
x2.block<1, 2>(1, 0) /= 240;
|
||||||
|
x1+=Mat2::Constant(0.5);
|
||||||
|
x2+=Mat2::Constant(0.5);
|
||||||
|
|
||||||
|
vector<double> fs;
|
||||||
|
F_FromCorrespondance_2points(x1, x2, &fs);
|
||||||
|
|
||||||
|
// Assert we found a valid solution.
|
||||||
|
EXPECT_EQ(1, fs.size());
|
||||||
|
EXPECT_NEAR(1.01667, fs[1], 1e-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Panography, GetR_FixedCameraCenterWithIdentity) {
|
||||||
|
Mat x1(3, 3);
|
||||||
|
x1 << 0.5, 0.6, 0.7,
|
||||||
|
0.5, 0.5, 0.4,
|
||||||
|
10.0, 10.0, 10.0;
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
GetR_FixedCameraCenter(x1, x1, 1.0, &R);
|
||||||
|
R /= R(2, 2);
|
||||||
|
EXPECT_MATRIX_NEAR(Mat3::Identity(), R, 1e-8);
|
||||||
|
LOG(INFO) << "R \n" << R;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Panography, Homography_GetR_Test_PitchY30) {
|
||||||
|
int n = 3;
|
||||||
|
|
||||||
|
Mat x1(3, n);
|
||||||
|
x1 << 0.5, 0.6, 0.7,
|
||||||
|
0.5, 0.5, 0.4,
|
||||||
|
10, 10, 10;
|
||||||
|
|
||||||
|
Mat x2 = x1;
|
||||||
|
const double alpha = 30.0 * M_PI / 180.0;
|
||||||
|
Mat3 rotY;
|
||||||
|
rotY << cos(alpha), 0, -sin(alpha),
|
||||||
|
0, 1, 0,
|
||||||
|
sin(alpha), 0, cos(alpha);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
x2.block<3, 1>(0, i) = rotY * x1.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat3 R;
|
||||||
|
GetR_FixedCameraCenter(x1, x2, 1.0, &R);
|
||||||
|
|
||||||
|
// Assert that residuals are small enough
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
Vec residuals = (R * x1.col(i)) - x2.col(i);
|
||||||
|
EXPECT_NEAR(0, residuals.norm(), 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the rotation angle along Y is the expected one.
|
||||||
|
// Use the euler approximation to recover the angle.
|
||||||
|
double pitch_y = asin(R(2, 0)) * 180.0 / M_PI;
|
||||||
|
EXPECT_NEAR(30, pitch_y, 1e-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(MinimalPanoramic, Real_Case_Kernel) {
|
||||||
|
const int n = 2;
|
||||||
|
Mat x1(2, n); // From image 0.jpg
|
||||||
|
x1<< 158, 78,
|
||||||
|
124, 113;
|
||||||
|
|
||||||
|
Mat x2(2, n); // From image 3.jpg
|
||||||
|
x2<< 300, 214,
|
||||||
|
125, 114;
|
||||||
|
|
||||||
|
Mat3 Ground_TruthHomography;
|
||||||
|
Ground_TruthHomography<< 1, 0.02, 129.83,
|
||||||
|
-0.02, 1.012, 0.07823,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
vector<Mat3> Hs;
|
||||||
|
|
||||||
|
libmv::panography::kernel::TwoPointSolver::Solve(x1, x2, &Hs);
|
||||||
|
|
||||||
|
LOG(INFO) << "Got " << Hs.size() << " solutions.";
|
||||||
|
for (int j = 0; j < Hs.size(); ++j) {
|
||||||
|
Mat3 H = Hs[j];
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(H, Ground_TruthHomography, 1e-1);
|
||||||
|
|
||||||
|
Mat x1h, x2h;
|
||||||
|
EuclideanToHomogeneous(x1, &x1h);
|
||||||
|
EuclideanToHomogeneous(x2, &x2h);
|
||||||
|
|
||||||
|
// Assert that residuals are small enough
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
Vec x1p = H * x1h.col(i);
|
||||||
|
Vec residuals = x1p/x1p(2) - x2h.col(i);
|
||||||
|
EXPECT_MATRIX_NEAR_ZERO(residuals, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
// TODO(pmoulon): Add a real test case based on images.
|
||||||
|
// TODO(pmoulon): Add a check for the actual f value for the real images.
|
||||||
|
// TODO(pmoulon): Add a test that has some inliers and outliers.
|
115
extern/libmv/libmv/multiview/projection_test.cc
vendored
Normal file
115
extern/libmv/libmv/multiview/projection_test.cc
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
TEST(Projection, P_From_KRt) {
|
||||||
|
Mat3 K, Kp;
|
||||||
|
K << 10, 1, 30,
|
||||||
|
0, 20, 40,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
Mat3 R, Rp;
|
||||||
|
R << 1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
Vec3 t, tp;
|
||||||
|
t << 1, 2, 3;
|
||||||
|
|
||||||
|
Mat34 P;
|
||||||
|
P_From_KRt(K, R, t, &P);
|
||||||
|
KRt_From_P(P, &Kp, &Rp, &tp);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(K, Kp, 1e-8);
|
||||||
|
EXPECT_MATRIX_NEAR(R, Rp, 1e-8);
|
||||||
|
EXPECT_MATRIX_NEAR(t, tp, 1e-8);
|
||||||
|
|
||||||
|
// TODO(keir): Change the code to ensure det(R) == 1, which is not currently
|
||||||
|
// the case. Also add a test for that here.
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec4 GetRandomPoint() {
|
||||||
|
Vec4 X;
|
||||||
|
X.setRandom();
|
||||||
|
X(3) = 1;
|
||||||
|
return X;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Projection, isInFrontOfCamera) {
|
||||||
|
Mat34 P;
|
||||||
|
P << 1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
|
||||||
|
Vec4 X_front = GetRandomPoint();
|
||||||
|
Vec4 X_back = GetRandomPoint();
|
||||||
|
X_front(2) = 10; // Any point in the positive Z direction
|
||||||
|
// where Z > 1 is infront of the camera.
|
||||||
|
X_back(2) = -10; // Any point int he negative Z dirstaion
|
||||||
|
// is behind the camera.
|
||||||
|
|
||||||
|
bool res_front = isInFrontOfCamera(P, X_front);
|
||||||
|
bool res_back = isInFrontOfCamera(P, X_back);
|
||||||
|
|
||||||
|
EXPECT_EQ(true, res_front);
|
||||||
|
EXPECT_EQ(false, res_back);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AutoCalibration, ProjectionShiftPrincipalPoint) {
|
||||||
|
Mat34 P1, P2;
|
||||||
|
P1 << 1, 0, 0, 0,
|
||||||
|
0, 1, 0, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
P2 << 1, 0, 3, 0,
|
||||||
|
0, 1, 4, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
Mat34 P1_computed, P2_computed;
|
||||||
|
ProjectionShiftPrincipalPoint(P1, Vec2(0, 0), Vec2(3, 4), &P2_computed);
|
||||||
|
ProjectionShiftPrincipalPoint(P2, Vec2(3, 4), Vec2(0, 0), &P1_computed);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_EQ(P1, P1_computed);
|
||||||
|
EXPECT_MATRIX_EQ(P2, P2_computed);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(AutoCalibration, ProjectionChangeAspectRatio) {
|
||||||
|
Mat34 P1, P2;
|
||||||
|
P1 << 1, 0, 3, 0,
|
||||||
|
0, 1, 4, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
P2 << 1, 0, 3, 0,
|
||||||
|
0, 2, 4, 0,
|
||||||
|
0, 0, 1, 0;
|
||||||
|
Mat34 P1_computed, P2_computed;
|
||||||
|
ProjectionChangeAspectRatio(P1, Vec2(3, 4), 1, 2, &P2_computed);
|
||||||
|
ProjectionChangeAspectRatio(P2, Vec2(3, 4), 2, 1, &P1_computed);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_EQ(P1, P1_computed);
|
||||||
|
EXPECT_MATRIX_EQ(P2, P2_computed);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
61
extern/libmv/libmv/multiview/resection_test.cc
vendored
Normal file
61
extern/libmv/libmv/multiview/resection_test.cc
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/resection.h"
|
||||||
|
#include "libmv/multiview/test_data_sets.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
using namespace libmv::resection;
|
||||||
|
|
||||||
|
TEST(Resection, ThreeViews) {
|
||||||
|
int nviews = 5;
|
||||||
|
int npoints = 6;
|
||||||
|
NViewDataSet d = NRealisticCamerasFull(nviews, npoints);
|
||||||
|
for (int i = 0; i < nviews; ++i) {
|
||||||
|
Mat4X X(4, npoints);
|
||||||
|
X.block(0, 0, 3, npoints) = d.X;
|
||||||
|
X.row(3).setOnes();
|
||||||
|
const Mat2X &x = d.x[i];
|
||||||
|
Mat34 P;
|
||||||
|
Resection(x, X, &P);
|
||||||
|
Mat34 P_expected = d.P(i);
|
||||||
|
|
||||||
|
// Because the P matrices are homogeneous, it is necessary to be tricky
|
||||||
|
// about the scale factor to make them match.
|
||||||
|
P_expected *= 1/P_expected.array().abs().sum();
|
||||||
|
P *= 1/P.array().abs().sum();
|
||||||
|
if (!((P(0, 0) > 0 && P_expected(0, 0) > 0) ||
|
||||||
|
(P(0, 0) < 0 && P_expected(0, 0) < 0))) {
|
||||||
|
P *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(P_expected, P, 1e-9);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
196
extern/libmv/libmv/multiview/test_data_sets.cc
vendored
Normal file
196
extern/libmv/libmv/multiview/test_data_sets.cc
vendored
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/multiview/test_data_sets.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/fundamental.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
TwoViewDataSet TwoRealisticCameras(bool same_K) {
|
||||||
|
TwoViewDataSet d;
|
||||||
|
|
||||||
|
d.K1 << 320, 0, 160,
|
||||||
|
0, 320, 120,
|
||||||
|
0, 0, 1;
|
||||||
|
if (same_K) {
|
||||||
|
d.K2 = d.K1;
|
||||||
|
} else {
|
||||||
|
d.K2 << 360, 0, 170,
|
||||||
|
0, 360, 110,
|
||||||
|
0, 0, 1;
|
||||||
|
}
|
||||||
|
d.R1 = RotationAroundZ(-0.1);
|
||||||
|
d.R2 = RotationAroundX(-0.1);
|
||||||
|
d.t1 << 1, 1, 10;
|
||||||
|
d.t2 << -2, -1, 10;
|
||||||
|
P_From_KRt(d.K1, d.R1, d.t1, &d.P1);
|
||||||
|
P_From_KRt(d.K2, d.R2, d.t2, &d.P2);
|
||||||
|
|
||||||
|
FundamentalFromProjections(d.P1, d.P2, &d.F);
|
||||||
|
|
||||||
|
d.X.resize(3, 30);
|
||||||
|
d.X.setRandom();
|
||||||
|
|
||||||
|
Project(d.P1, d.X, &d.x1);
|
||||||
|
Project(d.P2, d.X, &d.x2);
|
||||||
|
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
nViewDatasetConfigator::nViewDatasetConfigator(int fx , int fy,
|
||||||
|
int cx, int cy,
|
||||||
|
double distance,
|
||||||
|
double jitter_amount) {
|
||||||
|
_fx = fx;
|
||||||
|
_fy = fy;
|
||||||
|
_cx = cx;
|
||||||
|
_cy = cy;
|
||||||
|
_dist = distance;
|
||||||
|
_jitter_amount = jitter_amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
|
||||||
|
const nViewDatasetConfigator config) {
|
||||||
|
NViewDataSet d;
|
||||||
|
d.n = nviews;
|
||||||
|
d.K.resize(nviews);
|
||||||
|
d.R.resize(nviews);
|
||||||
|
d.t.resize(nviews);
|
||||||
|
d.C.resize(nviews);
|
||||||
|
d.x.resize(nviews);
|
||||||
|
d.x_ids.resize(nviews);
|
||||||
|
|
||||||
|
d.X.resize(3, npoints);
|
||||||
|
d.X.setRandom();
|
||||||
|
d.X *= 0.6;
|
||||||
|
|
||||||
|
Vecu all_point_ids(npoints);
|
||||||
|
for (size_t j = 0; j < npoints; ++j)
|
||||||
|
all_point_ids[j] = j;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nviews; ++i) {
|
||||||
|
Vec3 camera_center, t, jitter, lookdir;
|
||||||
|
|
||||||
|
double theta = i * 2 * M_PI / nviews;
|
||||||
|
camera_center << sin(theta), 0.0, cos(theta);
|
||||||
|
camera_center *= config._dist;
|
||||||
|
d.C[i] = camera_center;
|
||||||
|
|
||||||
|
jitter.setRandom();
|
||||||
|
jitter *= config._jitter_amount / camera_center.norm();
|
||||||
|
lookdir = -camera_center + jitter;
|
||||||
|
|
||||||
|
d.K[i] << config._fx, 0, config._cx,
|
||||||
|
0, config._fy, config._cy,
|
||||||
|
0, 0, 1;
|
||||||
|
d.R[i] = LookAt(lookdir);
|
||||||
|
d.t[i] = -d.R[i] * camera_center;
|
||||||
|
d.x[i] = Project(d.P(i), d.X);
|
||||||
|
d.x_ids[i] = all_point_ids;
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
|
||||||
|
float view_ratio, unsigned min_projections,
|
||||||
|
const nViewDatasetConfigator config) {
|
||||||
|
assert(view_ratio <= 1.0);
|
||||||
|
assert(view_ratio > 0.0);
|
||||||
|
assert(min_projections <= npoints);
|
||||||
|
NViewDataSet d;
|
||||||
|
d.n = nviews;
|
||||||
|
d.K.resize(nviews);
|
||||||
|
d.R.resize(nviews);
|
||||||
|
d.t.resize(nviews);
|
||||||
|
d.C.resize(nviews);
|
||||||
|
d.x.resize(nviews);
|
||||||
|
d.x_ids.resize(nviews);
|
||||||
|
|
||||||
|
d.X.resize(3, npoints);
|
||||||
|
d.X.setRandom();
|
||||||
|
d.X *= 0.6;
|
||||||
|
|
||||||
|
Mat visibility(nviews, npoints);
|
||||||
|
visibility.setZero();
|
||||||
|
Mat randoms(nviews, npoints);
|
||||||
|
randoms.setRandom();
|
||||||
|
randoms = (randoms.array() + 1)/2.0;
|
||||||
|
unsigned num_visibles = 0;
|
||||||
|
for (size_t i = 0; i < nviews; ++i) {
|
||||||
|
num_visibles = 0;
|
||||||
|
for (size_t j = 0; j < npoints; j++) {
|
||||||
|
if (randoms(i, j) <= view_ratio) {
|
||||||
|
visibility(i, j) = true;
|
||||||
|
num_visibles++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (num_visibles < min_projections) {
|
||||||
|
unsigned num_projections_to_add = min_projections - num_visibles;
|
||||||
|
for (size_t j = 0; j < npoints && num_projections_to_add > 0; ++j) {
|
||||||
|
if (!visibility(i, j)) {
|
||||||
|
num_projections_to_add--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
num_visibles += num_projections_to_add;
|
||||||
|
}
|
||||||
|
d.x_ids[i].resize(num_visibles);
|
||||||
|
d.x[i].resize(2, num_visibles);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t j_visible = 0;
|
||||||
|
Vec3 X;
|
||||||
|
for (size_t i = 0; i < nviews; ++i) {
|
||||||
|
Vec3 camera_center, t, jitter, lookdir;
|
||||||
|
|
||||||
|
double theta = i * 2 * M_PI / nviews;
|
||||||
|
camera_center << sin(theta), 0.0, cos(theta);
|
||||||
|
camera_center *= config._dist;
|
||||||
|
d.C[i] = camera_center;
|
||||||
|
|
||||||
|
jitter.setRandom();
|
||||||
|
jitter *= config._jitter_amount / camera_center.norm();
|
||||||
|
lookdir = -camera_center + jitter;
|
||||||
|
|
||||||
|
d.K[i] << config._fx, 0, config._cx,
|
||||||
|
0, config._fy, config._cy,
|
||||||
|
0, 0, 1;
|
||||||
|
d.R[i] = LookAt(lookdir);
|
||||||
|
d.t[i] = -d.R[i] * camera_center;
|
||||||
|
j_visible = 0;
|
||||||
|
for (size_t j = 0; j < npoints; j++) {
|
||||||
|
if (visibility(i, j)) {
|
||||||
|
X = d.X.col(j);
|
||||||
|
d.x[i].col(j_visible) = Project(d.P(i), X);
|
||||||
|
d.x_ids[i][j_visible] = j;
|
||||||
|
j_visible++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace libmv
|
105
extern/libmv/libmv/multiview/test_data_sets.h
vendored
Normal file
105
extern/libmv/libmv/multiview/test_data_sets.h
vendored
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_MULTIVIEW_TEST_DATA_SETS_H_
|
||||||
|
#define LIBMV_MULTIVIEW_TEST_DATA_SETS_H_
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/multiview/fundamental.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
struct TwoViewDataSet {
|
||||||
|
Mat3 K1, K2; // Internal parameters.
|
||||||
|
Mat3 R1, R2; // Rotation.
|
||||||
|
Vec3 t1, t2; // Translation.
|
||||||
|
Mat34 P1, P2; // Projection matrix, P = K(R|t)
|
||||||
|
Mat3 F; // Fundamental matrix.
|
||||||
|
Mat3X X; // 3D points.
|
||||||
|
Mat2X x1, x2; // Projected points.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Two cameras at (-1,-1,-10) and (2,1,-10) looking approximately towards z+.
|
||||||
|
TwoViewDataSet TwoRealisticCameras(bool same_K = false);
|
||||||
|
|
||||||
|
// An N-view metric dataset . An important difference between this
|
||||||
|
// and the other reconstruction data types is that all points are seen by all
|
||||||
|
// cameras.
|
||||||
|
struct NViewDataSet {
|
||||||
|
vector<Mat3> K; // Internal parameters (fx, fy, etc).
|
||||||
|
vector<Mat3> R; // Rotation.
|
||||||
|
vector<Vec3> t; // Translation.
|
||||||
|
vector<Vec3> C; // Camera centers.
|
||||||
|
Mat3X X; // 3D points.
|
||||||
|
vector<Mat2X> x; // Projected points; may have noise added.
|
||||||
|
vector<Vecu> x_ids; // Indexes of points corresponding to the projections
|
||||||
|
|
||||||
|
int n; // Actual number of cameras.
|
||||||
|
|
||||||
|
Mat34 P(int i) {
|
||||||
|
assert(i < n);
|
||||||
|
return K[i] * HStack(R[i], t[i]);
|
||||||
|
}
|
||||||
|
Mat3 F(int i, int j) {
|
||||||
|
Mat3 F_;
|
||||||
|
FundamentalFromProjections(P(i), P(j), &F_);
|
||||||
|
return F_;
|
||||||
|
}
|
||||||
|
void Reproject() {
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
x[i] = Project(P(i), X);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO(keir): Add gaussian jitter functions.
|
||||||
|
};
|
||||||
|
|
||||||
|
struct nViewDatasetConfigator {
|
||||||
|
/// Internal camera parameters
|
||||||
|
int _fx;
|
||||||
|
int _fy;
|
||||||
|
int _cx;
|
||||||
|
int _cy;
|
||||||
|
|
||||||
|
/// Camera random position parameters
|
||||||
|
double _dist;
|
||||||
|
double _jitter_amount;
|
||||||
|
|
||||||
|
nViewDatasetConfigator(int fx = 1000, int fy = 1000,
|
||||||
|
int cx = 500, int cy = 500,
|
||||||
|
double distance = 1.5,
|
||||||
|
double jitter_amount = 0.01);
|
||||||
|
};
|
||||||
|
|
||||||
|
NViewDataSet NRealisticCamerasFull(int nviews, int npoints,
|
||||||
|
const nViewDatasetConfigator
|
||||||
|
config = nViewDatasetConfigator());
|
||||||
|
|
||||||
|
// Generates sparse projections (not all points are projected)
|
||||||
|
NViewDataSet NRealisticCamerasSparse(int nviews, int npoints,
|
||||||
|
float view_ratio = 0.6,
|
||||||
|
unsigned min_projections = 3,
|
||||||
|
const nViewDatasetConfigator
|
||||||
|
config = nViewDatasetConfigator());
|
||||||
|
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_MULTIVIEW_TEST_DATA_SETS_H_
|
47
extern/libmv/libmv/multiview/triangulation_test.cc
vendored
Normal file
47
extern/libmv/libmv/multiview/triangulation_test.cc
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "libmv/multiview/triangulation.h"
|
||||||
|
#include "libmv/multiview/fundamental.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/multiview/test_data_sets.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
TEST(Triangulation, TriangulateDLT) {
|
||||||
|
TwoViewDataSet d = TwoRealisticCameras();
|
||||||
|
|
||||||
|
for (int i = 0; i < d.X.cols(); ++i) {
|
||||||
|
Vec2 x1, x2;
|
||||||
|
MatrixColumn(d.x1, i, &x1);
|
||||||
|
MatrixColumn(d.x2, i, &x2);
|
||||||
|
Vec3 X_estimated, X_gt;
|
||||||
|
MatrixColumn(d.X, i, &X_gt);
|
||||||
|
TriangulateDLT(d.P1, x1, d.P2, x2, &X_estimated);
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(X_estimated, X_gt), 1e-8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
137
extern/libmv/libmv/multiview/two_view_kernel.h
vendored
Normal file
137
extern/libmv/libmv/multiview/two_view_kernel.h
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_
|
||||||
|
#define LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_
|
||||||
|
|
||||||
|
#include "libmv/base/vector.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/multiview/conditioning.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace two_view {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
template<typename Solver, typename Unnormalizer>
|
||||||
|
struct NormalizedSolver {
|
||||||
|
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
|
||||||
|
static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) {
|
||||||
|
assert(2 == x1.rows());
|
||||||
|
assert(MINIMUM_SAMPLES <= x1.cols());
|
||||||
|
assert(x1.rows() == x2.rows());
|
||||||
|
assert(x1.cols() == x2.cols());
|
||||||
|
|
||||||
|
// Normalize the data.
|
||||||
|
Mat3 T1, T2;
|
||||||
|
Mat x1_normalized, x2_normalized;
|
||||||
|
NormalizePoints(x1, &x1_normalized, &T1);
|
||||||
|
NormalizePoints(x2, &x2_normalized, &T2);
|
||||||
|
|
||||||
|
Solver::Solve(x1_normalized, x2_normalized, models);
|
||||||
|
|
||||||
|
for (int i = 0; i < models->size(); ++i) {
|
||||||
|
Unnormalizer::Unnormalize(T1, T2, &(*models)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename Solver, typename Unnormalizer>
|
||||||
|
struct IsotropicNormalizedSolver {
|
||||||
|
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
|
||||||
|
static void Solve(const Mat &x1, const Mat &x2, vector<Mat3> *models) {
|
||||||
|
assert(2 == x1.rows());
|
||||||
|
assert(MINIMUM_SAMPLES <= x1.cols());
|
||||||
|
assert(x1.rows() == x2.rows());
|
||||||
|
assert(x1.cols() == x2.cols());
|
||||||
|
|
||||||
|
// Normalize the data.
|
||||||
|
Mat3 T1, T2;
|
||||||
|
Mat x1_normalized, x2_normalized;
|
||||||
|
NormalizeIsotropicPoints(x1, &x1_normalized, &T1);
|
||||||
|
NormalizeIsotropicPoints(x2, &x2_normalized, &T2);
|
||||||
|
|
||||||
|
Solver::Solve(x1_normalized, x2_normalized, models);
|
||||||
|
|
||||||
|
for (int i = 0; i < models->size(); ++i) {
|
||||||
|
Unnormalizer::Unnormalize(T1, T2, &(*models)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// This is one example (targeted at solvers that operate on correspondences
|
||||||
|
// between two views) that shows the "kernel" part of a robust fitting
|
||||||
|
// problem:
|
||||||
|
//
|
||||||
|
// 1. The model; Mat3 in the case of the F or H matrix.
|
||||||
|
// 2. The minimum number of samples needed to fit; 7 or 8 (or 4).
|
||||||
|
// 3. A way to convert samples to a model.
|
||||||
|
// 4. A way to convert a sample and a model to an error.
|
||||||
|
//
|
||||||
|
// Of particular note is that the kernel does not expose what the samples are.
|
||||||
|
// All the robust fitting algorithm sees is that there is some number of
|
||||||
|
// samples; it is able to fit subsets of them (via the kernel) and check their
|
||||||
|
// error, but can never access the samples themselves.
|
||||||
|
//
|
||||||
|
// The Kernel objects must follow the following concept so that the robust
|
||||||
|
// fitting alogrithm can fit this type of relation:
|
||||||
|
//
|
||||||
|
// 1. Kernel::Model
|
||||||
|
// 2. Kernel::MINIMUM_SAMPLES
|
||||||
|
// 3. Kernel::Fit(vector<int>, vector<Kernel::Model> *)
|
||||||
|
// 4. Kernel::Error(int, Model) -> error
|
||||||
|
//
|
||||||
|
// The fit routine must not clear existing entries in the vector of models; it
|
||||||
|
// should append new solutions to the end.
|
||||||
|
template<typename SolverArg,
|
||||||
|
typename ErrorArg,
|
||||||
|
typename ModelArg = Mat3>
|
||||||
|
class Kernel {
|
||||||
|
public:
|
||||||
|
Kernel(const Mat &x1, const Mat &x2) : x1_(x1), x2_(x2) {}
|
||||||
|
typedef SolverArg Solver;
|
||||||
|
typedef ModelArg Model;
|
||||||
|
enum { MINIMUM_SAMPLES = Solver::MINIMUM_SAMPLES };
|
||||||
|
void Fit(const vector<int> &samples, vector<Model> *models) const {
|
||||||
|
Mat x1 = ExtractColumns(x1_, samples);
|
||||||
|
Mat x2 = ExtractColumns(x2_, samples);
|
||||||
|
Solver::Solve(x1, x2, models);
|
||||||
|
}
|
||||||
|
double Error(int sample, const Model &model) const {
|
||||||
|
return ErrorArg::Error(model,
|
||||||
|
static_cast<Vec>(x1_.col(sample)),
|
||||||
|
static_cast<Vec>(x2_.col(sample)));
|
||||||
|
}
|
||||||
|
int NumSamples() const {
|
||||||
|
return x1_.cols();
|
||||||
|
}
|
||||||
|
static void Solve(const Mat &x1, const Mat &x2, vector<Model> *models) {
|
||||||
|
// By offering this, Kernel types can be passed to templates.
|
||||||
|
Solver::Solve(x1, x2, models);
|
||||||
|
}
|
||||||
|
protected:
|
||||||
|
const Mat &x1_;
|
||||||
|
const Mat &x2_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace two_view
|
||||||
|
} // namespace libmv
|
||||||
|
|
||||||
|
#endif // LIBMV_MULTIVIEW_TWO_VIEW_KERNEL_H_
|
95
extern/libmv/libmv/numeric/dogleg_test.cc
vendored
Normal file
95
extern/libmv/libmv/numeric/dogleg_test.cc
vendored
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/numeric/dogleg.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class F {
|
||||||
|
public:
|
||||||
|
typedef Vec4 FMatrixType;
|
||||||
|
typedef Vec3 XMatrixType;
|
||||||
|
Vec4 operator()(const Vec3 &x) const {
|
||||||
|
double x1 = x.x() - 2;
|
||||||
|
double y1 = x.y() - 5;
|
||||||
|
double z1 = x.z();
|
||||||
|
Vec4 fx; fx << x1*x1 + z1*z1,
|
||||||
|
y1*y1 + z1*z1,
|
||||||
|
z1*z1,
|
||||||
|
x1*x1;
|
||||||
|
return fx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(Dogleg, SimpleCase) {
|
||||||
|
Vec3 x; x << 0.76026643, -30.01799744, 0.55192142;
|
||||||
|
F f;
|
||||||
|
Dogleg<F>::SolverParameters params;
|
||||||
|
Dogleg<F> lm(f);
|
||||||
|
/* TODO(sergey): Better error handling. */
|
||||||
|
/* Dogleg<F>::Results results = */ lm.minimize(params, &x);
|
||||||
|
Vec3 expected_min_x; expected_min_x << 2, 5, 0;
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example 3.2 from [1]; page 11 of the pdf, 20 of the document. This is a
|
||||||
|
// tricky problem because of the singluar Jacobian near the origin.
|
||||||
|
class F32 {
|
||||||
|
public:
|
||||||
|
typedef Vec2 FMatrixType;
|
||||||
|
typedef Vec2 XMatrixType;
|
||||||
|
Vec2 operator()(const Vec2 &x) const {
|
||||||
|
double x1 = x(0);
|
||||||
|
double x2 = 10*x(0)/(x(0) + 0.1) + 2*x(1)*x(1);
|
||||||
|
Vec2 fx; fx << x1, x2;
|
||||||
|
return fx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class JF32 {
|
||||||
|
public:
|
||||||
|
JF32(const F32 &f) { (void) f; }
|
||||||
|
Mat2 operator()(const Vec2 &x) {
|
||||||
|
Mat2 J; J << 1, 0,
|
||||||
|
1./pow(x(0) + 0.1, 2), 4*x(1)*x(1);
|
||||||
|
return J;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO(keir): Re-enable this when the dogleg code properly handles singular
|
||||||
|
// normal equations.
|
||||||
|
/*
|
||||||
|
TEST(Dogleg, Example32) {
|
||||||
|
Vec2 x; x << 3, 1;
|
||||||
|
F32 f;
|
||||||
|
CheckJacobian<F32, JF32>(f, x);
|
||||||
|
Dogleg<F32, JF32> dogleg(f);
|
||||||
|
Dogleg<F32, JF32>::Results results = dogleg.minimize(&x);
|
||||||
|
Vec2 expected_min_x; expected_min_x << 0, 0;
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
} // namespace
|
57
extern/libmv/libmv/numeric/function_derivative_test.cc
vendored
Normal file
57
extern/libmv/libmv/numeric/function_derivative_test.cc
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
// Copyright (c) 2007, 2008, 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/numeric/function_derivative.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class F {
|
||||||
|
public:
|
||||||
|
typedef Vec2 FMatrixType;
|
||||||
|
typedef Vec3 XMatrixType;
|
||||||
|
Vec2 operator()(const Vec3 &x) const {
|
||||||
|
Vec2 fx;
|
||||||
|
fx << 0.19*x(0) + 0.19*x(1)*x(1) + x(2),
|
||||||
|
3*sin(x(0)) + 2*cos(x(1));
|
||||||
|
return fx;
|
||||||
|
}
|
||||||
|
Mat23 J(const Vec3 &x) const {
|
||||||
|
Mat23 jacobian;
|
||||||
|
jacobian << 0.19, 2*0.19*x(1), 1.0,
|
||||||
|
3*cos(x(0)), -2*sin(x(1)), 0;
|
||||||
|
return jacobian;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(FunctionDerivative, SimpleCase) {
|
||||||
|
Vec3 x; x << 0.76026643, 0.01799744, 0.55192142;
|
||||||
|
F f;
|
||||||
|
NumericJacobian<F, CENTRAL> J(f);
|
||||||
|
EXPECT_MATRIX_NEAR(f.J(x), J(x), 1e-8);
|
||||||
|
NumericJacobian<F, FORWARD> J_forward(f);
|
||||||
|
// Forward difference is very inaccurate.
|
||||||
|
EXPECT_MATRIX_NEAR(f.J(x), J_forward(x), 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
56
extern/libmv/libmv/numeric/levenberg_marquardt_test.cc
vendored
Normal file
56
extern/libmv/libmv/numeric/levenberg_marquardt_test.cc
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2007, 2008, 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/numeric/levenberg_marquardt.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class F {
|
||||||
|
public:
|
||||||
|
typedef Vec4 FMatrixType;
|
||||||
|
typedef Vec3 XMatrixType;
|
||||||
|
Vec4 operator()(const Vec3 &x) const {
|
||||||
|
double x1 = x.x() - 2;
|
||||||
|
double y1 = x.y() - 5;
|
||||||
|
double z1 = x.z();
|
||||||
|
Vec4 fx; fx << x1*x1 + z1*z1,
|
||||||
|
y1*y1 + z1*z1,
|
||||||
|
z1*z1,
|
||||||
|
x1*x1;
|
||||||
|
return fx;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(LevenbergMarquardt, SimpleCase) {
|
||||||
|
Vec3 x(0.76026643, -30.01799744, 0.55192142);
|
||||||
|
F f;
|
||||||
|
LevenbergMarquardt<F>::SolverParameters params;
|
||||||
|
LevenbergMarquardt<F> lm(f);
|
||||||
|
/* TODO(sergey): Better error handling. */
|
||||||
|
/* LevenbergMarquardt<F>::Results results = */ lm.minimize(params, &x);
|
||||||
|
Vec3 expected_min_x(2, 5, 0);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(expected_min_x, x, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
439
extern/libmv/libmv/numeric/numeric_test.cc
vendored
Normal file
439
extern/libmv/libmv/numeric/numeric_test.cc
vendored
Normal file
@ -0,0 +1,439 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(Numeric, DynamicSizedNullspace) {
|
||||||
|
Mat A(3, 4);
|
||||||
|
A << 0.76026643, 0.01799744, 0.55192142, 0.8699745,
|
||||||
|
0.42016166, 0.97863392, 0.33711682, 0.14479271,
|
||||||
|
0.51016811, 0.66528302, 0.54395496, 0.57794893;
|
||||||
|
Vec x;
|
||||||
|
double s = Nullspace(&A, &x);
|
||||||
|
EXPECT_NEAR(0.0, s, 1e-15);
|
||||||
|
EXPECT_NEAR(0.0, (A * x).norm(), 1e-15);
|
||||||
|
EXPECT_NEAR(1.0, x.norm(), 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, FixedSizeMatrixNullspace) {
|
||||||
|
Mat34 A;
|
||||||
|
A << 0.76026643, 0.01799744, 0.55192142, 0.8699745,
|
||||||
|
0.42016166, 0.97863392, 0.33711682, 0.14479271,
|
||||||
|
0.51016811, 0.66528302, 0.54395496, 0.57794893;
|
||||||
|
Vec x;
|
||||||
|
double s = Nullspace(&A, &x);
|
||||||
|
EXPECT_NEAR(0.0, s, 1e-15);
|
||||||
|
EXPECT_NEAR(0.0, (A * x).norm(), 1e-15);
|
||||||
|
EXPECT_NEAR(1.0, x.norm(), 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, NullspaceMatchesLapackSVD) {
|
||||||
|
Mat43 A;
|
||||||
|
A << 0.76026643, 0.01799744, 0.55192142,
|
||||||
|
0.8699745, 0.42016166, 0.97863392,
|
||||||
|
0.33711682, 0.14479271, 0.51016811,
|
||||||
|
0.66528302, 0.54395496, 0.57794893;
|
||||||
|
Vec x;
|
||||||
|
double s = Nullspace(&A, &x);
|
||||||
|
EXPECT_NEAR(1.0, x.norm(), 1e-15);
|
||||||
|
EXPECT_NEAR(0.206694992663, s, 1e-9);
|
||||||
|
EXPECT_NEAR(0.206694992663, (A * x).norm(), 1e-9);
|
||||||
|
|
||||||
|
EXPECT_NEAR(-0.64999717, x(0), 1e-8);
|
||||||
|
EXPECT_NEAR(-0.18452646, x(1), 1e-8);
|
||||||
|
EXPECT_NEAR(0.7371931, x(2), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, Nullspace2) {
|
||||||
|
Mat43 A;
|
||||||
|
A << 0.76026643, 0.01799744, 0.55192142,
|
||||||
|
0.8699745, 0.42016166, 0.97863392,
|
||||||
|
0.33711682, 0.14479271, 0.51016811,
|
||||||
|
0.66528302, 0.54395496, 0.57794893;
|
||||||
|
Vec3 x1, x2;
|
||||||
|
double s = Nullspace2(&A, &x1, &x2);
|
||||||
|
EXPECT_NEAR(1.0, x1.norm(), 1e-15);
|
||||||
|
EXPECT_NEAR(0.206694992663, s, 1e-9);
|
||||||
|
EXPECT_NEAR(0.206694992663, (A * x1).norm(), 1e-9);
|
||||||
|
|
||||||
|
EXPECT_NEAR(-0.64999717, x1(0), 1e-8);
|
||||||
|
EXPECT_NEAR(-0.18452646, x1(1), 1e-8);
|
||||||
|
EXPECT_NEAR( 0.7371931, x1(2), 1e-8);
|
||||||
|
|
||||||
|
if (x2(0) < 0) {
|
||||||
|
x2 *= -1;
|
||||||
|
}
|
||||||
|
EXPECT_NEAR( 0.34679618, x2(0), 1e-8);
|
||||||
|
EXPECT_NEAR(-0.93519689, x2(1), 1e-8);
|
||||||
|
EXPECT_NEAR( 0.07168809, x2(2), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, TinyMatrixSquareTranspose) {
|
||||||
|
Mat2 A;
|
||||||
|
A << 1.0, 2.0, 3.0, 4.0;
|
||||||
|
libmv::TransposeInPlace(&A);
|
||||||
|
EXPECT_EQ(1.0, A(0, 0));
|
||||||
|
EXPECT_EQ(3.0, A(0, 1));
|
||||||
|
EXPECT_EQ(2.0, A(1, 0));
|
||||||
|
EXPECT_EQ(4.0, A(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, NormalizeL1) {
|
||||||
|
Vec2 x;
|
||||||
|
x << 1, 2;
|
||||||
|
double l1 = NormalizeL1(&x);
|
||||||
|
EXPECT_DOUBLE_EQ(3., l1);
|
||||||
|
EXPECT_DOUBLE_EQ(1./3., x(0));
|
||||||
|
EXPECT_DOUBLE_EQ(2./3., x(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, NormalizeL2) {
|
||||||
|
Vec2 x;
|
||||||
|
x << 1, 2;
|
||||||
|
double l2 = NormalizeL2(&x);
|
||||||
|
EXPECT_DOUBLE_EQ(sqrt(5.0), l2);
|
||||||
|
EXPECT_DOUBLE_EQ(1./sqrt(5.), x(0));
|
||||||
|
EXPECT_DOUBLE_EQ(2./sqrt(5.), x(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, Diag) {
|
||||||
|
Vec x(2);
|
||||||
|
x << 1, 2;
|
||||||
|
Mat D = Diag(x);
|
||||||
|
EXPECT_EQ(1, D(0, 0));
|
||||||
|
EXPECT_EQ(0, D(0, 1));
|
||||||
|
EXPECT_EQ(0, D(1, 0));
|
||||||
|
EXPECT_EQ(2, D(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, Determinant) {
|
||||||
|
Mat A(2, 2);
|
||||||
|
A << 1, 2,
|
||||||
|
-1, 3;
|
||||||
|
double detA = A.determinant();
|
||||||
|
EXPECT_NEAR(5, detA, 1e-8);
|
||||||
|
|
||||||
|
Mat B(4, 4);
|
||||||
|
B << 0, 1, 2, 3,
|
||||||
|
4, 5, 6, 7,
|
||||||
|
8, 9, 10, 11,
|
||||||
|
12, 13, 14, 15;
|
||||||
|
double detB = B.determinant();
|
||||||
|
EXPECT_NEAR(0, detB, 1e-8);
|
||||||
|
|
||||||
|
Mat3 C;
|
||||||
|
C << 0, 1, 2,
|
||||||
|
3, 4, 5,
|
||||||
|
6, 7, 1;
|
||||||
|
double detC = C.determinant();
|
||||||
|
EXPECT_NEAR(21, detC, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, Inverse) {
|
||||||
|
Mat A(2, 2), A1;
|
||||||
|
A << 1, 2,
|
||||||
|
-1, 3;
|
||||||
|
Mat I = A * A.inverse();
|
||||||
|
|
||||||
|
EXPECT_NEAR(1, I(0, 0), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I(0, 1), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I(1, 0), 1e-8);
|
||||||
|
EXPECT_NEAR(1, I(1, 1), 1e-8);
|
||||||
|
|
||||||
|
Mat B(4, 4), B1;
|
||||||
|
B << 0, 1, 2, 3,
|
||||||
|
4, 5, 6, 7,
|
||||||
|
8, 9, 2, 11,
|
||||||
|
12, 13, 14, 4;
|
||||||
|
Mat I2 = B * B.inverse();
|
||||||
|
EXPECT_NEAR(1, I2(0, 0), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(0, 1), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(0, 2), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(1, 0), 1e-8);
|
||||||
|
EXPECT_NEAR(1, I2(1, 1), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(1, 2), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(2, 0), 1e-8);
|
||||||
|
EXPECT_NEAR(0, I2(2, 1), 1e-8);
|
||||||
|
EXPECT_NEAR(1, I2(2, 2), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, MeanAndVarianceAlongRows) {
|
||||||
|
int n = 4;
|
||||||
|
Mat points(2, n);
|
||||||
|
points << 0, 0, 1, 1,
|
||||||
|
0, 2, 1, 3;
|
||||||
|
|
||||||
|
Vec mean, variance;
|
||||||
|
MeanAndVarianceAlongRows(points, &mean, &variance);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, mean(0), 1e-8);
|
||||||
|
EXPECT_NEAR(1.5, mean(1), 1e-8);
|
||||||
|
EXPECT_NEAR(0.25, variance(0), 1e-8);
|
||||||
|
EXPECT_NEAR(1.25, variance(1), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, HorizontalStack) {
|
||||||
|
Mat x(2, 1), y(2, 1), z;
|
||||||
|
x << 1, 2;
|
||||||
|
y << 3, 4;
|
||||||
|
|
||||||
|
HorizontalStack(x, y, &z);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, z.cols());
|
||||||
|
EXPECT_EQ(2, z.rows());
|
||||||
|
EXPECT_EQ(1, z(0, 0));
|
||||||
|
EXPECT_EQ(2, z(1, 0));
|
||||||
|
EXPECT_EQ(3, z(0, 1));
|
||||||
|
EXPECT_EQ(4, z(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, HStack) {
|
||||||
|
Mat x(2, 1), y(2, 1), z(2, 2);
|
||||||
|
x << 1, 2;
|
||||||
|
y << 3, 4;
|
||||||
|
z << 1, 3,
|
||||||
|
2, 4;
|
||||||
|
Vec2 xC = x, yC = y;
|
||||||
|
|
||||||
|
Mat2 xy = HStack(x, y);
|
||||||
|
EXPECT_MATRIX_EQ(z, xy);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_EQ(z, HStack(x, y));
|
||||||
|
EXPECT_MATRIX_EQ(z, HStack(x, yC));
|
||||||
|
EXPECT_MATRIX_EQ(z, HStack(xC, y));
|
||||||
|
EXPECT_MATRIX_EQ(z, HStack(xC, yC));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(keir): Need some way of verifying that the compile time types of the
|
||||||
|
// resulting stacked matrices properly propagate the fixed dimensions.
|
||||||
|
TEST(Numeric, VStack) {
|
||||||
|
Mat x(2, 2), y(2, 2), z(4, 2);
|
||||||
|
x << 1, 2,
|
||||||
|
3, 4;
|
||||||
|
y << 10, 20,
|
||||||
|
30, 40;
|
||||||
|
z << 1, 2,
|
||||||
|
3, 4,
|
||||||
|
10, 20,
|
||||||
|
30, 40;
|
||||||
|
Mat2 xC = x, yC = y;
|
||||||
|
|
||||||
|
Mat xy = VStack(x, y);
|
||||||
|
EXPECT_MATRIX_EQ(z, xy);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_EQ(z, VStack(x, y));
|
||||||
|
EXPECT_MATRIX_EQ(z, VStack(x, yC));
|
||||||
|
EXPECT_MATRIX_EQ(z, VStack(xC, y));
|
||||||
|
EXPECT_MATRIX_EQ(z, VStack(xC, yC));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, VerticalStack) {
|
||||||
|
Mat x(1, 2), y(1, 2), z;
|
||||||
|
x << 1, 2;
|
||||||
|
y << 3, 4;
|
||||||
|
VerticalStack(x, y, &z);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, z.cols());
|
||||||
|
EXPECT_EQ(2, z.rows());
|
||||||
|
EXPECT_EQ(1, z(0, 0));
|
||||||
|
EXPECT_EQ(2, z(0, 1));
|
||||||
|
EXPECT_EQ(3, z(1, 0));
|
||||||
|
EXPECT_EQ(4, z(1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, CrossProduct) {
|
||||||
|
Vec3 x, y, z;
|
||||||
|
x << 1, 0, 0;
|
||||||
|
y << 0, 1, 0;
|
||||||
|
z << 0, 0, 1;
|
||||||
|
Vec3 xy = CrossProduct(x, y);
|
||||||
|
Vec3 yz = CrossProduct(y, z);
|
||||||
|
Vec3 zx = CrossProduct(z, x);
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(xy, z), 1e-8);
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(yz, x), 1e-8);
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(zx, y), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, CrossProductMatrix) {
|
||||||
|
Vec3 x, y;
|
||||||
|
x << 1, 2, 3;
|
||||||
|
y << 2, 3, 4;
|
||||||
|
Vec3 xy = CrossProduct(x, y);
|
||||||
|
Vec3 yx = CrossProduct(y, x);
|
||||||
|
Mat3 X = CrossProductMatrix(x);
|
||||||
|
Vec3 Xy, Xty;
|
||||||
|
Xy = X * y;
|
||||||
|
Xty = X.transpose() * y;
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(xy, Xy), 1e-8);
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(yx, Xty), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, MatrixColumn) {
|
||||||
|
Mat A2(2, 3);
|
||||||
|
Vec2 v2;
|
||||||
|
A2 << 1, 2, 3,
|
||||||
|
4, 5, 6;
|
||||||
|
MatrixColumn(A2, 1, &v2);
|
||||||
|
EXPECT_EQ(2, v2(0));
|
||||||
|
EXPECT_EQ(5, v2(1));
|
||||||
|
|
||||||
|
Mat A3(3, 3);
|
||||||
|
Vec3 v3;
|
||||||
|
A3 << 1, 2, 3,
|
||||||
|
4, 5, 6,
|
||||||
|
7, 8, 9;
|
||||||
|
MatrixColumn(A3, 1, &v3);
|
||||||
|
EXPECT_EQ(2, v3(0));
|
||||||
|
EXPECT_EQ(5, v3(1));
|
||||||
|
EXPECT_EQ(8, v3(2));
|
||||||
|
|
||||||
|
Mat A4(4, 3);
|
||||||
|
Vec4 v4;
|
||||||
|
A4 << 1, 2, 3,
|
||||||
|
4, 5, 6,
|
||||||
|
7, 8, 9,
|
||||||
|
10, 11, 12;
|
||||||
|
MatrixColumn(A4, 1, &v4);
|
||||||
|
EXPECT_EQ( 2, v4(0));
|
||||||
|
EXPECT_EQ( 5, v4(1));
|
||||||
|
EXPECT_EQ( 8, v4(2));
|
||||||
|
EXPECT_EQ(11, v4(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This used to give a compile error with FLENS.
|
||||||
|
TEST(Numeric, TinyMatrixView) {
|
||||||
|
Mat34 P;
|
||||||
|
Mat K = P.block(0, 0, 3, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gives a compile error.
|
||||||
|
TEST(Numeric, Mat3MatProduct) {
|
||||||
|
Mat3 A;
|
||||||
|
Mat3 B;
|
||||||
|
Mat C = A * B;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gives a compile error.
|
||||||
|
TEST(Numeric, Vec3Negative) {
|
||||||
|
Vec3 y; y << 1, 2, 3;
|
||||||
|
Vec3 x = -y;
|
||||||
|
EXPECT_EQ(-1, x(0));
|
||||||
|
EXPECT_EQ(-2, x(1));
|
||||||
|
EXPECT_EQ(-3, x(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gives a compile error.
|
||||||
|
TEST(Numeric, Vec3VecInteroperability) {
|
||||||
|
Vec y(3);
|
||||||
|
y << 1, 2, 3;
|
||||||
|
Vec3 x = y + y;
|
||||||
|
EXPECT_EQ(2, x(0));
|
||||||
|
EXPECT_EQ(4, x(1));
|
||||||
|
EXPECT_EQ(6, x(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This segfaults inside lapack.
|
||||||
|
TEST(Numeric, DeterminantLU7) {
|
||||||
|
Mat A(5, 5);
|
||||||
|
A << 1, 0, 0, 0, 0,
|
||||||
|
0, 1, 0, 0, 0,
|
||||||
|
0, 0, 1, 0, 0,
|
||||||
|
0, 0, 0, 1, 0,
|
||||||
|
0, 0, 0, 0, 1;
|
||||||
|
EXPECT_NEAR(1, A.determinant(), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This segfaults inside lapack.
|
||||||
|
TEST(Numeric, DeterminantLU) {
|
||||||
|
Mat A(2, 2);
|
||||||
|
A << 1, 2,
|
||||||
|
-1, 3;
|
||||||
|
EXPECT_NEAR(5, A.determinant(), 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This does unexpected things.
|
||||||
|
// Keir: Not with eigen2!
|
||||||
|
TEST(Numeric, InplaceProduct) {
|
||||||
|
Mat2 K, S;
|
||||||
|
K << 1, 0,
|
||||||
|
0, 1;
|
||||||
|
S << 1, 0,
|
||||||
|
0, 1;
|
||||||
|
K = K * S;
|
||||||
|
EXPECT_MATRIX_NEAR(Mat2::Identity(), K, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, ExtractColumns) {
|
||||||
|
Mat2X A(2, 5);
|
||||||
|
A << 1, 2, 3, 4, 5,
|
||||||
|
6, 7, 8, 9, 10;
|
||||||
|
Vec2i columns; columns << 0, 2;
|
||||||
|
Mat2X extracted = ExtractColumns(A, columns);
|
||||||
|
EXPECT_NEAR(1, extracted(0, 0), 1e-15);
|
||||||
|
EXPECT_NEAR(3, extracted(0, 1), 1e-15);
|
||||||
|
EXPECT_NEAR(6, extracted(1, 0), 1e-15);
|
||||||
|
EXPECT_NEAR(8, extracted(1, 1), 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, RotationRodrigues) {
|
||||||
|
Vec3 x, y, z;
|
||||||
|
x << 1, 0, 0;
|
||||||
|
y << 0, 1, 0;
|
||||||
|
z << 0, 0, 1;
|
||||||
|
|
||||||
|
Mat3 rodrigues_x = RotationRodrigues(x);
|
||||||
|
Mat3 rodrigues_y = RotationRodrigues(y);
|
||||||
|
Mat3 rodrigues_z = RotationRodrigues(z);
|
||||||
|
|
||||||
|
Mat3 Rx = RotationAroundX(1);
|
||||||
|
Mat3 Ry = RotationAroundY(1);
|
||||||
|
Mat3 Rz = RotationAroundZ(1);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(Rx, rodrigues_x, 1e-15);
|
||||||
|
EXPECT_MATRIX_NEAR(Ry, rodrigues_y, 1e-15);
|
||||||
|
EXPECT_MATRIX_NEAR(Rz, rodrigues_z, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, LookAt) {
|
||||||
|
// Simple orthogonality check.
|
||||||
|
Vec3 e; e << 1, 2, 3;
|
||||||
|
Mat3 R = LookAt(e), I = Mat3::Identity();
|
||||||
|
Mat3 RRT = R*R.transpose();
|
||||||
|
Mat3 RTR = R.transpose()*R;
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(I, RRT, 1e-15);
|
||||||
|
EXPECT_MATRIX_NEAR(I, RTR, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Numeric, Reshape) {
|
||||||
|
Vec4 x; x << 1, 2, 3, 4;
|
||||||
|
Mat2 M, M_expected;
|
||||||
|
reshape(x, 2, 2, &M);
|
||||||
|
M_expected << 1, 2,
|
||||||
|
3, 4;
|
||||||
|
EXPECT_MATRIX_NEAR(M_expected, M, 1e-15);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
98
extern/libmv/libmv/numeric/poly_test.cc
vendored
Normal file
98
extern/libmv/libmv/numeric/poly_test.cc
vendored
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/numeric/poly.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
using namespace libmv;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Find the polynomial coefficients of x in the equation
|
||||||
|
//
|
||||||
|
// (x - a)(x - b)(x - c) == 0
|
||||||
|
//
|
||||||
|
// by expanding to
|
||||||
|
//
|
||||||
|
// x^3 - (c+b+a) * x^2 + (a*b+(b+a)*c) * x - a*b*c = 0.
|
||||||
|
// = p = q = r
|
||||||
|
void CoeffsForCubicZeros(double a, double b, double c,
|
||||||
|
double *p, double *q, double *r) {
|
||||||
|
*p = -(c + b + a);
|
||||||
|
*q = (a * b + (b + a) * c);
|
||||||
|
*r = -a * b * c;
|
||||||
|
}
|
||||||
|
// Find the polynomial coefficients of x in the equation
|
||||||
|
//
|
||||||
|
// (x - a)(x - b)(x - c)(x - d) == 0
|
||||||
|
//
|
||||||
|
// by expanding to
|
||||||
|
//
|
||||||
|
// x^4 - (d+c+b+a) * x^3 + (d*(c+b+a) + a*b+(b+a)*c) * x^2
|
||||||
|
// - (d*(a*b+(b+a)*c)+a*b*c) * x + a*b*c*d = 0.
|
||||||
|
void CoeffsForQuarticZeros(double a, double b, double c, double d,
|
||||||
|
double *p, double *q, double *r, double *s) {
|
||||||
|
*p = -(d + c + b + a);
|
||||||
|
*q = (d * (c + b + a) + a * b + (b + a) * c);
|
||||||
|
*r = -(d * (a * b + (b + a) * c) + a * b * c);
|
||||||
|
*s = a * b * c *d;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Poly, SolveCubicPolynomial) {
|
||||||
|
double a, b, c, aa, bb, cc;
|
||||||
|
double p, q, r;
|
||||||
|
|
||||||
|
a = 1; b = 2; c = 3;
|
||||||
|
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
|
||||||
|
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
|
||||||
|
EXPECT_NEAR(a, aa, 1e-10);
|
||||||
|
EXPECT_NEAR(b, bb, 1e-10);
|
||||||
|
EXPECT_NEAR(c, cc, 1e-10);
|
||||||
|
|
||||||
|
a = 0; b = 1; c = 3;
|
||||||
|
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
|
||||||
|
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
|
||||||
|
EXPECT_NEAR(a, aa, 1e-10);
|
||||||
|
EXPECT_NEAR(b, bb, 1e-10);
|
||||||
|
EXPECT_NEAR(c, cc, 1e-10);
|
||||||
|
|
||||||
|
a = -10; b = 0; c = 1;
|
||||||
|
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
|
||||||
|
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
|
||||||
|
EXPECT_NEAR(a, aa, 1e-10);
|
||||||
|
EXPECT_NEAR(b, bb, 1e-10);
|
||||||
|
EXPECT_NEAR(c, cc, 1e-10);
|
||||||
|
|
||||||
|
a = -8; b = 1; c = 3;
|
||||||
|
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
|
||||||
|
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
|
||||||
|
EXPECT_NEAR(a, aa, 1e-10);
|
||||||
|
EXPECT_NEAR(b, bb, 1e-10);
|
||||||
|
EXPECT_NEAR(c, cc, 1e-10);
|
||||||
|
|
||||||
|
a = 28; b = 28; c = 105;
|
||||||
|
CoeffsForCubicZeros(a, b, c, &p, &q, &r);
|
||||||
|
ASSERT_EQ(3, SolveCubicPolynomial(p, q, r, &aa, &bb, &cc));
|
||||||
|
EXPECT_NEAR(a, aa, 1e-10);
|
||||||
|
EXPECT_NEAR(b, bb, 1e-10);
|
||||||
|
EXPECT_NEAR(c, cc, 1e-10);
|
||||||
|
}
|
||||||
|
} // namespace
|
239
extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
vendored
Normal file
239
extern/libmv/libmv/simple_pipeline/camera_intrinsics_test.cc
vendored
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/image/image_drawing.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics2, ApplyOnFocalCenter) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1300.0, 1300.0);
|
||||||
|
intrinsics.SetPrincipalPoint(640.0, 540.0);
|
||||||
|
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
|
||||||
|
|
||||||
|
double distorted_x, distorted_y;
|
||||||
|
intrinsics.ApplyIntrinsics(0.0, 0.0, &distorted_x, &distorted_y);
|
||||||
|
|
||||||
|
EXPECT_NEAR(640.0, distorted_x, 1e-8);
|
||||||
|
EXPECT_NEAR(540.0, distorted_y, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, InvertOnFocalCenter) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1300.0, 1300.0);
|
||||||
|
intrinsics.SetPrincipalPoint(640.0, 540.0);
|
||||||
|
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
|
||||||
|
|
||||||
|
double normalized_x, normalized_y;
|
||||||
|
intrinsics.InvertIntrinsics(640.0, 540.0, &normalized_x, &normalized_y);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.0, normalized_x, 1e-8);
|
||||||
|
EXPECT_NEAR(0.0, normalized_y, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, ApplyIntrinsics) {
|
||||||
|
const int N = 5;
|
||||||
|
|
||||||
|
double expected[N][N][2] = {
|
||||||
|
{ {75.312500, -24.687500}, {338.982239, -62.035522},
|
||||||
|
{640.000000, -72.929688}, {941.017761, -62.035522},
|
||||||
|
{1204.687500, -24.687500}},
|
||||||
|
|
||||||
|
{ {37.964478, 238.982239}, {323.664551, 223.664551},
|
||||||
|
{640.000000, 219.193420}, {956.335449, 223.664551},
|
||||||
|
{1242.035522, 238.982239}},
|
||||||
|
|
||||||
|
{ {27.070312, 540.000000}, {319.193420, 540.000000},
|
||||||
|
{640.000000, 540.000000}, {960.806580, 540.000000},
|
||||||
|
{1252.929688, 540.000000}},
|
||||||
|
|
||||||
|
{ {37.964478, 841.017761}, {323.664551, 856.335449},
|
||||||
|
{640.000000, 860.806580}, {956.335449, 856.335449},
|
||||||
|
{1242.035522, 841.017761}},
|
||||||
|
|
||||||
|
{ {75.312500, 1104.687500}, {338.982239, 1142.035522},
|
||||||
|
{640.000000, 1152.929688}, {941.017761, 1142.035522},
|
||||||
|
{1204.687500, 1104.687500}}
|
||||||
|
};
|
||||||
|
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1300.0, 1300.0);
|
||||||
|
intrinsics.SetPrincipalPoint(640.0, 540.0);
|
||||||
|
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
|
||||||
|
|
||||||
|
double step = 1.0 / (N - 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
double normalized_x = j * step - 0.5,
|
||||||
|
normalized_y = i * step - 0.5;
|
||||||
|
|
||||||
|
double distorted_x, distorted_y;
|
||||||
|
intrinsics.ApplyIntrinsics(normalized_x, normalized_y,
|
||||||
|
&distorted_x, &distorted_y);
|
||||||
|
|
||||||
|
EXPECT_NEAR(expected[i][j][0], distorted_x, 1e-6);
|
||||||
|
EXPECT_NEAR(expected[i][j][1], distorted_y, 1e-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, InvertIntrinsics) {
|
||||||
|
const int N = 5;
|
||||||
|
|
||||||
|
double expected[N][N][2] = {
|
||||||
|
{ {-0.524482, -0.437069}, {-0.226237, -0.403994},
|
||||||
|
{ 0.031876, -0.398446}, { 0.293917, -0.408218},
|
||||||
|
{ 0.632438, -0.465028}},
|
||||||
|
|
||||||
|
{ {-0.493496, -0.189173}, {-0.219052, -0.179936},
|
||||||
|
{ 0.030975, -0.178107}, { 0.283742, -0.181280},
|
||||||
|
{ 0.574557, -0.194335}},
|
||||||
|
|
||||||
|
{ {-0.488013, 0.032534}, {-0.217537, 0.031077},
|
||||||
|
{ 0.030781, 0.030781}, { 0.281635, 0.031293},
|
||||||
|
{ 0.566344, 0.033314}},
|
||||||
|
|
||||||
|
{ {-0.498696, 0.257660}, {-0.220424, 0.244041},
|
||||||
|
{ 0.031150, 0.241409}, { 0.285660, 0.245985},
|
||||||
|
{ 0.582670, 0.265629}},
|
||||||
|
|
||||||
|
{ {-0.550617, 0.532263}, {-0.230399, 0.477255},
|
||||||
|
{ 0.032380, 0.469510}, { 0.299986, 0.483311},
|
||||||
|
{ 0.684740, 0.584043}}
|
||||||
|
};
|
||||||
|
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1300.0, 1300.0);
|
||||||
|
intrinsics.SetPrincipalPoint(600.0, 500.0);
|
||||||
|
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
|
||||||
|
|
||||||
|
double step_x = 1280.0 / (N - 1),
|
||||||
|
step_y = 1080.0 / (N - 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
for (int j = 0; j < N; j++) {
|
||||||
|
double distorted_x = j * step_x,
|
||||||
|
distorted_y = i * step_y;
|
||||||
|
|
||||||
|
double normalized_x, normalized_y;
|
||||||
|
intrinsics.InvertIntrinsics(distorted_x, distorted_y,
|
||||||
|
&normalized_x, &normalized_y);
|
||||||
|
|
||||||
|
EXPECT_NEAR(expected[i][j][0], normalized_x, 1e-6);
|
||||||
|
EXPECT_NEAR(expected[i][j][1], normalized_y, 1e-6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, ApplyIsInvertibleSimple) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1300.0, 1300.0);
|
||||||
|
intrinsics.SetPrincipalPoint(640.0, 540.0);
|
||||||
|
intrinsics.SetRadialDistortion(-0.2, -0.1, -0.05);
|
||||||
|
|
||||||
|
// Scan over image coordinates, invert the intrinsics, then re-apply them to
|
||||||
|
// make sure the cycle gets back where it started.
|
||||||
|
for (double y = 0; y < 1000; y += 100) {
|
||||||
|
for (double x = 0; x < 1000; x += 100) {
|
||||||
|
double normalized_x, normalized_y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &normalized_x, &normalized_y);
|
||||||
|
|
||||||
|
double xp, yp;
|
||||||
|
intrinsics.ApplyIntrinsics(normalized_x, normalized_y, &xp, &yp);
|
||||||
|
|
||||||
|
EXPECT_NEAR(x, xp, 1e-8) << "y: " << y;
|
||||||
|
EXPECT_NEAR(y, yp, 1e-8) << "x: " << x;
|
||||||
|
LG << "Error x: " << (x - xp);
|
||||||
|
LG << "Error y: " << (y - yp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, IdentityDistortBuffer) {
|
||||||
|
const int w = 101, h = 101;
|
||||||
|
FloatImage image(h, w);
|
||||||
|
image.Fill(0);
|
||||||
|
|
||||||
|
DrawLine(0.0, h / 2.0, w - 1, h / 2.0, 1.0, &image);
|
||||||
|
DrawLine(0.0, h / 4.0, w - 1, h / 4.0, 1.0, &image);
|
||||||
|
DrawLine(0.0, h / 4.0 * 3.0, w - 1.0, h / 4.0 * 3.0, 1.0, &image);
|
||||||
|
DrawLine(w / 2.0, 0.0, w / 2.0, h - 1.0, 1.0, &image);
|
||||||
|
DrawLine(w / 4.0, 0.0, w / 4.0, h - 1.0, 1.0, &image);
|
||||||
|
DrawLine(w / 4.0 * 3.0, 0.0, w / 4.0 * 3.0, h - 1.0, 1.0, &image);
|
||||||
|
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
FloatImage distorted_image(h, w);
|
||||||
|
intrinsics.SetImageSize(w, h);
|
||||||
|
intrinsics.SetFocalLength(10.0, 10.0);
|
||||||
|
intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
intrinsics.DistortBuffer(image.Data(),
|
||||||
|
image.Width(), image.Height(),
|
||||||
|
0.0,
|
||||||
|
image.Depth(),
|
||||||
|
distorted_image.Data());
|
||||||
|
|
||||||
|
for (int x = 0; x < image.Width(); ++x) {
|
||||||
|
for (int y = 0; y < image.Height(); ++y) {
|
||||||
|
EXPECT_EQ(image(y, x), distorted_image(y, x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(PolynomialCameraIntrinsics, IdentityUndistortBuffer) {
|
||||||
|
const int w = 101, h = 101;
|
||||||
|
FloatImage image(h, w);
|
||||||
|
image.Fill(0);
|
||||||
|
|
||||||
|
DrawLine(0.0, h / 2.0, w - 1, h / 2.0, 1.0, &image);
|
||||||
|
DrawLine(0.0, h / 4.0, w - 1, h / 4.0, 1.0, &image);
|
||||||
|
DrawLine(0.0, h / 4.0 * 3.0, w - 1.0, h / 4.0 * 3.0, 1.0, &image);
|
||||||
|
DrawLine(w / 2.0, 0.0, w / 2.0, h - 1.0, 1.0, &image);
|
||||||
|
DrawLine(w / 4.0, 0.0, w / 4.0, h - 1.0, 1.0, &image);
|
||||||
|
DrawLine(w / 4.0 * 3.0, 0.0, w / 4.0 * 3.0, h - 1.0, 1.0, &image);
|
||||||
|
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
FloatImage distorted_image(h, w);
|
||||||
|
intrinsics.SetImageSize(w, h);
|
||||||
|
intrinsics.SetFocalLength(10.0, 10.0);
|
||||||
|
intrinsics.SetPrincipalPoint((double) w / 2.0, (double) h / 2.0);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
intrinsics.UndistortBuffer(image.Data(),
|
||||||
|
image.Width(), image.Height(),
|
||||||
|
0.0,
|
||||||
|
image.Depth(),
|
||||||
|
distorted_image.Data());
|
||||||
|
|
||||||
|
for (int x = 0; x < image.Width(); ++x) {
|
||||||
|
for (int y = 0; y < image.Height(); ++y) {
|
||||||
|
EXPECT_EQ(image(y, x), distorted_image(y, x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
230
extern/libmv/libmv/simple_pipeline/detect_test.cc
vendored
Normal file
230
extern/libmv/libmv/simple_pipeline/detect_test.cc
vendored
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
// Copyright (c) 2014 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/detect.h"
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void PreformSinglePointTest(const DetectOptions &options) {
|
||||||
|
// Prepare the image.
|
||||||
|
FloatImage image(15, 15);
|
||||||
|
image.fill(1.0);
|
||||||
|
image(7, 7) = 0.0;
|
||||||
|
|
||||||
|
// Run the detector.
|
||||||
|
vector<Feature> detected_features;
|
||||||
|
Detect(image, options, &detected_features);
|
||||||
|
|
||||||
|
// Check detected features matches our expectations.
|
||||||
|
EXPECT_EQ(1, detected_features.size());
|
||||||
|
if (detected_features.size() == 1) {
|
||||||
|
Feature &feature = detected_features[0];
|
||||||
|
EXPECT_EQ(7, feature.x);
|
||||||
|
EXPECT_EQ(7, feature.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreformCheckerBoardTest(const DetectOptions &options) {
|
||||||
|
// Prepare the image.
|
||||||
|
FloatImage image(30, 30);
|
||||||
|
for (int y = 0; y < image.Height(); ++y) {
|
||||||
|
for (int x = 0; x < image.Width(); ++x) {
|
||||||
|
image(y, x) = (x / 10 + y / 10) % 2 ? 1.0 : 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the detector.
|
||||||
|
vector<Feature> detected_features;
|
||||||
|
Detect(image, options, &detected_features);
|
||||||
|
|
||||||
|
// Check detected features matches our expectations.
|
||||||
|
|
||||||
|
// We expect here only corners of a center square to be
|
||||||
|
// considered a feature points.
|
||||||
|
EXPECT_EQ(4, detected_features.size());
|
||||||
|
|
||||||
|
// We don't know which side of the corner detector will choose,
|
||||||
|
// so what we're checking here is that detected feature is from
|
||||||
|
// any side of the corner.
|
||||||
|
//
|
||||||
|
// This doesn't check whether there're multiple features which
|
||||||
|
// are placed on different sides of the same corner. The way we
|
||||||
|
// deal with this is requiring min_distance to be greater than 2px.
|
||||||
|
for (int i = 0; i < detected_features.size(); ++i) {
|
||||||
|
Feature &feature = detected_features[i];
|
||||||
|
int rounded_x = ((feature.x + 1) / 10) * 10,
|
||||||
|
rounded_y = ((feature.y + 1) / 10) * 10;
|
||||||
|
EXPECT_LE(1, std::abs(feature.x - rounded_x));
|
||||||
|
EXPECT_LE(1, std::abs(feature.y - rounded_y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckExpectedFeatures(const vector<Feature> &detected_features,
|
||||||
|
const vector<Feature> &expected_features) {
|
||||||
|
EXPECT_EQ(expected_features.size(), detected_features.size());
|
||||||
|
|
||||||
|
// That's unsafe to iterate over vectors when their lengths
|
||||||
|
// doesn't match. And it doesn't make any sense actually since
|
||||||
|
// the test will already be considered failed here.
|
||||||
|
if (expected_features.size() != detected_features.size()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < expected_features.size(); ++i) {
|
||||||
|
const Feature &extected_feature = expected_features[i];
|
||||||
|
bool found = false;
|
||||||
|
for (int j = 0; j < detected_features.size(); ++j) {
|
||||||
|
const Feature &detected_feature = detected_features[j];
|
||||||
|
if (extected_feature.x == detected_feature.x &&
|
||||||
|
extected_feature.y == detected_feature.y) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(found);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreformSingleTriangleTest(const DetectOptions &options) {
|
||||||
|
// Prepare the image.
|
||||||
|
FloatImage image(15, 21);
|
||||||
|
image.fill(1.0);
|
||||||
|
|
||||||
|
int vertex_x = 10, vertex_y = 5;
|
||||||
|
for (int i = 0; i < 6; ++i) {
|
||||||
|
int current_x = vertex_x - i,
|
||||||
|
current_y = vertex_y + i;
|
||||||
|
for (int j = 0; j < i * 2 + 1; ++j, ++current_x) {
|
||||||
|
image(current_y, current_x) = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the detector.
|
||||||
|
vector<Feature> detected_features;
|
||||||
|
Detect(image, options, &detected_features);
|
||||||
|
|
||||||
|
// Check detected features matches our expectations.
|
||||||
|
vector<Feature> expected_features;
|
||||||
|
expected_features.push_back(Feature(6, 10));
|
||||||
|
expected_features.push_back(Feature(14, 10));
|
||||||
|
expected_features.push_back(Feature(10, 6));
|
||||||
|
|
||||||
|
CheckExpectedFeatures(detected_features, expected_features);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#ifndef LIBMV_NO_FAST_DETECTOR
|
||||||
|
TEST(Detect, FASTSinglePointTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::FAST;
|
||||||
|
options.min_distance = 0;
|
||||||
|
options.fast_min_trackness = 1;
|
||||||
|
|
||||||
|
PreformSinglePointTest(options);
|
||||||
|
}
|
||||||
|
#endif // LIBMV_NO_FAST_DETECTOR
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(sergey): FAST doesn't detect checker board corners, but should it?
|
||||||
|
TEST(Detect, FASTCheckerBoardTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::FAST;
|
||||||
|
options.min_distance = 0;
|
||||||
|
options.fast_min_trackness = 1;
|
||||||
|
|
||||||
|
PreformCheckerBoardTest(options);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(sergey): FAST doesn't detect triangle corners!
|
||||||
|
TEST(Detect, FASTSingleTriangleTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::FAST;
|
||||||
|
options.margin = 3;
|
||||||
|
options.min_distance = 0;
|
||||||
|
options.fast_min_trackness = 2;
|
||||||
|
|
||||||
|
PreformSingleTriangleTest(options);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO(sergey): This doesn't actually detect single point,
|
||||||
|
// but should it or it's expected that Moravec wouldn't consider
|
||||||
|
// single point as feature?
|
||||||
|
//
|
||||||
|
// Uncomment this or remove as soon as we know answer for the
|
||||||
|
// question.
|
||||||
|
TEST(Detect, MoravecSinglePointTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::MORAVEC;
|
||||||
|
options.min_distance = 0;
|
||||||
|
options.moravec_max_count = 10;
|
||||||
|
|
||||||
|
PreformSinglePointTest(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sergey): Moravec doesn't detect checker board corners, but should it?
|
||||||
|
TEST(Detect, MoravecCheckerBoardTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::MORAVEC;
|
||||||
|
options.min_distance = 0;
|
||||||
|
options.moravec_max_count = 10;
|
||||||
|
|
||||||
|
PreformCheckerBoardTest(options);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST(Detect, HarrisSinglePointTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::HARRIS;
|
||||||
|
|
||||||
|
// Set this to non-zero so image corners are not considered
|
||||||
|
// a feature points and avoid center point neighbors to be
|
||||||
|
// considered a features as well.
|
||||||
|
options.margin = 3;
|
||||||
|
options.min_distance = 3;
|
||||||
|
|
||||||
|
PreformSinglePointTest(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Detect, HarrisSingleTriangleTest) {
|
||||||
|
DetectOptions options;
|
||||||
|
options.type = DetectOptions::HARRIS;
|
||||||
|
|
||||||
|
options.margin = 3;
|
||||||
|
options.min_distance = 2;
|
||||||
|
options.harris_threshold = 1e-3;
|
||||||
|
|
||||||
|
PreformSingleTriangleTest(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(sergey): Add tests for margin option.
|
||||||
|
|
||||||
|
// TODO(sergey): Add tests for min_distance option.
|
||||||
|
|
||||||
|
} // namespace libmv
|
81
extern/libmv/libmv/simple_pipeline/intersect_test.cc
vendored
Normal file
81
extern/libmv/libmv/simple_pipeline/intersect_test.cc
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// Copyright (c) 2007, 2008 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/intersect.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/multiview/projection.h"
|
||||||
|
#include "libmv/numeric/numeric.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
TEST(Intersect, EuclideanIntersect) {
|
||||||
|
Mat3 K1 = Mat3::Identity();
|
||||||
|
// K1 << 320, 0, 160,
|
||||||
|
// 0, 320, 120,
|
||||||
|
// 0, 0, 1;
|
||||||
|
Mat3 K2 = Mat3::Identity();
|
||||||
|
// K2 << 360, 0, 170,
|
||||||
|
// 0, 360, 110,
|
||||||
|
// 0, 0, 1;
|
||||||
|
Mat3 R1 = RotationAroundZ(-0.1);
|
||||||
|
Mat3 R2 = RotationAroundX(-0.1);
|
||||||
|
Vec3 t1; t1 << 1, 1, 10;
|
||||||
|
Vec3 t2; t2 << -2, -1, 10;
|
||||||
|
Mat34 P1, P2;
|
||||||
|
P_From_KRt(K1, R1, t1, &P1);
|
||||||
|
P_From_KRt(K2, R2, t2, &P2);
|
||||||
|
|
||||||
|
//Mat3 F; FundamentalFromProjections(P1, P2, &F);
|
||||||
|
|
||||||
|
Mat3X X;
|
||||||
|
X.resize(3, 30);
|
||||||
|
X.setRandom();
|
||||||
|
|
||||||
|
Mat2X X1, X2;
|
||||||
|
Project(P1, X, &X1);
|
||||||
|
Project(P2, X, &X2);
|
||||||
|
|
||||||
|
for (int i = 0; i < X.cols(); ++i) {
|
||||||
|
Vec2 x1, x2;
|
||||||
|
MatrixColumn(X1, i, &x1);
|
||||||
|
MatrixColumn(X2, i, &x2);
|
||||||
|
Vec3 expected;
|
||||||
|
MatrixColumn(X, i, &expected);
|
||||||
|
|
||||||
|
EuclideanReconstruction reconstruction;
|
||||||
|
reconstruction.InsertCamera(1, R1, t1);
|
||||||
|
reconstruction.InsertCamera(2, R2, t2);
|
||||||
|
|
||||||
|
vector<Marker> markers;
|
||||||
|
Marker a = { 1, 0, x1.x(), x1.y(), 1.0 };
|
||||||
|
markers.push_back(a);
|
||||||
|
Marker b = { 2, 0, x2.x(), x2.y(), 1.0 };
|
||||||
|
markers.push_back(b);
|
||||||
|
|
||||||
|
EuclideanIntersect(markers, &reconstruction);
|
||||||
|
Vec3 estimated = reconstruction.PointForTrack(0)->X;
|
||||||
|
EXPECT_NEAR(0, DistanceLInfinity(estimated, expected), 1e-8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
307
extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
vendored
Normal file
307
extern/libmv/libmv/simple_pipeline/keyframe_selection_test.cc
vendored
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/keyframe_selection.h"
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
// Synthetic test, N markers with the same translation
|
||||||
|
// Should not be keyframe
|
||||||
|
TEST(KeyframeSelection, SyntheticNeighborFrame) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(900.0,900.0);
|
||||||
|
intrinsics.SetPrincipalPoint(640.0, 540.0);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
const int markers_per_size = 15;
|
||||||
|
|
||||||
|
// Fill in tracks for homography estimation
|
||||||
|
for (int x = 0; x < markers_per_size; x++) {
|
||||||
|
for (int y = 0; y < markers_per_size; y++) {
|
||||||
|
double current_x = 10 + x * 40, current_y = 10 + y * 40;
|
||||||
|
double next_x = current_x + 10, next_y = current_y + 10;
|
||||||
|
|
||||||
|
intrinsics.InvertIntrinsics(current_x, current_y, ¤t_x, ¤t_y);
|
||||||
|
intrinsics.InvertIntrinsics(next_x, next_y, &next_x, &next_y);
|
||||||
|
|
||||||
|
tracks.Insert(1, y * markers_per_size + x, current_x, current_y);
|
||||||
|
tracks.Insert(2, y * markers_per_size + x, next_x, next_y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
// Synthetic second frame shouldn't be considered a keyframe
|
||||||
|
EXPECT_EQ(0, keyframes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frames 1 and 2 of FabrikEingang footage
|
||||||
|
// Only one wall is tracked, should not be keyframes
|
||||||
|
TEST(KeyframeSelection, FabrikEingangNeighborFrames) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1605.797, 1605.797);
|
||||||
|
intrinsics.SetPrincipalPoint(960.000, 544.000);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 0, 737.599983, 646.397594, 1.0}, {2, 0, 737.906628, 648.113327, 1.0}, {1, 1, 863.045425, 646.081905, 1.0},
|
||||||
|
{2, 1, 863.339767, 647.650040, 1.0}, {1, 2, 736.959972, 574.080151, 1.0}, {2, 2, 737.217350, 575.604900, 1.0},
|
||||||
|
{1, 3, 864.097424, 573.374908, 1.0}, {2, 3, 864.383469, 574.900307, 1.0}, {1, 4, 789.429073, 631.677521, 1.0},
|
||||||
|
{2, 4, 789.893131, 633.124451, 1.0}, {1, 5, 791.051960, 573.442028, 1.0}, {2, 5, 791.336575, 575.088890, 1.0},
|
||||||
|
{1, 6, 738.973961, 485.130308, 1.0}, {2, 6, 739.435501, 486.734207, 1.0}, {1, 7, 862.403240, 514.866074, 1.0},
|
||||||
|
{2, 7, 862.660618, 516.413261, 1.0}, {1, 8, 802.240162, 485.759838, 1.0}, {2, 8, 802.602253, 487.432899, 1.0},
|
||||||
|
{1, 9, 754.340630, 500.624559, 1.0}, {2, 9, 754.559956, 502.079920, 1.0}, {1, 10, 849.398689, 484.480545, 1.0},
|
||||||
|
{2, 10, 849.599934, 486.079937, 1.0}, {1, 11, 788.803768, 515.924391, 1.0}, {2, 11, 789.119911, 517.439932, 1.0},
|
||||||
|
{1, 12, 838.733940, 558.212688, 1.0}, {2, 12, 839.039898, 559.679916, 1.0}, {1, 13, 760.014782, 575.194466, 1.0},
|
||||||
|
{2, 13, 760.319881, 576.639904, 1.0}, {1, 14, 765.321636, 616.015957, 1.0}, {2, 14, 765.759945, 617.599915, 1.0},
|
||||||
|
{1, 15, 800.963230, 660.032082, 1.0}, {2, 15, 801.279945, 661.759876, 1.0}, {1, 16, 846.321087, 602.313053, 1.0},
|
||||||
|
{2, 16, 846.719913, 603.839878, 1.0}, {1, 17, 864.288311, 616.790524, 1.0}, {2, 17, 864.639931, 618.239918, 1.0},
|
||||||
|
{1, 18, 800.006790, 602.573425, 1.0}, {2, 18, 800.319958, 604.159912, 1.0}, {1, 19, 739.026890, 617.944138, 1.0},
|
||||||
|
{2, 19, 739.199924, 619.519924, 1.0}, {1, 20, 801.987419, 544.134888, 1.0}, {2, 20, 802.239933, 545.599911, 1.0},
|
||||||
|
{1, 21, 753.619823, 542.961300, 1.0}, {2, 21, 753.919945, 544.639874, 1.0}, {1, 22, 787.921257, 499.910206, 1.0},
|
||||||
|
{2, 22, 788.159924, 501.439917, 1.0}, {1, 23, 839.095459, 529.287903, 1.0}, {2, 23, 839.359932, 530.879934, 1.0},
|
||||||
|
{1, 24, 811.760330, 630.732269, 1.0}, {2, 24, 812.159901, 632.319859, 1.0}
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, keyframes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frames 120 and 200 from FabrikEingang footage
|
||||||
|
// Should be enough of parallax for keyframing
|
||||||
|
TEST(KeyframeSelection, FabrikEingangFarFrames) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1605.797, 1605.797);
|
||||||
|
intrinsics.SetPrincipalPoint(960.000, 544.000);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 0, 369.459200, 619.315258, 1.0}, {2, 0, 279.677496, 722.086842, 1.0}, {1, 1, 376.831970, 370.278397, 1.0},
|
||||||
|
{2, 1, 221.695247, 460.065418, 1.0}, {1, 2, 1209.139023, 567.705605, 1.0}, {2, 2, 1080.760117, 659.230083, 1.0},
|
||||||
|
{1, 3, 1643.495750, 903.620453, 1.0}, {2, 3, 1618.405037, 1015.374908, 1.0}, {1, 4, 1494.849815, 425.302460, 1.0},
|
||||||
|
{2, 4, 1457.467575, 514.727587, 1.0}, {1, 5, 1794.637299, 328.728609, 1.0}, {2, 5, 1742.161446, 408.988636, 1.0},
|
||||||
|
{1, 6, 1672.822723, 102.240358, 1.0}, {2, 6, 1539.287224, 153.536892, 1.0}, {1, 7, 1550.843925, 53.424943, 1.0},
|
||||||
|
{2, 7, 1385.579109, 96.450085, 1.0}, {1, 8, 852.953281, 465.399578, 1.0}, {2, 8, 779.404564, 560.091843, 1.0},
|
||||||
|
{1, 9, 906.853752, 299.827040, 1.0}, {2, 9, 786.923218, 385.570770, 1.0}, {1, 10, 406.322966, 87.556041, 1.0},
|
||||||
|
{2, 10, 140.339413, 150.877481, 1.0}, {1, 11, 254.811573, 851.296478, 1.0}, {2, 11, 94.478302, 969.350189, 1.0},
|
||||||
|
{1, 12, 729.087868, 806.092758, 1.0}, {2, 12, 606.212139, 919.876560, 1.0}, {1, 13, 1525.719452, 920.398083, 1.0},
|
||||||
|
{2, 13, 1495.579720, 1031.971218, 1.0}
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, keyframes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually selected keyframes from copter footage from Sebastian
|
||||||
|
// Keyframes were 167 and 237
|
||||||
|
TEST(KeyframeSelection, CopterManualKeyFrames) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1155.043, 1155.043);
|
||||||
|
intrinsics.SetPrincipalPoint(640.000, 360.000);
|
||||||
|
intrinsics.SetRadialDistortion(-0.08590, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 0, 645.792694, 403.115931, 1.0}, {2, 0, 630.641174, 307.996409, 1.0}, {1, 1, 783.469086, 403.904328, 1.0},
|
||||||
|
{2, 1, 766.001129, 308.998225, 1.0}, {1, 2, 650.000000, 160.000001, 1.0}, {1, 3, 785.225906, 158.619039, 1.0},
|
||||||
|
{2, 3, 767.526474, 70.449695, 1.0}, {1, 4, 290.640526, 382.335634, 1.0}, {2, 4, 273.001728, 86.993319, 1.0},
|
||||||
|
{1, 5, 291.162739, 410.602684, 1.0}, {2, 5, 273.287849, 111.937487, 1.0}, {1, 6, 136.919317, 349.895797, 1.0},
|
||||||
|
{1, 7, 490.844345, 47.572222, 1.0}, {1, 8, 454.406433, 488.935761, 1.0}, {1, 9, 378.655815, 618.522248, 1.0},
|
||||||
|
{2, 9, 357.061806, 372.265077, 1.0}, {1, 10, 496.011391, 372.668824, 1.0}, {2, 10, 477.979164, 222.986112, 1.0},
|
||||||
|
{1, 11, 680.060272, 256.103625, 1.0}, {2, 11, 670.587540, 204.830453, 1.0}, {1, 12, 1070.817108, 218.775322, 1.0},
|
||||||
|
{2, 12, 1046.129913, 128.969783, 1.0}, {1, 14, 242.516403, 596.048512, 1.0}, {2, 14, 224.182606, 248.272154, 1.0},
|
||||||
|
{1, 15, 613.936272, 287.519073, 1.0}, {2, 15, 600.467644, 196.085722, 1.0}, {1, 31, 844.637451, 256.354315, 1.0},
|
||||||
|
{2, 31, 823.200150, 165.714952, 1.0},
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, keyframes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used old friend elevator scene MMI_2366 with automatic feature selection
|
||||||
|
// and manual outlier elimination and manual keyframe selection
|
||||||
|
// Selected keyframes were 29 and 41
|
||||||
|
TEST(KeyframeSelection, ElevatorManualKeyframesFrames) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1380.000, 1380.000);
|
||||||
|
intrinsics.SetPrincipalPoint(960.000, 540.000);
|
||||||
|
intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 2, 1139.861412, 1034.634984, 1.0}, {2, 2, 1143.512192, 1065.355718, 1.0}, {1, 3, 1760.821953, 644.658036, 1.0},
|
||||||
|
{2, 3, 1770.901108, 697.899928, 1.0}, {1, 4, 858.071823, 1068.520746, 1.0}, {1, 6, 1633.952408, 797.050145, 1.0},
|
||||||
|
{2, 6, 1642.508469, 849.157140, 1.0}, {1, 8, 1716.695824, 451.805491, 1.0}, {2, 8, 1726.513939, 502.095687, 1.0},
|
||||||
|
{1, 9, 269.577627, 724.986935, 1.0}, {2, 9, 269.424820, 764.154246, 1.0}, {1, 10, 1891.321907, 706.948843, 1.0},
|
||||||
|
{2, 10, 1903.338547, 766.068377, 1.0}, {1, 12, 1806.227074, 956.089604, 1.0}, {2, 12, 1816.619568, 1013.767376, 1.0},
|
||||||
|
{1, 14, 269.544153, 1002.333570, 1.0}, {2, 14, 269.367542, 1043.509254, 1.0}, {1, 15, 1402.772141, 281.392962, 1.0},
|
||||||
|
{2, 15, 1409.089165, 318.731629, 1.0}, {1, 16, 195.877233, 919.454341, 1.0}, {2, 16, 192.531109, 997.367899, 1.0},
|
||||||
|
{1, 17, 1789.584045, 120.036661, 1.0}, {2, 17, 1800.391846, 167.822964, 1.0}, {1, 18, 999.363213, 765.004807, 1.0},
|
||||||
|
{2, 18, 1002.345772, 790.560122, 1.0}, {1, 19, 647.342491, 1044.805727, 1.0}, {2, 19, 649.328041, 1058.682940, 1.0},
|
||||||
|
{1, 20, 1365.486832, 440.901829, 1.0}, {2, 20, 1371.413040, 477.888730, 1.0}, {1, 21, 1787.125282, 301.431606, 1.0},
|
||||||
|
{2, 21, 1798.527260, 355.224531, 1.0}, {1, 22, 1257.805824, 932.797258, 1.0}, {2, 22, 1263.017578, 969.376774, 1.0},
|
||||||
|
{1, 23, 961.969528, 843.148112, 1.0}, {2, 23, 964.869461, 868.587620, 1.0}, {1, 24, 158.076110, 1052.643592, 1.0},
|
||||||
|
{1, 25, 1072.884521, 1005.296981, 1.0}, {2, 25, 1076.091156, 1032.776856, 1.0}, {1, 26, 1107.656937, 526.577228, 1.0},
|
||||||
|
{2, 26, 1111.618423, 555.524454, 1.0}, {1, 27, 1416.410751, 529.857581, 1.0}, {2, 27, 1422.663574, 570.025957, 1.0},
|
||||||
|
{1, 28, 1498.673630, 1005.453086, 1.0}, {2, 28, 1505.381813, 1051.827149, 1.0}, {1, 29, 1428.647804, 652.473629, 1.0},
|
||||||
|
{2, 29, 1434.898224, 692.715390, 1.0}, {1, 30, 1332.318764, 503.673599, 1.0}, {2, 30, 1338.000069, 540.507967, 1.0},
|
||||||
|
{1, 32, 1358.642693, 709.837904, 1.0}, {2, 32, 1364.231529, 748.678265, 1.0}, {1, 33, 1850.911560, 460.475668, 1.0},
|
||||||
|
{2, 33, 1862.221413, 512.797347, 1.0}, {1, 34, 1226.117821, 607.053959, 1.0}, {2, 34, 1230.736084, 641.091449, 1.0},
|
||||||
|
{1, 35, 619.598236, 523.341744, 1.0}, {2, 35, 621.601124, 554.453287, 1.0}, {1, 36, 956.591492, 958.223183, 1.0},
|
||||||
|
{2, 36, 959.289265, 983.289263, 1.0}, {1, 37, 1249.922218, 419.095856, 1.0}, {2, 37, 1255.005913, 452.556177, 1.0},
|
||||||
|
{1, 39, 1300.528450, 386.251166, 1.0}, {2, 39, 1305.957413, 420.185595, 1.0}, {1, 40, 1128.689919, 972.558346, 1.0},
|
||||||
|
{2, 40, 1132.413712, 1003.984737, 1.0}, {1, 41, 503.304749, 1053.504388, 1.0}, {2, 41, 505.019703, 1069.175613, 1.0},
|
||||||
|
{1, 42, 1197.352982, 472.681564, 1.0}, {2, 42, 1201.910706, 503.459880, 1.0}, {1, 43, 1794.391022, 383.911400, 1.0},
|
||||||
|
{2, 43, 1805.324135, 436.116468, 1.0}, {1, 44, 789.641418, 1058.045647, 1.0}, {1, 45, 1376.575241, 928.714979, 1.0},
|
||||||
|
{2, 45, 1381.995850, 969.511957, 1.0}, {1, 46, 1598.023567, 93.975592, 1.0}, {2, 46, 1606.937141, 136.827035, 1.0},
|
||||||
|
{1, 47, 1455.550232, 762.128685, 1.0}, {2, 47, 1462.014313, 805.164878, 1.0}, {1, 48, 1357.123489, 354.460326, 1.0},
|
||||||
|
{2, 48, 1363.071899, 390.363121, 1.0}, {1, 49, 939.792652, 781.549895, 1.0}, {2, 49, 942.802620, 806.164012, 1.0},
|
||||||
|
{1, 50, 1380.251083, 805.948620, 1.0}, {2, 50, 1385.637932, 845.592098, 1.0}, {1, 51, 1021.769943, 1049.802361, 1.0},
|
||||||
|
{1, 52, 1065.634918, 608.099055, 1.0}, {2, 52, 1069.142189, 635.361736, 1.0}, {1, 53, 624.324188, 463.202863, 1.0},
|
||||||
|
{2, 53, 626.395454, 494.994088, 1.0}, {1, 54, 1451.459885, 881.557624, 1.0}, {2, 54, 1457.679634, 924.345531, 1.0},
|
||||||
|
{1, 55, 1201.885986, 1057.079022, 1.0}, {1, 56, 581.157532, 947.661438, 1.0}, {2, 56, 583.242359, 960.831449, 1.0},
|
||||||
|
{1, 58, 513.593102, 954.175858, 1.0}, {2, 58, 515.470047, 971.309574, 1.0}, {1, 59, 928.069038, 901.774421, 1.0},
|
||||||
|
{2, 59, 930.847950, 925.613744, 1.0}, {1, 60, 1065.860023, 740.395389, 1.0}, {2, 60, 1069.484253, 768.971086, 1.0},
|
||||||
|
{1, 61, 990.479393, 906.264632, 1.0}, {2, 61, 993.217506, 933.088803, 1.0}, {1, 62, 1776.196747, 776.278453, 1.0},
|
||||||
|
{2, 62, 1786.292496, 831.136880, 1.0}, {1, 63, 834.454365, 1012.449725, 1.0}, {2, 63, 836.868324, 1033.451807, 1.0},
|
||||||
|
{1, 64, 1355.190697, 869.184809, 1.0}, {2, 64, 1360.736618, 909.773347, 1.0}, {1, 65, 702.072487, 897.519686, 1.0},
|
||||||
|
{2, 65, 704.203377, 911.931131, 1.0}, {1, 66, 1214.022903, 856.199934, 1.0}, {2, 66, 1218.109016, 890.753052, 1.0},
|
||||||
|
{1, 67, 327.676048, 236.814036, 1.0}, {2, 67, 328.335285, 277.251878, 1.0}, {1, 68, 289.064083, 454.793912, 1.0},
|
||||||
|
{2, 68, 288.651924, 498.882444, 1.0}, {1, 69, 1626.240692, 278.374350, 1.0}, {2, 69, 1634.131508, 315.853672, 1.0},
|
||||||
|
{1, 70, 1245.375710, 734.862142, 1.0}, {2, 70, 1250.047417, 769.670885, 1.0}, {1, 71, 497.015305, 510.718904, 1.0},
|
||||||
|
{2, 71, 498.682308, 541.070201, 1.0}, {1, 72, 1280.542030, 153.939185, 1.0}, {2, 72, 1286.993637, 198.436196, 1.0},
|
||||||
|
{1, 73, 1534.748840, 138.601043, 1.0}, {2, 73, 1542.961349, 180.170819, 1.0}, {1, 74, 1477.412682, 200.608061, 1.0},
|
||||||
|
{2, 74, 1484.683914, 240.413260, 1.0}, {1, 76, 450.637321, 407.279642, 1.0}, {2, 76, 451.695642, 441.666291, 1.0},
|
||||||
|
{1, 78, 246.981239, 220.786298, 1.0}, {2, 78, 244.524879, 290.016564, 1.0}, {1, 79, 36.696489, 420.023407, 1.0},
|
||||||
|
{2, 79, 21.364746, 591.245492, 1.0},
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, keyframes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Elevator scene MMI_2366 with manual tracks, frames 1, 2, 3, 5 and 27
|
||||||
|
TEST(KeyframeSelection, ElevatorReconstructionVarianceTest) {
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(1380.000, 1380.000);
|
||||||
|
intrinsics.SetPrincipalPoint(960.000, 540.000);
|
||||||
|
intrinsics.SetRadialDistortion(-0.034, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 0, 182.999997, 1047.000010, 1.0}, {2, 0, 181.475730, 1052.091079, 1.0}, {3, 0, 181.741562, 1057.893341, 1.0},
|
||||||
|
{4, 0, 183.190498, 1068.310440, 1.0}, {1, 1, 271.000013, 666.000009, 1.0}, {2, 1, 270.596180, 668.665760, 1.0},
|
||||||
|
{3, 1, 270.523510, 671.559069, 1.0}, {4, 1, 271.856518, 676.818151, 1.0}, {5, 1, 268.989000, 727.051570, 1.0},
|
||||||
|
{1, 2, 264.999990, 1018.000031, 1.0}, {2, 2, 264.020061, 1021.157591, 1.0}, {3, 2, 264.606056, 1024.823506, 1.0},
|
||||||
|
{4, 2, 266.200933, 1031.168690, 1.0}, {1, 3, 270.000000, 938.000014, 1.0}, {2, 3, 269.022617, 941.153390, 1.0},
|
||||||
|
{3, 3, 269.605579, 944.454954, 1.0}, {4, 3, 271.281366, 949.452167, 1.0}, {5, 3, 268.963480, 1004.417453, 1.0},
|
||||||
|
{1, 4, 200.999994, 799.000003, 1.0}, {2, 4, 199.841366, 803.891838, 1.0}, {3, 4, 200.262208, 809.323246, 1.0},
|
||||||
|
{4, 4, 201.456513, 819.271195, 1.0}, {5, 4, 195.026493, 924.363234, 1.0}, {1, 5, 1775.000038, 49.999998, 1.0},
|
||||||
|
{2, 5, 1775.255127, 53.718264, 1.0}, {3, 5, 1776.449890, 55.951670, 1.0}, {4, 5, 1778.815727, 61.923309, 1.0},
|
||||||
|
{5, 5, 1790.274124, 123.074923, 1.0}, {1, 6, 164.000001, 927.999988, 1.0}, {2, 6, 162.665462, 933.169527, 1.0},
|
||||||
|
{3, 6, 163.067923, 938.577182, 1.0}, {4, 6, 164.370360, 948.840945, 1.0}, {5, 6, 157.199407, 1057.762341, 1.0},
|
||||||
|
{1, 7, 618.000011, 477.999998, 1.0}, {2, 7, 617.583504, 480.124243, 1.0}, {3, 7, 618.356495, 482.441897, 1.0},
|
||||||
|
{4, 7, 619.792500, 486.428132, 1.0}, {5, 7, 619.546051, 525.222627, 1.0}, {1, 8, 499.999981, 1036.999984, 1.0},
|
||||||
|
{2, 8, 499.080162, 1038.720160, 1.0}, {3, 8, 499.949398, 1039.014344, 1.0}, {4, 8, 501.828003, 1041.286647, 1.0},
|
||||||
|
{5, 8, 502.777576, 1055.196369, 1.0}, {1, 9, 1587.000046, 31.999999, 1.0}, {2, 9, 1586.988373, 34.635853, 1.0},
|
||||||
|
{3, 9, 1588.155899, 37.444186, 1.0}, {4, 9, 1589.973106, 42.492081, 1.0}, {5, 9, 1598.683205, 96.526332, 1.0},
|
||||||
|
{1, 10, 622.999992, 416.999999, 1.0}, {2, 10, 622.449017, 419.233485, 1.0}, {3, 10, 623.283234, 421.500703, 1.0},
|
||||||
|
{4, 10, 624.620132, 425.537406, 1.0}, {5, 10, 624.290829, 465.078338, 1.0}, {1, 11, 577.999992, 931.999998, 1.0},
|
||||||
|
{2, 11, 577.042294, 932.872703, 1.0}, {3, 11, 577.832451, 934.045451, 1.0}, {4, 11, 579.729137, 935.735435, 1.0},
|
||||||
|
{5, 11, 580.691242, 948.396256, 1.0}, {1, 12, 510.999985, 931.999998, 1.0}, {2, 12, 510.111237, 933.152146, 1.0},
|
||||||
|
{3, 12, 510.797081, 934.454219, 1.0}, {4, 12, 512.647362, 936.595910, 1.0}, {5, 12, 513.247204, 955.144157, 1.0},
|
||||||
|
{1, 13, 330.459995, 177.059993, 1.0}, {2, 13, 329.876347, 179.615586, 1.0}, {3, 13, 330.681696, 182.757810, 1.0},
|
||||||
|
{4, 13, 331.345053, 187.903853, 1.0}, {5, 13, 327.824135, 239.611639, 1.0}, {1, 14, 291.813097, 388.516195, 1.0},
|
||||||
|
{2, 14, 290.984058, 391.382725, 1.0}, {3, 14, 291.526737, 394.778595, 1.0}, {4, 14, 292.763815, 400.310973, 1.0},
|
||||||
|
{5, 14, 288.714552, 457.548015, 1.0}, {1, 15, 496.491680, 466.534005, 1.0}, {2, 15, 495.909519, 468.518561, 1.0},
|
||||||
|
{3, 15, 496.588383, 470.853596, 1.0}, {4, 15, 497.976780, 474.731458, 1.0}, {5, 15, 496.998882, 512.568694, 1.0},
|
||||||
|
{1, 16, 1273.000031, 89.000000, 1.0}, {2, 16, 1272.951965, 92.003637, 1.0}, {3, 16, 1273.934784, 94.972191, 1.0},
|
||||||
|
{4, 16, 1275.493584, 100.139952, 1.0}, {5, 16, 1281.003571, 156.880163, 1.0}, {1, 17, 1524.713173, 78.852922, 1.0},
|
||||||
|
{2, 17, 1524.782066, 81.427142, 1.0}, {3, 17, 1525.759048, 84.057939, 1.0}, {4, 17, 1527.579689, 88.966550, 1.0},
|
||||||
|
{5, 17, 1535.262451, 141.186054, 1.0}, {1, 18, 1509.425011, 94.371824, 1.0}, {1, 19, 451.000013, 357.000003, 1.0},
|
||||||
|
{2, 19, 450.354881, 359.312410, 1.0}, {3, 19, 451.107473, 361.837088, 1.0}, {4, 19, 452.186537, 366.318061, 1.0},
|
||||||
|
{5, 19, 450.507660, 409.257599, 1.0}, {1, 20, 254.004936, 114.784185, 1.0}, {2, 20, 253.291512, 119.288486, 1.0},
|
||||||
|
{3, 20, 253.745584, 124.114957, 1.0}, {4, 20, 254.453287, 132.795120, 1.0}, {5, 20, 246.772242, 225.165337, 1.0},
|
||||||
|
{1, 21, 65.262880, 147.889409, 1.0}, {2, 21, 63.634465, 157.656807, 1.0}, {3, 21, 63.306799, 169.067053, 1.0},
|
||||||
|
{4, 21, 62.462311, 189.724241, 1.0}, {5, 21, 35.396615, 430.308380, 1.0},
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<int> keyframes;
|
||||||
|
SelectKeyframesBasedOnGRICAndVariance(tracks, intrinsics, keyframes);
|
||||||
|
|
||||||
|
EXPECT_EQ(2, keyframes.size());
|
||||||
|
if (keyframes.size() == 2) {
|
||||||
|
EXPECT_EQ(1, keyframes[0]);
|
||||||
|
EXPECT_EQ(5, keyframes[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
79
extern/libmv/libmv/simple_pipeline/modal_solver_test.cc
vendored
Normal file
79
extern/libmv/libmv/simple_pipeline/modal_solver_test.cc
vendored
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) 2013 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/modal_solver.h"
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "libmv/simple_pipeline/bundle.h"
|
||||||
|
#include "libmv/simple_pipeline/camera_intrinsics.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
|
||||||
|
TEST(ModalSolver, SyntheticCubeSceneMotion) {
|
||||||
|
double kTolerance = 1e-8;
|
||||||
|
|
||||||
|
PolynomialCameraIntrinsics intrinsics;
|
||||||
|
intrinsics.SetFocalLength(658.286, 658.286);
|
||||||
|
intrinsics.SetPrincipalPoint(480.0, 270.0);
|
||||||
|
intrinsics.SetRadialDistortion(0.0, 0.0, 0.0);
|
||||||
|
|
||||||
|
Marker markers[] = {
|
||||||
|
{1, 0, 212.172775, 354.713538, 1.0}, {2, 0, 773.468399, 358.735306, 1.0},
|
||||||
|
{1, 1, 62.415197, 287.905354, 1.0}, {2, 1, 619.103336, 324.402537, 1.0},
|
||||||
|
{1, 2, 206.847939, 237.567925, 1.0}, {2, 2, 737.496986, 247.881383, 1.0},
|
||||||
|
{1, 3, 351.743889, 316.415906, 1.0}, {2, 3, 908.779621, 290.703617, 1.0},
|
||||||
|
{1, 4, 232.941413, 54.265443, 1.0}, {2, 4, 719.444847, 63.062531, 1.0},
|
||||||
|
{1, 5, 96.391611, 119.283537, 1.0}, {2, 5, 611.413136, 160.890715, 1.0},
|
||||||
|
{1, 6, 363.444958, 150.838144, 1.0}, {2, 6, 876.374531, 114.916206, 1.0},
|
||||||
|
};
|
||||||
|
int num_markers = sizeof(markers) / sizeof(Marker);
|
||||||
|
|
||||||
|
Tracks tracks;
|
||||||
|
for (int i = 0; i < num_markers; i++) {
|
||||||
|
double x = markers[i].x, y = markers[i].y;
|
||||||
|
intrinsics.InvertIntrinsics(x, y, &x, &y);
|
||||||
|
tracks.Insert(markers[i].image, markers[i].track, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
EuclideanReconstruction reconstruction;
|
||||||
|
ModalSolver(tracks, &reconstruction);
|
||||||
|
EuclideanBundleCommonIntrinsics(tracks,
|
||||||
|
BUNDLE_NO_INTRINSICS,
|
||||||
|
BUNDLE_NO_TRANSLATION,
|
||||||
|
&reconstruction,
|
||||||
|
&intrinsics,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
Mat3 expected_rotation;
|
||||||
|
expected_rotation << 0.98215101299251, 0.17798357184544, 0.06083778292258,
|
||||||
|
-0.16875286001759, 0.97665299913606, -0.13293378620359,
|
||||||
|
-0.08307743323957, 0.12029450291547, 0.98925596922871;
|
||||||
|
|
||||||
|
Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R;
|
||||||
|
Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R;
|
||||||
|
|
||||||
|
EXPECT_TRUE(Mat3::Identity().isApprox(first_camera_R, kTolerance));
|
||||||
|
EXPECT_TRUE(expected_rotation.isApprox(second_camera_R, kTolerance));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace libmv
|
234
extern/libmv/libmv/simple_pipeline/resect_test.cc
vendored
Normal file
234
extern/libmv/libmv/simple_pipeline/resect_test.cc
vendored
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
// Copyright (c) 2009 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/simple_pipeline/resect.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Generates all necessary inputs and expected outputs for EuclideanResection.
|
||||||
|
void CreateCameraSystem(const Mat3& KK,
|
||||||
|
const Mat3X& x_image,
|
||||||
|
const Vec& X_distances,
|
||||||
|
const Mat3& R_input,
|
||||||
|
const Vec3& T_input,
|
||||||
|
Mat2X *x_camera,
|
||||||
|
Mat3X *X_world,
|
||||||
|
Mat3 *R_expected,
|
||||||
|
Vec3 *T_expected) {
|
||||||
|
int num_points = x_image.cols();
|
||||||
|
|
||||||
|
Mat3X x_unit_cam(3, num_points);
|
||||||
|
x_unit_cam = KK.inverse() * x_image;
|
||||||
|
|
||||||
|
// Create normalized camera coordinates to be used as an input to the PnP
|
||||||
|
// function, instead of using NormalizeColumnVectors(&x_unit_cam).
|
||||||
|
*x_camera = x_unit_cam.block(0, 0, 2, num_points);
|
||||||
|
for (int i = 0; i < num_points; ++i) {
|
||||||
|
x_unit_cam.col(i).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the 3D points in the camera system.
|
||||||
|
Mat X_camera(3, num_points);
|
||||||
|
for (int i = 0; i < num_points; ++i) {
|
||||||
|
X_camera.col(i) = X_distances(i) * x_unit_cam.col(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the transformation to the camera 3D points
|
||||||
|
Mat translation_matrix(3, num_points);
|
||||||
|
translation_matrix.row(0).setConstant(T_input(0));
|
||||||
|
translation_matrix.row(1).setConstant(T_input(1));
|
||||||
|
translation_matrix.row(2).setConstant(T_input(2));
|
||||||
|
|
||||||
|
*X_world = R_input * X_camera + translation_matrix;
|
||||||
|
|
||||||
|
// Create the expected result for comparison.
|
||||||
|
*R_expected = R_input.transpose();
|
||||||
|
*T_expected = *R_expected * (-T_input);
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(AbsoluteOrientation, QuaternionSolution) {
|
||||||
|
int num_points = 4;
|
||||||
|
Mat X;
|
||||||
|
Mat Xp;
|
||||||
|
X = 100 * Mat::Random(3, num_points);
|
||||||
|
|
||||||
|
// Create a random translation and rotation.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 t_input;
|
||||||
|
t_input.setRandom();
|
||||||
|
t_input = 100 * t_input;
|
||||||
|
|
||||||
|
Mat translation_matrix(3, num_points);
|
||||||
|
translation_matrix.row(0).setConstant(t_input(0));
|
||||||
|
translation_matrix.row(1).setConstant(t_input(1));
|
||||||
|
translation_matrix.row(2).setConstant(t_input(2));
|
||||||
|
|
||||||
|
// Create the transformed 3D points Xp as Xp = R * X + t.
|
||||||
|
Xp = R_input * X + translation_matrix;
|
||||||
|
|
||||||
|
// Output variables.
|
||||||
|
Mat3 R;
|
||||||
|
Vec3 t;
|
||||||
|
|
||||||
|
AbsoluteOrientation(X, Xp, &R, &t);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(t, t_input, 1e-6);
|
||||||
|
EXPECT_MATRIX_NEAR(R, R_input, 1e-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EuclideanResection, Points4KnownImagePointsRandomTranslationRotation) {
|
||||||
|
// In this test only the translation and rotation are random. The image
|
||||||
|
// points are selected from a real case and are well conditioned.
|
||||||
|
Vec2i image_dimensions;
|
||||||
|
image_dimensions << 1600, 1200;
|
||||||
|
|
||||||
|
Mat3 KK;
|
||||||
|
KK << 2796, 0, 804,
|
||||||
|
0 , 2796, 641,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
// The real image points.
|
||||||
|
int num_points = 4;
|
||||||
|
Mat3X x_image(3, num_points);
|
||||||
|
x_image << 1164.06, 734.948, 749.599, 430.727,
|
||||||
|
681.386, 844.59, 496.315, 580.775,
|
||||||
|
1, 1, 1, 1;
|
||||||
|
|
||||||
|
|
||||||
|
// A vector of the 4 distances to the 3D points.
|
||||||
|
Vec X_distances = 100 * Vec::Random(num_points).array().abs();
|
||||||
|
|
||||||
|
// Create the random camera motion R and t that resection should recover.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 T_input;
|
||||||
|
T_input.setRandom();
|
||||||
|
T_input = 100 * T_input;
|
||||||
|
|
||||||
|
// Create the camera system, also getting the expected result of the
|
||||||
|
// transformation.
|
||||||
|
Mat3 R_expected;
|
||||||
|
Vec3 T_expected;
|
||||||
|
Mat3X X_world;
|
||||||
|
Mat2X x_camera;
|
||||||
|
CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
|
||||||
|
&x_camera, &X_world, &R_expected, &T_expected);
|
||||||
|
|
||||||
|
// Finally, run the code under test.
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_ANSAR_DANIILIDIS);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
|
||||||
|
// For now, the EPnP doesn't have a non-linear optimization step and so is
|
||||||
|
// not precise enough with only 4 points.
|
||||||
|
//
|
||||||
|
// TODO(jmichot): Reenable this test when there is nonlinear refinement.
|
||||||
|
#if 0
|
||||||
|
R_output.setIdentity();
|
||||||
|
T_output.setZero();
|
||||||
|
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_EPNP);
|
||||||
|
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);*/
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jmichot): Reduce the code duplication here with the code above.
|
||||||
|
TEST(EuclideanResection, Points6AllRandomInput) {
|
||||||
|
Mat3 KK;
|
||||||
|
KK << 2796, 0, 804,
|
||||||
|
0 , 2796, 641,
|
||||||
|
0, 0, 1;
|
||||||
|
|
||||||
|
// Create random image points for a 1600x1200 image.
|
||||||
|
int w = 1600;
|
||||||
|
int h = 1200;
|
||||||
|
int num_points = 6;
|
||||||
|
Mat3X x_image(3, num_points);
|
||||||
|
x_image.row(0) = w * Vec::Random(num_points).array().abs();
|
||||||
|
x_image.row(1) = h * Vec::Random(num_points).array().abs();
|
||||||
|
x_image.row(2).setOnes();
|
||||||
|
|
||||||
|
// Normalized camera coordinates to be used as an input to the PnP function.
|
||||||
|
Mat2X x_camera;
|
||||||
|
Vec X_distances = 100 * Vec::Random(num_points).array().abs();
|
||||||
|
|
||||||
|
// Create the random camera motion R and t that resection should recover.
|
||||||
|
Mat3 R_input;
|
||||||
|
R_input = Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitY())
|
||||||
|
* Eigen::AngleAxisd(rand(), Eigen::Vector3d::UnitZ());
|
||||||
|
|
||||||
|
Vec3 T_input;
|
||||||
|
T_input.setRandom();
|
||||||
|
T_input = 100 * T_input;
|
||||||
|
|
||||||
|
// Create the camera system.
|
||||||
|
Mat3 R_expected;
|
||||||
|
Vec3 T_expected;
|
||||||
|
Mat3X X_world;
|
||||||
|
CreateCameraSystem(KK, x_image, X_distances, R_input, T_input,
|
||||||
|
&x_camera, &X_world, &R_expected, &T_expected);
|
||||||
|
|
||||||
|
// Test each of the resection methods.
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_ANSAR_DANIILIDIS);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_camera, X_world,
|
||||||
|
&R_output, &T_output,
|
||||||
|
RESECTION_EPNP);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Mat3 R_output;
|
||||||
|
Vec3 T_output;
|
||||||
|
EuclideanResection(x_image, X_world, KK,
|
||||||
|
&R_output, &T_output);
|
||||||
|
EXPECT_MATRIX_NEAR(T_output, T_expected, 1e-5);
|
||||||
|
EXPECT_MATRIX_NEAR(R_output, R_expected, 1e-7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
51
extern/libmv/libmv/tracking/brute_region_tracker_test.cc
vendored
Normal file
51
extern/libmv/libmv/tracking/brute_region_tracker_test.cc
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/tracking/brute_region_tracker.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "libmv/logging/logging.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(KltRegionTracker, Track) {
|
||||||
|
Array3Df image1(51, 51);
|
||||||
|
image1.Fill(0);
|
||||||
|
|
||||||
|
Array3Df image2(image1);
|
||||||
|
|
||||||
|
int x0 = 25, y0 = 25;
|
||||||
|
int dx = 3, dy = 2;
|
||||||
|
image1(y0, x0) = 1.0f;
|
||||||
|
image2(y0 + dy, x0 + dx) = 1.0;
|
||||||
|
|
||||||
|
double x1 = x0;
|
||||||
|
double y1 = y0;
|
||||||
|
|
||||||
|
BruteRegionTracker tracker;
|
||||||
|
EXPECT_TRUE(tracker.Track(image1, image2, x0, y0, &x1, &y1));
|
||||||
|
|
||||||
|
EXPECT_NEAR(x1, x0 + dx, 0.001);
|
||||||
|
EXPECT_NEAR(y1, y0 + dy, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace libmv
|
51
extern/libmv/libmv/tracking/klt_region_tracker_test.cc
vendored
Normal file
51
extern/libmv/libmv/tracking/klt_region_tracker_test.cc
vendored
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/tracking/klt_region_tracker.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(KltRegionTracker, Track) {
|
||||||
|
Array3Df image1(51, 51);
|
||||||
|
image1.Fill(0);
|
||||||
|
|
||||||
|
Array3Df image2(image1);
|
||||||
|
|
||||||
|
int x0 = 25, y0 = 25;
|
||||||
|
int dx = 3, dy = 2;
|
||||||
|
image1(y0, x0) = 1.0f;
|
||||||
|
image2(y0 + dy, x0 + dx) = 1.0f;
|
||||||
|
|
||||||
|
double x1 = x0;
|
||||||
|
double y1 = y0;
|
||||||
|
|
||||||
|
KltRegionTracker tracker;
|
||||||
|
tracker.half_window_size = 6;
|
||||||
|
EXPECT_TRUE(tracker.Track(image1, image2, x0, y0, &x1, &y1));
|
||||||
|
|
||||||
|
EXPECT_NEAR(x1, x0 + dx, 0.001);
|
||||||
|
EXPECT_NEAR(y1, y0 + dy, 0.001);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace libmv
|
80
extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
vendored
Normal file
80
extern/libmv/libmv/tracking/pyramid_region_tracker_test.cc
vendored
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) 2011 libmv authors.
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
|
||||||
|
#include "libmv/tracking/pyramid_region_tracker.h"
|
||||||
|
#include "libmv/tracking/klt_region_tracker.h"
|
||||||
|
#include "libmv/image/image.h"
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
namespace libmv {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(PyramidKltRegionTracker, Track) {
|
||||||
|
Array3Df image1(100, 100);
|
||||||
|
image1.Fill(0);
|
||||||
|
|
||||||
|
Array3Df image2(image1);
|
||||||
|
|
||||||
|
int x1 = 25, y1 = 25;
|
||||||
|
image1(y1 + 0, x1 + 0) = 1.0f;
|
||||||
|
image1(y1 + 0, x1 + 1) = 1.0f;
|
||||||
|
image1(y1 + 1, x1 + 0) = 1.0f;
|
||||||
|
image1(y1 + 1, x1 + 1) = 1.0f;
|
||||||
|
|
||||||
|
// Make the displacement too large for a single-level KLT.
|
||||||
|
int x2 = x1 + 6, y2 = y1 + 5;
|
||||||
|
image2(y2 + 0, x2 + 0) = 1.0f;
|
||||||
|
image2(y2 + 0, x2 + 1) = 1.0f;
|
||||||
|
image2(y2 + 1, x2 + 0) = 1.0f;
|
||||||
|
image2(y2 + 1, x2 + 1) = 1.0f;
|
||||||
|
|
||||||
|
// Use a small 5x5 tracking region.
|
||||||
|
int half_window_size = 3;
|
||||||
|
|
||||||
|
// Ensure that the track doesn't work with one level of KLT.
|
||||||
|
{
|
||||||
|
double x2_actual = x1;
|
||||||
|
double y2_actual = y1;
|
||||||
|
|
||||||
|
KltRegionTracker tracker;
|
||||||
|
tracker.half_window_size = half_window_size;
|
||||||
|
EXPECT_FALSE(tracker.Track(image1, image2, x1, y1,
|
||||||
|
&x2_actual, &y2_actual));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that it works with the pyramid tracker.
|
||||||
|
{
|
||||||
|
double x2_actual = x1;
|
||||||
|
double y2_actual = y1;
|
||||||
|
|
||||||
|
KltRegionTracker *klt_tracker = new KltRegionTracker;
|
||||||
|
klt_tracker->half_window_size = half_window_size;
|
||||||
|
|
||||||
|
PyramidRegionTracker tracker(klt_tracker, 3);
|
||||||
|
EXPECT_TRUE(tracker.Track(image1, image2, x1, y1,
|
||||||
|
&x2_actual, &y2_actual));
|
||||||
|
|
||||||
|
EXPECT_NEAR(x2_actual, x2, 0.001);
|
||||||
|
EXPECT_NEAR(y2_actual, y2, 0.001);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace libmv
|
@ -154,6 +154,7 @@ endif()
|
|||||||
extern_rangetree
|
extern_rangetree
|
||||||
extern_wcwidth
|
extern_wcwidth
|
||||||
extern_libmv
|
extern_libmv
|
||||||
|
extern_glog
|
||||||
)
|
)
|
||||||
|
|
||||||
if(WITH_MOD_CLOTH_ELTOPO)
|
if(WITH_MOD_CLOTH_ELTOPO)
|
||||||
|
@ -174,6 +174,9 @@ if(WITH_BUILDINFO)
|
|||||||
list(APPEND SRC
|
list(APPEND SRC
|
||||||
buildinfo.c
|
buildinfo.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# make an object library so can load with it in tests
|
||||||
|
add_library(buildinofobj OBJECT buildinfo.c)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# message(STATUS "Configuring blender")
|
# message(STATUS "Configuring blender")
|
||||||
@ -884,241 +887,8 @@ unset(BLENDER_TEXT_FILES)
|
|||||||
|
|
||||||
add_dependencies(blender makesdna)
|
add_dependencies(blender makesdna)
|
||||||
|
|
||||||
get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS)
|
setup_blender_sorted_libs()
|
||||||
|
|
||||||
list(APPEND BLENDER_LINK_LIBS
|
target_link_libraries(blender ${BLENDER_SORTED_LIBS})
|
||||||
bf_windowmanager
|
|
||||||
bf_render
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WITH_MOD_FLUID)
|
|
||||||
list(APPEND BLENDER_LINK_LIBS bf_intern_elbeem)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_CYCLES)
|
|
||||||
list(APPEND BLENDER_LINK_LIBS
|
|
||||||
cycles_render
|
|
||||||
cycles_bvh
|
|
||||||
cycles_device
|
|
||||||
cycles_kernel
|
|
||||||
cycles_util
|
|
||||||
cycles_subd)
|
|
||||||
if(WITH_CYCLES_OSL)
|
|
||||||
list(APPEND BLENDER_LINK_LIBS cycles_kernel_osl)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#if(UNIX)
|
|
||||||
# Sort libraries
|
|
||||||
set(BLENDER_SORTED_LIBS
|
|
||||||
bf_windowmanager
|
|
||||||
|
|
||||||
bf_editor_space_api
|
|
||||||
bf_editor_space_action
|
|
||||||
bf_editor_space_buttons
|
|
||||||
bf_editor_space_console
|
|
||||||
bf_editor_space_file
|
|
||||||
bf_editor_space_graph
|
|
||||||
bf_editor_space_image
|
|
||||||
bf_editor_space_info
|
|
||||||
bf_editor_space_logic
|
|
||||||
bf_editor_space_nla
|
|
||||||
bf_editor_space_node
|
|
||||||
bf_editor_space_outliner
|
|
||||||
bf_editor_space_script
|
|
||||||
bf_editor_space_sequencer
|
|
||||||
bf_editor_space_text
|
|
||||||
bf_editor_space_time
|
|
||||||
bf_editor_space_userpref
|
|
||||||
bf_editor_space_view3d
|
|
||||||
bf_editor_space_clip
|
|
||||||
|
|
||||||
bf_editor_transform
|
|
||||||
bf_editor_util
|
|
||||||
bf_editor_uvedit
|
|
||||||
bf_editor_curve
|
|
||||||
bf_editor_gpencil
|
|
||||||
bf_editor_interface
|
|
||||||
bf_editor_mesh
|
|
||||||
bf_editor_metaball
|
|
||||||
bf_editor_object
|
|
||||||
bf_editor_armature
|
|
||||||
bf_editor_physics
|
|
||||||
bf_editor_render
|
|
||||||
bf_editor_screen
|
|
||||||
bf_editor_sculpt_paint
|
|
||||||
bf_editor_sound
|
|
||||||
bf_editor_animation
|
|
||||||
bf_editor_datafiles
|
|
||||||
bf_editor_mask
|
|
||||||
bf_editor_io
|
|
||||||
|
|
||||||
bf_render
|
|
||||||
bf_python
|
|
||||||
bf_python_ext
|
|
||||||
bf_python_mathutils
|
|
||||||
bf_python_bmesh
|
|
||||||
bf_freestyle
|
|
||||||
bf_ikplugin
|
|
||||||
bf_modifiers
|
|
||||||
bf_bmesh
|
|
||||||
bf_blenkernel
|
|
||||||
bf_nodes
|
|
||||||
bf_gpu
|
|
||||||
bf_blenloader
|
|
||||||
bf_imbuf
|
|
||||||
bf_blenlib
|
|
||||||
bf_intern_ghost
|
|
||||||
bf_intern_string
|
|
||||||
bf_avi
|
|
||||||
bf_imbuf_cineon
|
|
||||||
bf_imbuf_openexr
|
|
||||||
bf_imbuf_openimageio
|
|
||||||
bf_imbuf_dds
|
|
||||||
bf_collada
|
|
||||||
bf_intern_elbeem
|
|
||||||
bf_intern_memutil
|
|
||||||
bf_intern_guardedalloc
|
|
||||||
bf_intern_ctr
|
|
||||||
bf_intern_utfconv
|
|
||||||
ge_blen_routines
|
|
||||||
ge_converter
|
|
||||||
ge_phys_dummy
|
|
||||||
ge_phys_bullet
|
|
||||||
bf_intern_smoke
|
|
||||||
extern_minilzo
|
|
||||||
extern_lzma
|
|
||||||
extern_colamd
|
|
||||||
ge_logic_ketsji
|
|
||||||
extern_recastnavigation
|
|
||||||
ge_logic
|
|
||||||
ge_rasterizer
|
|
||||||
ge_oglrasterizer
|
|
||||||
ge_logic_expressions
|
|
||||||
ge_scenegraph
|
|
||||||
ge_logic_network
|
|
||||||
ge_logic_ngnetwork
|
|
||||||
ge_logic_loopbacknetwork
|
|
||||||
bf_intern_moto
|
|
||||||
extern_openjpeg
|
|
||||||
extern_redcode
|
|
||||||
ge_videotex
|
|
||||||
bf_rna
|
|
||||||
bf_dna
|
|
||||||
bf_blenfont
|
|
||||||
bf_intern_audaspace
|
|
||||||
bf_intern_mikktspace
|
|
||||||
bf_intern_dualcon
|
|
||||||
bf_intern_cycles
|
|
||||||
cycles_render
|
|
||||||
cycles_bvh
|
|
||||||
cycles_device
|
|
||||||
cycles_kernel
|
|
||||||
cycles_util
|
|
||||||
cycles_subd
|
|
||||||
bf_intern_raskter
|
|
||||||
bf_intern_opencolorio
|
|
||||||
extern_rangetree
|
|
||||||
extern_wcwidth
|
|
||||||
extern_libmv
|
|
||||||
)
|
|
||||||
|
|
||||||
if(WITH_COMPOSITOR)
|
|
||||||
# added for opencl compositor
|
|
||||||
list_insert_before(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_compositor")
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "bf_compositor" "bf_intern_opencl")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_LIBMV)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_ceres)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_MOD_CLOTH_ELTOPO)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT WITH_SYSTEM_GLEW)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_glew)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_BINRELOC)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_binreloc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_CXX_GUARDEDALLOC)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_IK_SOLVER)
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "bf_intern_elbeem" "bf_intern_iksolver")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_IK_ITASC)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS bf_intern_itasc)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_CODEC_QUICKTIME)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_INPUT_NDOF)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_MOD_BOOLEAN)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_carve)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_GHOST_XDND)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS extern_xdnd)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_CYCLES_OSL)
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "cycles_kernel" "cycles_kernel_osl")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_INTERNATIONAL)
|
|
||||||
list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_OPENNL)
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "bf_render" "bf_intern_opennl")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_BULLET)
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET)
|
|
||||||
list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
foreach(SORTLIB ${BLENDER_SORTED_LIBS})
|
|
||||||
set(REMLIB ${SORTLIB})
|
|
||||||
foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
|
|
||||||
if(${SEARCHLIB} STREQUAL ${SORTLIB})
|
|
||||||
set(REMLIB "")
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
if(REMLIB)
|
|
||||||
# message(STATUS "Removing library ${REMLIB} from blender linking because: not configured")
|
|
||||||
list(APPEND REM_MSG ${REMLIB})
|
|
||||||
list(REMOVE_ITEM BLENDER_SORTED_LIBS ${REMLIB})
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
if(REM_MSG)
|
|
||||||
list(SORT REM_MSG)
|
|
||||||
message(STATUS "Blender Skipping: (${REM_MSG})")
|
|
||||||
endif()
|
|
||||||
target_link_libraries(blender ${BLENDER_SORTED_LIBS})
|
|
||||||
|
|
||||||
unset(SEARCHLIB)
|
|
||||||
unset(SORTLIB)
|
|
||||||
unset(REMLIB)
|
|
||||||
unset(REM_MSG)
|
|
||||||
|
|
||||||
#else()
|
|
||||||
# target_link_libraries(blender ${BLENDER_LINK_LIBS})
|
|
||||||
#endif()
|
|
||||||
|
|
||||||
setup_liblinks(blender)
|
setup_liblinks(blender)
|
||||||
|
@ -2,3 +2,6 @@
|
|||||||
# Python CTests
|
# Python CTests
|
||||||
add_subdirectory(python)
|
add_subdirectory(python)
|
||||||
|
|
||||||
|
# GTest
|
||||||
|
add_subdirectory(gtests)
|
||||||
|
|
||||||
|
13
tests/gtests/CMakeLists.txt
Normal file
13
tests/gtests/CMakeLists.txt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
# GTest
|
||||||
|
if(WITH_TESTS)
|
||||||
|
|
||||||
|
Include(GTestTesting)
|
||||||
|
|
||||||
|
# Otherwise we get warnings here that we cant fix in external projects
|
||||||
|
remove_strict_flags()
|
||||||
|
|
||||||
|
add_subdirectory(testing)
|
||||||
|
add_subdirectory(blenlib)
|
||||||
|
endif()
|
||||||
|
|
88
tests/gtests/blenlib/BLI_math_color_test.cc
Normal file
88
tests/gtests/blenlib/BLI_math_color_test.cc
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "BLI_math.h"
|
||||||
|
|
||||||
|
TEST(mathutils, RGBToHSVRoundtrip)
|
||||||
|
{
|
||||||
|
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
|
||||||
|
float hsv[3], rgb[3];
|
||||||
|
rgb_to_hsv_v(orig_rgb, hsv);
|
||||||
|
hsv_to_rgb_v(hsv, rgb);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, RGBToHSLRoundtrip)
|
||||||
|
{
|
||||||
|
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
|
||||||
|
float hsl[3], rgb[3];
|
||||||
|
rgb_to_hsl_v(orig_rgb, hsl);
|
||||||
|
hsl_to_rgb_v(hsl, rgb);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, RGBToYUVRoundtrip)
|
||||||
|
{
|
||||||
|
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
|
||||||
|
float yuv[3], rgb[3];
|
||||||
|
rgb_to_yuv(orig_rgb[0], orig_rgb[1], orig_rgb[2],
|
||||||
|
&yuv[0], &yuv[1], &yuv[2]);
|
||||||
|
yuv_to_rgb(yuv[0], yuv[1], yuv[2],
|
||||||
|
&rgb[0], &rgb[1], &rgb[2]);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, RGBToYCCRoundtrip)
|
||||||
|
{
|
||||||
|
float orig_rgb[3] = {0.1f, 0.2f, 0.3f};
|
||||||
|
float ycc[3], rgb[3];
|
||||||
|
|
||||||
|
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2],
|
||||||
|
&ycc[0], &ycc[1], &ycc[2],
|
||||||
|
BLI_YCC_ITU_BT601);
|
||||||
|
ycc_to_rgb(ycc[0], ycc[1], ycc[2],
|
||||||
|
&rgb[0], &rgb[1], &rgb[2],
|
||||||
|
BLI_YCC_ITU_BT601);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
|
||||||
|
|
||||||
|
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2],
|
||||||
|
&ycc[0], &ycc[1], &ycc[2],
|
||||||
|
BLI_YCC_ITU_BT709);
|
||||||
|
ycc_to_rgb(ycc[0], ycc[1], ycc[2],
|
||||||
|
&rgb[0], &rgb[1], &rgb[2],
|
||||||
|
BLI_YCC_ITU_BT709);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
|
||||||
|
|
||||||
|
rgb_to_ycc(orig_rgb[0], orig_rgb[1], orig_rgb[2],
|
||||||
|
&ycc[0], &ycc[1], &ycc[2],
|
||||||
|
BLI_YCC_JFIF_0_255);
|
||||||
|
ycc_to_rgb(ycc[0], ycc[1], ycc[2],
|
||||||
|
&rgb[0], &rgb[1], &rgb[2],
|
||||||
|
BLI_YCC_JFIF_0_255);
|
||||||
|
EXPECT_V3_NEAR(orig_rgb, rgb, 1e-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, LinearRGBTosRGBNearZero)
|
||||||
|
{
|
||||||
|
float linear_color = 0.002f;
|
||||||
|
float srgb_color = linearrgb_to_srgb(linear_color);
|
||||||
|
EXPECT_NEAR(0.02584f, srgb_color, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, LinearRGBTosRGB)
|
||||||
|
{
|
||||||
|
float linear_color = 0.75f;
|
||||||
|
float srgb_color = linearrgb_to_srgb(linear_color);
|
||||||
|
EXPECT_NEAR(0.880824f, srgb_color, 1e-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, LinearRGBTosRGBRoundtrip)
|
||||||
|
{
|
||||||
|
const int N = 50;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < N; ++i) {
|
||||||
|
float orig_linear_color = (float) i / N;
|
||||||
|
float srgb_color = linearrgb_to_srgb(orig_linear_color);
|
||||||
|
float linear_color = srgb_to_linearrgb(srgb_color);
|
||||||
|
EXPECT_NEAR(orig_linear_color, linear_color, 1e-5);
|
||||||
|
}
|
||||||
|
}
|
21
tests/gtests/blenlib/BLI_math_geom_test.cc
Normal file
21
tests/gtests/blenlib/BLI_math_geom_test.cc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "BLI_math.h"
|
||||||
|
|
||||||
|
TEST(mathutils, DistToLine2DSimple)
|
||||||
|
{
|
||||||
|
float p[2] = {5.0f, 1.0f},
|
||||||
|
a[2] = {0.0f, 0.0f},
|
||||||
|
b[2] = {2.0f, 0.0f};
|
||||||
|
float distance = dist_to_line_v2(p, a, b);
|
||||||
|
EXPECT_NEAR(1.0f, distance, 1e-6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mathutils, DistToLineSegment2DSimple)
|
||||||
|
{
|
||||||
|
float p[2] = {3.0f, 1.0f},
|
||||||
|
a[2] = {0.0f, 0.0f},
|
||||||
|
b[2] = {2.0f, 0.0f};
|
||||||
|
float distance = dist_to_line_segment_v2(p, a, b);
|
||||||
|
EXPECT_NEAR(sqrtf(2.0f), distance, 1e-6);
|
||||||
|
}
|
219
tests/gtests/blenlib/BLI_path_util_test.cc
Normal file
219
tests/gtests/blenlib/BLI_path_util_test.cc
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "BLI_fileops.h"
|
||||||
|
#include "BLI_path_util.h"
|
||||||
|
#include "../../../source/blender/imbuf/IMB_imbuf.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* stubs */
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
const char *GHOST_getUserDir(int version, const char *versionstr);
|
||||||
|
const char *GHOST_getSystemDir(int version, const char *versionstr);
|
||||||
|
#ifdef __linux__
|
||||||
|
char *zLhm65070058860608_br_find_exe(const char *default_exe);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char *GHOST_getUserDir(int version, const char *versionstr)
|
||||||
|
{
|
||||||
|
return "/home/user";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *GHOST_getSystemDir(int version, const char *versionstr)
|
||||||
|
{
|
||||||
|
return "/system/path";
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ImBuf;
|
||||||
|
void IMB_freeImBuf(struct ImBuf *ibuf) {}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
char *zLhm65070058860608_br_find_exe(const char *default_exe)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* tests */
|
||||||
|
|
||||||
|
/* BLI_cleanup_path */
|
||||||
|
TEST(pathutils, PathUtilClean)
|
||||||
|
{
|
||||||
|
/* "/./" -> "/" */
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "/a/./b/./c/./";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("/a/b/c/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "/./././";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "/a/./././b/";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("/a/b/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "//" -> "/" */
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "a////";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("a/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0) /* FIXME */
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "./a////";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("./a/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* "foo/bar/../" -> "foo/" */
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "/a/b/c/../../../";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "/a/../a/b/../b/c/../c/";
|
||||||
|
BLI_cleanup_path(NULL, path);
|
||||||
|
EXPECT_STREQ("/a/b/c/", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "//../";
|
||||||
|
BLI_cleanup_path("/a/b/c/", path);
|
||||||
|
EXPECT_STREQ("/a/b/", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BLI_path_frame */
|
||||||
|
TEST(pathutils, PathUtilFrame)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "";
|
||||||
|
ret = BLI_path_frame(path, 123, 1);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("123", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "";
|
||||||
|
ret = BLI_path_frame(path, 123, 12);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("000000000123", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "test_";
|
||||||
|
ret = BLI_path_frame(path, 123, 1);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("test_123", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "test_";
|
||||||
|
ret = BLI_path_frame(path, 1, 12);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("test_000000000001", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "test_############";
|
||||||
|
ret = BLI_path_frame(path, 1, 0);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("test_000000000001", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "test_#_#_middle";
|
||||||
|
ret = BLI_path_frame(path, 123, 0);
|
||||||
|
EXPECT_EQ(1, ret);
|
||||||
|
EXPECT_STREQ("test_#_123_middle", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* intentionally fail */
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "";
|
||||||
|
ret = BLI_path_frame(path, 123, 0);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_STREQ("", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
char path[FILE_MAX] = "test_middle";
|
||||||
|
ret = BLI_path_frame(path, 123, 0);
|
||||||
|
EXPECT_EQ(0, ret);
|
||||||
|
EXPECT_STREQ("test_middle", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BLI_split_dirfile */
|
||||||
|
TEST(pathutils, PathUtilSplitDirfile)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
const char *path = "";
|
||||||
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("", dir);
|
||||||
|
EXPECT_STREQ("", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *path = "/";
|
||||||
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("/", dir);
|
||||||
|
EXPECT_STREQ("", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *path = "fileonly";
|
||||||
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("", dir);
|
||||||
|
EXPECT_STREQ("fileonly", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *path = "dironly/";
|
||||||
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("dironly/", dir);
|
||||||
|
EXPECT_STREQ("", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *path = "/a/b";
|
||||||
|
char dir[FILE_MAX], file[FILE_MAX];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("/a/", dir);
|
||||||
|
EXPECT_STREQ("b", file);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *path = "/dirtoobig/filetoobig";
|
||||||
|
char dir[5], file[5];
|
||||||
|
BLI_split_dirfile(path, dir, file, sizeof(dir), sizeof(file));
|
||||||
|
EXPECT_STREQ("/dir", dir);
|
||||||
|
EXPECT_STREQ("file", file);
|
||||||
|
|
||||||
|
BLI_split_dirfile(path, dir, file, 1, 1);
|
||||||
|
EXPECT_STREQ("", dir);
|
||||||
|
EXPECT_STREQ("", file);
|
||||||
|
}
|
||||||
|
}
|
39
tests/gtests/blenlib/CMakeLists.txt
Normal file
39
tests/gtests/blenlib/CMakeLists.txt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# The Original Code is Copyright (C) 2014, Blender Foundation
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Sergey Sharybin
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../
|
||||||
|
../../../source/blender/blenlib
|
||||||
|
../../../intern/guardedalloc
|
||||||
|
)
|
||||||
|
|
||||||
|
include_directories(${INC})
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${PLATFORM_LINKFLAGS_DEBUG}")
|
||||||
|
|
||||||
|
|
||||||
|
BLENDER_TEST(BLI_math_color "bf_blenlib")
|
||||||
|
BLENDER_TEST(BLI_math_geom "bf_blenlib")
|
||||||
|
BLENDER_TEST(BLI_path_util "bf_blenlib;extern_wcwidth;${ZLIB_LIBRARIES}")
|
48
tests/gtests/testing/CMakeLists.txt
Normal file
48
tests/gtests/testing/CMakeLists.txt
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License
|
||||||
|
# as published by the Free Software Foundation; either version 2
|
||||||
|
# of the License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
#
|
||||||
|
# The Original Code is Copyright (C) 2014, Blender Foundation
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# Contributor(s): Sergey Sharybin
|
||||||
|
#
|
||||||
|
# ***** END GPL LICENSE BLOCK *****
|
||||||
|
|
||||||
|
set(INC
|
||||||
|
.
|
||||||
|
../
|
||||||
|
../../../extern/libmv/third_party/gflags
|
||||||
|
../../../extern/gtest/include
|
||||||
|
)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
list(APPEND INC
|
||||||
|
../../../extern/libmv/third_party/glog/src/windows
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
list(APPEND INC
|
||||||
|
../../../extern/libmv/third_party/glog/src
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(INC_SYS
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SRC
|
||||||
|
testing_main.cc
|
||||||
|
)
|
||||||
|
|
||||||
|
blender_add_lib(bf_testing_main "${SRC}" "${INC}" "${INC_SYS}")
|
78
tests/gtests/testing/testing.h
Normal file
78
tests/gtests/testing/testing.h
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef __BLENDER_TESTING_H__
|
||||||
|
#define __BLENDER_TESTING_H__
|
||||||
|
|
||||||
|
#include "glog/logging.h"
|
||||||
|
#include "gflags/gflags.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
#define EXPECT_V3_NEAR(a, b, eps) \
|
||||||
|
{ \
|
||||||
|
EXPECT_NEAR(a[0], b[0], eps); \
|
||||||
|
EXPECT_NEAR(a[1], b[1], eps); \
|
||||||
|
EXPECT_NEAR(a[2], b[2], eps); \
|
||||||
|
} (void) 0
|
||||||
|
|
||||||
|
#define EXPECT_MATRIX_NEAR(a, b, tolerance) \
|
||||||
|
do { \
|
||||||
|
bool dims_match = (a.rows() == b.rows()) && (a.cols() == b.cols()); \
|
||||||
|
EXPECT_EQ(a.rows(), b.rows()) << "Matrix rows don't match."; \
|
||||||
|
EXPECT_EQ(a.cols(), b.cols()) << "Matrix cols don't match."; \
|
||||||
|
if (dims_match) { \
|
||||||
|
for (int r = 0; r < a.rows(); ++r) { \
|
||||||
|
for (int c = 0; c < a.cols(); ++c) { \
|
||||||
|
EXPECT_NEAR(a(r, c), b(r, c), tolerance) \
|
||||||
|
<< "r=" << r << ", c=" << c << "."; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
#define EXPECT_MATRIX_NEAR_ZERO(a, tolerance) \
|
||||||
|
do { \
|
||||||
|
for (int r = 0; r < a.rows(); ++r) { \
|
||||||
|
for (int c = 0; c < a.cols(); ++c) { \
|
||||||
|
EXPECT_NEAR(0.0, a(r, c), tolerance) \
|
||||||
|
<< "r=" << r << ", c=" << c << "."; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
#define EXPECT_MATRIX_EQ(a, b) \
|
||||||
|
do { \
|
||||||
|
bool dims_match = (a.rows() == b.rows()) && (a.cols() == b.cols()); \
|
||||||
|
EXPECT_EQ(a.rows(), b.rows()) << "Matrix rows don't match."; \
|
||||||
|
EXPECT_EQ(a.cols(), b.cols()) << "Matrix cols don't match."; \
|
||||||
|
if (dims_match) { \
|
||||||
|
for (int r = 0; r < a.rows(); ++r) { \
|
||||||
|
for (int c = 0; c < a.cols(); ++c) { \
|
||||||
|
EXPECT_EQ(a(r, c), b(r, c)) \
|
||||||
|
<< "r=" << r << ", c=" << c << "."; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
// Check that sin(angle(a, b)) < tolerance.
|
||||||
|
#define EXPECT_MATRIX_PROP(a, b, tolerance) \
|
||||||
|
do { \
|
||||||
|
bool dims_match = (a.rows() == b.rows()) && (a.cols() == b.cols()); \
|
||||||
|
EXPECT_EQ(a.rows(), b.rows()) << "Matrix rows don't match."; \
|
||||||
|
EXPECT_EQ(a.cols(), b.cols()) << "Matrix cols don't match."; \
|
||||||
|
if (dims_match) { \
|
||||||
|
double c = CosinusBetweenMatrices(a, b); \
|
||||||
|
if (c * c < 1) { \
|
||||||
|
double s = sqrt(1 - c * c); \
|
||||||
|
EXPECT_NEAR(0, s, tolerance); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
#ifdef LIBMV_NUMERIC_NUMERIC_H
|
||||||
|
template<class TMat>
|
||||||
|
double CosinusBetweenMatrices(const TMat &a, const TMat &b) {
|
||||||
|
return (a.array() * b.array()).sum() /
|
||||||
|
libmv::FrobeniusNorm(a) / libmv::FrobeniusNorm(b);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // __BLENDER_TESTING_H__
|
36
tests/gtests/testing/testing_main.cc
Normal file
36
tests/gtests/testing/testing_main.cc
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* The Original Code is Copyright (C) 2014 Blender Foundation.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s): Blender Foundation,
|
||||||
|
* Sergey Sharybin
|
||||||
|
*
|
||||||
|
* ***** END GPL LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
google::ParseCommandLineFlags(&argc, &argv, true);
|
||||||
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user